@sppk/auto-git-flow 0.0.2 → 0.0.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/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  - 🛠 **命名规范化**: 自动生成符合团队约定的 `feat/`, `DEV-`, `RELEASE-` 分支名称。
12
12
  - 🔄 **合并自动化**: 一键同步基准分支、合并代码并推送到远程,减少手工误操作。
13
+ - 🧠 **智能检测**: 自动检测分支落后状态,仅在必要时执行同步,避免冗余操作。
13
14
  - 📋 **全景视图**: 快速查看当前项目的开发(Dev)与发布(Release)分支状态。
14
15
  - 🛡 **安全检查**: 执行前自动检查工作区状态,确保代码提交安全。
15
16
  - ⌨️ **交互式体验**: 基于 `@inquirer/prompts` 提供平滑的命令行交互。
@@ -34,41 +35,53 @@ pnpx agf --help
34
35
 
35
36
  ## 🛠 常用命令
36
37
 
37
- ### 1. 查看分支状态 `agf list`
38
- 展示最近的开发分支与发布分支列表。
39
- ```bash
40
- agf list [count] # 默认查看最近 2
41
- ```
38
+ | 命令 | 说明 | 用法 |
39
+ | ------------ | ------------------------------------------------------- | -------------------------- |
40
+ | `agf list` | 展示最近的开发分支与发布分支列表 | `agf list [count]` |
41
+ | `agf create` | 根据类型(Feature/Dev/Release)和需求号自动生成规范分支 | `agf create` |
42
+ | `agf merge` | 将当前 Feature 分支合并到指定的目标分支 | `agf merge <dev\|release>` |
43
+ | `agf sync` | 同步基准分支代码到当前 Feature 分支 | `agf sync` |
42
44
 
43
- > 可以通过该命令检查 `agf` 获取的最新分支是否正确
45
+ ### 命令详解
44
46
 
45
- ### 2. 创建新分支 `agf create`
46
- 根据类型(Feature/Dev/Release)和需求号自动生成规范分支。
47
- ```bash
48
- agf create
49
- ```
47
+ #### `agf list [count]`
50
48
 
51
- ### 3. 合并分支 `agf merge`
52
- 将当前 Feature 分支自动同步基准代码并合并到指定的目标分支(Dev 或 Release)。
53
- ```bash
54
- agf merge [target] # target 为必填:dev 或 release。
55
- ```
49
+ 查看最近的 Dev Release 分支,默认显示最近 2 个。可用于检查 `agf` 识别的分支是否正确。
50
+
51
+ #### `agf create`
52
+
53
+ 交互式创建分支,根据类型自动生成规范命名。
54
+
55
+ #### `agf merge <target>`
56
+
57
+ 将当前 Feature 分支合并到目标分支(`dev` 或 `release`)。
58
+
59
+ **智能同步机制**:
60
+
61
+ - 自动检测目标分支是否落后于基准分支,仅在落后时执行同步
62
+ - 自动检测当前 Feature 分支是否落后于基准分支,必要时先同步 Feature
63
+
64
+ #### `agf sync`
65
+
66
+ 手动同步基准分支(最新 Release)到当前 Feature 分支。如果当前分支已包含基准分支的所有提交,则跳过同步。
56
67
 
57
68
  ## 📋 命名规范
58
69
 
59
70
  工具严格遵循以下命名约定:
60
71
 
61
- - **Feature**: `feat/<username>-<date>-<reqNo>`
62
- *示例: `feat/jack-20231024-QZ-8848`*
63
- - **Dev**: `<project>-DEV-<date>`
64
- *示例: `mall-DEV-20231024`*
65
- - **Release**: `<project>-RELEASE-<date>`
66
- *示例: `mall-RELEASE-20231024`*
72
+ | 分支类型 | 格式 | 示例 |
73
+ | -------- | ------------------------------- | ---------------------------- |
74
+ | Feature | `feat/<username>-<YYYYMMDD>-<reqNo>` | `feat/jack-20231024-QZ-8848` |
75
+ | Dev | `<project>-DEV-<YYYYMMDD>` | `mall-DEV-20231024` |
76
+ | Release | `<project>-RELEASE-<YYYYMMDD>` | `mall-RELEASE-20231024` |
77
+
78
+ > **需求编号格式**: `QZ-` 后跟 4~8 位数字(如 `QZ-8848` 或 `QZ-12345678`)
67
79
 
68
80
  ## 📐 工作流图解
69
81
 
70
82
  ### 分支创建流程 (Create)
71
- 如果是 `dev` 或 `release` 分支,会自动推送到远程并切回原分支;如果是 `feature` 分支,则留在新分支。
83
+
84
+ 所有分支创建后都会自动推送到远程。`dev` 或 `release` 分支推送后切回原分支;`feature` 分支则留在新分支继续开发。
72
85
 
73
86
  ```mermaid
74
87
  graph TD
@@ -78,46 +91,59 @@ graph TD
78
91
  Fetch --> Config[采集配置: 类型/日期/需求号]
79
92
  Config --> Name[生成规范名称]
80
93
  Name --> Checkout[从 Base 分支创建并切换]
81
- Checkout --> TypeCheck{分支类型?}
82
-
83
- TypeCheck -- Feature --> DoneFeature([切到新分支, 完成])
84
- TypeCheck -- Dev/Release --> Push[推送到远程]
85
- Push --> Back[切回原分支]
94
+ Checkout --> Push[推送到远程]
95
+ Push --> TypeCheck{分支类型?}
96
+
97
+ TypeCheck -- Feature --> DoneFeature([留在新分支, 完成])
98
+ TypeCheck -- Dev/Release --> Back[切回原分支]
86
99
  Back --> DoneOther([完成])
87
100
  ```
88
101
 
89
102
  ### 分支合并流程 (Merge)
90
- 将当前特性分支合并到目标环境。会自动先同步 `Release` 与 `Dev`、`Main` 分支的代码,确保环境一致性。
103
+
104
+ 将当前特性分支合并到目标环境。会**智能检测**分支落后状态,仅在必要时执行同步。
105
+
106
+ **基准分支选择逻辑**:
107
+ - 合并到 **Dev** 时:基准为**最新 Release** 分支
108
+ - 合并到 **Release** 时:基准为**上一个 Release** 分支(避免将未发布的代码带入)
91
109
 
92
110
  ```mermaid
93
111
  graph TD
94
112
  Start([开始合并]) --> CheckClean{检查工作区}
95
113
  CheckClean -- 脏 --> Error([提示保存并退出])
96
114
  CheckClean -- 干净 --> CheckType{当前是 Feature?}
97
-
115
+
98
116
  CheckType -- 否 --> ErrorType([只允许从 Feature 发起])
99
- CheckType -- 是 --> FindTarget[定位目标分支]
100
-
117
+ CheckType -- 是 --> ConfirmRelease{目标是 Release?}
118
+
119
+ ConfirmRelease -- 是 --> UserConfirm[二次人工确认]
120
+ ConfirmRelease -- 否 --> FindTarget
121
+ UserConfirm -- 取消 --> End([结束])
122
+ UserConfirm -- 确认 --> FindTarget[定位目标分支]
123
+
101
124
  FindTarget --> Exist{目标分支存在?}
102
125
  Exist -- 否 --> CreateNew[引导创建并推送]
103
- Exist -- 是 --> Sync[同步目标与基准分支]
104
-
105
- CreateNew --> Sync
106
- Sync --> Confirm{如果是 Release?}
107
- Confirm -- 是 --> UserConfirm[二次人工确认]
108
- Confirm -- 否 --> DoMerge
109
-
110
- UserConfirm -- 取消 --> End([结束])
111
- UserConfirm -- 确认 --> DoMerge[执行合并]
112
-
113
- DoMerge --> MergeBase[基准 -> 目标]
114
- MergeBase --> MergeFeat[Feature -> 目标]
126
+ Exist -- 是 --> Pull[拉取远程最新代码]
127
+ CreateNew --> Pull
128
+
129
+ Pull --> CheckTargetBehind{目标落后于基准?}
130
+ CheckTargetBehind -- 是 --> SyncTarget[同步: 基准 → 目标]
131
+ CheckTargetBehind -- 否 --> SkipTargetSync[跳过目标同步]
132
+ SyncTarget --> CheckFeatureBehind
133
+ SkipTargetSync --> CheckFeatureBehind{Feature 落后于基准?}
134
+
135
+ CheckFeatureBehind -- 是 --> SyncFeature[同步: 基准 → Feature]
136
+ CheckFeatureBehind -- 否 --> SkipFeatureSync[跳过 Feature 同步]
137
+ SyncFeature --> DoMerge
138
+ SkipFeatureSync --> DoMerge[执行合并]
139
+
140
+ DoMerge --> MergeFeat[Feature → 目标]
115
141
  MergeFeat --> Push[推送目标分支]
116
142
  Push --> Back[切回 Feature 分支]
117
143
  Back --> Done([合并完成])
118
144
 
119
145
  classDef highlight fill:#f96,stroke:#333,stroke-width:2px
120
- class MergeBase,UserConfirm highlight
146
+ classDef smart fill:#69f,stroke:#333,stroke-width:2px
147
+ class UserConfirm highlight
148
+ class CheckTargetBehind,CheckFeatureBehind smart
121
149
  ```
