@junheep/gwt 0.1.0 → 0.1.1
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 +7 -4
- package/bin/gwt.mjs +54 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -141,7 +141,8 @@ pnpm install --frozen-lockfile
|
|
|
141
141
|
|
|
142
142
|
Hook paths in user config are resolved relative to the directory containing
|
|
143
143
|
`config.json`; hook paths in `.gwt.json` are resolved relative to the target
|
|
144
|
-
worktree. Both run with the target worktree as their working directory
|
|
144
|
+
worktree. Both run with the target worktree as their working directory, and
|
|
145
|
+
their standard output and errors are streamed directly to the terminal.
|
|
145
146
|
|
|
146
147
|
Hooks in user config are trusted because the user added them directly. Hooks
|
|
147
148
|
from a committed `.gwt.json` require explicit trust because they execute
|
|
@@ -184,6 +185,8 @@ arrow keys, `j`/`k`, or Ctrl-n/Ctrl-p to move; press 1–9 to select a numbered
|
|
|
184
185
|
row immediately; or press `/` to filter by branch, ID, or path. Enter switches
|
|
185
186
|
to the selected worktree. Escape leaves filter mode or cancels the picker.
|
|
186
187
|
|
|
187
|
-
`gwt remove` refuses dirty worktrees
|
|
188
|
-
`git branch -d
|
|
189
|
-
|
|
188
|
+
`gwt remove` refuses dirty worktrees and first tries to delete the branch with
|
|
189
|
+
`git branch -d`. If Git rejects safe deletion, an interactive terminal asks
|
|
190
|
+
whether to force-delete the branch; non-interactive use keeps it and prints a
|
|
191
|
+
command for deleting it later. `--discard --yes` explicitly allows dirty
|
|
192
|
+
worktree removal and forced branch deletion.
|
package/bin/gwt.mjs
CHANGED
|
@@ -496,14 +496,14 @@ function runHook(name, repository, configDocument, worktree, metadata) {
|
|
|
496
496
|
GWT_BRANCH: context.branch,
|
|
497
497
|
...Object.fromEntries(Object.entries(context.ports).map(([key, value]) => [key, String(value)])),
|
|
498
498
|
}
|
|
499
|
+
console.log(`Running ${name}...`)
|
|
499
500
|
const result = run(hook.path, [], {
|
|
500
501
|
cwd: context.path,
|
|
501
502
|
env,
|
|
502
503
|
input: `${JSON.stringify(context)}\n`,
|
|
503
504
|
allowFailure: true,
|
|
505
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
504
506
|
})
|
|
505
|
-
if (result.stdout) process.stdout.write(result.stdout)
|
|
506
|
-
if (result.stderr) process.stderr.write(result.stderr)
|
|
507
507
|
if (result.status !== 0) throw new CliError(`${name} failed with status ${result.status}`)
|
|
508
508
|
}
|
|
509
509
|
|
|
@@ -817,18 +817,46 @@ function worktreeRows(repository) {
|
|
|
817
817
|
return rows
|
|
818
818
|
}
|
|
819
819
|
|
|
820
|
+
function displayWidth(value) {
|
|
821
|
+
let width = 0
|
|
822
|
+
for (const character of value.normalize("NFC")) {
|
|
823
|
+
const codePoint = character.codePointAt(0)
|
|
824
|
+
if (/\p{Mark}/u.test(character) || codePoint === 0x200d) continue
|
|
825
|
+
const fullWidth = codePoint >= 0x1100 && (
|
|
826
|
+
codePoint <= 0x115f
|
|
827
|
+
|| codePoint === 0x2329
|
|
828
|
+
|| codePoint === 0x232a
|
|
829
|
+
|| (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f)
|
|
830
|
+
|| (codePoint >= 0xac00 && codePoint <= 0xd7a3)
|
|
831
|
+
|| (codePoint >= 0xf900 && codePoint <= 0xfaff)
|
|
832
|
+
|| (codePoint >= 0xfe10 && codePoint <= 0xfe19)
|
|
833
|
+
|| (codePoint >= 0xfe30 && codePoint <= 0xfe6f)
|
|
834
|
+
|| (codePoint >= 0xff00 && codePoint <= 0xff60)
|
|
835
|
+
|| (codePoint >= 0xffe0 && codePoint <= 0xffe6)
|
|
836
|
+
|| (codePoint >= 0x1f300 && codePoint <= 0x1faff)
|
|
837
|
+
|| (codePoint >= 0x20000 && codePoint <= 0x3fffd)
|
|
838
|
+
)
|
|
839
|
+
width += fullWidth ? 2 : 1
|
|
840
|
+
}
|
|
841
|
+
return width
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function padDisplay(value, width) {
|
|
845
|
+
return `${value}${" ".repeat(Math.max(0, width - displayWidth(value)))}`
|
|
846
|
+
}
|
|
847
|
+
|
|
820
848
|
function commandList(args) {
|
|
821
849
|
if (args.length > 0) throw new CliError("Usage: gwt list")
|
|
822
850
|
const repository = discoverRepository()
|
|
823
851
|
const rows = worktreeRows(repository)
|
|
824
852
|
const widths = {
|
|
825
|
-
id: Math.max(2, ...rows.map((row) => row.id
|
|
826
|
-
branch: Math.max(6, ...rows.map((row) => row.branch
|
|
827
|
-
setup: Math.max(5, ...rows.map((row) => row.setup
|
|
853
|
+
id: Math.max(2, ...rows.map((row) => displayWidth(row.id))),
|
|
854
|
+
branch: Math.max(6, ...rows.map((row) => displayWidth(row.branch))),
|
|
855
|
+
setup: Math.max(5, ...rows.map((row) => displayWidth(row.setup))),
|
|
828
856
|
}
|
|
829
|
-
console.log(` ${"ID"
|
|
857
|
+
console.log(` ${padDisplay("ID", widths.id)} ${padDisplay("BRANCH", widths.branch)} ${padDisplay("SETUP", widths.setup)} PATH`)
|
|
830
858
|
for (const row of rows) {
|
|
831
|
-
console.log(`${row.current ? "*" : " "} ${row.id
|
|
859
|
+
console.log(`${row.current ? "*" : " "} ${padDisplay(row.id, widths.id)} ${padDisplay(row.branch, widths.branch)} ${padDisplay(row.setup, widths.setup)} ${row.path}`)
|
|
832
860
|
}
|
|
833
861
|
}
|
|
834
862
|
|
|
@@ -890,6 +918,7 @@ async function commandRemove(args) {
|
|
|
890
918
|
const removeArgs = ["worktree", "remove"]
|
|
891
919
|
if (options.discard) removeArgs.push("--force")
|
|
892
920
|
removeArgs.push(targetPath)
|
|
921
|
+
console.log(`Removing worktree ${metadata?.id ?? targetPath}...`)
|
|
893
922
|
git(removeArgs, repository.primaryPath)
|
|
894
923
|
if (metadata?.metadataPath && existsSync(metadata.metadataPath)) unlinkSync(metadata.metadataPath)
|
|
895
924
|
|
|
@@ -897,7 +926,20 @@ async function commandRemove(args) {
|
|
|
897
926
|
if (worktree.branch && !options["keep-branch"]) {
|
|
898
927
|
const deleteArgs = ["branch", options.discard ? "-D" : "-d", "--", worktree.branch]
|
|
899
928
|
const result = git(deleteArgs, repository.primaryPath, { allowFailure: true })
|
|
900
|
-
|
|
929
|
+
if (result.status === 0) {
|
|
930
|
+
branchMessage = `Deleted branch: ${worktree.branch}`
|
|
931
|
+
} else if (!options.discard) {
|
|
932
|
+
console.log(`Branch '${worktree.branch}' could not be deleted safely.`)
|
|
933
|
+
const forceDelete = await ask("Force-delete the branch? [y/N] ")
|
|
934
|
+
if (forceDelete) {
|
|
935
|
+
git(["branch", "-D", "--", worktree.branch], repository.primaryPath)
|
|
936
|
+
branchMessage = `Deleted branch: ${worktree.branch}`
|
|
937
|
+
} else {
|
|
938
|
+
branchMessage = `Kept branch: ${worktree.branch}\nDelete later: git branch -D -- ${worktree.branch}`
|
|
939
|
+
}
|
|
940
|
+
} else {
|
|
941
|
+
branchMessage = `Kept branch: ${worktree.branch}`
|
|
942
|
+
}
|
|
901
943
|
} else if (worktree.branch) branchMessage = `Kept branch: ${worktree.branch}`
|
|
902
944
|
|
|
903
945
|
console.log(`Removed worktree: ${metadata?.id ?? targetPath}`)
|
|
@@ -1311,9 +1353,10 @@ Options:
|
|
|
1311
1353
|
|
|
1312
1354
|
Behavior:
|
|
1313
1355
|
Without --discard, dirty worktrees are rejected and branches are deleted only
|
|
1314
|
-
when 'git branch -d' considers deletion safe.
|
|
1315
|
-
|
|
1316
|
-
primary worktree.
|
|
1356
|
+
when 'git branch -d' considers deletion safe. If safe deletion fails, an
|
|
1357
|
+
interactive terminal asks whether to force-delete the branch; non-interactive
|
|
1358
|
+
use keeps it. The primary worktree cannot be removed. Removing the current
|
|
1359
|
+
worktree returns an integrated shell to the primary worktree.
|
|
1317
1360
|
|
|
1318
1361
|
Examples:
|
|
1319
1362
|
gwt remove
|