@alejandrochaves/devflow-cli 0.1.1 → 0.2.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.
Files changed (47) hide show
  1. package/README.md +106 -11
  2. package/dist/colors.d.ts +9 -0
  3. package/dist/colors.d.ts.map +1 -0
  4. package/dist/colors.js +13 -0
  5. package/dist/colors.js.map +1 -0
  6. package/dist/commands/amend.d.ts +4 -0
  7. package/dist/commands/amend.d.ts.map +1 -0
  8. package/dist/commands/amend.js +138 -0
  9. package/dist/commands/amend.js.map +1 -0
  10. package/dist/commands/branch.d.ts +3 -1
  11. package/dist/commands/branch.d.ts.map +1 -1
  12. package/dist/commands/branch.js +10 -5
  13. package/dist/commands/branch.js.map +1 -1
  14. package/dist/commands/changelog.d.ts +4 -0
  15. package/dist/commands/changelog.d.ts.map +1 -0
  16. package/dist/commands/changelog.js +204 -0
  17. package/dist/commands/changelog.js.map +1 -0
  18. package/dist/commands/cleanup.d.ts +4 -0
  19. package/dist/commands/cleanup.d.ts.map +1 -0
  20. package/dist/commands/cleanup.js +121 -0
  21. package/dist/commands/cleanup.js.map +1 -0
  22. package/dist/commands/commit.d.ts +3 -1
  23. package/dist/commands/commit.d.ts.map +1 -1
  24. package/dist/commands/commit.js +91 -24
  25. package/dist/commands/commit.js.map +1 -1
  26. package/dist/commands/doctor.d.ts +2 -0
  27. package/dist/commands/doctor.d.ts.map +1 -0
  28. package/dist/commands/doctor.js +122 -0
  29. package/dist/commands/doctor.js.map +1 -0
  30. package/dist/commands/init.d.ts.map +1 -1
  31. package/dist/commands/init.js +248 -22
  32. package/dist/commands/init.js.map +1 -1
  33. package/dist/commands/pr.d.ts +3 -1
  34. package/dist/commands/pr.d.ts.map +1 -1
  35. package/dist/commands/pr.js +41 -40
  36. package/dist/commands/pr.js.map +1 -1
  37. package/dist/commands/status.d.ts +2 -0
  38. package/dist/commands/status.d.ts.map +1 -0
  39. package/dist/commands/status.js +83 -0
  40. package/dist/commands/status.js.map +1 -0
  41. package/dist/config.d.ts +13 -0
  42. package/dist/config.d.ts.map +1 -1
  43. package/dist/config.js +52 -1
  44. package/dist/config.js.map +1 -1
  45. package/dist/index.js +103 -5
  46. package/dist/index.js.map +1 -1
  47. package/package.json +1 -1
package/README.md CHANGED
@@ -40,7 +40,15 @@ Or add scripts to your `package.json`:
40
40
 
41
41
  ### `devflow init`
42
42
 
43
- Generates a `.devflow.json` config file in your project root. Prompts for your ticket base URL and creates a starter config with default scopes and checklist items.
43
+ Interactive setup wizard that configures your entire project. Walks you through:
44
+
45
+ 1. **Ticket base URL** — for linking tickets in PRs
46
+ 2. **Scopes** — add project-specific scopes one by one (or use defaults)
47
+ 3. **PR checklist** — customize or use defaults
48
+ 4. **package.json scripts** — auto-adds `commit`, `branch`, `pr` scripts
49
+ 5. **Commitlint** — creates config with the devflow parser preset, installs deps
50
+ 6. **Husky** — installs, initializes, creates `commit-msg` hook
51
+ 7. **CI workflow** — optionally generates `.github/workflows/ci.yml` (lint, typecheck, test)
44
52
 
45
53
  ### `devflow branch`
46
54
 
@@ -123,6 +131,67 @@ Create or update a pull request with an auto-filled template.
123
131
  - Test Plan