122
-
123
-
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{Command as H}from"commander";import{input as G,select as O}from"@inquirer/prompts";import{format as _}from"date-fns";import{simpleGit as Z}from"simple-git";import C from"chalk";var i=Z();async function A(){if(!(await i.status()).isClean())throw new Error("\u274C \u5DE5\u4F5C\u533A\u6709\u672A\u63D0\u4EA4\u7684\u4EE3\u7801\uFF0C\u8BF7\u5148 Commit \u6216 Stash\u3002")}async function U(){let e=await i.getConfig("user.name");if(!e.value)throw new Error("\u274C \u83B7\u53D6\u4E0D\u5230\u7528\u6237\u540D\uFF0C\u8BF7\u6267\u884C git config user.name \u914D\u7F6E\u3002");return e.value}async function u(){console.log(C.gray("\u6B63\u5728\u62C9\u53D6\u8FDC\u7A0B\u6700\u65B0\u5206\u652F\u5217\u8868...")),await i.fetch(["--prune"])}async function d(){return(await i.branch()).current}async function w(e,t=!1,r){t?r?await i.checkout(["-b",e,r]):await i.checkoutLocalBranch(e):await i.checkout(e)}async function v(e,t){try{await i.merge([t])}catch{throw new Error(`\u26A0\uFE0F \u53D1\u751F\u4EE3\u7801\u51B2\u7A81\uFF01\u4ECE ${t} \u5408\u5E76\u5230 ${e} \u5931\u8D25\u3002
3
- \u8BF7\u624B\u52A8\u89E3\u51B3\u51B2\u7A81\u6587\u4EF6\u5E76\u63D0\u4EA4\uFF0C\u7136\u540E\u5207\u6362\u56DE\u539F\u5206\u652F\u3002`)}}async function x(e){await i.push(["-u","origin",e])}async function L(e){let t=await i.branch();if(t.all.includes(e))console.log(C.gray(`\u6B63\u5728\u66F4\u65B0\u672C\u5730\u5206\u652F ${e}...`)),await i.checkout(e),await i.pull("origin",e);else if(t.all.includes(`remotes/origin/${e}`))console.log(C.gray(`\u6B63\u5728\u4ECE\u8FDC\u7A0B\u62C9\u53D6\u5206\u652F ${e}...`)),await i.checkout(["-b",e,`origin/${e}`]);else throw new Error(`\u274C \u9519\u8BEF: \u8FDC\u7A0B\u4E0D\u5B58\u5728\u5206\u652F ${e}`)}async function h(){let e=await i.branch(["-a"]);return Array.from(new Set(e.all.map(t=>t.replace("remotes/origin/",""))))}import{compareDesc as M,compareAsc as N,parse as F}from"date-fns";var b=/^QZ-\d{4}$/;function $(e){let t=e.match(/^(.+)-RELEASE-(\d{8})$/);if(t)return{name:e,type:"RELEASE",project:t[1],date:F(t[2],"yyyyMMdd",new Date)};let r=e.match(/^(.+)-(?:DEV|dev)-(\d{8})$/);if(r)return{name:e,type:"DEV",project:r[1],date:F(r[2],"yyyyMMdd",new Date)};let n=e.match(/^feat\/(.+)-(\d{8})-(QZ-\d{4})$/);return n?{name:e,type:"FEATURE",date:F(n[2],"yyyyMMdd",new Date)}:null}function D(e){return e.map($).filter(r=>r?.type==="RELEASE").sort((r,n)=>M(r.date,n.date))[0]||null}function j(e){return e.map($).filter(r=>r?.type==="RELEASE").sort((r,n)=>M(r.date,n.date))[1]||null}function S(e,t){let r=new Date,n=new Date(r.getFullYear(),r.getMonth(),r.getDate());return e.map($).filter(s=>s?.type===t&&!!s.date).filter(s=>s.date>=n).sort((s,c)=>N(s.date,c.date))[0]||null}function k(e,t,r){return e.map($).filter(n=>n?.type===t).sort((n,o)=>M(n.date,o.date)).slice(0,r)}import l from"chalk";var p=l.gray("\u2502"),a={header:e=>{console.log(`
4
- ${l.bgCyan.black.bold(" GIT-FLOW ")} ${l.cyan.bold(e)}`),console.log(p)},info:e=>console.log(`${p} ${l.blue("\u2139")} ${e}`),step:e=>{process.stdout.write(`${p} ${l.yellow("\u279C")} ${e}`)},success:e=>console.log(`${p} ${l.green("\u2714")} ${e}`),done:()=>{process.stdout.write(l.green(` [OK]
5
- `))},warn:e=>console.log(`${p} ${l.yellow("\u26A0")} ${e}`),error:e=>console.error(`${p} ${l.red("\u2718")} ${e}`),errorRaw:e=>console.error(`${p} ${l.red(e)}`),dim:e=>console.log(`${p} ${l.gray(e)}`),dimRaw:e=>{process.stdout.write(`${p} ${l.gray(e)}`)},footer:()=>console.log(p+`
6
- `)};async function q(e){let t=await d(),r=await h(),n=D(r),o=n?.name||t;a.info(`\u5F53\u524D\u5206\u652F: ${t}`),n?a.info(`\u57FA\u51C6\u5206\u652F: ${n.name}`):a.warn("\u672A\u627E\u5230 Release \u5206\u652F\uFF0C\u5C06\u4EE5\u5F53\u524D\u5206\u652F\u4E3A\u57FA\u51C6");let s=e||await O({message:"\u8BF7\u9009\u62E9\u8981\u521B\u5EFA\u7684\u5206\u652F\u7C7B\u578B:",choices:[{name:"Feature (\u7279\u6027\u5F00\u53D1)",value:"FEATURE"},{name:"Dev (\u6D4B\u8BD5\u73AF\u5883)",value:"DEV"},{name:"Release (\u751F\u4EA7\u73AF\u5883)",value:"RELEASE"}]}),c=n?.project||"mall",m=_(new Date,"yyyyMMdd"),R=await G({message:`\u8BF7\u8F93\u5165\u65E5\u671F (\u683C\u5F0F: YYYYMMDD, \u9ED8\u8BA4: ${m}):`,default:m,validate:g=>/^\d{8}$/.test(g)?g<m?`\u274C \u65E5\u671F\u8FC7\u65E9: \u65E5\u671F\u5FC5\u987B\u5927\u4E8E\u6216\u7B49\u4E8E\u5F53\u524D\u65E5\u671F (${m})`:!0:"\u274C \u683C\u5F0F\u9519\u8BEF: \u8BF7\u8F93\u51658\u4F4D\u6570\u5B57\u65E5\u671F"}),f;return s==="FEATURE"&&(f=await G({message:"\u8BF7\u8F93\u5165\u9700\u6C42\u7F16\u53F7 (\u4F8B\u5982 QZ-8848):",validate:g=>b.test(g)||"\u274C \u683C\u5F0F\u9519\u8BEF: \u9700\u6C42\u7F16\u53F7\u5FC5\u987B\u4E3A QZ \u540E\u63A54\u4F4D\u6570\u5B57 (\u5982 QZ-8848)"})),{type:s,baseBranch:o,project:c,date:R,reqNo:f}}async function I(e){let t=typeof e=="string"?e:void 0;try{a.header("\u521B\u5EFA\u5206\u652F"),await A(),await u();let r=await d(),n=await q(t),{type:o,baseBranch:s,project:c,date:m,reqNo:R}=n,f;o==="FEATURE"?f=`feat/${await U()}-${m}-${R}`:f=`${c}-${o}-${m}`,a.step(`\u6B63\u5728\u4ECE ${s} \u521B\u5EFA ${f}...`),await w(f,!0,s),o!=="FEATURE"&&await x(f),a.done(),o==="FEATURE"?a.success("\u5206\u652F\u521B\u5EFA\u6210\u529F\uFF0C\u5DF2\u5207\u6362\u81F3\u8BE5\u5206\u652F"):(a.success("\u5206\u652F\u521B\u5EFA\u6210\u529F\u5E76\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B"),r!==await d()&&(a.dimRaw(`\u6B63\u5728\u5207\u56DE\u539F\u5206\u652F ${r}...`),await w(r),a.done())),a.footer()}catch(r){a.errorRaw(r.message),a.footer()}}import{confirm as V}from"@inquirer/prompts";async function X(e){await u();let t=await h(),r=S(t,e);if(r||(a.warn(`\u672A\u627E\u5230\u53EF\u7528\u7684 ${e} \u5206\u652F\uFF08\u9700\u4E3A\u4ECA\u65E5\u6216\u672A\u6765\u65F6\u95F4\uFF09\u3002`),await V({message:`\u786E\u5B9A\u8981\u73B0\u5728\u521B\u5EFA\u4E00\u4E2A\u65B0\u7684 ${e} \u5206\u652F\u5417\uFF1F`,default:!0})&&(await I(e),await u(),t=await h(),r=S(t,e))),!r)throw new Error(`\u7EC8\u6B62: \u672A\u80FD\u5B9A\u4F4D\u5230\u6709\u6548\u7684 ${e} \u76EE\u6807\u5206\u652F\u3002`);return r}async function K(e,t){a.step("\u6B63\u5728\u540C\u6B65\u8FDC\u7A0B\u4EE3\u7801..."),await L(e.name),t&&await L(t.name),a.done(),t&&e.name!==t.name&&(a.step(`\u6B63\u5728\u540C\u6B65\u57FA\u51C6 ${t.name} -> ${e.name}...`),await w(e.name),await v(e.name,t.name),a.done())}async function Q(e){let t=await d();try{await A(),a.header("\u5408\u5E76\u5206\u652F"),await u();let r=$(t);if(!r||r.type!=="FEATURE")throw new Error("\u7981\u6B62\u64CD\u4F5C\uFF1A\u8BF7\u5148\u5207\u6362\u5230 Feature \u5206\u652F\u518D\u6267\u884C\u5408\u5E76\u3002");let n=e==="dev"?"DEV":e==="release"?"RELEASE":null;if(!n)throw new Error("\u9519\u8BEF\u53C2\u6570\uFF1A\u8BF7\u6307\u5B9A\u5408\u5E76\u76EE\u6807 (dev \u6216 release)\u3002");a.info(`\u5F53\u524D\u5206\u652F: ${t}`);let o=await X(n),s=await h(),c=n==="DEV"?D(s):j(s);if(a.info(`\u76EE\u6807\u73AF\u5883: ${o.name}${c?` (\u57FA\u51C6: ${c.name})`:""}`),n==="RELEASE"&&!await V({message:`\u26A0\uFE0F \u786E\u5B9A\u8981\u5C06\u7279\u6027\u5206\u652F\u5408\u5E76\u5230\u751F\u4EA7\u73AF\u5883 ${o.name} \u5417\uFF1F`,default:!1})){a.dim("\u64CD\u4F5C\u5DF2\u53D6\u6D88\u3002"),a.footer();return}await K(o,c),a.step(`\u6B63\u5728\u5408\u5E76 Feature \u5230 ${o.name}...`),await w(o.name),await v(o.name,t),a.done(),a.step("\u6B63\u5728\u63A8\u9001\u5230\u8FDC\u7A0B..."),await x(o.name),a.done(),await w(t),a.success(`\u6210\u529F\uFF01Feature \u5DF2\u5408\u5E76\u81F3 ${o.name} \u5E76\u63A8\u9001\u5230 origin\u3002`),a.dim(`\u5DF2\u81EA\u52A8\u5207\u56DE ${t}`),a.footer()}catch(r){a.errorRaw(r.message),await d()!==t&&a.warn(`\u6D41\u7A0B\u4E2D\u65AD\uFF0C\u7531\u4E8E\u4EE3\u7801\u51B2\u7A81\u6216\u5176\u4ED6\u9519\u8BEF\uFF0C\u8BF7\u624B\u52A8\u5904\u7406\u540E\u5207\u56DE ${t}\u3002`),a.footer()}}import W from"cli-table3";import B from"chalk";import{format as z}from"date-fns";async function Y(e){try{await u();let t=await h(),r=parseInt(e,10),n=k(t,"RELEASE",r),o=k(t,"DEV",r);a.header(`\u5206\u652F\u5217\u8868 (Latest ${r})`);let s=new W({head:[B.cyan("Type"),B.cyan("Branch Name"),B.cyan("Date"),B.cyan("Project")],style:{head:[],border:[]}}),c=(m,R,f)=>{m.forEach(g=>{s.push([f(R),g.name,g.date?z(g.date,"yyyy-MM-dd"):"-",g.project||"-"])})};if(c(n,"Release",B.green),c(o,"Dev",B.yellow),s.length===0){a.warn("\u672A\u53D1\u73B0\u7B26\u5408\u89C4\u8303\u7684 dev \u6216 release \u5206\u652F\u3002"),a.footer();return}console.log(s.toString()),a.footer()}catch(t){a.errorRaw(`\u83B7\u53D6\u5206\u652F\u5217\u8868\u5931\u8D25: ${t.message}`),a.footer()}}var T=new H;T.name("agf").description("Auto Git Flow CLI - \u81EA\u52A8\u5316 Git \u5206\u652F\u7BA1\u7406\u5DE5\u5177").version("1.0.0");T.command("create").description("\u521B\u5EFA\u65B0\u5206\u652F (Release, Dev, Feature)").action(I);T.command("merge").description("\u5408\u5E76\u5206\u652F (Safe-Merge \u7B56\u7565)").argument("<target>","\u76EE\u6807\u73AF\u5883 (dev \u6216 release)").action(Q);T.command("list").description("\u67E5\u770B\u6700\u65B0\u7684 dev \u548C release \u5206\u652F").argument("[count]","\u5217\u51FA\u7684\u5206\u652F\u4E2A\u6570 (\u9ED8\u8BA4 2)","2").action(Y);T.parse();
2
+ import{Command as te}from"commander";import{createRequire as re}from"module";import{input as j,select as X}from"@inquirer/prompts";import{format as K}from"date-fns";import{simpleGit as N}from"simple-git";import k from"chalk";var F=null;function s(){return F||(F=N()),F}async function T(){if(!(await s().status()).isClean())throw new Error("\u274C \u5DE5\u4F5C\u533A\u6709\u672A\u63D0\u4EA4\u7684\u4EE3\u7801\uFF0C\u8BF7\u5148 Commit \u6216 Stash\u3002")}async function V(){let e=await s().getConfig("user.name");if(!e.value)throw new Error("\u274C \u83B7\u53D6\u4E0D\u5230\u7528\u6237\u540D\uFF0C\u8BF7\u6267\u884C git config user.name \u914D\u7F6E\u3002");return e.value}async function g(){console.log(k.gray("\u6B63\u5728\u62C9\u53D6\u8FDC\u7A0B\u6700\u65B0\u5206\u652F\u5217\u8868...")),await s().fetch(["--prune"])}async function p(){return(await s().branch()).current}async function u(e,r=!1,n){if(r)if(n){let a=await s().branch(),o=`remotes/origin/${n}`;if(!a.all.includes(o))throw new Error(`\u274C \u9519\u8BEF: \u8FDC\u7A0B\u5206\u652F origin/${n} \u4E0D\u5B58\u5728`);await s().checkout(["-b",e,"--no-track",`origin/${n}`])}else await s().checkoutLocalBranch(e);else await s().checkout(e)}async function x(e,r){try{await s().merge([r])}catch(n){throw console.error(n),new Error(`\u26A0\uFE0F \u53D1\u751F\u4EE3\u7801\u51B2\u7A81\uFF01\u4ECE ${r} \u5408\u5E76\u5230 ${e} \u5931\u8D25\u3002
3
+ \u8BF7\u624B\u52A8\u89E3\u51B3\u51B2\u7A81\u6587\u4EF6\u5E76\u63D0\u4EA4\uFF0C\u7136\u540E\u5207\u6362\u56DE\u539F\u5206\u652F\u3002`)}}async function d(e){await s().push(["-u","origin",e])}async function A(e){let r=await s().branch();if(r.all.includes(e))console.log(k.gray(`\u6B63\u5728\u66F4\u65B0\u672C\u5730\u5206\u652F ${e}...`)),await s().checkout(e),await s().pull("origin",e);else if(r.all.includes(`remotes/origin/${e}`))console.log(k.gray(`\u6B63\u5728\u4ECE\u8FDC\u7A0B\u62C9\u53D6\u5206\u652F ${e}...`)),await s().checkout(["-b",e,`origin/${e}`]);else throw new Error(`\u274C \u9519\u8BEF: \u8FDC\u7A0B\u4E0D\u5B58\u5728\u5206\u652F ${e}`)}async function h(){let e=await s().branch(["-a"]);return Array.from(new Set(e.all.map(r=>r.replace("remotes/origin/",""))))}async function D(e,r){let n=`origin/${e}`,a=`origin/${r}`,o=await s().raw(["rev-list","--count",`${n}..${a}`]);return parseInt(o.trim(),10)>0}import{compareDesc as S,compareAsc as O,parse as M}from"date-fns";var P=/^QZ-\d{4,8}$/;function y(e){let r=e.match(/^(.+)-RELEASE-(\d{8})$/);if(r)return{name:e,type:"RELEASE",project:r[1],date:M(r[2],"yyyyMMdd",new Date)};let n=e.match(/^(.+)-(?:DEV|dev)-(\d{8})$/);if(n)return{name:e,type:"DEV",project:n[1],date:M(n[2],"yyyyMMdd",new Date)};let a=e.match(/^feat\/(.+)-(\d{8})-(QZ-\d{4})$/);return a?{name:e,type:"FEATURE",date:M(a[2],"yyyyMMdd",new Date)}:null}function I(e){return e.map(y).filter(n=>n?.type==="RELEASE").sort((n,a)=>S(n.date,a.date))[0]||null}function Q(e){return e.map(y).filter(n=>n?.type==="RELEASE").sort((n,a)=>S(n.date,a.date))[1]||null}function U(e,r){let n=new Date,a=new Date(n.getFullYear(),n.getMonth(),n.getDate());return e.map(y).filter(i=>i?.type===r&&!!i.date).filter(i=>i.date>=a).sort((i,c)=>O(i.date,c.date))[0]||null}function b(e,r,n){return e.map(y).filter(a=>a?.type===r).sort((a,o)=>S(a.date,o.date)).slice(0,n)}import f from"chalk";var w=f.gray("\u2502"),t={header:e=>{console.log(`
4
+ ${f.bgCyan.black.bold(" GIT-FLOW ")} ${f.cyan.bold(e)}`),console.log(w)},info:e=>console.log(`${w} ${f.blue("\u2139")} ${e}`),step:e=>{process.stdout.write(`${w} ${f.yellow("\u279C")} ${e}`)},success:e=>console.log(`${w} ${f.green("\u2714")} ${e}`),done:()=>{process.stdout.write(f.green(` [OK]
5
+ `))},warn:e=>console.log(`${w} ${f.yellow("\u26A0")} ${e}`),error:e=>console.error(`${w} ${f.red("\u2718")} ${e}`),errorRaw:e=>console.error(`${w} ${f.red(e)}`),dim:e=>console.log(`${w} ${f.gray(e)}`),dimRaw:e=>{process.stdout.write(`${w} ${f.gray(e)}`)},footer:()=>console.log(w+`
6
+ `)};async function W(e){let r=await p(),n=await h(),a=I(n),o=a?.name||r;t.info(`\u5F53\u524D\u5206\u652F: ${r}`),a?t.info(`\u57FA\u51C6\u5206\u652F: ${a.name}`):t.warn("\u672A\u627E\u5230 Release \u5206\u652F\uFF0C\u5C06\u4EE5\u5F53\u524D\u5206\u652F\u4E3A\u57FA\u51C6");let i=e||await X({message:"\u8BF7\u9009\u62E9\u8981\u521B\u5EFA\u7684\u5206\u652F\u7C7B\u578B:",choices:[{name:"Feature (\u7279\u6027\u5F00\u53D1)",value:"FEATURE"},{name:"Dev (\u6D4B\u8BD5\u73AF\u5883)",value:"DEV"},{name:"Release (\u751F\u4EA7\u73AF\u5883)",value:"RELEASE"}]}),c=K(new Date,"yyyyMMdd"),$=await j({message:`\u8BF7\u8F93\u5165\u65E5\u671F (\u683C\u5F0F: YYYYMMDD, \u9ED8\u8BA4: ${c}):`,default:c,validate:l=>/^\d{8}$/.test(l)?l<c?`\u274C \u65E5\u671F\u8FC7\u65E9: \u65E5\u671F\u5FC5\u987B\u5927\u4E8E\u6216\u7B49\u4E8E\u5F53\u524D\u65E5\u671F (${c})`:!0:"\u274C \u683C\u5F0F\u9519\u8BEF: \u8BF7\u8F93\u51658\u4F4D\u6570\u5B57\u65E5\u671F"}),E=a?.project||"";i!=="FEATURE"&&!E&&(E=await j({message:"\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0:",validate:l=>l.trim()?!0:"\u274C \u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A"}));let m;return i==="FEATURE"&&(m=await j({message:"\u8BF7\u8F93\u5165\u9700\u6C42\u7F16\u53F7 (\u4F8B\u5982 QZ-8848):",validate:l=>P.test(l)||"\u274C \u683C\u5F0F\u9519\u8BEF: \u9700\u6C42\u7F16\u53F7\u5FC5\u987B\u4E3A QZ \u540E\u63A54-8\u4F4D\u6570\u5B57 (\u5982 QZ-8848)"})),{type:i,baseBranch:o,project:E,date:$,reqNo:m}}async function L(e){let r=typeof e=="string"?e:void 0;try{t.header("\u521B\u5EFA\u5206\u652F"),await T(),await g();let n=await p(),a=await W(r),{type:o,baseBranch:i,project:c,date:$,reqNo:E}=a,m;o==="FEATURE"?m=`feat/${await V()}-${$}-${E}`:m=`${c}-${o}-${$}`,t.step(`\u6B63\u5728\u4ECE ${i} \u521B\u5EFA ${m}...`),await u(m,!0,i),await d(m),t.done(),o==="FEATURE"?t.success(`\u5206\u652F ${m} \u521B\u5EFA\u6210\u529F\u5E76\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B\uFF0C\u5DF2\u5207\u6362\u81F3\u8BE5\u5206\u652F`):(t.success(`\u5206\u652F ${m} \u521B\u5EFA\u6210\u529F\u5E76\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B`),n!==await p()&&(t.dimRaw(`\u6B63\u5728\u5207\u56DE\u539F\u5206\u652F ${n}...`),await u(n),t.done())),t.footer()}catch(n){t.errorRaw(n.message),t.footer()}}import{confirm as q}from"@inquirer/prompts";async function z(e){await g();let r=await h(),n=U(r,e);if(n||(t.warn(`\u672A\u627E\u5230\u53EF\u7528\u7684 ${e} \u5206\u652F\uFF08\u9700\u4E3A\u4ECA\u65E5\u6216\u672A\u6765\u65F6\u95F4\uFF09\u3002`),await q({message:`\u786E\u5B9A\u8981\u73B0\u5728\u521B\u5EFA\u4E00\u4E2A\u65B0\u7684 ${e} \u5206\u652F\u5417\uFF1F`,default:!0})&&(await L(e),await g(),r=await h(),n=U(r,e))),!n)throw new Error(`\u7EC8\u6B62: \u672A\u80FD\u5B9A\u4F4D\u5230\u6709\u6548\u7684 ${e} \u76EE\u6807\u5206\u652F\u3002`);return n}async function H(e,r,n){t.step("\u6B63\u5728\u540C\u6B65\u8FDC\u7A0B\u4EE3\u7801..."),await A(e.name),r&&(await A(r.name),await A(n)),t.done(),r&&(await D(e.name,r.name)?(t.step(`\u6B63\u5728\u540C\u6B65\u57FA\u51C6 ${r.name} -> ${e.name}...`),await u(e.name),await x(e.name,r.name),await d(e.name),t.done()):t.dim(`${e.name} \u5DF2\u5305\u542B ${r.name} \u7684\u6240\u6709\u63D0\u4EA4\uFF0C\u8DF3\u8FC7\u540C\u6B65`),await D(n,r.name)&&(t.step(`\u68C0\u6D4B\u5230 ${n} \u843D\u540E\u4E8E ${r.name}\uFF0C\u6B63\u5728\u540C\u6B65...`),await u(n),await x(n,r.name),await d(n),t.done()))}async function Y(e){let r=await p();try{await T(),t.header("\u5408\u5E76\u5206\u652F"),await g();let n=y(r);if(!n||n.type!=="FEATURE")throw new Error("\u7981\u6B62\u64CD\u4F5C\uFF1A\u8BF7\u5148\u5207\u6362\u5230 Feature \u5206\u652F\u518D\u6267\u884C\u5408\u5E76\u3002");let a=e==="dev"?"DEV":e==="release"?"RELEASE":null;if(!a)throw new Error("\u9519\u8BEF\u53C2\u6570\uFF1A\u8BF7\u6307\u5B9A\u5408\u5E76\u76EE\u6807 (dev \u6216 release)\u3002");t.info(`\u5F53\u524D\u5206\u652F: ${r}`);let o=await z(a),i=await h(),c=a==="DEV"?I(i):Q(i);if(t.info(`\u76EE\u6807\u73AF\u5883: ${o.name}${c?` (\u57FA\u51C6: ${c.name})`:""}`),a==="RELEASE"&&!await q({message:`\u26A0\uFE0F \u786E\u5B9A\u8981\u5C06\u7279\u6027\u5206\u652F\u5408\u5E76\u5230\u751F\u4EA7\u73AF\u5883 ${o.name} \u5417\uFF1F`,default:!1})){t.dim("\u64CD\u4F5C\u5DF2\u53D6\u6D88\u3002"),t.footer();return}await H(o,c,r),t.step(`\u6B63\u5728\u5408\u5E76 Feature \u5230 ${o.name}...`),await u(o.name),await x(o.name,r),t.done(),t.step("\u6B63\u5728\u63A8\u9001\u5230\u8FDC\u7A0B..."),await d(o.name),t.done(),await u(r),t.success(`\u6210\u529F\uFF01Feature \u5DF2\u5408\u5E76\u81F3 ${o.name} \u5E76\u63A8\u9001\u5230 origin\u3002`),t.dim(`\u5DF2\u81EA\u52A8\u5207\u56DE ${r}`),t.footer()}catch(n){t.errorRaw(n.message),await p()!==r&&t.warn(`\u6D41\u7A0B\u4E2D\u65AD\uFF0C\u7531\u4E8E\u4EE3\u7801\u51B2\u7A81\u6216\u5176\u4ED6\u9519\u8BEF\uFF0C\u8BF7\u624B\u52A8\u5904\u7406\u540E\u5207\u56DE ${r}\u3002`),t.footer()}}import J from"cli-table3";import v from"chalk";import{format as ee}from"date-fns";async function Z(e){try{await g();let r=await h(),n=parseInt(e,10),a=b(r,"RELEASE",n),o=b(r,"DEV",n);t.header(`\u5206\u652F\u5217\u8868 (Latest ${n})`);let i=new J({head:[v.cyan("Type"),v.cyan("Branch Name"),v.cyan("Date"),v.cyan("Project")],style:{head:[],border:[]}}),c=($,E,m)=>{$.forEach(l=>{i.push([m(E),l.name,l.date?ee(l.date,"yyyy-MM-dd"):"-",l.project||"-"])})};if(c(a,"Release",v.green),c(o,"Dev",v.yellow),i.length===0){t.warn("\u672A\u53D1\u73B0\u7B26\u5408\u89C4\u8303\u7684 dev \u6216 release \u5206\u652F\u3002"),t.footer();return}console.log(i.toString()),t.footer()}catch(r){t.errorRaw(`\u83B7\u53D6\u5206\u652F\u5217\u8868\u5931\u8D25: ${r.message}`),t.footer()}}async function _(){let e=await p();try{await T(),t.header("\u540C\u6B65\u57FA\u51C6\u5206\u652F"),await g();let r=y(e);if(!r||r.type!=="FEATURE")throw new Error("\u7981\u6B62\u64CD\u4F5C\uFF1A\u8BF7\u5148\u5207\u6362\u5230 Feature \u5206\u652F\u518D\u6267\u884C\u540C\u6B65\u3002");t.info(`\u5F53\u524D\u5206\u652F: ${e}`);let n=await h(),a=I(n);if(!a)throw new Error("\u672A\u627E\u5230\u53EF\u7528\u7684 Release \u57FA\u51C6\u5206\u652F\u3002");if(t.info(`\u57FA\u51C6\u5206\u652F: ${a.name}`),t.step("\u6B63\u5728\u62C9\u53D6\u8FDC\u7A0B\u4EE3\u7801..."),await A(a.name),await A(e),t.done(),!await D(e,a.name)){t.success(`\u5F53\u524D\u5206\u652F ${e} \u5DF2\u5305\u542B ${a.name} \u7684\u6240\u6709\u63D0\u4EA4\uFF0C\u65E0\u9700\u540C\u6B65\u3002`),t.footer();return}t.step(`\u6B63\u5728\u5408\u5E76 ${a.name} -> ${e}...`),await u(e),await x(e,a.name),t.done(),t.step("\u6B63\u5728\u63A8\u9001\u5230\u8FDC\u7A0B..."),await d(e),t.done(),t.success(`\u6210\u529F\uFF01${a.name} \u5DF2\u5408\u5E76\u81F3 ${e} \u5E76\u63A8\u9001\u5230 origin\u3002`),t.footer()}catch(r){t.errorRaw(r.message),await p()!==e&&t.warn(`\u6D41\u7A0B\u4E2D\u65AD\uFF0C\u7531\u4E8E\u4EE3\u7801\u51B2\u7A81\u6216\u5176\u4ED6\u9519\u8BEF\uFF0C\u8BF7\u624B\u52A8\u5904\u7406\u540E\u5207\u56DE ${e}\u3002`),t.footer()}}var ne=re(import.meta.url),{version:ae}=ne("../package.json"),C=new te;C.name("agf").description("Auto Git Flow CLI - \u81EA\u52A8\u5316 Git \u5206\u652F\u7BA1\u7406\u5DE5\u5177").version(ae);C.command("create").description("\u521B\u5EFA\u65B0\u5206\u652F (Release, Dev, Feature)").action(L);C.command("merge").description("\u5408\u5E76\u5206\u652F (Safe-Merge \u7B56\u7565)").argument("<target>","\u76EE\u6807\u73AF\u5883 (dev \u6216 release)").action(Y);C.command("list").description("\u67E5\u770B\u6700\u65B0\u7684 dev \u548C release \u5206\u652F").argument("[count]","\u5217\u51FA\u7684\u5206\u652F\u4E2A\u6570 (\u9ED8\u8BA4 2)","2").action(Z);C.command("sync").description("\u540C\u6B65\u57FA\u51C6\u5206\u652F\u5230\u5F53\u524D Feature \u5206\u652F").action(_);C.parse();
7
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/create.ts","../src/utils/git.ts","../src/utils/branch.ts","../src/utils/ui.ts","../src/commands/merge.ts","../src/commands/list.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { createAction } from './commands/create.js';\nimport { mergeAction } from './commands/merge.js';\nimport { listAction } from './commands/list.js';\n\nconst program = new Command();\n\nprogram\n .name('agf')\n .description('Auto Git Flow CLI - 自动化 Git 分支管理工具')\n .version('1.0.0');\n\nprogram\n .command('create')\n .description('创建新分支 (Release, Dev, Feature)')\n .action(createAction);\n\nprogram\n .command('merge')\n .description('合并分支 (Safe-Merge 策略)')\n .argument('<target>', '目标环境 (dev 或 release)')\n .action(mergeAction);\n\nprogram\n .command('list')\n .description('查看最新的 dev 和 release 分支')\n .argument('[count]', '列出的分支个数 (默认 2)', '2')\n .action(listAction);\n\nprogram.parse();\n","import { input, select } from '@inquirer/prompts';\nimport { format } from 'date-fns';\nimport { \n checkClean, \n fetchRemote, \n getBranches, \n getUserName, \n checkout, \n push,\n getCurrentBranch\n} from '../utils/git.js';\nimport { \n getLatestRelease, \n REQ_NO_REGEX, \n BranchType \n} from '../utils/branch.js';\nimport { logger } from '../utils/ui.js';\n\ninterface CreateConfig {\n type: BranchType;\n baseBranch: string;\n project: string;\n date: string;\n reqNo?: string | undefined;\n}\n\nasync function getCreateConfig(forcedType?: BranchType): Promise<CreateConfig> {\n const originalBranch = await getCurrentBranch();\n const branches = await getBranches();\n const latestRelease = getLatestRelease(branches);\n const baseBranch = latestRelease?.name || originalBranch;\n\n logger.info(`当前分支: ${originalBranch}`);\n if (latestRelease) {\n logger.info(`基准分支: ${latestRelease.name}`);\n } else {\n logger.warn('未找到 Release 分支,将以当前分支为基准');\n }\n\n const type = forcedType || await select({\n message: '请选择要创建的分支类型:',\n choices: [\n { name: 'Feature (特性开发)', value: BranchType.FEATURE },\n { name: 'Dev (测试环境)', value: BranchType.DEV },\n { name: 'Release (生产环境)', value: BranchType.RELEASE },\n ],\n });\n\n const project = latestRelease?.project || 'mall';\n const today = format(new Date(), 'yyyyMMdd');\n\n const dateInput = await input({\n message: `请输入日期 (格式: YYYYMMDD, 默认: ${today}):`,\n default: today,\n validate: (value) => {\n if (!/^\\d{8}$/.test(value)) return '❌ 格式错误: 请输入8位数字日期';\n if (value < today) return `❌ 日期过早: 日期必须大于或等于当前日期 (${today})`;\n return true;\n },\n });\n\n let reqNo;\n if (type === BranchType.FEATURE) {\n reqNo = await input({\n message: '请输入需求编号 (例如 QZ-8848):',\n validate: (input) => REQ_NO_REGEX.test(input) || '❌ 格式错误: 需求编号必须为 QZ 后接4位数字 (如 QZ-8848)',\n });\n }\n\n return { type, baseBranch, project, date: dateInput, reqNo };\n}\n\nexport async function createAction(arg?: BranchType | any) {\n // Commander passes the Command object if no args are defined, so we need to filter that out\n const forcedType = typeof arg === 'string' ? arg as BranchType : undefined;\n try {\n logger.header('创建分支');\n await checkClean();\n await fetchRemote();\n\n const originalBranch = await getCurrentBranch();\n const config = await getCreateConfig(forcedType);\n const { type, baseBranch, project, date, reqNo } = config;\n\n let branchName: string;\n if (type === BranchType.FEATURE) {\n const user = await getUserName();\n branchName = `feat/${user}-${date}-${reqNo}`;\n } else {\n branchName = `${project}-${type}-${date}`;\n }\n\n logger.step(`正在从 ${baseBranch} 创建 ${branchName}...`);\n await checkout(branchName, true, baseBranch);\n \n if (type !== BranchType.FEATURE) {\n await push(branchName);\n }\n logger.done();\n\n if (type === BranchType.FEATURE) {\n logger.success('分支创建成功,已切换至该分支');\n } else {\n logger.success('分支创建成功并已推送到远程');\n \n // 非特性分支创建后切回原分支\n if (originalBranch !== (await getCurrentBranch())) {\n logger.dimRaw(`正在切回原分支 ${originalBranch}...`);\n await checkout(originalBranch);\n logger.done();\n }\n }\n\n logger.footer();\n\n } catch (err: any) {\n logger.errorRaw(err.message);\n logger.footer();\n }\n}\n","import { simpleGit, type SimpleGit } from 'simple-git';\nimport chalk from 'chalk';\n\nconst git: SimpleGit = simpleGit();\n\nexport async function checkClean() {\n const status = await git.status();\n if (!status.isClean()) {\n throw new Error('❌ 工作区有未提交的代码,请先 Commit 或 Stash。');\n }\n}\n\nexport async function getUserName(): Promise<string> {\n const name = await git.getConfig('user.name');\n if (!name.value) {\n throw new Error('❌ 获取不到用户名,请执行 git config user.name 配置。');\n }\n return name.value;\n}\n\nexport async function fetchRemote() {\n console.log(chalk.gray('正在拉取远程最新分支列表...'));\n await git.fetch(['--prune']);\n}\n\nexport async function getCurrentBranch(): Promise<string> {\n const branchInfo = await git.branch();\n return branchInfo.current;\n}\n\nexport async function checkout(branch: string, create = false, startPoint?: string) {\n if (create) {\n if (startPoint) {\n await git.checkout(['-b', branch, startPoint]);\n } else {\n await git.checkoutLocalBranch(branch);\n }\n } else {\n await git.checkout(branch);\n }\n}\n\nexport async function merge(target: string, source: string) {\n try {\n await git.merge([source]);\n } catch (err: any) {\n throw new Error(`⚠️ 发生代码冲突!从 ${source} 合并到 ${target} 失败。\\n请手动解决冲突文件并提交,然后切换回原分支。`);\n }\n}\n\nexport async function push(branch: string) {\n await git.push(['-u', 'origin', branch]);\n}\n\nexport async function pullBranch(branch: string) {\n const branches = await git.branch();\n const isLocal = branches.all.includes(branch);\n \n if (!isLocal) {\n // Check if remote exists\n const remoteExists = branches.all.includes(`remotes/origin/${branch}`);\n if (remoteExists) {\n console.log(chalk.gray(`正在从远程拉取分支 ${branch}...`));\n await git.checkout(['-b', branch, `origin/${branch}`]);\n } else {\n throw new Error(`❌ 错误: 远程不存在分支 ${branch}`);\n }\n } else {\n console.log(chalk.gray(`正在更新本地分支 ${branch}...`));\n await git.checkout(branch);\n await git.pull('origin', branch);\n }\n}\n\nexport async function getBranches() {\n const summary = await git.branch(['-a']);\n return Array.from(new Set(summary.all.map(b => b.replace('remotes/origin/', ''))));\n}\n\nexport { git };\n","import { compareDesc, compareAsc, parse } from 'date-fns';\n\nexport enum BranchType {\n RELEASE = 'RELEASE',\n DEV = 'DEV',\n FEATURE = 'FEATURE'\n}\n\nexport const REQ_NO_REGEX = /^QZ-\\d{4}$/;\n\nexport interface BranchInfo {\n name: string;\n type: BranchType;\n date?: Date;\n project?: string;\n}\n\nexport function parseBranch(branchName: string): BranchInfo | null {\n // Release: {project}-RELEASE-{YYYYMMDD}\n const releaseMatch = branchName.match(/^(.+)-RELEASE-(\\d{8})$/);\n if (releaseMatch) {\n return {\n name: branchName,\n type: BranchType.RELEASE,\n project: releaseMatch[1]!,\n date: parse(releaseMatch[2]!, 'yyyyMMdd', new Date())\n };\n }\n\n // Dev: {project}-DEV-{YYYYMMDD}\n // {project}-dev-{YYYYMMDD}\n const devMatch = branchName.match(/^(.+)-(?:DEV|dev)-(\\d{8})$/);\n if (devMatch) {\n return {\n name: branchName,\n type: BranchType.DEV,\n project: devMatch[1]!,\n date: parse(devMatch[2]!, 'yyyyMMdd', new Date())\n };\n }\n\n // Feature: feat/{user}-{date}-{reqNo}\n const featMatch = branchName.match(/^feat\\/(.+)-(\\d{8})-(QZ-\\d{4})$/);\n if (featMatch) {\n return {\n name: branchName,\n type: BranchType.FEATURE,\n date: parse(featMatch[2]!, 'yyyyMMdd', new Date())\n };\n }\n\n return null;\n}\n\nexport function getLatestRelease(branches: string[]): BranchInfo | null {\n const releases = branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === BranchType.RELEASE)\n .sort((a, b) => compareDesc(a.date!, b.date!));\n\n return releases[0] || null;\n}\n\nexport function getPreviousRelease(branches: string[]): BranchInfo | null {\n const releases = branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === BranchType.RELEASE)\n .sort((a, b) => compareDesc(a.date!, b.date!));\n\n return releases[1] || null;\n}\n\nexport function getTargetBranch(branches: string[], type: BranchType): BranchInfo | null {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); // Start of today\n\n const targets = branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === type && !!b.date)\n .filter(b => b.date! >= today) // Only today or future\n .sort((a, b) => compareAsc(a.date!, b.date!));\n\n return targets[0] || null; // Return the earliest one (which is the closest to today)\n}\nexport function getLatestBranches(branches: string[], type: BranchType, limit: number): BranchInfo[] {\n return branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === type)\n .sort((a, b) => compareDesc(a.date!, b.date!))\n .slice(0, limit);\n}\n","import chalk from 'chalk';\n\nconst PREFIX = chalk.gray('│');\n\nexport const logger = {\n header: (title: string) => {\n console.log(`\\n${chalk.bgCyan.black.bold(' GIT-FLOW ')} ${chalk.cyan.bold(title)}`);\n console.log(PREFIX);\n },\n info: (msg: string) => console.log(`${PREFIX} ${chalk.blue('ℹ')} ${msg}`),\n step: (msg: string) => {\n process.stdout.write(`${PREFIX} ${chalk.yellow('➜')} ${msg}`);\n },\n success: (msg: string) => console.log(`${PREFIX} ${chalk.green('✔')} ${msg}`),\n done: () => {\n process.stdout.write(chalk.green(' [OK]\\n'));\n },\n warn: (msg: string) => console.log(`${PREFIX} ${chalk.yellow('⚠')} ${msg}`),\n error: (msg: string) => console.error(`${PREFIX} ${chalk.red('✘')} ${msg}`),\n errorRaw: (msg: string) => console.error(`${PREFIX} ${chalk.red(msg)}`),\n dim: (msg: string) => console.log(`${PREFIX} ${chalk.gray(msg)}`),\n dimRaw: (msg: string) => {\n process.stdout.write(`${PREFIX} ${chalk.gray(msg)}`);\n },\n footer: () => console.log(PREFIX + '\\n'),\n};\n","import { confirm } from '@inquirer/prompts';\nimport { \n checkClean, \n fetchRemote, \n getBranches, \n getCurrentBranch, \n checkout, \n merge, \n push,\n pullBranch\n} from '../utils/git.js';\nimport { \n getTargetBranch, \n getLatestRelease, \n getPreviousRelease,\n parseBranch, \n BranchType,\n type BranchInfo\n} from '../utils/branch.js';\nimport { createAction } from './create.js';\nimport { logger } from '../utils/ui.js';\n\n/**\n * 确保目标分支存在,如果不存在则引导用户创建\n */\nasync function ensureTargetBranch(type: BranchType): Promise<BranchInfo> {\n await fetchRemote();\n let branches = await getBranches();\n let target = getTargetBranch(branches, type);\n\n if (!target) {\n logger.warn(`未找到可用的 ${type} 分支(需为今日或未来时间)。`);\n const shouldCreate = await confirm({\n message: `确定要现在创建一个新的 ${type} 分支吗?`,\n default: true\n });\n\n if (shouldCreate) {\n await createAction(type);\n await fetchRemote();\n branches = await getBranches();\n target = getTargetBranch(branches, type);\n }\n }\n\n if (!target) {\n throw new Error(`终止: 未能定位到有效的 ${type} 目标分支。`);\n }\n\n return target;\n}\n\n/**\n * 执行同步逻辑:拉取远程最新代码并同步基准分支\n */\nasync function syncAndPrepare(target: BranchInfo, base: BranchInfo | null) {\n logger.step('正在同步远程代码...');\n await pullBranch(target.name);\n if (base) {\n await pullBranch(base.name);\n }\n logger.done();\n\n if (base && target.name !== base.name) {\n logger.step(`正在同步基准 ${base.name} -> ${target.name}...`);\n await checkout(target.name);\n await merge(target.name, base.name);\n logger.done();\n }\n}\n\nexport async function mergeAction(targetArg?: string) {\n const originalBranch = await getCurrentBranch();\n \n try {\n await checkClean();\n logger.header('合并分支');\n await fetchRemote();\n\n // 1. 语法校验与状态检查\n const currentInfo = parseBranch(originalBranch);\n if (!currentInfo || currentInfo.type !== BranchType.FEATURE) {\n throw new Error('禁止操作:请先切换到 Feature 分支再执行合并。');\n }\n\n const targetType = targetArg === 'dev' ? BranchType.DEV : \n targetArg === 'release' ? BranchType.RELEASE : null;\n \n if (!targetType) {\n throw new Error('错误参数:请指定合并目标 (dev 或 release)。');\n }\n\n logger.info(`当前分支: ${originalBranch}`);\n\n // 2. 定位目标与基准\n const targetBranch = await ensureTargetBranch(targetType);\n const branches = await getBranches();\n const baseBranch = targetType === BranchType.DEV ? getLatestRelease(branches) : getPreviousRelease(branches);\n\n logger.info(`目标环境: ${targetBranch.name}${baseBranch ? ` (基准: ${baseBranch.name})` : ''}`);\n\n // 3. 二次确认 (Release)\n if (targetType === BranchType.RELEASE) {\n const isConfirmed = await confirm({\n message: `⚠️ 确定要将特性分支合并到生产环境 ${targetBranch.name} 吗?`,\n default: false,\n });\n if (!isConfirmed) {\n logger.dim('操作已取消。');\n logger.footer();\n return;\n }\n }\n\n // 4. 同步与合并\n await syncAndPrepare(targetBranch, baseBranch);\n\n logger.step(`正在合并 Feature 到 ${targetBranch.name}...`);\n await checkout(targetBranch.name);\n await merge(targetBranch.name, originalBranch);\n logger.done();\n \n logger.step('正在推送到远程...');\n await push(targetBranch.name);\n logger.done();\n\n // 5. 还原\n await checkout(originalBranch);\n logger.success(`成功!Feature 已合并至 ${targetBranch.name} 并推送到 origin。`);\n logger.dim(`已自动切回 ${originalBranch}`);\n \n logger.footer();\n\n } catch (err: any) {\n logger.errorRaw(err.message);\n const nowBranch = await getCurrentBranch();\n if (nowBranch !== originalBranch) {\n logger.warn(`流程中断,由于代码冲突或其他错误,请手动处理后切回 ${originalBranch}。`);\n }\n logger.footer();\n }\n}\n","import Table from 'cli-table3';\nimport chalk from 'chalk';\nimport { getBranches, fetchRemote } from '../utils/git.js';\nimport { BranchType, getLatestBranches, type BranchInfo } from '../utils/branch.js';\nimport { format } from 'date-fns';\nimport { logger } from '../utils/ui.js';\n\nexport async function listAction(count: string) {\n try {\n await fetchRemote();\n const branches = await getBranches();\n\n const limit = parseInt(count, 10);\n const latestRelease = getLatestBranches(branches, BranchType.RELEASE, limit);\n const latestDev = getLatestBranches(branches, BranchType.DEV, limit);\n\n logger.header(`分支列表 (Latest ${limit})`);\n\n const table = new Table({\n head: [chalk.cyan('Type'), chalk.cyan('Branch Name'), chalk.cyan('Date'), chalk.cyan('Project')],\n style: {\n head: [],\n border: [],\n }\n });\n\n const addRows = (branchInfos: BranchInfo[], typeName: string, color: (s: string) => string) => {\n branchInfos.forEach(info => {\n table.push([\n color(typeName),\n info.name,\n info.date ? format(info.date, 'yyyy-MM-dd') : '-',\n info.project || '-'\n ]);\n });\n };\n\n addRows(latestRelease, 'Release', chalk.green);\n addRows(latestDev, 'Dev', chalk.yellow);\n\n if (table.length === 0) {\n logger.warn('未发现符合规范的 dev 或 release 分支。');\n logger.footer();\n return;\n }\n\n console.log(table.toString());\n logger.footer();\n\n } catch (error: any) {\n logger.errorRaw(`获取分支列表失败: ${error.message}`);\n logger.footer();\n }\n}\n"],"mappings":"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","names":["Command","input","select","format","simpleGit","chalk","git","checkClean","getUserName","name","fetchRemote","getCurrentBranch","checkout","branch","create","startPoint","merge","target","source","push","pullBranch","branches","getBranches","summary","b","compareDesc","compareAsc","parse","REQ_NO_REGEX","parseBranch","branchName","releaseMatch","parse","devMatch","featMatch","getLatestRelease","branches","b","a","compareDesc","getPreviousRelease","getTargetBranch","type","now","today","compareAsc","getLatestBranches","limit","chalk","PREFIX","logger","title","msg","getCreateConfig","forcedType","originalBranch","getCurrentBranch","branches","getBranches","latestRelease","getLatestRelease","baseBranch","logger","type","select","project","today","format","dateInput","input","value","reqNo","REQ_NO_REGEX","createAction","arg","checkClean","fetchRemote","config","date","branchName","getUserName","checkout","push","err","confirm","ensureTargetBranch","type","fetchRemote","branches","getBranches","target","getTargetBranch","logger","confirm","createAction","syncAndPrepare","base","pullBranch","checkout","merge","mergeAction","targetArg","originalBranch","getCurrentBranch","checkClean","currentInfo","parseBranch","targetType","targetBranch","baseBranch","getLatestRelease","getPreviousRelease","push","err","Table","chalk","format","listAction","count","fetchRemote","branches","getBranches","limit","latestRelease","getLatestBranches","latestDev","logger","table","Table","chalk","addRows","branchInfos","typeName","color","info","format","error","program","Command","createAction","mergeAction","listAction"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/create.ts","../src/utils/git.ts","../src/utils/branch.ts","../src/utils/ui.ts","../src/commands/merge.ts","../src/commands/list.ts","../src/commands/sync.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander'\nimport { createRequire } from 'module'\nimport { createAction } from './commands/create.js'\nimport { mergeAction } from './commands/merge.js'\nimport { listAction } from './commands/list.js'\nimport { syncAction } from './commands/sync.js'\n\n// todo: optimize json import\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json')\n\nconst program = new Command()\n\nprogram\n .name('agf')\n .description('Auto Git Flow CLI - 自动化 Git 分支管理工具')\n .version(version)\n\nprogram\n .command('create')\n .description('创建新分支 (Release, Dev, Feature)')\n .action(createAction)\n\nprogram\n .command('merge')\n .description('合并分支 (Safe-Merge 策略)')\n .argument('<target>', '目标环境 (dev 或 release)')\n .action(mergeAction)\n\nprogram\n .command('list')\n .description('查看最新的 dev 和 release 分支')\n .argument('[count]', '列出的分支个数 (默认 2)', '2')\n .action(listAction)\n\nprogram\n .command('sync')\n .description('同步基准分支到当前 Feature 分支')\n .action(syncAction)\n\nprogram.parse()\n","import { input, select } from '@inquirer/prompts'\nimport { format } from 'date-fns'\nimport {\n checkClean,\n fetchRemote,\n getBranches,\n getUserName,\n checkout,\n push,\n getCurrentBranch,\n} from '../utils/git.js'\nimport { getLatestRelease, REQ_NO_REGEX, BranchType } from '../utils/branch.js'\nimport { logger } from '../utils/ui.js'\n\ninterface CreateConfig {\n type: BranchType\n baseBranch: string\n project: string\n date: string\n reqNo?: string | undefined\n}\n\nasync function getCreateConfig(forcedType?: BranchType): Promise<CreateConfig> {\n const originalBranch = await getCurrentBranch()\n const branches = await getBranches()\n const latestRelease = getLatestRelease(branches)\n const baseBranch = latestRelease?.name || originalBranch\n\n logger.info(`当前分支: ${originalBranch}`)\n if (latestRelease) {\n logger.info(`基准分支: ${latestRelease.name}`)\n } else {\n // TODO: Is this logic correctly ?\n logger.warn('未找到 Release 分支,将以当前分支为基准')\n }\n\n const type =\n forcedType ||\n (await select({\n message: '请选择要创建的分支类型:',\n choices: [\n { name: 'Feature (特性开发)', value: BranchType.FEATURE },\n { name: 'Dev (测试环境)', value: BranchType.DEV },\n { name: 'Release (生产环境)', value: BranchType.RELEASE },\n ],\n }))\n\n const today = format(new Date(), 'yyyyMMdd')\n\n const dateInput = await input({\n message: `请输入日期 (格式: YYYYMMDD, 默认: ${today}):`,\n default: today,\n validate: (value) => {\n if (!/^\\d{8}$/.test(value)) return '❌ 格式错误: 请输入8位数字日期'\n if (value < today)\n return `❌ 日期过早: 日期必须大于或等于当前日期 (${today})`\n return true\n },\n })\n\n let project = latestRelease?.project || ''\n if (type !== BranchType.FEATURE && !project) {\n project = await input({\n message: '请输入项目名称:',\n validate: (v) => (v.trim() ? true : '❌ 项目名称不能为空'),\n })\n }\n\n let reqNo\n if (type === BranchType.FEATURE) {\n reqNo = await input({\n message: '请输入需求编号 (例如 QZ-8848):',\n validate: (input) =>\n REQ_NO_REGEX.test(input) ||\n '❌ 格式错误: 需求编号必须为 QZ 后接4-8位数字 (如 QZ-8848)',\n })\n }\n\n return { type, baseBranch, project, date: dateInput, reqNo }\n}\n\nexport async function createAction(arg?: BranchType | any) {\n // Commander passes the Command object if no args are defined, so we need to filter that out\n const forcedType = typeof arg === 'string' ? (arg as BranchType) : undefined\n try {\n logger.header('创建分支')\n await checkClean()\n await fetchRemote()\n\n const originalBranch = await getCurrentBranch()\n const config = await getCreateConfig(forcedType)\n const { type, baseBranch, project, date, reqNo } = config\n\n let branchName: string\n if (type === BranchType.FEATURE) {\n const user = await getUserName()\n branchName = `feat/${user}-${date}-${reqNo}`\n } else {\n branchName = `${project}-${type}-${date}`\n }\n\n logger.step(`正在从 ${baseBranch} 创建 ${branchName}...`)\n await checkout(branchName, true, baseBranch)\n await push(branchName)\n logger.done()\n\n if (type === BranchType.FEATURE) {\n logger.success(\n `分支 ${branchName} 创建成功并已推送到远程,已切换至该分支`\n )\n } else {\n logger.success(`分支 ${branchName} 创建成功并已推送到远程`)\n // 非特性分支创建后切回原分支\n if (originalBranch !== (await getCurrentBranch())) {\n logger.dimRaw(`正在切回原分支 ${originalBranch}...`)\n await checkout(originalBranch)\n logger.done()\n }\n }\n\n logger.footer()\n } catch (err: any) {\n logger.errorRaw(err.message)\n logger.footer()\n }\n}\n","import { simpleGit, type SimpleGit } from 'simple-git'\nimport chalk from 'chalk'\n\nlet _git: SimpleGit | null = null\n\nexport function getGit() {\n if (!_git) {\n _git = simpleGit()\n }\n return _git\n}\n\nexport function resetGitInstance() {\n _git = null\n}\n\nexport async function checkClean() {\n const status = await getGit().status()\n if (!status.isClean()) {\n throw new Error('❌ 工作区有未提交的代码,请先 Commit 或 Stash。')\n }\n}\n\nexport async function getUserName(): Promise<string> {\n const name = await getGit().getConfig('user.name')\n if (!name.value) {\n throw new Error('❌ 获取不到用户名,请执行 git config user.name 配置。')\n }\n return name.value\n}\n\nexport async function fetchRemote() {\n console.log(chalk.gray('正在拉取远程最新分支列表...'))\n await getGit().fetch(['--prune'])\n}\n\nexport async function getCurrentBranch(): Promise<string> {\n const branchInfo = await getGit().branch()\n // TODO: Why this occur empty string ?\n return branchInfo.current\n}\n\nexport async function checkout(\n branch: string,\n create = false,\n startPoint?: string\n) {\n if (create) {\n if (startPoint) {\n // 始终使用远程分支作为基准\n const branches = await getGit().branch()\n const remoteRef = `remotes/origin/${startPoint}`\n const remoteExists = branches.all.includes(remoteRef)\n\n if (!remoteExists) {\n throw new Error(`❌ 错误: 远程分支 origin/${startPoint} 不存在`)\n }\n\n // https://git-scm.com/docs/git-config#Documentation/git-config.txt-branchautoSetupMerge\n // Use --no-track to prevent auto track\n await getGit().checkout([\n '-b',\n branch,\n '--no-track',\n `origin/${startPoint}`,\n ])\n } else {\n await getGit().checkoutLocalBranch(branch)\n }\n } else {\n await getGit().checkout(branch)\n }\n}\n\nexport async function merge(target: string, source: string) {\n try {\n await getGit().merge([source])\n } catch (err: any) {\n console.error(err)\n throw new Error(\n `⚠️ 发生代码冲突!从 ${source} 合并到 ${target} 失败。\\n请手动解决冲突文件并提交,然后切换回原分支。`\n )\n }\n}\n\nexport async function push(branch: string) {\n await getGit().push(['-u', 'origin', branch])\n}\n\nexport async function pullBranch(branch: string) {\n const branches = await getGit().branch()\n const isLocal = branches.all.includes(branch)\n\n if (!isLocal) {\n // Check if remote exists\n const remoteExists = branches.all.includes(`remotes/origin/${branch}`)\n if (remoteExists) {\n console.log(chalk.gray(`正在从远程拉取分支 ${branch}...`))\n await getGit().checkout(['-b', branch, `origin/${branch}`])\n } else {\n throw new Error(`❌ 错误: 远程不存在分支 ${branch}`)\n }\n } else {\n console.log(chalk.gray(`正在更新本地分支 ${branch}...`))\n await getGit().checkout(branch)\n await getGit().pull('origin', branch)\n }\n}\n\nexport async function getBranches() {\n const summary = await getGit().branch(['-a'])\n return Array.from(\n new Set(summary.all.map((b) => b.replace('remotes/origin/', '')))\n )\n}\n\n/**\n * 检查分支 A 是否落后于分支 B\n * @returns true 表示 A 落后于 B(B 有 A 没有的提交)\n */\nexport async function isBranchBehind(\n branchA: string,\n branchB: string\n): Promise<boolean> {\n // 使用远程分支进行比对\n const refA = `origin/${branchA}`\n const refB = `origin/${branchB}`\n\n const result = await getGit().raw(['rev-list', '--count', `${refA}..${refB}`])\n return parseInt(result.trim(), 10) > 0\n}\n","import { compareDesc, compareAsc, parse } from 'date-fns'\n\nexport enum BranchType {\n RELEASE = 'RELEASE',\n DEV = 'DEV',\n FEATURE = 'FEATURE',\n}\n\nexport const REQ_NO_REGEX = /^QZ-\\d{4,8}$/\n\nexport interface BranchInfo {\n name: string\n type: BranchType\n date?: Date\n project?: string\n}\n\nexport function parseBranch(branchName: string): BranchInfo | null {\n // Release: {project}-RELEASE-{YYYYMMDD}\n const releaseMatch = branchName.match(/^(.+)-RELEASE-(\\d{8})$/)\n if (releaseMatch) {\n return {\n name: branchName,\n type: BranchType.RELEASE,\n project: releaseMatch[1]!,\n date: parse(releaseMatch[2]!, 'yyyyMMdd', new Date()),\n }\n }\n\n // Dev: {project}-DEV-{YYYYMMDD}\n // {project}-dev-{YYYYMMDD}\n const devMatch = branchName.match(/^(.+)-(?:DEV|dev)-(\\d{8})$/)\n if (devMatch) {\n return {\n name: branchName,\n type: BranchType.DEV,\n project: devMatch[1]!,\n date: parse(devMatch[2]!, 'yyyyMMdd', new Date()),\n }\n }\n\n // Feature: feat/{user}-{date}-{reqNo}\n const featMatch = branchName.match(/^feat\\/(.+)-(\\d{8})-(QZ-\\d{4})$/)\n if (featMatch) {\n return {\n name: branchName,\n type: BranchType.FEATURE,\n date: parse(featMatch[2]!, 'yyyyMMdd', new Date()),\n }\n }\n\n return null\n}\n\nexport function getLatestRelease(branches: string[]): BranchInfo | null {\n const releases = branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === BranchType.RELEASE)\n .sort((a, b) => compareDesc(a.date!, b.date!))\n\n return releases[0] || null\n}\n\nexport function getPreviousRelease(branches: string[]): BranchInfo | null {\n const releases = branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === BranchType.RELEASE)\n .sort((a, b) => compareDesc(a.date!, b.date!))\n\n return releases[1] || null\n}\n\nexport function getTargetBranch(\n branches: string[],\n type: BranchType\n): BranchInfo | null {\n const now = new Date()\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()) // Start of today\n\n const targets = branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === type && !!b.date)\n .filter((b) => b.date! >= today) // Only today or future\n .sort((a, b) => compareAsc(a.date!, b.date!))\n\n return targets[0] || null // Return the earliest one (which is the closest to today)\n}\nexport function getLatestBranches(\n branches: string[],\n type: BranchType,\n limit: number\n): BranchInfo[] {\n return branches\n .map(parseBranch)\n .filter((b): b is BranchInfo => b?.type === type)\n .sort((a, b) => compareDesc(a.date!, b.date!))\n .slice(0, limit)\n}\n","import chalk from 'chalk'\n\nconst PREFIX = chalk.gray('│')\n\nexport const logger = {\n header: (title: string) => {\n console.log(\n `\\n${chalk.bgCyan.black.bold(' GIT-FLOW ')} ${chalk.cyan.bold(title)}`\n )\n console.log(PREFIX)\n },\n info: (msg: string) => console.log(`${PREFIX} ${chalk.blue('ℹ')} ${msg}`),\n step: (msg: string) => {\n process.stdout.write(`${PREFIX} ${chalk.yellow('➜')} ${msg}`)\n },\n success: (msg: string) => console.log(`${PREFIX} ${chalk.green('✔')} ${msg}`),\n done: () => {\n process.stdout.write(chalk.green(' [OK]\\n'))\n },\n warn: (msg: string) => console.log(`${PREFIX} ${chalk.yellow('⚠')} ${msg}`),\n error: (msg: string) => console.error(`${PREFIX} ${chalk.red('✘')} ${msg}`),\n errorRaw: (msg: string) => console.error(`${PREFIX} ${chalk.red(msg)}`),\n dim: (msg: string) => console.log(`${PREFIX} ${chalk.gray(msg)}`),\n dimRaw: (msg: string) => {\n process.stdout.write(`${PREFIX} ${chalk.gray(msg)}`)\n },\n footer: () => console.log(PREFIX + '\\n'),\n}\n","import { confirm } from '@inquirer/prompts'\nimport {\n checkClean,\n fetchRemote,\n getBranches,\n getCurrentBranch,\n checkout,\n merge,\n push,\n pullBranch,\n isBranchBehind,\n} from '../utils/git.js'\nimport {\n getTargetBranch,\n getLatestRelease,\n getPreviousRelease,\n parseBranch,\n BranchType,\n type BranchInfo,\n} from '../utils/branch.js'\nimport { createAction } from './create.js'\nimport { logger } from '../utils/ui.js'\n\n/**\n * 确保目标分支存在,如果不存在则引导用户创建\n */\nasync function ensureTargetBranch(type: BranchType): Promise<BranchInfo> {\n await fetchRemote()\n let branches = await getBranches()\n let target = getTargetBranch(branches, type)\n\n if (!target) {\n logger.warn(`未找到可用的 ${type} 分支(需为今日或未来时间)。`)\n const shouldCreate = await confirm({\n message: `确定要现在创建一个新的 ${type} 分支吗?`,\n default: true,\n })\n\n if (shouldCreate) {\n await createAction(type)\n await fetchRemote()\n branches = await getBranches()\n target = getTargetBranch(branches, type)\n }\n }\n\n if (!target) {\n throw new Error(`终止: 未能定位到有效的 ${type} 目标分支。`)\n }\n\n return target\n}\n\n/**\n * 执行同步逻辑:拉取远程最新代码并按需同步基准分支\n */\nasync function syncAndPrepare(\n target: BranchInfo,\n base: BranchInfo | null,\n feature: string\n) {\n logger.step('正在同步远程代码...')\n await pullBranch(target.name)\n if (base) {\n await pullBranch(base.name)\n await pullBranch(feature)\n }\n logger.done()\n\n if (base) {\n // 1. 检查目标分支是否落后于基准分支\n if (await isBranchBehind(target.name, base.name)) {\n logger.step(`正在同步基准 ${base.name} -> ${target.name}...`)\n await checkout(target.name)\n await merge(target.name, base.name)\n await push(target.name)\n logger.done()\n } else {\n logger.dim(`${target.name} 已包含 ${base.name} 的所有提交,跳过同步`)\n }\n\n // 2. 检查特性分支是否落后于基准分支\n if (await isBranchBehind(feature, base.name)) {\n logger.step(`检测到 ${feature} 落后于 ${base.name},正在同步...`)\n await checkout(feature)\n await merge(feature, base.name)\n await push(feature)\n logger.done()\n }\n }\n}\n\nexport async function mergeAction(targetArg?: string) {\n const originalBranch = await getCurrentBranch()\n\n try {\n await checkClean()\n logger.header('合并分支')\n await fetchRemote()\n\n // 1. 语法校验与状态检查\n const currentInfo = parseBranch(originalBranch)\n if (!currentInfo || currentInfo.type !== BranchType.FEATURE) {\n throw new Error('禁止操作:请先切换到 Feature 分支再执行合并。')\n }\n\n const targetType =\n targetArg === 'dev'\n ? BranchType.DEV\n : targetArg === 'release'\n ? BranchType.RELEASE\n : null\n\n if (!targetType) {\n throw new Error('错误参数:请指定合并目标 (dev 或 release)。')\n }\n\n logger.info(`当前分支: ${originalBranch}`)\n\n // 2. 定位目标与基准\n const targetBranch = await ensureTargetBranch(targetType)\n const branches = await getBranches()\n const baseBranch =\n targetType === BranchType.DEV\n ? getLatestRelease(branches)\n : getPreviousRelease(branches)\n\n logger.info(\n `目标环境: ${targetBranch.name}${baseBranch ? ` (基准: ${baseBranch.name})` : ''}`\n )\n\n // 3. 二次确认 (Release)\n if (targetType === BranchType.RELEASE) {\n const isConfirmed = await confirm({\n message: `⚠️ 确定要将特性分支合并到生产环境 ${targetBranch.name} 吗?`,\n default: false,\n })\n if (!isConfirmed) {\n logger.dim('操作已取消。')\n logger.footer()\n return\n }\n }\n\n // 4. 同步与合并\n await syncAndPrepare(targetBranch, baseBranch, originalBranch)\n\n logger.step(`正在合并 Feature 到 ${targetBranch.name}...`)\n await checkout(targetBranch.name)\n await merge(targetBranch.name, originalBranch)\n logger.done()\n\n logger.step('正在推送到远程...')\n await push(targetBranch.name)\n logger.done()\n\n // 5. 还原\n await checkout(originalBranch)\n logger.success(\n `成功!Feature 已合并至 ${targetBranch.name} 并推送到 origin。`\n )\n logger.dim(`已自动切回 ${originalBranch}`)\n\n logger.footer()\n } catch (err: any) {\n logger.errorRaw(err.message)\n const nowBranch = await getCurrentBranch()\n if (nowBranch !== originalBranch) {\n logger.warn(\n `流程中断,由于代码冲突或其他错误,请手动处理后切回 ${originalBranch}。`\n )\n }\n logger.footer()\n }\n}\n","import Table from 'cli-table3'\nimport chalk from 'chalk'\nimport { getBranches, fetchRemote } from '../utils/git.js'\nimport {\n BranchType,\n getLatestBranches,\n type BranchInfo,\n} from '../utils/branch.js'\nimport { format } from 'date-fns'\nimport { logger } from '../utils/ui.js'\n\nexport async function listAction(count: string) {\n try {\n await fetchRemote()\n const branches = await getBranches()\n\n const limit = parseInt(count, 10)\n const latestRelease = getLatestBranches(branches, BranchType.RELEASE, limit)\n const latestDev = getLatestBranches(branches, BranchType.DEV, limit)\n\n logger.header(`分支列表 (Latest ${limit})`)\n\n const table = new Table({\n head: [\n chalk.cyan('Type'),\n chalk.cyan('Branch Name'),\n chalk.cyan('Date'),\n chalk.cyan('Project'),\n ],\n style: {\n head: [],\n border: [],\n },\n })\n\n const addRows = (\n branchInfos: BranchInfo[],\n typeName: string,\n color: (s: string) => string\n ) => {\n branchInfos.forEach((info) => {\n table.push([\n color(typeName),\n info.name,\n info.date ? format(info.date, 'yyyy-MM-dd') : '-',\n info.project || '-',\n ])\n })\n }\n\n addRows(latestRelease, 'Release', chalk.green)\n addRows(latestDev, 'Dev', chalk.yellow)\n\n if (table.length === 0) {\n logger.warn('未发现符合规范的 dev 或 release 分支。')\n logger.footer()\n return\n }\n\n console.log(table.toString())\n logger.footer()\n } catch (error: any) {\n logger.errorRaw(`获取分支列表失败: ${error.message}`)\n logger.footer()\n }\n}\n","import {\n checkClean,\n fetchRemote,\n getBranches,\n getCurrentBranch,\n checkout,\n merge,\n push,\n pullBranch,\n isBranchBehind,\n} from '../utils/git.js'\nimport { getLatestRelease, parseBranch, BranchType } from '../utils/branch.js'\nimport { logger } from '../utils/ui.js'\n\nexport async function syncAction() {\n const currentBranch = await getCurrentBranch()\n\n try {\n await checkClean()\n logger.header('同步基准分支')\n await fetchRemote()\n\n const currentInfo = parseBranch(currentBranch)\n if (!currentInfo || currentInfo.type !== BranchType.FEATURE) {\n throw new Error('禁止操作:请先切换到 Feature 分支再执行同步。')\n }\n\n logger.info(`当前分支: ${currentBranch}`)\n\n const branches = await getBranches()\n const baseBranch = getLatestRelease(branches)\n\n if (!baseBranch) {\n throw new Error('未找到可用的 Release 基准分支。')\n }\n\n logger.info(`基准分支: ${baseBranch.name}`)\n\n logger.step('正在拉取远程代码...')\n await pullBranch(baseBranch.name)\n await pullBranch(currentBranch)\n logger.done()\n\n const isBehind = await isBranchBehind(currentBranch, baseBranch.name)\n\n if (!isBehind) {\n logger.success(\n `当前分支 ${currentBranch} 已包含 ${baseBranch.name} 的所有提交,无需同步。`\n )\n logger.footer()\n return\n }\n\n logger.step(`正在合并 ${baseBranch.name} -> ${currentBranch}...`)\n await checkout(currentBranch)\n await merge(currentBranch, baseBranch.name)\n logger.done()\n\n logger.step('正在推送到远程...')\n await push(currentBranch)\n logger.done()\n\n logger.success(\n `成功!${baseBranch.name} 已合并至 ${currentBranch} 并推送到 origin。`\n )\n logger.footer()\n } catch (err: any) {\n logger.errorRaw(err.message)\n const nowBranch = await getCurrentBranch()\n if (nowBranch !== currentBranch) {\n logger.warn(\n `流程中断,由于代码冲突或其他错误,请手动处理后切回 ${currentBranch}。`\n )\n }\n logger.footer()\n }\n}\n"],"mappings":";AACA,OAAS,WAAAA,OAAe,YACxB,OAAS,iBAAAC,OAAqB,SCF9B,OAAS,SAAAC,EAAO,UAAAC,MAAc,oBAC9B,OAAS,UAAAC,MAAc,WCDvB,OAAS,aAAAC,MAAiC,aAC1C,OAAOC,MAAW,QAElB,IAAIC,EAAyB,KAEtB,SAASC,GAAS,CACvB,OAAKD,IACHA,EAAOF,EAAU,GAEZE,CACT,CAMA,eAAsBE,GAAa,CAEjC,GAAI,EADW,MAAMC,EAAO,EAAE,OAAO,GACzB,QAAQ,EAClB,MAAM,IAAI,MAAM,iHAAiC,CAErD,CAEA,eAAsBC,GAA+B,CACnD,IAAMC,EAAO,MAAMF,EAAO,EAAE,UAAU,WAAW,EACjD,GAAI,CAACE,EAAK,MACR,MAAM,IAAI,MAAM,mHAAwC,EAE1D,OAAOA,EAAK,KACd,CAEA,eAAsBC,GAAc,CAClC,QAAQ,IAAIC,EAAM,KAAK,6EAAiB,CAAC,EACzC,MAAMJ,EAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAClC,CAEA,eAAsBK,GAAoC,CAGxD,OAFmB,MAAML,EAAO,EAAE,OAAO,GAEvB,OACpB,CAEA,eAAsBM,EACpBC,EACAC,EAAS,GACTC,EACA,CACA,GAAID,EACF,GAAIC,EAAY,CAEd,IAAMC,EAAW,MAAMV,EAAO,EAAE,OAAO,EACjCW,EAAY,kBAAkBF,CAAU,GAG9C,GAAI,CAFiBC,EAAS,IAAI,SAASC,CAAS,EAGlD,MAAM,IAAI,MAAM,wDAAqBF,CAAU,qBAAM,EAKvD,MAAMT,EAAO,EAAE,SAAS,CACtB,KACAO,EACA,aACA,UAAUE,CAAU,EACtB,CAAC,CACH,MACE,MAAMT,EAAO,EAAE,oBAAoBO,CAAM,OAG3C,MAAMP,EAAO,EAAE,SAASO,CAAM,CAElC,CAEA,eAAsBK,EAAMC,EAAgBC,EAAgB,CAC1D,GAAI,CACF,MAAMd,EAAO,EAAE,MAAM,CAACc,CAAM,CAAC,CAC/B,OAASC,EAAU,CACjB,cAAQ,MAAMA,CAAG,EACX,IAAI,MACR,iEAAeD,CAAM,uBAAQD,CAAM;AAAA,qIACrC,CACF,CACF,CAEA,eAAsBG,EAAKT,EAAgB,CACzC,MAAMP,EAAO,EAAE,KAAK,CAAC,KAAM,SAAUO,CAAM,CAAC,CAC9C,CAEA,eAAsBU,EAAWV,EAAgB,CAC/C,IAAMG,EAAW,MAAMV,EAAO,EAAE,OAAO,EAGvC,GAFgBU,EAAS,IAAI,SAASH,CAAM,EAY1C,QAAQ,IAAIH,EAAM,KAAK,oDAAYG,CAAM,KAAK,CAAC,EAC/C,MAAMP,EAAO,EAAE,SAASO,CAAM,EAC9B,MAAMP,EAAO,EAAE,KAAK,SAAUO,CAAM,UAVfG,EAAS,IAAI,SAAS,kBAAkBH,CAAM,EAAE,EAEnE,QAAQ,IAAIH,EAAM,KAAK,0DAAaG,CAAM,KAAK,CAAC,EAChD,MAAMP,EAAO,EAAE,SAAS,CAAC,KAAMO,EAAQ,UAAUA,CAAM,EAAE,CAAC,MAE1D,OAAM,IAAI,MAAM,mEAAiBA,CAAM,EAAE,CAO/C,CAEA,eAAsBW,GAAc,CAClC,IAAMC,EAAU,MAAMnB,EAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAC5C,OAAO,MAAM,KACX,IAAI,IAAImB,EAAQ,IAAI,IAAKC,GAAMA,EAAE,QAAQ,kBAAmB,EAAE,CAAC,CAAC,CAClE,CACF,CAMA,eAAsBC,EACpBC,EACAC,EACkB,CAElB,IAAMC,EAAO,UAAUF,CAAO,GACxBG,EAAO,UAAUF,CAAO,GAExBG,EAAS,MAAM1B,EAAO,EAAE,IAAI,CAAC,WAAY,UAAW,GAAGwB,CAAI,KAAKC,CAAI,EAAE,CAAC,EAC7E,OAAO,SAASC,EAAO,KAAK,EAAG,EAAE,EAAI,CACvC,CClIA,OAAS,eAAAC,EAAa,cAAAC,EAAY,SAAAC,MAAa,WAQxC,IAAMC,EAAe,eASrB,SAASC,EAAYC,EAAuC,CAEjE,IAAMC,EAAeD,EAAW,MAAM,wBAAwB,EAC9D,GAAIC,EACF,MAAO,CACL,KAAMD,EACN,KAAM,UACN,QAASC,EAAa,CAAC,EACvB,KAAMC,EAAMD,EAAa,CAAC,EAAI,WAAY,IAAI,IAAM,CACtD,EAKF,IAAME,EAAWH,EAAW,MAAM,4BAA4B,EAC9D,GAAIG,EACF,MAAO,CACL,KAAMH,EACN,KAAM,MACN,QAASG,EAAS,CAAC,EACnB,KAAMD,EAAMC,EAAS,CAAC,EAAI,WAAY,IAAI,IAAM,CAClD,EAIF,IAAMC,EAAYJ,EAAW,MAAM,iCAAiC,EACpE,OAAII,EACK,CACL,KAAMJ,EACN,KAAM,UACN,KAAME,EAAME,EAAU,CAAC,EAAI,WAAY,IAAI,IAAM,CACnD,EAGK,IACT,CAEO,SAASC,EAAiBC,EAAuC,CAMtE,OALiBA,EACd,IAAIP,CAAW,EACf,OAAQQ,GAAuBA,GAAG,OAAS,SAAkB,EAC7D,KAAK,CAACC,EAAGD,IAAME,EAAYD,EAAE,KAAOD,EAAE,IAAK,CAAC,EAE/B,CAAC,GAAK,IACxB,CAEO,SAASG,EAAmBJ,EAAuC,CAMxE,OALiBA,EACd,IAAIP,CAAW,EACf,OAAQQ,GAAuBA,GAAG,OAAS,SAAkB,EAC7D,KAAK,CAACC,EAAGD,IAAME,EAAYD,EAAE,KAAOD,EAAE,IAAK,CAAC,EAE/B,CAAC,GAAK,IACxB,CAEO,SAASI,EACdL,EACAM,EACmB,CACnB,IAAMC,EAAM,IAAI,KACVC,EAAQ,IAAI,KAAKD,EAAI,YAAY,EAAGA,EAAI,SAAS,EAAGA,EAAI,QAAQ,CAAC,EAQvE,OANgBP,EACb,IAAIP,CAAW,EACf,OAAQQ,GAAuBA,GAAG,OAASK,GAAQ,CAAC,CAACL,EAAE,IAAI,EAC3D,OAAQA,GAAMA,EAAE,MAASO,CAAK,EAC9B,KAAK,CAACN,EAAGD,IAAMQ,EAAWP,EAAE,KAAOD,EAAE,IAAK,CAAC,EAE/B,CAAC,GAAK,IACvB,CACO,SAASS,EACdV,EACAM,EACAK,EACc,CACd,OAAOX,EACJ,IAAIP,CAAW,EACf,OAAQQ,GAAuBA,GAAG,OAASK,CAAI,EAC/C,KAAK,CAAC,EAAGL,IAAME,EAAY,EAAE,KAAOF,EAAE,IAAK,CAAC,EAC5C,MAAM,EAAGU,CAAK,CACnB,CCjGA,OAAOC,MAAW,QAElB,IAAMC,EAASD,EAAM,KAAK,QAAG,EAEhBE,EAAS,CACpB,OAASC,GAAkB,CACzB,QAAQ,IACN;AAAA,EAAKH,EAAM,OAAO,MAAM,KAAK,YAAY,CAAC,IAAIA,EAAM,KAAK,KAAKG,CAAK,CAAC,EACtE,EACA,QAAQ,IAAIF,CAAM,CACpB,EACA,KAAOG,GAAgB,QAAQ,IAAI,GAAGH,CAAM,IAAID,EAAM,KAAK,QAAG,CAAC,IAAII,CAAG,EAAE,EACxE,KAAOA,GAAgB,CACrB,QAAQ,OAAO,MAAM,GAAGH,CAAM,IAAID,EAAM,OAAO,QAAG,CAAC,IAAII,CAAG,EAAE,CAC9D,EACA,QAAUA,GAAgB,QAAQ,IAAI,GAAGH,CAAM,IAAID,EAAM,MAAM,QAAG,CAAC,IAAII,CAAG,EAAE,EAC5E,KAAM,IAAM,CACV,QAAQ,OAAO,MAAMJ,EAAM,MAAM;AAAA,CAAS,CAAC,CAC7C,EACA,KAAOI,GAAgB,QAAQ,IAAI,GAAGH,CAAM,IAAID,EAAM,OAAO,QAAG,CAAC,IAAII,CAAG,EAAE,EAC1E,MAAQA,GAAgB,QAAQ,MAAM,GAAGH,CAAM,IAAID,EAAM,IAAI,QAAG,CAAC,IAAII,CAAG,EAAE,EAC1E,SAAWA,GAAgB,QAAQ,MAAM,GAAGH,CAAM,IAAID,EAAM,IAAII,CAAG,CAAC,EAAE,EACtE,IAAMA,GAAgB,QAAQ,IAAI,GAAGH,CAAM,IAAID,EAAM,KAAKI,CAAG,CAAC,EAAE,EAChE,OAASA,GAAgB,CACvB,QAAQ,OAAO,MAAM,GAAGH,CAAM,IAAID,EAAM,KAAKI,CAAG,CAAC,EAAE,CACrD,EACA,OAAQ,IAAM,QAAQ,IAAIH,EAAS;AAAA,CAAI,CACzC,EHLA,eAAeI,EAAgBC,EAAgD,CAC7E,IAAMC,EAAiB,MAAMC,EAAiB,EACxCC,EAAW,MAAMC,EAAY,EAC7BC,EAAgBC,EAAiBH,CAAQ,EACzCI,EAAaF,GAAe,MAAQJ,EAE1CO,EAAO,KAAK,6BAASP,CAAc,EAAE,EACjCI,EACFG,EAAO,KAAK,6BAASH,EAAc,IAAI,EAAE,EAGzCG,EAAO,KAAK,qGAA0B,EAGxC,IAAMC,EACJT,GACC,MAAMU,EAAO,CACZ,QAAS,sEACT,QAAS,CACP,CAAE,KAAM,qCAAkB,eAA0B,EACpD,CAAE,KAAM,iCAAc,WAAsB,EAC5C,CAAE,KAAM,qCAAkB,eAA0B,CACtD,CACF,CAAC,EAEGC,EAAQC,EAAO,IAAI,KAAQ,UAAU,EAErCC,EAAY,MAAMC,EAAM,CAC5B,QAAS,yEAA4BH,CAAK,KAC1C,QAASA,EACT,SAAWI,GACJ,UAAU,KAAKA,CAAK,EACrBA,EAAQJ,EACH,oHAA0BA,CAAK,IACjC,GAH4B,oFAKvC,CAAC,EAEGK,EAAUX,GAAe,SAAW,GACpCI,IAAS,WAAsB,CAACO,IAClCA,EAAU,MAAMF,EAAM,CACpB,QAAS,8CACT,SAAWG,GAAOA,EAAE,KAAK,EAAI,GAAO,yDACtC,CAAC,GAGH,IAAIC,EACJ,OAAIT,IAAS,YACXS,EAAQ,MAAMJ,EAAM,CAClB,QAAS,qEACT,SAAWA,GACTK,EAAa,KAAKL,CAAK,GACvB,mIACJ,CAAC,GAGI,CAAE,KAAAL,EAAM,WAAAF,EAAY,QAAAS,EAAS,KAAMH,EAAW,MAAAK,CAAM,CAC7D,CAEA,eAAsBE,EAAaC,EAAwB,CAEzD,IAAMrB,EAAa,OAAOqB,GAAQ,SAAYA,EAAqB,OACnE,GAAI,CACFb,EAAO,OAAO,0BAAM,EACpB,MAAMc,EAAW,EACjB,MAAMC,EAAY,EAElB,IAAMtB,EAAiB,MAAMC,EAAiB,EACxCsB,EAAS,MAAMzB,EAAgBC,CAAU,EACzC,CAAE,KAAAS,EAAM,WAAAF,EAAY,QAAAS,EAAS,KAAAS,EAAM,MAAAP,CAAM,EAAIM,EAE/CE,EACAjB,IAAS,UAEXiB,EAAa,QADA,MAAMC,EAAY,CACN,IAAIF,CAAI,IAAIP,CAAK,GAE1CQ,EAAa,GAAGV,CAAO,IAAIP,CAAI,IAAIgB,CAAI,GAGzCjB,EAAO,KAAK,sBAAOD,CAAU,iBAAOmB,CAAU,KAAK,EACnD,MAAME,EAASF,EAAY,GAAMnB,CAAU,EAC3C,MAAMsB,EAAKH,CAAU,EACrBlB,EAAO,KAAK,EAERC,IAAS,UACXD,EAAO,QACL,gBAAMkB,CAAU,qHAClB,GAEAlB,EAAO,QAAQ,gBAAMkB,CAAU,qEAAc,EAEzCzB,IAAoB,MAAMC,EAAiB,IAC7CM,EAAO,OAAO,8CAAWP,CAAc,KAAK,EAC5C,MAAM2B,EAAS3B,CAAc,EAC7BO,EAAO,KAAK,IAIhBA,EAAO,OAAO,CAChB,OAASsB,EAAU,CACjBtB,EAAO,SAASsB,EAAI,OAAO,EAC3BtB,EAAO,OAAO,CAChB,CACF,CI7HA,OAAS,WAAAuB,MAAe,oBA0BxB,eAAeC,EAAmBC,EAAuC,CACvE,MAAMC,EAAY,EAClB,IAAIC,EAAW,MAAMC,EAAY,EAC7BC,EAASC,EAAgBH,EAAUF,CAAI,EAiB3C,GAfKI,IACHE,EAAO,KAAK,wCAAUN,CAAI,uFAAiB,EACtB,MAAMO,EAAQ,CACjC,QAAS,sEAAeP,CAAI,4BAC5B,QAAS,EACX,CAAC,IAGC,MAAMQ,EAAaR,CAAI,EACvB,MAAMC,EAAY,EAClBC,EAAW,MAAMC,EAAY,EAC7BC,EAASC,EAAgBH,EAAUF,CAAI,IAIvC,CAACI,EACH,MAAM,IAAI,MAAM,kEAAgBJ,CAAI,iCAAQ,EAG9C,OAAOI,CACT,CAKA,eAAeK,EACbL,EACAM,EACAC,EACA,CACAL,EAAO,KAAK,qDAAa,EACzB,MAAMM,EAAWR,EAAO,IAAI,EACxBM,IACF,MAAME,EAAWF,EAAK,IAAI,EAC1B,MAAME,EAAWD,CAAO,GAE1BL,EAAO,KAAK,EAERI,IAEE,MAAMG,EAAeT,EAAO,KAAMM,EAAK,IAAI,GAC7CJ,EAAO,KAAK,wCAAUI,EAAK,IAAI,OAAON,EAAO,IAAI,KAAK,EACtD,MAAMU,EAASV,EAAO,IAAI,EAC1B,MAAMW,EAAMX,EAAO,KAAMM,EAAK,IAAI,EAClC,MAAMM,EAAKZ,EAAO,IAAI,EACtBE,EAAO,KAAK,GAEZA,EAAO,IAAI,GAAGF,EAAO,IAAI,uBAAQM,EAAK,IAAI,+DAAa,EAIrD,MAAMG,EAAeF,EAASD,EAAK,IAAI,IACzCJ,EAAO,KAAK,sBAAOK,CAAO,uBAAQD,EAAK,IAAI,mCAAU,EACrD,MAAMI,EAASH,CAAO,EACtB,MAAMI,EAAMJ,EAASD,EAAK,IAAI,EAC9B,MAAMM,EAAKL,CAAO,EAClBL,EAAO,KAAK,GAGlB,CAEA,eAAsBW,EAAYC,EAAoB,CACpD,IAAMC,EAAiB,MAAMC,EAAiB,EAE9C,GAAI,CACF,MAAMC,EAAW,EACjBf,EAAO,OAAO,0BAAM,EACpB,MAAML,EAAY,EAGlB,IAAMqB,EAAcC,EAAYJ,CAAc,EAC9C,GAAI,CAACG,GAAeA,EAAY,OAAS,UACvC,MAAM,IAAI,MAAM,uHAA6B,EAG/C,IAAME,EACJN,IAAc,YAEVA,IAAc,oBAEZ,KAER,GAAI,CAACM,EACH,MAAM,IAAI,MAAM,qGAA+B,EAGjDlB,EAAO,KAAK,6BAASa,CAAc,EAAE,EAGrC,IAAMM,EAAe,MAAM1B,EAAmByB,CAAU,EAClDtB,EAAW,MAAMC,EAAY,EAC7BuB,EACJF,IAAe,MACXG,EAAiBzB,CAAQ,EACzB0B,EAAmB1B,CAAQ,EAOjC,GALAI,EAAO,KACL,6BAASmB,EAAa,IAAI,GAAGC,EAAa,mBAASA,EAAW,IAAI,IAAM,EAAE,EAC5E,EAGIF,IAAe,WAKb,CAJgB,MAAMjB,EAAQ,CAChC,QAAS,2GAAsBkB,EAAa,IAAI,gBAChD,QAAS,EACX,CAAC,EACiB,CAChBnB,EAAO,IAAI,sCAAQ,EACnBA,EAAO,OAAO,EACd,MACF,CAIF,MAAMG,EAAegB,EAAcC,EAAYP,CAAc,EAE7Db,EAAO,KAAK,2CAAkBmB,EAAa,IAAI,KAAK,EACpD,MAAMX,EAASW,EAAa,IAAI,EAChC,MAAMV,EAAMU,EAAa,KAAMN,CAAc,EAC7Cb,EAAO,KAAK,EAEZA,EAAO,KAAK,+CAAY,EACxB,MAAMU,EAAKS,EAAa,IAAI,EAC5BnB,EAAO,KAAK,EAGZ,MAAMQ,EAASK,CAAc,EAC7Bb,EAAO,QACL,sDAAmBmB,EAAa,IAAI,wCACtC,EACAnB,EAAO,IAAI,kCAASa,CAAc,EAAE,EAEpCb,EAAO,OAAO,CAChB,OAASuB,EAAU,CACjBvB,EAAO,SAASuB,EAAI,OAAO,EACT,MAAMT,EAAiB,IACvBD,GAChBb,EAAO,KACL,0JAA6Ba,CAAc,QAC7C,EAEFb,EAAO,OAAO,CAChB,CACF,CC9KA,OAAOwB,MAAW,aAClB,OAAOC,MAAW,QAOlB,OAAS,UAAAC,OAAc,WAGvB,eAAsBC,EAAWC,EAAe,CAC9C,GAAI,CACF,MAAMC,EAAY,EAClB,IAAMC,EAAW,MAAMC,EAAY,EAE7BC,EAAQ,SAASJ,EAAO,EAAE,EAC1BK,EAAgBC,EAAkBJ,YAA8BE,CAAK,EACrEG,EAAYD,EAAkBJ,QAA0BE,CAAK,EAEnEI,EAAO,OAAO,oCAAgBJ,CAAK,GAAG,EAEtC,IAAMK,EAAQ,IAAIC,EAAM,CACtB,KAAM,CACJC,EAAM,KAAK,MAAM,EACjBA,EAAM,KAAK,aAAa,EACxBA,EAAM,KAAK,MAAM,EACjBA,EAAM,KAAK,SAAS,CACtB,EACA,MAAO,CACL,KAAM,CAAC,EACP,OAAQ,CAAC,CACX,CACF,CAAC,EAEKC,EAAU,CACdC,EACAC,EACAC,IACG,CACHF,EAAY,QAASG,GAAS,CAC5BP,EAAM,KAAK,CACTM,EAAMD,CAAQ,EACdE,EAAK,KACLA,EAAK,KAAOC,GAAOD,EAAK,KAAM,YAAY,EAAI,IAC9CA,EAAK,SAAW,GAClB,CAAC,CACH,CAAC,CACH,EAKA,GAHAJ,EAAQP,EAAe,UAAWM,EAAM,KAAK,EAC7CC,EAAQL,EAAW,MAAOI,EAAM,MAAM,EAElCF,EAAM,SAAW,EAAG,CACtBD,EAAO,KAAK,wFAA4B,EACxCA,EAAO,OAAO,EACd,MACF,CAEA,QAAQ,IAAIC,EAAM,SAAS,CAAC,EAC5BD,EAAO,OAAO,CAChB,OAASU,EAAY,CACnBV,EAAO,SAAS,qDAAaU,EAAM,OAAO,EAAE,EAC5CV,EAAO,OAAO,CAChB,CACF,CCnDA,eAAsBW,GAAa,CACjC,IAAMC,EAAgB,MAAMC,EAAiB,EAE7C,GAAI,CACF,MAAMC,EAAW,EACjBC,EAAO,OAAO,sCAAQ,EACtB,MAAMC,EAAY,EAElB,IAAMC,EAAcC,EAAYN,CAAa,EAC7C,GAAI,CAACK,GAAeA,EAAY,OAAS,UACvC,MAAM,IAAI,MAAM,uHAA6B,EAG/CF,EAAO,KAAK,6BAASH,CAAa,EAAE,EAEpC,IAAMO,EAAW,MAAMC,EAAY,EAC7BC,EAAaC,EAAiBH,CAAQ,EAE5C,GAAI,CAACE,EACH,MAAM,IAAI,MAAM,6EAAsB,EAYxC,GATAN,EAAO,KAAK,6BAASM,EAAW,IAAI,EAAE,EAEtCN,EAAO,KAAK,qDAAa,EACzB,MAAMQ,EAAWF,EAAW,IAAI,EAChC,MAAME,EAAWX,CAAa,EAC9BG,EAAO,KAAK,EAIR,CAFa,MAAMS,EAAeZ,EAAeS,EAAW,IAAI,EAErD,CACbN,EAAO,QACL,4BAAQH,CAAa,uBAAQS,EAAW,IAAI,qEAC9C,EACAN,EAAO,OAAO,EACd,MACF,CAEAA,EAAO,KAAK,4BAAQM,EAAW,IAAI,OAAOT,CAAa,KAAK,EAC5D,MAAMa,EAASb,CAAa,EAC5B,MAAMc,EAAMd,EAAeS,EAAW,IAAI,EAC1CN,EAAO,KAAK,EAEZA,EAAO,KAAK,+CAAY,EACxB,MAAMY,EAAKf,CAAa,EACxBG,EAAO,KAAK,EAEZA,EAAO,QACL,qBAAMM,EAAW,IAAI,6BAAST,CAAa,wCAC7C,EACAG,EAAO,OAAO,CAChB,OAASa,EAAU,CACjBb,EAAO,SAASa,EAAI,OAAO,EACT,MAAMf,EAAiB,IACvBD,GAChBG,EAAO,KACL,0JAA6BH,CAAa,QAC5C,EAEFG,EAAO,OAAO,CAChB,CACF,CPnEA,IAAMc,GAAUC,GAAc,YAAY,GAAG,EACvC,CAAE,QAAAC,EAAQ,EAAIF,GAAQ,iBAAiB,EAEvCG,EAAU,IAAIC,GAEpBD,EACG,KAAK,KAAK,EACV,YAAY,iFAAoC,EAChD,QAAQD,EAAO,EAElBC,EACG,QAAQ,QAAQ,EAChB,YAAY,wDAA+B,EAC3C,OAAOE,CAAY,EAEtBF,EACG,QAAQ,OAAO,EACf,YAAY,oDAAsB,EAClC,SAAS,WAAY,+CAAsB,EAC3C,OAAOG,CAAW,EAErBH,EACG,QAAQ,MAAM,EACd,YAAY,gEAAwB,EACpC,SAAS,UAAW,8DAAkB,GAAG,EACzC,OAAOI,CAAU,EAEpBJ,EACG,QAAQ,MAAM,EACd,YAAY,6EAAsB,EAClC,OAAOK,CAAU,EAEpBL,EAAQ,MAAM","names":["Command","createRequire","input","select","format","simpleGit","chalk","_git","getGit","checkClean","getGit","getUserName","name","fetchRemote","chalk","getCurrentBranch","checkout","branch","create","startPoint","branches","remoteRef","merge","target","source","err","push","pullBranch","getBranches","summary","b","isBranchBehind","branchA","branchB","refA","refB","result","compareDesc","compareAsc","parse","REQ_NO_REGEX","parseBranch","branchName","releaseMatch","parse","devMatch","featMatch","getLatestRelease","branches","b","a","compareDesc","getPreviousRelease","getTargetBranch","type","now","today","compareAsc","getLatestBranches","limit","chalk","PREFIX","logger","title","msg","getCreateConfig","forcedType","originalBranch","getCurrentBranch","branches","getBranches","latestRelease","getLatestRelease","baseBranch","logger","type","select","today","format","dateInput","input","value","project","v","reqNo","REQ_NO_REGEX","createAction","arg","checkClean","fetchRemote","config","date","branchName","getUserName","checkout","push","err","confirm","ensureTargetBranch","type","fetchRemote","branches","getBranches","target","getTargetBranch","logger","confirm","createAction","syncAndPrepare","base","feature","pullBranch","isBranchBehind","checkout","merge","push","mergeAction","targetArg","originalBranch","getCurrentBranch","checkClean","currentInfo","parseBranch","targetType","targetBranch","baseBranch","getLatestRelease","getPreviousRelease","err","Table","chalk","format","listAction","count","fetchRemote","branches","getBranches","limit","latestRelease","getLatestBranches","latestDev","logger","table","Table","chalk","addRows","branchInfos","typeName","color","info","format","error","syncAction","currentBranch","getCurrentBranch","checkClean","logger","fetchRemote","currentInfo","parseBranch","branches","getBranches","baseBranch","getLatestRelease","pullBranch","isBranchBehind","checkout","merge","push","err","require","createRequire","version","program","Command","createAction","mergeAction","listAction","syncAction"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sppk/auto-git-flow",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,21 @@
13
13
  "scripts": {
14
14
  "dev": "tsx src/index.ts",
15
15
  "build": "tsup",
16
- "prepublishOnly": "pnpm build"
16
+ "prepublishOnly": "pnpm build",
17
+ "prepare": "husky",
18
+ "lint": "eslint .",
19
+ "lint:fix": "eslint . --fix",
20
+ "format": "prettier --write .",
21
+ "format:check": "prettier --check ."
22
+ },
23
+ "lint-staged": {
24
+ "*.{ts,js}": [
25
+ "eslint --fix",
26
+ "prettier --write"
27
+ ],
28
+ "*.json": [
29
+ "prettier --write"
30
+ ]
17
31
  },
18
32
  "publishConfig": {
19
33
  "access": "public",
@@ -24,10 +38,20 @@
24
38
  "license": "ISC",
25
39
  "packageManager": "pnpm@10.8.0",
26
40
  "devDependencies": {
41
+ "@commitlint/cli": "^20.3.0",
42
+ "@commitlint/config-conventional": "^20.3.0",
43
+ "@eslint/js": "^9.39.2",
27
44
  "@types/node": "^25.0.3",
45
+ "eslint": "^9.39.2",
46
+ "eslint-config-prettier": "^10.1.8",
47
+ "husky": "^9.1.7",
48
+ "lint-staged": "^16.2.7",
49
+ "prettier": "^3.7.4",
28
50
  "tsup": "^8.5.1",
29
51
  "tsx": "^4.21.0",
30
- "typescript": "^5.9.3"
52
+ "typescript": "^5.9.3",
53
+ "typescript-eslint": "^8.52.0",
54
+ "vitest": "^4.0.16"
31
55
  },
32
56
  "dependencies": {
33
57
  "@inquirer/prompts": "^8.1.0",