@solaqua/gji 0.6.1 → 0.6.2
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/gji-bundle.mjs +89 -35
- package/dist/repo-registry.js +32 -6
- package/dist/warp.js +31 -3
- 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-go.1 +1 -1
- package/man/man1/gji-history.1 +1 -1
- package/man/man1/gji-init.1 +1 -1
- 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 +1 -1
- package/man/man1/gji-remove.1 +1 -1
- package/man/man1/gji-root.1 +1 -1
- package/man/man1/gji-status.1 +1 -1
- package/man/man1/gji-sync.1 +1 -1
- package/man/man1/gji-trigger-hook.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +1 -1
- package/package.json +1 -1
package/dist/gji-bundle.mjs
CHANGED
|
@@ -9740,7 +9740,7 @@ var retryifyAsync = (fn, options) => {
|
|
|
9740
9740
|
throw error;
|
|
9741
9741
|
const delay2 = Math.round(interval * Math.random());
|
|
9742
9742
|
if (delay2 > 0) {
|
|
9743
|
-
const delayPromise = new Promise((
|
|
9743
|
+
const delayPromise = new Promise((resolve6) => setTimeout(resolve6, delay2));
|
|
9744
9744
|
return delayPromise.then(() => attempt.apply(void 0, args));
|
|
9745
9745
|
} else {
|
|
9746
9746
|
return attempt.apply(void 0, args);
|
|
@@ -9999,14 +9999,14 @@ var Temp = {
|
|
|
9999
9999
|
}
|
|
10000
10000
|
},
|
|
10001
10001
|
truncate: (filePath) => {
|
|
10002
|
-
const
|
|
10003
|
-
if (
|
|
10002
|
+
const basename9 = path2.basename(filePath);
|
|
10003
|
+
if (basename9.length <= LIMIT_BASENAME_LENGTH)
|
|
10004
10004
|
return filePath;
|
|
10005
|
-
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(
|
|
10005
|
+
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename9);
|
|
10006
10006
|
if (!truncable)
|
|
10007
10007
|
return filePath;
|
|
10008
|
-
const truncationLength =
|
|
10009
|
-
return `${filePath.slice(0, -
|
|
10008
|
+
const truncationLength = basename9.length - LIMIT_BASENAME_LENGTH;
|
|
10009
|
+
return `${filePath.slice(0, -basename9.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
|
|
10010
10010
|
}
|
|
10011
10011
|
};
|
|
10012
10012
|
node_default(Temp.purgeSyncAll);
|
|
@@ -11306,14 +11306,14 @@ var TimeoutError = class extends Error {
|
|
|
11306
11306
|
|
|
11307
11307
|
// node_modules/.pnpm/ky@1.14.3/node_modules/ky/distribution/utils/timeout.js
|
|
11308
11308
|
async function timeout(request, init, abortController, options) {
|
|
11309
|
-
return new Promise((
|
|
11309
|
+
return new Promise((resolve6, reject) => {
|
|
11310
11310
|
const timeoutId = setTimeout(() => {
|
|
11311
11311
|
if (abortController) {
|
|
11312
11312
|
abortController.abort();
|
|
11313
11313
|
}
|
|
11314
11314
|
reject(new TimeoutError(request));
|
|
11315
11315
|
}, options.timeout);
|
|
11316
|
-
void options.fetch(request, init).then(
|
|
11316
|
+
void options.fetch(request, init).then(resolve6).catch(reject).then(() => {
|
|
11317
11317
|
clearTimeout(timeoutId);
|
|
11318
11318
|
});
|
|
11319
11319
|
});
|
|
@@ -11321,7 +11321,7 @@ async function timeout(request, init, abortController, options) {
|
|
|
11321
11321
|
|
|
11322
11322
|
// node_modules/.pnpm/ky@1.14.3/node_modules/ky/distribution/utils/delay.js
|
|
11323
11323
|
async function delay(ms, { signal }) {
|
|
11324
|
-
return new Promise((
|
|
11324
|
+
return new Promise((resolve6, reject) => {
|
|
11325
11325
|
if (signal) {
|
|
11326
11326
|
signal.throwIfAborted();
|
|
11327
11327
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
@@ -11332,7 +11332,7 @@ async function delay(ms, { signal }) {
|
|
|
11332
11332
|
}
|
|
11333
11333
|
const timeoutId = setTimeout(() => {
|
|
11334
11334
|
signal?.removeEventListener("abort", abortHandler);
|
|
11335
|
-
|
|
11335
|
+
resolve6();
|
|
11336
11336
|
}, ms);
|
|
11337
11337
|
});
|
|
11338
11338
|
}
|
|
@@ -13048,7 +13048,7 @@ async function runArgvHook(hookCmd, cwd, context, stderr) {
|
|
|
13048
13048
|
stderr("gji: hook argv command must include a non-empty command\n");
|
|
13049
13049
|
return;
|
|
13050
13050
|
}
|
|
13051
|
-
await new Promise((
|
|
13051
|
+
await new Promise((resolve6) => {
|
|
13052
13052
|
const child = spawn2(command, args, {
|
|
13053
13053
|
cwd,
|
|
13054
13054
|
shell: false,
|
|
@@ -13063,18 +13063,18 @@ async function runArgvHook(hookCmd, cwd, context, stderr) {
|
|
|
13063
13063
|
stderr(`gji: hook exited with code ${code}: ${formatArgvHook(command, args)}
|
|
13064
13064
|
`);
|
|
13065
13065
|
}
|
|
13066
|
-
|
|
13066
|
+
resolve6();
|
|
13067
13067
|
});
|
|
13068
13068
|
child.on("error", (err) => {
|
|
13069
13069
|
stderr(`gji: hook failed to start: ${err.message}
|
|
13070
13070
|
`);
|
|
13071
|
-
|
|
13071
|
+
resolve6();
|
|
13072
13072
|
});
|
|
13073
13073
|
});
|
|
13074
13074
|
}
|
|
13075
13075
|
async function runShellHook(hookCmd, cwd, context, stderr) {
|
|
13076
13076
|
const interpolated = interpolate(hookCmd, context);
|
|
13077
|
-
await new Promise((
|
|
13077
|
+
await new Promise((resolve6) => {
|
|
13078
13078
|
const child = spawn2(interpolated, {
|
|
13079
13079
|
cwd,
|
|
13080
13080
|
shell: true,
|
|
@@ -13089,12 +13089,12 @@ async function runShellHook(hookCmd, cwd, context, stderr) {
|
|
|
13089
13089
|
stderr(`gji: hook exited with code ${code}: ${interpolated}
|
|
13090
13090
|
`);
|
|
13091
13091
|
}
|
|
13092
|
-
|
|
13092
|
+
resolve6();
|
|
13093
13093
|
});
|
|
13094
13094
|
child.on("error", (err) => {
|
|
13095
13095
|
stderr(`gji: hook failed to start: ${err.message}
|
|
13096
13096
|
`);
|
|
13097
|
-
|
|
13097
|
+
resolve6();
|
|
13098
13098
|
});
|
|
13099
13099
|
});
|
|
13100
13100
|
}
|
|
@@ -14881,7 +14881,11 @@ function writeJson(stdout, value) {
|
|
|
14881
14881
|
}
|
|
14882
14882
|
|
|
14883
14883
|
// src/go.ts
|
|
14884
|
-
import { basename as
|
|
14884
|
+
import { basename as basename6 } from "node:path";
|
|
14885
|
+
|
|
14886
|
+
// src/warp.ts
|
|
14887
|
+
import { realpath as realpath2 } from "node:fs/promises";
|
|
14888
|
+
import { basename as basename5, resolve as resolve5 } from "node:path";
|
|
14885
14889
|
|
|
14886
14890
|
// src/new.ts
|
|
14887
14891
|
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
@@ -14900,9 +14904,9 @@ var EDITORS = [
|
|
|
14900
14904
|
];
|
|
14901
14905
|
async function defaultSpawnEditor(cli, args) {
|
|
14902
14906
|
const child = spawn3(cli, args, { detached: true, stdio: "ignore" });
|
|
14903
|
-
await new Promise((
|
|
14907
|
+
await new Promise((resolve6, reject) => {
|
|
14904
14908
|
child.once("error", reject);
|
|
14905
|
-
child.once("spawn",
|
|
14909
|
+
child.once("spawn", resolve6);
|
|
14906
14910
|
});
|
|
14907
14911
|
child.unref();
|
|
14908
14912
|
}
|
|
@@ -15117,7 +15121,7 @@ async function maybeRunInstallPrompt(worktreePath, repoRoot, config, stderr, dep
|
|
|
15117
15121
|
}
|
|
15118
15122
|
}
|
|
15119
15123
|
async function defaultRunInstallCommand(command, cwd, stderr) {
|
|
15120
|
-
await new Promise((
|
|
15124
|
+
await new Promise((resolve6, reject) => {
|
|
15121
15125
|
const child = spawn4(command, { cwd, shell: true, stdio: ["ignore", "inherit", "pipe"] });
|
|
15122
15126
|
child.stderr.on("data", (chunk) => {
|
|
15123
15127
|
stderr(chunk.toString());
|
|
@@ -15126,7 +15130,7 @@ async function defaultRunInstallCommand(command, cwd, stderr) {
|
|
|
15126
15130
|
if (code !== 0) {
|
|
15127
15131
|
reject(new Error(`exited with code ${code}`));
|
|
15128
15132
|
} else {
|
|
15129
|
-
|
|
15133
|
+
resolve6();
|
|
15130
15134
|
}
|
|
15131
15135
|
});
|
|
15132
15136
|
child.on("error", (err) => {
|
|
@@ -15467,7 +15471,7 @@ async function openWorktree(worktreePath, editorCli, spawnFn, stderr) {
|
|
|
15467
15471
|
}
|
|
15468
15472
|
|
|
15469
15473
|
// src/repo-registry.ts
|
|
15470
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
15474
|
+
import { mkdir as mkdir5, readFile as readFile3, realpath, writeFile as writeFile4 } from "node:fs/promises";
|
|
15471
15475
|
import { homedir as homedir4 } from "node:os";
|
|
15472
15476
|
import { basename as basename4, dirname as dirname6, join as join6, resolve as resolve4 } from "node:path";
|
|
15473
15477
|
var REGISTRY_FILE_NAME = "repos.json";
|
|
@@ -15490,21 +15494,46 @@ async function loadRegistry(home = homedir4()) {
|
|
|
15490
15494
|
return [];
|
|
15491
15495
|
}
|
|
15492
15496
|
}
|
|
15497
|
+
async function canonicalizeRepoPath(repoPath) {
|
|
15498
|
+
try {
|
|
15499
|
+
return await realpath(repoPath);
|
|
15500
|
+
} catch {
|
|
15501
|
+
return resolve4(repoPath);
|
|
15502
|
+
}
|
|
15503
|
+
}
|
|
15493
15504
|
async function registerRepo(repoPath, home = homedir4()) {
|
|
15494
15505
|
const registryPath = REGISTRY_FILE_PATH(home);
|
|
15495
|
-
const existing = await loadRegistry(home);
|
|
15496
|
-
|
|
15506
|
+
const existing = await normalizeRegistryForWrite(await loadRegistry(home));
|
|
15507
|
+
const canonicalRepoPath = await canonicalizeRepoPath(repoPath);
|
|
15508
|
+
if (existing.length > 0 && existing[0].path === canonicalRepoPath) return;
|
|
15497
15509
|
const entry = {
|
|
15498
15510
|
lastUsed: Date.now(),
|
|
15499
|
-
name: basename4(
|
|
15500
|
-
path:
|
|
15511
|
+
name: basename4(canonicalRepoPath),
|
|
15512
|
+
path: canonicalRepoPath
|
|
15501
15513
|
};
|
|
15502
|
-
const filtered = existing.filter((e2) => e2.path !==
|
|
15514
|
+
const filtered = existing.filter((e2) => e2.path !== canonicalRepoPath);
|
|
15503
15515
|
const next = [entry, ...filtered].slice(0, MAX_REGISTRY_ENTRIES);
|
|
15504
15516
|
await mkdir5(dirname6(registryPath), { recursive: true });
|
|
15505
15517
|
await writeFile4(registryPath, `${JSON.stringify(next, null, 2)}
|
|
15506
15518
|
`, "utf8");
|
|
15507
15519
|
}
|
|
15520
|
+
async function normalizeRegistryForWrite(entries) {
|
|
15521
|
+
const normalized = [];
|
|
15522
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
15523
|
+
for (const entry of entries) {
|
|
15524
|
+
const canonicalPath = await canonicalizeRepoPath(entry.path);
|
|
15525
|
+
if (seenPaths.has(canonicalPath)) {
|
|
15526
|
+
continue;
|
|
15527
|
+
}
|
|
15528
|
+
seenPaths.add(canonicalPath);
|
|
15529
|
+
normalized.push({
|
|
15530
|
+
...entry,
|
|
15531
|
+
name: basename4(canonicalPath),
|
|
15532
|
+
path: canonicalPath
|
|
15533
|
+
});
|
|
15534
|
+
}
|
|
15535
|
+
return normalized;
|
|
15536
|
+
}
|
|
15508
15537
|
function isRegistryEntry(value) {
|
|
15509
15538
|
return typeof value === "object" && value !== null && "path" in value && typeof value.path === "string" && "name" in value && typeof value.name === "string" && "lastUsed" in value && typeof value.lastUsed === "number";
|
|
15510
15539
|
}
|
|
@@ -15549,9 +15578,10 @@ async function runWarpNavigate(options) {
|
|
|
15549
15578
|
return 0;
|
|
15550
15579
|
}
|
|
15551
15580
|
async function runWarpNew(options, registry) {
|
|
15581
|
+
const deduplicatedRegistry = await deduplicateRegistryForNew(registry);
|
|
15552
15582
|
let targetRepoRoot;
|
|
15553
|
-
if (
|
|
15554
|
-
targetRepoRoot =
|
|
15583
|
+
if (deduplicatedRegistry.length === 1) {
|
|
15584
|
+
targetRepoRoot = deduplicatedRegistry[0].path;
|
|
15555
15585
|
} else {
|
|
15556
15586
|
if (isHeadless()) {
|
|
15557
15587
|
options.stderr(
|
|
@@ -15561,7 +15591,7 @@ async function runWarpNew(options, registry) {
|
|
|
15561
15591
|
}
|
|
15562
15592
|
const choice = await ve({
|
|
15563
15593
|
message: "Create worktree in which repo?",
|
|
15564
|
-
options:
|
|
15594
|
+
options: deduplicatedRegistry.map((entry) => ({
|
|
15565
15595
|
value: entry.path,
|
|
15566
15596
|
label: entry.name,
|
|
15567
15597
|
hint: entry.path
|
|
@@ -15602,6 +15632,30 @@ async function runWarpNew(options, registry) {
|
|
|
15602
15632
|
await writeShellOutput(WARP_OUTPUT_FILE_ENV, capturedPath, options.stdout);
|
|
15603
15633
|
return 0;
|
|
15604
15634
|
}
|
|
15635
|
+
async function deduplicateRegistryForNew(registry) {
|
|
15636
|
+
const deduplicated = [];
|
|
15637
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
15638
|
+
for (const entry of registry) {
|
|
15639
|
+
const canonicalPath = await canonicalizeRepoPath2(entry.path);
|
|
15640
|
+
if (seenPaths.has(canonicalPath)) {
|
|
15641
|
+
continue;
|
|
15642
|
+
}
|
|
15643
|
+
seenPaths.add(canonicalPath);
|
|
15644
|
+
deduplicated.push({
|
|
15645
|
+
...entry,
|
|
15646
|
+
name: basename5(canonicalPath),
|
|
15647
|
+
path: canonicalPath
|
|
15648
|
+
});
|
|
15649
|
+
}
|
|
15650
|
+
return deduplicated;
|
|
15651
|
+
}
|
|
15652
|
+
async function canonicalizeRepoPath2(repoPath) {
|
|
15653
|
+
try {
|
|
15654
|
+
return await realpath2(repoPath);
|
|
15655
|
+
} catch {
|
|
15656
|
+
return resolve5(repoPath);
|
|
15657
|
+
}
|
|
15658
|
+
}
|
|
15605
15659
|
function findByQuery(items, query) {
|
|
15606
15660
|
const slashIdx = query.indexOf("/");
|
|
15607
15661
|
if (slashIdx !== -1) {
|
|
@@ -15746,7 +15800,7 @@ function createGoCommand(dependencies = {}) {
|
|
|
15746
15800
|
await runHook(
|
|
15747
15801
|
hooks.afterEnter,
|
|
15748
15802
|
resolvedPath,
|
|
15749
|
-
{ branch: chosenWorktree?.branch ?? void 0, path: resolvedPath, repo:
|
|
15803
|
+
{ branch: chosenWorktree?.branch ?? void 0, path: resolvedPath, repo: basename6(repository.repoRoot) },
|
|
15750
15804
|
options.stderr
|
|
15751
15805
|
);
|
|
15752
15806
|
appendHistory(resolvedPath, chosenWorktree?.branch ?? null).catch(() => void 0);
|
|
@@ -16320,7 +16374,7 @@ function sortWorktrees(worktrees) {
|
|
|
16320
16374
|
|
|
16321
16375
|
// src/pr.ts
|
|
16322
16376
|
import { mkdir as mkdir7 } from "node:fs/promises";
|
|
16323
|
-
import { basename as
|
|
16377
|
+
import { basename as basename7, dirname as dirname8 } from "node:path";
|
|
16324
16378
|
import { execFile as execFile5 } from "node:child_process";
|
|
16325
16379
|
import { promisify as promisify6 } from "node:util";
|
|
16326
16380
|
var execFileAsync5 = promisify6(execFile5);
|
|
@@ -16422,7 +16476,7 @@ function createPrCommand(dependencies = {}) {
|
|
|
16422
16476
|
await runHook(
|
|
16423
16477
|
hooks.afterCreate,
|
|
16424
16478
|
worktreePath,
|
|
16425
|
-
{ branch: branchName, path: worktreePath, repo:
|
|
16479
|
+
{ branch: branchName, path: worktreePath, repo: basename7(repository.repoRoot) },
|
|
16426
16480
|
options.stderr
|
|
16427
16481
|
);
|
|
16428
16482
|
if (options.json) {
|
|
@@ -16495,7 +16549,7 @@ async function writeOutput2(worktreePath, stdout) {
|
|
|
16495
16549
|
}
|
|
16496
16550
|
|
|
16497
16551
|
// src/remove.ts
|
|
16498
|
-
import { basename as
|
|
16552
|
+
import { basename as basename8 } from "node:path";
|
|
16499
16553
|
var REMOVE_OUTPUT_FILE_ENV = "GJI_REMOVE_OUTPUT_FILE";
|
|
16500
16554
|
function createRemoveCommand(dependencies = {}) {
|
|
16501
16555
|
const promptForWorktree2 = dependencies.promptForWorktree ?? defaultPromptForWorktree2;
|
|
@@ -16560,7 +16614,7 @@ function createRemoveCommand(dependencies = {}) {
|
|
|
16560
16614
|
await runHook(
|
|
16561
16615
|
hooks.beforeRemove,
|
|
16562
16616
|
worktree.path,
|
|
16563
|
-
{ branch: worktree.branch ?? void 0, path: worktree.path, repo:
|
|
16617
|
+
{ branch: worktree.branch ?? void 0, path: worktree.path, repo: basename8(repository.repoRoot) },
|
|
16564
16618
|
options.stderr
|
|
16565
16619
|
);
|
|
16566
16620
|
try {
|
package/dist/repo-registry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
4
4
|
import { GLOBAL_CONFIG_DIRECTORY } from './config.js';
|
|
@@ -24,22 +24,48 @@ export async function loadRegistry(home = homedir()) {
|
|
|
24
24
|
return [];
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
async function canonicalizeRepoPath(repoPath) {
|
|
28
|
+
try {
|
|
29
|
+
return await realpath(repoPath);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return resolve(repoPath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
27
35
|
export async function registerRepo(repoPath, home = homedir()) {
|
|
28
36
|
const registryPath = REGISTRY_FILE_PATH(home);
|
|
29
|
-
const existing = await loadRegistry(home);
|
|
37
|
+
const existing = await normalizeRegistryForWrite(await loadRegistry(home));
|
|
38
|
+
const canonicalRepoPath = await canonicalizeRepoPath(repoPath);
|
|
30
39
|
// Skip write if this repo is already the most-recently-used entry (common case).
|
|
31
|
-
if (existing.length > 0 && existing[0].path ===
|
|
40
|
+
if (existing.length > 0 && existing[0].path === canonicalRepoPath)
|
|
32
41
|
return;
|
|
33
42
|
const entry = {
|
|
34
43
|
lastUsed: Date.now(),
|
|
35
|
-
name: basename(
|
|
36
|
-
path:
|
|
44
|
+
name: basename(canonicalRepoPath),
|
|
45
|
+
path: canonicalRepoPath,
|
|
37
46
|
};
|
|
38
|
-
const filtered = existing.filter((e) => e.path !==
|
|
47
|
+
const filtered = existing.filter((e) => e.path !== canonicalRepoPath);
|
|
39
48
|
const next = [entry, ...filtered].slice(0, MAX_REGISTRY_ENTRIES);
|
|
40
49
|
await mkdir(dirname(registryPath), { recursive: true });
|
|
41
50
|
await writeFile(registryPath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
|
|
42
51
|
}
|
|
52
|
+
async function normalizeRegistryForWrite(entries) {
|
|
53
|
+
const normalized = [];
|
|
54
|
+
const seenPaths = new Set();
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
const canonicalPath = await canonicalizeRepoPath(entry.path);
|
|
57
|
+
if (seenPaths.has(canonicalPath)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
seenPaths.add(canonicalPath);
|
|
61
|
+
normalized.push({
|
|
62
|
+
...entry,
|
|
63
|
+
name: basename(canonicalPath),
|
|
64
|
+
path: canonicalPath,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return normalized;
|
|
68
|
+
}
|
|
43
69
|
function isRegistryEntry(value) {
|
|
44
70
|
return (typeof value === 'object' &&
|
|
45
71
|
value !== null &&
|
package/dist/warp.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isCancel, select } from '@clack/prompts';
|
|
2
|
+
import { realpath } from 'node:fs/promises';
|
|
3
|
+
import { basename, resolve } from 'node:path';
|
|
2
4
|
import { readWorktreeHealth } from './git.js';
|
|
3
5
|
import { isHeadless } from './headless.js';
|
|
4
6
|
import { appendHistory } from './history.js';
|
|
@@ -43,9 +45,10 @@ async function runWarpNavigate(options) {
|
|
|
43
45
|
return 0;
|
|
44
46
|
}
|
|
45
47
|
async function runWarpNew(options, registry) {
|
|
48
|
+
const deduplicatedRegistry = await deduplicateRegistryForNew(registry);
|
|
46
49
|
let targetRepoRoot;
|
|
47
|
-
if (
|
|
48
|
-
targetRepoRoot =
|
|
50
|
+
if (deduplicatedRegistry.length === 1) {
|
|
51
|
+
targetRepoRoot = deduplicatedRegistry[0].path;
|
|
49
52
|
}
|
|
50
53
|
else {
|
|
51
54
|
if (isHeadless()) {
|
|
@@ -54,7 +57,7 @@ async function runWarpNew(options, registry) {
|
|
|
54
57
|
}
|
|
55
58
|
const choice = await select({
|
|
56
59
|
message: 'Create worktree in which repo?',
|
|
57
|
-
options:
|
|
60
|
+
options: deduplicatedRegistry.map((entry) => ({
|
|
58
61
|
value: entry.path,
|
|
59
62
|
label: entry.name,
|
|
60
63
|
hint: entry.path,
|
|
@@ -98,6 +101,31 @@ async function runWarpNew(options, registry) {
|
|
|
98
101
|
await writeShellOutput(WARP_OUTPUT_FILE_ENV, capturedPath, options.stdout);
|
|
99
102
|
return 0;
|
|
100
103
|
}
|
|
104
|
+
async function deduplicateRegistryForNew(registry) {
|
|
105
|
+
const deduplicated = [];
|
|
106
|
+
const seenPaths = new Set();
|
|
107
|
+
for (const entry of registry) {
|
|
108
|
+
const canonicalPath = await canonicalizeRepoPath(entry.path);
|
|
109
|
+
if (seenPaths.has(canonicalPath)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
seenPaths.add(canonicalPath);
|
|
113
|
+
deduplicated.push({
|
|
114
|
+
...entry,
|
|
115
|
+
name: basename(canonicalPath),
|
|
116
|
+
path: canonicalPath,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return deduplicated;
|
|
120
|
+
}
|
|
121
|
+
async function canonicalizeRepoPath(repoPath) {
|
|
122
|
+
try {
|
|
123
|
+
return await realpath(repoPath);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return resolve(repoPath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
101
129
|
function findByQuery(items, query) {
|
|
102
130
|
const slashIdx = query.indexOf('/');
|
|
103
131
|
if (slashIdx !== -1) {
|
package/man/man1/gji-back.1
CHANGED
package/man/man1/gji-clean.1
CHANGED
package/man/man1/gji-config.1
CHANGED
package/man/man1/gji-go.1
CHANGED
package/man/man1/gji-history.1
CHANGED
package/man/man1/gji-init.1
CHANGED
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
package/man/man1/gji-remove.1
CHANGED
package/man/man1/gji-root.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