124
132
  - Checklist (customizable via config)
125
133
 
134
+ ### `devflow status`
135
+
136
+ At-a-glance view of your current branch context:
137
+ - Branch name, type, ticket, and description
138
+ - Inferred base branch
139
+ - Commit count with recent messages
140
+ - Working tree status (staged/modified/untracked)
141
+ - PR link and state (if exists)
142
+
143
+ ### `devflow amend`
144
+
145
+ Re-edit the last commit message using the same guided prompts. Pre-fills all fields from the existing message. Also includes any staged changes in the amend.
146
+
147
+ ### `devflow cleanup`
148
+
149
+ Finds and deletes local branches that are:
150
+ - Merged into `main`
151
+ - Tracking a remote branch that no longer exists
152
+
153
+ Fetches remote state first, shows checkbox selection, and asks for confirmation before force-deleting unmerged branches.
154
+
155
+ ### `devflow changelog`
156
+
157
+ Generates a changelog entry from conventional commits since the last git tag:
158
+ - Groups by type (Features, Bug Fixes, etc.)
159
+ - Highlights breaking changes
160
+ - Auto-suggests the next version (semver bump based on commit types)
161
+ - Prepends to `CHANGELOG.md`
162
+
163
+ ### `devflow doctor`
164
+
165
+ Checks that all devflow dependencies are properly configured:
166
+ - git, node (>= 18), gh CLI + auth
167
+ - `.devflow.json`, commitlint config, husky hooks
168
+ - `package.json` scripts
169
+
170
+ ### `devflow completions`
171
+
172
+ Outputs shell completion scripts for tab-completion of commands:
173
+
174
+ ```bash
175
+ # zsh (add to ~/.zshrc)
176
+ eval "$(devflow completions --shell zsh)"
177
+
178
+ # bash (add to ~/.bashrc)
179
+ eval "$(devflow completions --shell bash)"
180
+ ```
181
+
182
+ ## Global Options
183
+
184
+ Commands that modify git state support `--dry-run` to preview without executing:
185
+
186
+ ```bash
187
+ devflow commit --dry-run
188
+ devflow branch --dry-run
189
+ devflow pr --dry-run
190
+ devflow amend --dry-run
191
+ devflow cleanup --dry-run
192
+ devflow changelog --dry-run
193
+ ```
194
+
126
195
  ## Configuration
127
196
 
128
197
  Create a `.devflow.json` in your project root (or run `devflow init`):
@@ -131,20 +200,26 @@ Create a `.devflow.json` in your project root (or run `devflow init`):
131
200
  {
132
201
  "ticketBaseUrl": "https://github.com/org/repo/issues",
133
202
  "scopes": [
134
- { "value": "auth", "description": "Authentication & login" },
135
- { "value": "ui", "description": "UI components" },
136
- { "value": "api", "description": "API layer" }
203
+ { "value": "auth", "description": "Authentication & login", "paths": ["src/auth/**"] },
204
+ { "value": "ui", "description": "UI components", "paths": ["src/components/**"] },
205
+ { "value": "api", "description": "API layer", "paths": ["src/api/**", "src/services/**"] }
137
206
  ],
138
207
  "branchTypes": ["feat", "fix", "chore", "refactor", "docs", "test", "release", "hotfix"],
139
208
  "commitTypes": [
140
209
  { "value": "feat", "label": "feat: A new feature" },
141
210
  { "value": "fix", "label": "fix: A bug fix" }
142
211
  ],
212
+ "commitFormat": "{type}[{ticket}]{breaking}({scope}): {message}",
143
213
  "checklist": [
144
214
  "Code follows project conventions",
145
215
  "Self-reviewed the changes",
146
216
  "No new warnings or errors introduced"
147
- ]
217
+ ],
218
+ "prTemplate": {
219
+ "sections": ["summary", "ticket", "type", "screenshots", "testPlan", "checklist"],
220
+ "screenshotsTable": true
221
+ },
222
+ "prReviewers": ["copilot"]
148
223
  }
