gflows 0.1.17 → 0.1.18

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 CHANGED
@@ -265,7 +265,7 @@ Release and hotfix names must be a version (`vX.Y.Z` or `X.Y.Z`). Branch names u
265
265
  | `init` | `-I` | Ensure main exists; create dev from main. |
266
266
  | `start` | `-S` | Create a workflow branch (requires type + name). |
267
267
  | `finish` | `-F` | Merge branch into target(s), optional tag (release/hotfix), delete, push. |
268
- | `switch` | `-W` | Switch to a workflow branch (picker or name); with uncommitted changes: prompt or `--move` / `--restore` / `--clean` / `--cancel`. |
268
+ | `switch` | `-W` | Switch to a workflow branch (picker or name); with uncommitted changes: prompt or `--move` / `--restore` / `--clean` / `--destroy` / `--cancel`. |
269
269
  | `delete` | `-L` | Delete local workflow branch(es). Never main/dev. |
270
270
  | `list` | `-l` | List workflow branches; optional type filter and remote. |
271
271
  | `bump` | — | Bump or rollback package version (patch/minor/major). |
@@ -404,6 +404,7 @@ Switch to a workflow branch. With TTY and no branch name, shows a picker; otherw
404
404
  | **Move** | Move current changes to the target branch. |
405
405
  | **Restore** | Save changes for this branch; restore target's saved state (if any). |
406
406
  | **Clean** | Discard changes and switch clean at HEAD. |
407
+ | **Destroy** | Delete current branch and switch to the target branch (cannot destroy main or dev). |
407
408
  | **Cancel** | Abort switching. |
408
409
 
409
410
  You can skip the prompt by passing exactly one of the flags below. If the target branch has saved changes and you use **Clean**, a warning is shown (unless `-q`).
@@ -415,6 +416,7 @@ bun gflows switch
415
416
  bun gflows switch feature/auth-refactor
416
417
  bun gflows switch dev --restore
417
418
  bun gflows switch main --clean
419
+ bun gflows switch dev --destroy
418
420
  bun gflows -W feature/auth-refactor
