@doccy/fell 0.1.3 → 0.1.4
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/cli.ts +6 -2
- package/lib/git.ts +26 -3
- package/package.json +1 -1
package/cli.ts
CHANGED
|
@@ -838,7 +838,7 @@ async function handleBrowseKey(state: State, key: Key): Promise<void> {
|
|
|
838
838
|
}
|
|
839
839
|
|
|
840
840
|
// Quit
|
|
841
|
-
if (key === "ctrl-c" || ch === "q") {
|
|
841
|
+
if (key === "ctrl-c" || key === "escape" || ch === "q") {
|
|
842
842
|
state.shouldQuit = true
|
|
843
843
|
return
|
|
844
844
|
}
|
|
@@ -1171,7 +1171,7 @@ async function main() {
|
|
|
1171
1171
|
|
|
1172
1172
|
case "deleting":
|
|
1173
1173
|
// Background delete in progress - ignore keys (spinner keeps animating via timer)
|
|
1174
|
-
if (key === "ctrl-c") {
|
|
1174
|
+
if (key === "ctrl-c" || key === "escape" || keyChar(key) === "q") {
|
|
1175
1175
|
state.shouldQuit = true
|
|
1176
1176
|
}
|
|
1177
1177
|
break
|
|
@@ -1201,6 +1201,10 @@ async function main() {
|
|
|
1201
1201
|
clearInterval(spinnerTimer)
|
|
1202
1202
|
} finally {
|
|
1203
1203
|
cleanup()
|
|
1204
|
+
// Force exit immediately. Background async tasks (PR fetching, size
|
|
1205
|
+
// estimation) hold the event loop open. They're non-critical UI state
|
|
1206
|
+
// -- no data corruption risk from terminating mid-flight.
|
|
1207
|
+
process.exit(0)
|
|
1204
1208
|
}
|
|
1205
1209
|
}
|
|
1206
1210
|
|
package/lib/git.ts
CHANGED
|
@@ -130,6 +130,10 @@ export async function listWorktrees(): Promise<Worktree[]> {
|
|
|
130
130
|
/**
|
|
131
131
|
* Remove a worktree directory and its git administrative tracking.
|
|
132
132
|
* Use force when the worktree has uncommitted changes.
|
|
133
|
+
*
|
|
134
|
+
* Handles zombie worktrees (directory exists but .git file is missing):
|
|
135
|
+
* falls back to `git worktree prune` to clean the reference, then
|
|
136
|
+
* removes the leftover directory manually.
|
|
133
137
|
*/
|
|
134
138
|
export async function removeWorktree(
|
|
135
139
|
path: string,
|
|
@@ -137,10 +141,29 @@ export async function removeWorktree(
|
|
|
137
141
|
): Promise<{ ok: boolean; error?: string }> {
|
|
138
142
|
const flags = force ? ["--force"] : []
|
|
139
143
|
const result = await $`git worktree remove ${flags} ${path}`.nothrow().quiet()
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
|
|
145
|
+
if (result.exitCode === 0) return { ok: true }
|
|
146
|
+
|
|
147
|
+
const stderr = result.stderr.toString().trim()
|
|
148
|
+
|
|
149
|
+
// Zombie worktree: directory exists but .git is missing.
|
|
150
|
+
// git worktree remove refuses to act, so we prune the reference
|
|
151
|
+
// and remove the leftover directory ourselves.
|
|
152
|
+
const isZombie =
|
|
153
|
+
stderr.includes("does not exist") &&
|
|
154
|
+
(stderr.includes(".git") || stderr.includes("validation failed"))
|
|
155
|
+
|
|
156
|
+
if (isZombie) {
|
|
157
|
+
// Prune cleans the stale git reference
|
|
158
|
+
await $`git worktree prune`.nothrow().quiet()
|
|
159
|
+
|
|
160
|
+
// Remove the leftover directory if it still exists
|
|
161
|
+
await $`rm -rf ${path}`.nothrow().quiet()
|
|
162
|
+
|
|
163
|
+
return { ok: true }
|
|
142
164
|
}
|
|
143
|
-
|
|
165
|
+
|
|
166
|
+
return { ok: false, error: stderr }
|
|
144
167
|
}
|
|
145
168
|
|
|
146
169
|
/**
|