149
224
  ```
150
225
 
@@ -152,17 +227,37 @@ Create a `.devflow.json` in your project root (or run `devflow init`):
152
227
 
153
228
  | Option | Description | Default |
154
229
  |--------|-------------|---------|
155
- | `ticketBaseUrl` | Base URL for linking tickets in PRs (e.g., `https://github.com/org/repo/issues`) | — |
156
- | `scopes` | List of scopes with `value` and `description`. Enables searchable selection in commit command. | `[]` (free text input) |
157
- | `branchTypes` | Allowed branch type prefixes. | `["feat", "fix", "chore", "refactor", "docs", "test", "release", "hotfix"]` |
158
- | `commitTypes` | Commit types shown in the selection menu. Each has `value` and `label`. | Standard conventional commit types |
159
- | `checklist` | PR checklist items added to the template. | Basic code review items |
230
+ | `ticketBaseUrl` | Base URL for linking tickets in PRs | — |
231
+ | `scopes` | List of scopes with `value`, `description`, and optional `paths` for auto-inference | `[]` (free text input) |
232
+ | `scopes[].paths` | Glob patterns to auto-suggest this scope when matching files are staged | |
233
+ | `branchTypes` | Allowed branch type prefixes | `["feat", "fix", "chore", ...]` |
234
+ | `commitTypes` | Commit types shown in selection menu (`value` + `label`) | Standard conventional types |
235
+ | `commitFormat` | Commit message format with `{type}`, `{ticket}`, `{breaking}`, `{scope}`, `{message}` placeholders | `{type}[{ticket}]{breaking}({scope}): {message}` |
236
+ | `checklist` | PR checklist items | Basic code review items |
237
+ | `prTemplate.sections` | PR body sections to include | All sections |
238
+ | `prTemplate.screenshotsTable` | Include before/after screenshots table | `true` |
239
+ | `prReviewers` | Default PR reviewers (GitHub usernames) | — |
160
240
 
161
241
  ### Scopes
162
242
 
163
243
  When `scopes` is an empty array, the commit command shows a free text input for scope. When populated, it shows a searchable list that can be filtered by typing.
164
244
 
165
- The commit command also infers the scope from previous commits on the branch (`git log main..HEAD`) and pre-selects it as the default.
245
+ **Scope inference** works in two ways (first match wins):
246
+
247
+ 1. **From file paths** — if a scope has `paths` configured, staged files are matched against those glob patterns. The scope with the most matching files is suggested.
248
+ 2. **From git history** — previous commits on the branch (`git log main..HEAD`) are parsed for existing scopes.
249
+
250
+ Example with paths:
251
+ ```json
252
+ {
253
+ "scopes": [
254
+ { "value": "auth", "description": "Authentication", "paths": ["src/auth/**", "src/hooks/useAuth*"] },
255
+ { "value": "ui", "description": "UI components", "paths": ["src/components/**"] }
256
+ ]
257
+ }
258
+ ```
259
+
260
+ If you stage `src/auth/login.ts`, the `auth` scope is auto-suggested.
166
261
 
167
262
  ## Commitlint Integration
168
263
 