419
421
  ```
420
422
 
@@ -428,6 +430,7 @@ bun gflows -W feature/auth-refactor
428
430
  | `--move` | — | Move current changes to the target branch; no prompt. |
429
431
  | `--restore` | — | Save for this branch; restore target's saved state (if any); no prompt. |
430
432
  | `--clean` | — | Discard changes and switch clean at HEAD; no prompt. |
433
+ | `--destroy` | — | Delete current branch and switch to target; no prompt (not main/dev). |
431
434
  | `--cancel` | — | Abort switching; no prompt. |
432
435
  | `--verbose` | `-v` | Verbose output. |
433
436
  | `--quiet` | `-q` | Minimal output (suppresses Clean warning about saved changes on target). |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gflows",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "A lightweight CLI for consistent Git branching workflows (main + dev, feature/bugfix/chore/release/hotfix).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,6 +14,7 @@
14
14
  "lint": "biome check .",
15
15
  "lint:fix": "biome check . --write",
16
16
  "format": "biome format . --write",
17
+ "check": "bun run test && bun run typecheck && bun run lint",
17
18
  "gflows": "bun run src/cli.ts",
18
19
  "publish:all": "bun run scripts/publish.ts",
19
20
  "publish:npm": "bun run scripts/publish.ts -- --npm-only",
package/src/cli.ts CHANGED
@@ -95,11 +95,12 @@ function buildParseArgsOptions() {
95
95
  // list (-r is context-dependent: list → include-remote; start/finish → release)
96
96
  includeRemote: { type: "boolean" as const },
97
97
  "include-remote": { type: "boolean" as const },
98
- // switch: explicit mode (--restore, --clean, --cancel, --move)
98
+ // switch: explicit mode (--restore, --clean, --cancel, --move, --destroy)
99
99
  restore: { type: "boolean" as const },
100
100
  clean: { type: "boolean" as const },
101
101
  cancel: { type: "boolean" as const },
102
102
  move: { type: "boolean" as const },
103
+ destroy: { type: "boolean" as const },
103
104
  },
104
105
  };
105
106
  }
@@ -317,16 +318,17 @@ export function parse(argv: string[] = Bun.argv.slice(2)): ParsedArgs {
317
318
  else if (command === "completion" && name === "zsh") completionShell = "zsh";
318
319
  else if (command === "completion" && name === "fish") completionShell = "fish";
319
320
 
320
- let switchMode: "restore" | "clean" | "cancel" | "move" | undefined;
321
+ let switchMode: "restore" | "clean" | "cancel" | "move" | "destroy" | undefined;
321
322
  if (command === "switch") {
322
323
  const restore = v.restore === true;
323
324
  const clean = v.clean === true;
324
325
  const cancel = v.cancel === true;
325
326
  const move = v.move === true;
326
- const count = [restore, clean, cancel, move].filter(Boolean).length;
327
+ const destroy = v.destroy === true;
328
+ const count = [restore, clean, cancel, move, destroy].filter(Boolean).length;
327
329
  if (count > 1) {
328
330
  console.error(
329
- "gflows switch: only one of --restore, --clean, --cancel, or --move may be used at a time.",
331
+ "gflows switch: only one of --restore, --clean, --cancel, --move, or --destroy may be used at a time.",
330
332
  );
331
333
  process.exit(EXIT_USER);
332
334
  }
@@ -334,6 +336,7 @@ export function parse(argv: string[] = Bun.argv.slice(2)): ParsedArgs {
334
336
  else if (clean) switchMode = "clean";
335
337
  else if (cancel) switchMode = "cancel";
336
338
  else if (move) switchMode = "move";
339
+ else if (destroy) switchMode = "destroy";
337
340
  }
338
341
 
339
342
  return {
@@ -51,6 +51,7 @@ List: -r, --include-remote Include remote-tracking branches
51
51
  Switch: --move Move current changes to the target branch
52
52
  --restore Save for this branch; restore target's saved state (if any)
53
53
  --clean Discard changes and switch clean at HEAD
54
+ --destroy Delete current branch and switch to target (not main/dev)
54
55
  --cancel Abort switching
55
56
 
56
57
  Exit codes: 0 success, 1 usage/validation, 2 Git or system error.
@@ -5,11 +5,12 @@
5
5
 
6
6
  import { resolveConfig } from "../config.js";
7
7
  import { EXIT_GIT, EXIT_OK, EXIT_USER } from "../constants.js";
8
- import { NotRepoError } from "../errors.js";
8
+ import { CannotDeleteMainOrDevError, NotRepoError } from "../errors.js";
9
9
  import {
10
10
  branchList,
11
11
  checkout,
12
12
  cleanUntracked,
13
+ deleteBranch,
13
14
  findStashRefByBranch,
14
15
  findStashRefByMessage,
15
16
  getCurrentBranch,
@@ -26,7 +27,7 @@ import { hint, success } from "../out.js";
26
27
  import type { BranchType, ParsedArgs } from "../types.js";
27
28
 
28
29
  /** User choice when switching with uncommitted changes. */
29
- type SwitchWhenUncommitted = "cancel" | "restore" | "clean" | "move";
30
+ type SwitchWhenUncommitted = "cancel" | "restore" | "clean" | "move" | "destroy";
30
31
 
31
32
  const BRANCH_TYPES: BranchType[] = ["feature", "bugfix", "chore", "release", "hotfix", "spike"];
32
33
 
@@ -124,6 +125,10 @@ export async function run(args: ParsedArgs): Promise<void> {
124
125
  value: "restore" as const,
125
126
  },
126
127
  { name: "Clean — Discard changes and switch clean at HEAD", value: "clean" as const },
128
+ {
129
+ name: "Destroy — Delete current branch and switch to the target branch",
130
+ value: "destroy" as const,
131
+ },
127
132
  { name: "Cancel — Abort switching", value: "cancel" as const },
128
133
  ],
129
134
  });
@@ -139,6 +144,31 @@ export async function run(args: ParsedArgs): Promise<void> {
139
144
  process.exit(EXIT_USER);
140
145
  }
141
146
 
147
+ let branchToDestroy: string | undefined;
148
+ if (whenUncommitted === "destroy") {
149
+ const currentBranch = await getCurrentBranch(root, gitOpts);
150
+ if (!currentBranch) {
151
+ console.error("gflows switch: cannot destroy when HEAD is detached.");
152
+ process.exit(EXIT_USER);
153
+ }
154
+ if (currentBranch === config.main || currentBranch === config.dev) {
155
+ throw new CannotDeleteMainOrDevError(
156
+ `Cannot destroy the long-lived branch '${currentBranch}'.`,
157
+ );
158
+ }
159
+ if (currentBranch === targetBranch) {
160
+ console.error(
161
+ "gflows switch: cannot destroy current branch when switching to the same branch.",
162
+ );
163
+ process.exit(EXIT_USER);
164
+ }
165
+ branchToDestroy = currentBranch;
166
+ if (!treeClean) {
167
+ await restoreTracked(root, gitOpts);
168
+ await cleanUntracked(root, gitOpts);
169
+ }
170
+ }
171
+
142
172
  if (!treeClean && whenUncommitted === "move") {
143
173
  await stashPushMove(root, gitOpts);
144
174
  }
@@ -210,7 +240,12 @@ export async function run(args: ParsedArgs): Promise<void> {
210
240
  await tryRestoreTargetStash();
211
241
  }
212
242
 
213
- if (!quiet && !dryRun) {
243
+ if (branchToDestroy) {
244
+ await deleteBranch(root, branchToDestroy, gitOpts);
245
+ if (!quiet && !dryRun) {
246
+ success(`Deleted branch '${branchToDestroy}' and switched to '${targetBranch}'.`);
247
+ }
248
+ } else if (!quiet && !dryRun) {
214
249
  success(`Switched to branch '${targetBranch}'.`);
215
250
  hint("Use gflows list to see all workflow branches.");
216
251
  }
package/src/types.ts CHANGED
@@ -120,5 +120,5 @@ export interface ParsedArgs {
120
120
  // list
121
121
  includeRemote: boolean;
122
122
  // switch: explicit mode when uncommitted (overrides prompt)
123
- switchMode?: "restore" | "clean" | "cancel" | "move";
123
+ switchMode?: "restore" | "clean" | "cancel" | "move" | "destroy";
124
124
  }