@@ -0,0 +1,9 @@
1
+ export declare const bold: (text: string) => string;
2
+ export declare const dim: (text: string) => string;
3
+ export declare const green: (text: string) => string;
4
+ export declare const yellow: (text: string) => string;
5
+ export declare const red: (text: string) => string;
6
+ export declare const cyan: (text: string) => string;
7
+ export declare const gray: (text: string) => string;
8
+ export declare const magenta: (text: string) => string;
9
+ //# sourceMappingURL=colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,IAAI,SAJD,MAAM,WAIS,CAAC;AAChC,eAAO,MAAM,GAAG,SALA,MAAM,WAKQ,CAAC;AAC/B,eAAO,MAAM,KAAK,SANF,MAAM,WAMW,CAAC;AAClC,eAAO,MAAM,MAAM,SAPH,MAAM,WAOY,CAAC;AACnC,eAAO,MAAM,GAAG,SARA,MAAM,WAQS,CAAC;AAChC,eAAO,MAAM,IAAI,SATD,MAAM,WASU,CAAC;AACjC,eAAO,MAAM,IAAI,SAVD,MAAM,WAUU,CAAC;AACjC,eAAO,MAAM,OAAO,SAXJ,MAAM,WAWa,CAAC"}
package/dist/colors.js ADDED
@@ -0,0 +1,13 @@
1
+ const enabled = process.stdout.isTTY !== false;
2
+ function wrap(code, resetCode) {
3
+ return (text) => enabled ? `\x1b[${code}m${text}\x1b[${resetCode}m` : text;
4
+ }
5
+ export const bold = wrap(1, 22);
6
+ export const dim = wrap(2, 22);
7
+ export const green = wrap(32, 39);
8
+ export const yellow = wrap(33, 39);
9
+ export const red = wrap(31, 39);
10
+ export const cyan = wrap(36, 39);
11
+ export const gray = wrap(90, 39);
12
+ export const magenta = wrap(35, 39);
13
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC;AAE/C,SAAS,IAAI,CAAC,IAAY,EAAE,SAAiB;IAC3C,OAAO,CAAC,IAAY,EAAE,EAAE,CACtB,OAAO,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,QAAQ,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function amendCommand(options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=amend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amend.d.ts","sourceRoot":"","sources":["../../src/commands/amend.ts"],"names":[],"mappings":"AA4CA,wBAAsB,YAAY,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA2HpF"}
@@ -0,0 +1,138 @@
1
+ import { confirm, input, select, search } from "@inquirer/prompts";
2
+ import { execSync } from "child_process";
3
+ import { loadConfig } from "../config.js";
4
+ import { inferTicket } from "../git.js";
5
+ import { bold, dim, green, yellow, cyan } from "../colors.js";
6
+ function getLastCommitMessage() {
7
+ return execSync("git log -1 --format=%s", { encoding: "utf-8" }).trim();
8
+ }
9
+ function parseCommitMessage(msg, format) {
10
+ // Try to parse the default format: type[ticket]!(scope): message
11
+ const match = msg.match(/^(\w+)\[([^\]]*)\](!?)\(([^)]*)\): (.+)$/);
12
+ if (match) {
13
+ return {
14
+ type: match[1],
15
+ ticket: match[2],
16
+ breaking: match[3] === "!",
17
+ scope: match[4],
18
+ message: match[5],
19
+ };
20
+ }
21
+ // Try standard conventional commit: type(scope): message
22
+ const conventional = msg.match(/^(\w+)(!?)\(([^)]*)\): (.+)$/);
23
+ if (conventional) {
24
+ return {
25
+ type: conventional[1],
26
+ breaking: conventional[2] === "!",
27
+ scope: conventional[3],
28
+ message: conventional[4],
29
+ };
30
+ }
31
+ // Fallback: treat whole thing as message
32
+ return { message: msg, breaking: false };
33
+ }
34
+ export async function amendCommand(options = {}) {
35
+ try {
36
+ const config = loadConfig();
37
+ const lastMessage = getLastCommitMessage();
38
+ const parsed = parseCommitMessage(lastMessage, config.commitFormat);
39
+ console.log(`\n${dim("Last commit:")} ${lastMessage}\n`);
40
+ const editMessage = await confirm({
41
+ message: "Edit commit message?",
42
+ default: true,
43
+ });
44
+ let newMessage = lastMessage;
45
+ if (editMessage) {
46
+ const type = await select({
47
+ message: "Select commit type:",
48
+ choices: config.commitTypes.map((t) => ({ value: t.value, name: t.label })),
49
+ default: parsed.type,
50
+ });
51
+ let finalScope;
52
+ if (config.scopes.length > 0) {
53
+ finalScope = await search({
54
+ message: parsed.scope
55
+ ? `Select scope (current: ${cyan(parsed.scope)}):`
56
+ : "Select scope (type to filter):",
57
+ source: (term) => {
58
+ const filtered = config.scopes.filter((s) => !term ||
59
+ s.value.includes(term.toLowerCase()) ||
60
+ s.description.toLowerCase().includes(term.toLowerCase()));
61
+ if (parsed.scope) {
62
+ filtered.sort((a, b) => a.value === parsed.scope ? -1 : b.value === parsed.scope ? 1 : 0);
63
+ }
64
+ return filtered.map((s) => ({
65
+ value: s.value,
66
+ name: `${s.value} — ${s.description}`,
67
+ }));
68
+ },
69
+ });
70
+ }
71
+ else {
72
+ finalScope = await input({
73
+ message: "Enter scope (optional):",
74
+ default: parsed.scope,
75
+ });
76
+ }
77
+ const message = await input({
78
+ message: "Enter commit message:",
79
+ default: parsed.message,
80
+ validate: (val) => val.trim().length > 0 || "Commit message is required",
81
+ });
82
+ const isBreaking = await confirm({
83
+ message: "Is this a breaking change?",
84
+ default: parsed.breaking,
85
+ });
86
+ const ticket = parsed.ticket || inferTicket();
87
+ const breaking = isBreaking ? "!" : "";
88
+ const scope = finalScope || "";
89
+ // Build using format
90
+ let result = config.commitFormat;
91
+ result = result.replace("{type}", type);
92
+ result = result.replace("{ticket}", ticket);
93
+ result = result.replace("{breaking}", breaking);
94
+ result = result.replace("{scope}", scope);
95
+ result = result.replace("{message}", message.trim());
96
+ result = result.replace(/\[\]/g, "");
97
+ result = result.replace(/\(\)/g, "");
98
+ newMessage = result;
99
+ }
100
+ // Check for additional staged changes
101
+ const staged = execSync("git diff --cached --name-only", { encoding: "utf-8" }).trim();
102
+ if (staged) {
103
+ console.log(dim("\nStaged changes will be included:"));
104
+ staged.split("\n").forEach((f) => console.log(dim(` ${f}`)));
105
+ }
106
+ console.log(`\n${dim("───")} ${bold("Amend Preview")} ${dim("───")}`);
107
+ console.log(`${dim("Before:")} ${yellow(lastMessage)}`);
108
+ console.log(`${dim("After:")} ${green(newMessage)}`);
109
+ if (staged) {
110
+ console.log(`${dim("Files:")} +${staged.split("\n").length} staged`);
111
+ }
112
+ console.log(`${dim("───────────────────")}\n`);
113
+ if (options.dryRun) {
114
+ console.log(dim("[dry-run] No amend performed."));
115
+ return;
116
+ }
117
+ const confirmed = await confirm({
118
+ message: "Amend this commit?",
119
+ default: true,
120
+ });
121
+ if (!confirmed) {
122
+ console.log("Aborted.");
123
+ process.exit(0);
124
+ }
125
+ execSync(`git commit --amend -m ${JSON.stringify(newMessage)}`, {
126
+ stdio: "inherit",
127
+ });
128
+ console.log(green("✓ Commit amended successfully."));
129
+ }
130
+ catch (error) {
131
+ if (error.name === "ExitPromptError") {
132
+ console.log("\nCancelled.");
133
+ process.exit(0);
134
+ }
135
+ process.exit(1);
136
+ }
137
+ }
138
+ //# sourceMappingURL=amend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amend.js","sourceRoot":"","sources":["../../src/commands/amend.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,4 @@
1
- export declare function branchCommand(): Promise<void>;
1
+ export declare function branchCommand(options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
2
4
  //# sourceMappingURL=branch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAiDnD"}
1
+ {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAKA,wBAAsB,aAAa,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDrF"}
@@ -1,7 +1,8 @@
1
1
  import { select, input, confirm } from "@inquirer/prompts";
2
2
  import { execSync } from "child_process";
3
3
  import { loadConfig } from "../config.js";
4
- export async function branchCommand() {
4
+ import { bold, dim, green, cyan } from "../colors.js";
5
+ export async function branchCommand(options = {}) {
5
6
  try {
6
7
  const config = loadConfig();
7
8
  const type = await select({
@@ -22,9 +23,13 @@ export async function branchCommand() {
22
23
  .replace(/[^a-z0-9]+/g, "-")
23
24
  .replace(/^-|-$/g, "");
24
25
  const branchName = `${type}/${ticketPart}_${kebab}`;
25
- console.log(`\n--- Branch Preview ---`);
26
- console.log(branchName);
27
- console.log(`---------------------\n`);
26
+ console.log(`\n${dim("───")} ${bold("Branch Preview")} ${dim("───")}`);
27
+ console.log(cyan(branchName));
28
+ console.log(`${dim("───────────────────")}\n`);
29
+ if (options.dryRun) {
30
+ console.log(dim("[dry-run] No branch created."));
31
+ return;
32
+ }
28
33
  const confirmed = await confirm({
29
34
  message: "Create this branch?",
30
35
  default: true,
@@ -34,7 +39,7 @@ export async function branchCommand() {
34
39
  process.exit(0);
35
40
  }
36
41
  execSync(`git checkout -b ${branchName}`, { stdio: "inherit" });
37
- console.log(`Branch created and checked out: ${branchName}`);
42
+ console.log(green(`✓ Branch created: ${branchName}`));
38
43
  }
39
44
  catch (error) {
40
45
  if (error.name === "ExitPromptError") {
@@ -1 +1 @@
1
- {"version":3,"file":"branch.js","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAE5B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC;YACxB,OAAO,EAAE,qBAAqB;YAC9B,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;SAChE,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;YACzB,OAAO,EAAE,4CAA4C;SACtD,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC;YAC9B,OAAO,EAAE,oBAAoB;YAC7B,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,yBAAyB;SACtE,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,WAAW,CAAC;QAChD,MAAM,KAAK,GAAG,WAAW;aACtB,IAAI,EAAE;aACN,WAAW,EAAE;aACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzB,MAAM,UAAU,GAAG,GAAG,IAAI,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;QAEpD,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QAEvC,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC;YAC9B,OAAO,EAAE,qBAAqB;YAC9B,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,QAAQ,CAAC,mBAAmB,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,mCAAmC,UAAU,EAAE,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAAe,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"branch.js","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAgC,EAAE;IACpE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAE5B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC;YACxB,OAAO,EAAE,qBAAqB;YAC9B,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;SAChE,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;YACzB,OAAO,EAAE,4CAA4C;SACtD,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC;YAC9B,OAAO,EAAE,oBAAoB;YAC7B,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,yBAAyB;SACtE,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,WAAW,CAAC;QAChD,MAAM,KAAK,GAAG,WAAW;aACtB,IAAI,EAAE;aACN,WAAW,EAAE;aACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzB,MAAM,UAAU,GAAG,GAAG,IAAI,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;QAEpD,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE/C,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC;YAC9B,OAAO,EAAE,qBAAqB;YAC9B,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,QAAQ,CAAC,mBAAmB,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAAe,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function changelogCommand(options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=changelog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/commands/changelog.ts"],"names":[],"mappings":"AAuIA,wBAAsB,gBAAgB,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAsExF"}
@@ -0,0 +1,204 @@
1
+ import { execSync } from "child_process";
2
+ import { writeFileSync, existsSync, readFileSync } from "fs";
3
+ import { confirm, input } from "@inquirer/prompts";
4
+ import { bold, dim, green, cyan, gray } from "../colors.js";
5
+ function getLatestTag() {
6
+ try {
7
+ return execSync("git describe --tags --abbrev=0", { encoding: "utf-8" }).trim();
8
+ }
9
+ catch {
10
+ return undefined;
11
+ }
12
+ }
13
+ function getCommitsSinceTag(tag) {
14
+ try {
15
+ const range = tag ? `${tag}..HEAD` : "HEAD";
16
+ const log = execSync(`git log ${range} --format=%s`, { encoding: "utf-8" }).trim();
17
+ return log ? log.split("\n") : [];
18
+ }
19
+ catch {
20
+ return [];
21
+ }
22
+ }
23
+ function parseCommit(msg) {
24
+ // Match: type[ticket]!(scope): message
25
+ const match = msg.match(/^(\w+)\[.*?\](!?)\(([^)]*)\): (.+)$/);
26
+ if (match) {
27
+ return {
28
+ type: match[1],
29
+ breaking: match[2] === "!",
30
+ scope: match[3] || undefined,
31
+ message: match[4],
32
+ };
33
+ }
34
+ // Match: type!(scope): message
35
+ const conventional = msg.match(/^(\w+)(!?)\(([^)]*)\): (.+)$/);
36
+ if (conventional) {
37
+ return {
38
+ type: conventional[1],
39
+ breaking: conventional[2] === "!",
40
+ scope: conventional[3] || undefined,
41
+ message: conventional[4],
42
+ };
43
+ }
44
+ // Match: type: message
45
+ const simple = msg.match(/^(\w+): (.+)$/);
46
+ if (simple) {
47
+ return { type: simple[1], breaking: false, message: simple[2] };
48
+ }
49
+ return undefined;
50
+ }
51
+ function groupByType(entries) {
52
+ const groups = {};
53
+ for (const entry of entries) {
54
+ const key = entry.type;
55
+ if (!groups[key])
56
+ groups[key] = [];
57
+ groups[key].push(entry);
58
+ }
59
+ return groups;
60
+ }
61
+ const TYPE_HEADINGS = {
62
+ feat: "Features",
63
+ fix: "Bug Fixes",
64
+ perf: "Performance",
65
+ refactor: "Refactoring",
66
+ docs: "Documentation",
67
+ test: "Tests",
68
+ chore: "Maintenance",
69
+ ci: "CI/CD",
70
+ build: "Build",
71
+ style: "Styling",
72
+ };
73
+ function formatChangelog(version, entries, date) {
74
+ const lines = [];
75
+ lines.push(`## ${version} (${date})`);
76
+ lines.push("");
77
+ // Breaking changes first
78
+ const breaking = entries.filter((e) => e.breaking);
79
+ if (breaking.length > 0) {
80
+ lines.push("### ⚠ Breaking Changes");
81
+ lines.push("");
82
+ for (const entry of breaking) {
83
+ const scope = entry.scope ? `**${entry.scope}:** ` : "";
84
+ lines.push(`- ${scope}${entry.message}`);
85
+ }
86
+ lines.push("");
87
+ }
88
+ // Grouped by type
89
+ const grouped = groupByType(entries.filter((e) => !e.breaking));
90
+ const typeOrder = ["feat", "fix", "perf", "refactor", "docs", "test", "chore", "ci", "build", "style"];
91
+ for (const type of typeOrder) {
92
+ const group = grouped[type];
93
+ if (!group || group.length === 0)
94
+ continue;
95
+ const heading = TYPE_HEADINGS[type] || type;
96
+ lines.push(`### ${heading}`);
97
+ lines.push("");
98
+ for (const entry of group) {
99
+ const scope = entry.scope ? `**${entry.scope}:** ` : "";
100
+ lines.push(`- ${scope}${entry.message}`);
101
+ }
102
+ lines.push("");
103
+ }
104
+ // Any remaining types not in the order
105
+ for (const [type, group] of Object.entries(grouped)) {
106
+ if (typeOrder.includes(type))
107
+ continue;
108
+ const heading = TYPE_HEADINGS[type] || type;
109
+ lines.push(`### ${heading}`);
110
+ lines.push("");
111
+ for (const entry of group) {
112
+ const scope = entry.scope ? `**${entry.scope}:** ` : "";
113
+ lines.push(`- ${scope}${entry.message}`);
114
+ }
115
+ lines.push("");
116
+ }
117
+ return lines.join("\n");
118
+ }
119
+ export async function changelogCommand(options = {}) {
120
+ try {
121
+ const latestTag = getLatestTag();
122
+ const commits = getCommitsSinceTag(latestTag);
123
+ if (commits.length === 0) {
124
+ console.log("No commits found since last tag.");
125
+ return;
126
+ }
127
+ console.log(`\n${dim("───")} ${bold("Changelog")} ${dim("───")}\n`);
128
+ console.log(`${dim("Since:")} ${latestTag ? cyan(latestTag) : gray("beginning")}`);
129
+ console.log(`${dim("Commits:")} ${commits.length}\n`);
130
+ const entries = commits
131
+ .map(parseCommit)
132
+ .filter((e) => e !== undefined);
133
+ if (entries.length === 0) {
134
+ console.log("No conventional commits found to generate changelog from.");
135
+ return;
136
+ }
137
+ const version = await input({
138
+ message: "Version for this changelog entry:",
139
+ default: latestTag ? bumpVersion(latestTag, entries) : "0.1.0",
140
+ validate: (val) => val.trim().length > 0 || "Version is required",
141
+ });
142
+ const date = new Date().toISOString().split("T")[0];
143
+ const changelog = formatChangelog(version.trim(), entries, date);
144
+ console.log(`\n${dim("Preview:")}\n`);
145
+ console.log(changelog);
146
+ if (options.dryRun) {
147
+ console.log(dim("[dry-run] No file written."));
148
+ return;
149
+ }
150
+ const writeFile = await confirm({
151
+ message: "Write to CHANGELOG.md?",
152
+ default: true,
153
+ });
154
+ if (writeFile) {
155
+ const changelogPath = "CHANGELOG.md";
156
+ let existing = "";
157
+ if (existsSync(changelogPath)) {
158
+ existing = readFileSync(changelogPath, "utf-8");
159
+ // Insert after the title if it exists
160
+ const titleMatch = existing.match(/^# .+\n/);
161
+ if (titleMatch) {
162
+ const afterTitle = existing.slice(titleMatch[0].length);
163
+ writeFileSync(changelogPath, `${titleMatch[0]}\n${changelog}\n${afterTitle}`);
164
+ }
165
+ else {
166
+ writeFileSync(changelogPath, `${changelog}\n\n${existing}`);
167
+ }
168
+ }
169
+ else {
170
+ writeFileSync(changelogPath, `# Changelog\n\n${changelog}\n`);
171
+ }
172
+ console.log(green("✓ CHANGELOG.md updated."));
173
+ }
174
+ }
175
+ catch (error) {
176
+ if (error.name === "ExitPromptError") {
177
+ console.log("\nCancelled.");
178
+ process.exit(0);
179
+ }
180
+ process.exit(1);
181
+ }
182
+ }
183
+ function bumpVersion(tag, entries) {
184
+ const clean = tag.replace(/^v/, "");
185
+ const parts = clean.split(".").map(Number);
186
+ if (parts.length !== 3)
187
+ return clean;
188
+ const hasBreaking = entries.some((e) => e.breaking);
189
+ const hasFeature = entries.some((e) => e.type === "feat");
190
+ if (hasBreaking) {
191
+ parts[0]++;
192
+ parts[1] = 0;
193
+ parts[2] = 0;
194
+ }
195
+ else if (hasFeature) {
196
+ parts[1]++;
197
+ parts[2] = 0;
198
+ }
199
+ else {
200
+ parts[2]++;
201
+ }
202
+ return parts.join(".");
203
+ }
204
+ //# sourceMappingURL=changelog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.js","sourceRoot":"","sources":["../../src/commands/changelog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function cleanupCommand(options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"AA8BA,wBAAsB,cAAc,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA4FtF"}