@loviusc/sa-spec 0.2.4 → 0.2.6
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.en.md +6 -6
- package/README.ja.md +5 -5
- package/README.ko.md +5 -5
- package/README.zh-CN.md +5 -5
- package/README.zh-TW.md +25 -13
- package/package.json +1 -1
- package/readme.md +25 -13
- package/src/cli.js +119 -13
- package/templates/AGENTS.md +12 -8
- package/templates/project/req/handoff.md +3 -0
- package/templates/project/req/srs.md +3 -0
- package/templates/project/req/uml/wireframe.puml +13 -0
- package/templates/readme.md +25 -13
- package/templates/rules/uml-style.md +1 -0
- package/templates/skills/system-analysis/SKILL.md +13 -9
package/README.en.md
CHANGED
|
@@ -102,18 +102,18 @@ To solve sequential ID collisions and Git merge conflicts in team environments,
|
|
|
102
102
|
|
|
103
103
|
```mermaid
|
|
104
104
|
flowchart TD
|
|
105
|
-
A["New Requirement: scp or sa-spec new --branch"] --> B["Create & switch to feat/cart branch<br/>Draft directory: project/cart/"]
|
|
105
|
+
A["New Requirement: scp or sa-spec new --branch"] --> B["Create & switch to feat/cart branch<br/>Push branch to remote if configured<br/>Draft directory: project/cart/"]
|
|
106
106
|
B --> C["AI Analysis: sca<br/>Uses {{REQ_ID}} placeholder<br/>Pre-check against master spec baseline"]
|
|
107
107
|
C --> D{"User Approved?<br/>Execute scc or finalize"}
|
|
108
|
-
D --> E["
|
|
109
|
-
E --> F["Auto assign project/REQ-N+1-cart/<br/>Replace {{REQ_ID}}
|
|
110
|
-
F --> G["Auto merge into master
|
|
108
|
+
D --> E["Push branch to remote & fetch first<br/>Then query latest ID N from master"]
|
|
109
|
+
E --> F["Auto assign project/REQ-N+1-cart/<br/>Replace {{REQ_ID}}, commit & push branch"]
|
|
110
|
+
F --> G["Auto merge into master & push to remote<br/>Dynamically rebuild project/index.md"]
|
|
111
111
|
G --> H["Closed Loop: Zero conflicts, Continuous IDs!"]
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
1. **Draft Phase (No ID Contention)**: Run `sa-spec new --name checkout --branch` or prompt `scp checkout` in AI chat. It creates `feat/checkout` and `project/checkout/` using `{{REQ_ID}}`. Parallel branches never collide. If an idea is abandoned, deleting the branch leaves zero ghost IDs.
|
|
114
|
+
1. **Draft Phase (No ID Contention)**: Run `sa-spec new --name checkout --branch` or prompt `scp checkout` in AI chat. It creates `feat/checkout` (and automatically pushes it to Git remote if configured) and `project/checkout/` using `{{REQ_ID}}`. Parallel branches never collide. If an idea is abandoned, deleting the branch leaves zero ghost IDs.
|
|
115
115
|
2. **Baseline Protection**: `spec:analyze` fetches latest `master` before analyzing to prevent missing newly merged API or table changes.
|
|
116
|
-
3. **Late-Binding Finalize
|
|
116
|
+
3. **Late-Binding Finalize, Auto-Merge & Remote Push**: Running `scc` in AI chat (or `sa-spec finalize --name checkout`) first pushes the feature branch to remote (if a remote exists) and syncs remote refs, then inspects master's latest ID, assigns `REQ-xxx`, replaces placeholders, commits, **automatically merges into master** (`git checkout master && git merge feat/checkout`), updates `project/index.md`, and pushes `master` to remote.
|
|
117
117
|
4. **Conflict-Free Reindex**: `sa-spec reindex` builds `project/index.md` on the fly from disk.
|
|
118
118
|
|
|
119
119
|
---
|
package/README.ja.md
CHANGED
|
@@ -102,18 +102,18 @@ sa-spec --version
|
|
|
102
102
|
|
|
103
103
|
```mermaid
|
|
104
104
|
flowchart TD
|
|
105
|
-
A["要件提案: scp または sa-spec new --branch"] --> B["feat/cart ブランチを作成して切替<br/>ドラフトディレクトリ: project/cart/"]
|
|
105
|
+
A["要件提案: scp または sa-spec new --branch"] --> B["feat/cart ブランチを作成して切替<br/>remote があればブランチを自動 push<br/>ドラフトディレクトリ: project/cart/"]
|
|
106
106
|
B --> C["AI による分析: sca<br/>内部で {{REQ_ID}} プレースホルダー使用<br/>master の最新仕様との競合予防チェック"]
|
|
107
107
|
C --> D{"ユーザー承認?<br/>scc または finalize を実行"}
|
|
108
|
-
D --> E["master
|
|
108
|
+
D --> E["先にブランチを remote へ push & fetch<br/>その後 master から最新番号 N を自動取得"]
|
|
109
109
|
E --> F["project/REQ-N+1-cart/ に自動正式採番<br/>{{REQ_ID}} を置換してコミット"]
|
|
110
|
-
F --> G["master
|
|
110
|
+
F --> G["master ブランチへ自動マージ&remote へ push<br/>project/index.md を動的に再生成"]
|
|
111
111
|
G --> H["自動閉ループ:競合ゼロ、連番維持!"]
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
1. **ドラフト時は番号を奪い合わない**: `scp` または `sa-spec new --branch`
|
|
114
|
+
1. **ドラフト時は番号を奪い合わない**: `scp` または `sa-spec new --branch` でブランチを切り(Git remote が設定されていれば自動的に remote へ push)、`project/cart/` と `{{REQ_ID}}` を使って作業します。途中で要件を破棄する場合も、ブランチを削除するだけで済み、欠番(ゴーストID)を残しません。
|
|
115
115
|
2. **基線同期で競合見落としを防止**: `spec:analyze` の実行前に master の最新状態を取得し、他メンバーがマージした最新の API やテーブル変更を反映して競合チェックを行います。
|
|
116
|
-
3.
|
|
116
|
+
3. **先行 push・自動採番・主ブランチ自動マージ**: `scc` または `sa-spec finalize` を実行すると、remote が存在する場合は**まずブランチを remote に push して同期**した後、**master から次の番号を自動取得して採番・置換・コミット**し、**master ブランチへ自動切り替え&自動マージ・`project/index.md` 再生成・remote への自動 push** までを一気通貫で行います。
|
|
117
117
|
4. **インデックスのコンフリクト解消**: `sa-spec reindex` でディレクトリから常に決定論的に `project/index.md` を再構築します。
|
|
118
118
|
|
|
119
119
|
---
|
package/README.ko.md
CHANGED
|
@@ -102,18 +102,18 @@ sa-spec --version
|
|
|
102
102
|
|
|
103
103
|
```mermaid
|
|
104
104
|
flowchart TD
|
|
105
|
-
A["요구사항 제안: scp 또는 sa-spec new --branch"] --> B["feat/cart 브랜치 생성 및 전환<br/>초안 디렉토리: project/cart/"]
|
|
105
|
+
A["요구사항 제안: scp 또는 sa-spec new --branch"] --> B["feat/cart 브랜치 생성 및 전환<br/>remote가 있으면 브랜치 자동 push<br/>초안 디렉토리: project/cart/"]
|
|
106
106
|
B --> C["AI 분석 및 초안: sca<br/>내부에서 {{REQ_ID}} 플레이스홀더 사용<br/>master 최신 사양 기반 충돌 검사"]
|
|
107
107
|
C --> D{"사용자 승인 완료?<br/>scc 또는 finalize 실행"}
|
|
108
|
-
D --> E["master에서 최신
|
|
108
|
+
D --> E["먼저 브랜치를 remote에 push 및 fetch 동기화<br/>그 후 master에서 최신 번호 N 자동 확인"]
|
|
109
109
|
E --> F["project/REQ-N+1-cart/ 자동 채번 및 커밋<br/>{{REQ_ID}}를 공식 번호로 일괄 치환"]
|
|
110
|
-
F --> G["master 브랜치로 자동
|
|
110
|
+
F --> G["master 브랜치로 자동 머지 및 remote push<br/>project/index.md 동적 재생성"]
|
|
111
111
|
G --> H["자동 루프 완성: 충돌 제로, 연속된 번호 유지!"]
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
1. **초안 단계 번호 미선점**: `scp` 또는 `sa-spec new --branch` 명령으로 독립 브랜치를 생성하고 `project/cart/`와 `{{REQ_ID}}` 플레이스홀더를 사용합니다. 요구사항이 중도 폐기되어도 브랜치만 삭제하면 되며, 결번(고스트 번호)이 발생하지 않습니다.
|
|
114
|
+
1. **초안 단계 번호 미선점**: `scp` 또는 `sa-spec new --branch` 명령으로 독립 브랜치를 생성하고(Git remote가 설정되어 있으면 자동으로 remote에 push) `project/cart/`와 `{{REQ_ID}}` 플레이스홀더를 사용합니다. 요구사항이 중도 폐기되어도 브랜치만 삭제하면 되며, 결번(고스트 번호)이 발생하지 않습니다.
|
|
115
115
|
2. **사양 기준선 동기화**: `spec:analyze` 실행 전 master의 최신 상태를 동기화하여 다른 팀원이 머지한 API나 테이블과의 충돌 누락을 방지합니다.
|
|
116
|
-
3.
|
|
116
|
+
3. **선행 push, 자동 신규 번호 채번 및 메인 브랜치 자동 머지**: `scc` 또는 `sa-spec finalize` 실행 시 remote가 있으면 **먼저 현재 브랜치를 remote에 push하고 최신 상태를 동기화**한 뒤, **master에서 다음 번호를 자동 조회하여 채번·치환·커밋**하고, **master 브랜치로 자동 전환 후 자동 머지 및 remote push**를 수행하며 `project/index.md`를 최신 상태로 정렬 재생성합니다.
|
|
117
117
|
4. **인덱스 머지 충돌 제거**: `sa-spec reindex` 명령으로 디렉토리 상태에서 `project/index.md`를 언제든 완벽하게 재생성합니다.
|
|
118
118
|
|
|
119
119
|
---
|
package/README.zh-CN.md
CHANGED
|
@@ -102,18 +102,18 @@ sa-spec --version
|
|
|
102
102
|
|
|
103
103
|
```mermaid
|
|
104
104
|
flowchart TD
|
|
105
|
-
A["提出需求: scp 或 sa-spec new --branch"] --> B["建立并切换至 feat/cart 分支<br/>创建草稿目录 project/cart/"]
|
|
105
|
+
A["提出需求: scp 或 sa-spec new --branch"] --> B["建立并切换至 feat/cart 分支<br/>若有 remote 自动推分支至远端<br/>创建草稿目录 project/cart/"]
|
|
106
106
|
B --> C["AI 分析与起草: sca<br/>内部使用 {{REQ_ID}} 占位<br/>自动同步 master 最新规格防冲突"]
|
|
107
107
|
C --> D{"用户确认通过<br/>执行 scc 或 finalize"}
|
|
108
|
-
D --> E["
|
|
108
|
+
D --> E["先推分支至 remote 并同步远端状态<br/>再向主分支查询最新可用序号 N"]
|
|
109
109
|
E --> F["自动定号为 project/REQ-N+1-cart/<br/>批量替换 {{REQ_ID}} 并建立提交"]
|
|
110
|
-
F --> G["自动合并至 master
|
|
110
|
+
F --> G["自动合并至 master 主分支并推上 remote<br/>动态重新生成 project/index.md"]
|
|
111
111
|
G --> H["完成闭环:零冲突、序号永远连续!"]
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
1.
|
|
114
|
+
1. **草稿不抢号(自动推分支)**:在分支开发时使用 `scp` 或 `sa-spec new --branch`,建立 `feat/cart`(若配置了 Git remote 则自动推送分支至远端)以及 `project/cart/` 与 `{{REQ_ID}}` 占位符。多人同时提出需求互不冲突。如果需求放弃,直接删除分支,**绝不遗留幽灵跳号**。
|
|
115
115
|
2. **基线同步防漏检**:执行 `spec:analyze` 前先确认同步远端 master 规格,确保以全系统最新状态进行冲突检查。
|
|
116
|
-
3.
|
|
116
|
+
3. **先推分支、自动拿新号与自动合并推送**:执行 `scc`(或 `sa-spec finalize --name cart`)时,若有 remote 会**先将当前分支推送至 remote 并同步远端**,再**自动向 master 申请下一个新号定号**、批量替换占位符、完成提交,并**自动切换回 master 合并该 feature 分支、重建 `project/index.md` 后推送至 remote**。
|
|
117
117
|
4. **动态重建索引**:`sa-spec reindex` 随时可由目录动态排序生成总表,消除 `index.md` 的 merge conflict。
|
|
118
118
|
|
|
119
119
|
---
|
package/README.zh-TW.md
CHANGED
|
@@ -385,7 +385,7 @@ commit (scc) -> 歸檔 -> 本機 Git commit
|
|
|
385
385
|
docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
**鐵律**:只要 Git repository 有設定 remote(例如 `origin`),在 `scp` 建立分支與 `scc` 歸檔合併時,都會**自動執行 `git push` 推送至 remote**。如果 push 失敗,只回報認證或網路問題,不會回滾已完成的文件歸檔與本機 commit。
|
|
389
389
|
|
|
390
390
|
## 多人協作解決方案(Git-Flow 與延遲綁定 ID)
|
|
391
391
|
|
|
@@ -397,12 +397,12 @@ docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
|
|
|
397
397
|
|
|
398
398
|
```mermaid
|
|
399
399
|
flowchart TD
|
|
400
|
-
A["開新需求: scp 或 sa-spec new --branch"] --> B["建立並切換至 feat/cart 分支<br/>以 project/cart/ 建立草稿目錄"]
|
|
400
|
+
A["開新需求: scp 或 sa-spec new --branch"] --> B["建立並切換至 feat/cart 分支<br/>若有 remote 自動推分支至遠端<br/>以 project/cart/ 建立草稿目錄"]
|
|
401
401
|
B --> C["AI 分析與起草: sca<br/>內部使用 {{REQ_ID}} 佔位<br/>自動同步 master 規格防護"]
|
|
402
402
|
C --> D{"使用者確認通過<br/>執行 scc 或 finalize"}
|
|
403
|
-
D --> E["
|
|
403
|
+
D --> E["先推分支至 remote 並同步遠端狀態<br/>再查詢主分支最新序號 N"]
|
|
404
404
|
E --> F["自動定號為 project/REQ-N+1-cart/<br/>批次置換 {{REQ_ID}} 並建立 commit"]
|
|
405
|
-
F --> G["自動合併至 master
|
|
405
|
+
F --> G["自動合併至 master 主分支並推上 remote<br/>動態重新生成 project/index.md"]
|
|
406
406
|
G --> H["完成閉環:零衝突、序號永遠連續!"]
|
|
407
407
|
```
|
|
408
408
|
|
|
@@ -415,7 +415,7 @@ flowchart TD
|
|
|
415
415
|
```text
|
|
416
416
|
scp 購物車結帳需求
|
|
417
417
|
```
|
|
418
|
-
AI 收到後,會**自動在背景執行 `git checkout -b feat/cart-checkout`
|
|
418
|
+
AI 收到後,會**自動在背景執行 `git checkout -b feat/cart-checkout` 建立並切換分支**,檢查若有設定 Git remote 則自動將分支推上遠端(`git push -u origin feat/cart-checkout`),並在 `project/cart-checkout/` 建立草稿目錄!
|
|
419
419
|
* **方式 B(CLI 終端指令)**:
|
|
420
420
|
```bash
|
|
421
421
|
sa-spec new --name cart-checkout --branch
|
|
@@ -425,7 +425,7 @@ flowchart TD
|
|
|
425
425
|
#### 2. 分析與衝突檢查(規格基線同步)
|
|
426
426
|
在分支上執行 `spec:analyze`(或 `sca`)前,工具會確認已取得 `master`(或 `origin/master`)的最新規格,確保是以全專案最新基準進行影響評估,避免因分支落後而漏檢權限、API 或資料表衝突。
|
|
427
427
|
|
|
428
|
-
#### 3.
|
|
428
|
+
#### 3. 確認歸檔與延遲定號(先推分支 + 自動領號 + 自動合併並推上 Remote)
|
|
429
429
|
當需求規格經使用者確認無誤,準備歸檔時:
|
|
430
430
|
|
|
431
431
|
* **方式 A(純 AI 自動化,最推薦)**:在 AI 側邊欄直接輸入:
|
|
@@ -433,15 +433,16 @@ flowchart TD
|
|
|
433
433
|
scc
|
|
434
434
|
```
|
|
435
435
|
AI 收到後會自動完成全自動 Git-Flow 閉環作業:
|
|
436
|
-
1.
|
|
437
|
-
2.
|
|
438
|
-
3.
|
|
439
|
-
4.
|
|
436
|
+
1. **先推分支至 Remote 並同步遠端**:若 Git 有設定 remote,先將目前分支推送至遠端並執行 `git fetch` 同步最新狀態。
|
|
437
|
+
2. **自動向主分支查詢並取得新號**:查詢 master/main(含遠端主分支)目前最大序號(例如最大是 `REQ-005`,自動領取最新號 `REQ-006`),避免號碼競爭。
|
|
438
|
+
3. **自動定名更名**:使用 `git mv` 將目錄重命名為 `project/REQ-006-cart-checkout`,並將目錄內所有檔案的 `{{REQ_ID}}` 批次置換為 `REQ-006`。
|
|
439
|
+
4. **自動建立提交並推送分支**:在 feature 分支自動建立 commit `docs(REQ-006): cart-checkout - 規格確認歸檔`,若有 remote 則同步推送至遠端。
|
|
440
|
+
5. **自動合併至主分支並推送至 Remote**:自動切換至主分支(`git checkout master`),將 feature 分支自動合併回主分支(`git merge feat/cart-checkout`),重新生成主分支的 `project/index.md`,若有 remote 則自動將主分支推送至遠端(`git push origin master`),保證主分支規格最新且永遠不衝突!
|
|
440
441
|
* **方式 B(CLI 終端指令)**:
|
|
441
442
|
```bash
|
|
442
443
|
sa-spec finalize --name cart-checkout
|
|
443
444
|
```
|
|
444
|
-
CLI
|
|
445
|
+
CLI 同樣會先推分支至 remote、查詢主分支最新序號定號、置換佔位符、完成提交、自動合併回 master 並推送至 remote!若想保留在當前分支手動處理,可加上 `--no-merge` 參數。
|
|
445
446
|
|
|
446
447
|
#### 4. 消除索引合併衝突(`sa-spec reindex`)
|
|
447
448
|
`project/index.md` 改為由目錄動態生成的「衍生清單」,不再依賴脆弱的手動 append:
|
|
@@ -702,7 +703,7 @@ git status
|
|
|
702
703
|
git log -1 --oneline
|
|
703
704
|
```
|
|
704
705
|
|
|
705
|
-
|
|
706
|
+
若 Git 有設定 remote,AI 與 CLI 會在建立分支與歸檔合併時自動執行 `git push` 推送至遠端;若當時尚未設定 remote,事後也可手動執行:
|
|
706
707
|
|
|
707
708
|
```bash
|
|
708
709
|
git push origin main
|
|
@@ -719,11 +720,22 @@ git push origin master
|
|
|
719
720
|
- 未經使用者確認,不得標示為 `已審核`。
|
|
720
721
|
- `spec:analyze` 發現衝突時不得產出最終文件,也不得修改既有需求文件。
|
|
721
722
|
- `project/system-spec.md` 只能在 `spec:commit` 依使用者確認內容更新。
|
|
722
|
-
-
|
|
723
|
+
- **鐵律**:只要 Git 有設定 remote,`scp` 與 `scc` 都會自動將分支與主分支推送至 remote。
|
|
723
724
|
- 一次最多問 3 個待確認問題,優先詢問會影響範圍、資料、權限、API、DB 或驗收的問題。
|
|
724
725
|
|
|
725
726
|
## 更新紀錄
|
|
726
727
|
|
|
728
|
+
### v0.2.6
|
|
729
|
+
- **Git Remote 自動推送鐵律(Remote Auto-Push)**:
|
|
730
|
+
- **`scp` 建立分支自動推上遠端**:執行 `spec:propose`(`scp`)或 `sa-spec new --branch` 建立 feature 分支後,自動偵測是否有設定 Git remote;若有則立即將新分支推送至遠端(`git push -u <remote> feat/<name>`)。
|
|
731
|
+
- **`scc` 先推分支再領號與主分支自動推送**:執行 `spec:commit`(`scc`)或 `sa-spec finalize` 時,若有設定 Git remote,會**先將目前分支推送至 remote 並同步遠端狀態**,接著才查詢主分支(`master`/`main`)最新可用序號定號,完成 feature 分支提交與推送、自動合併回主分支後,**自動將主分支推送至 remote**。
|
|
732
|
+
|
|
733
|
+
### v0.2.5
|
|
734
|
+
- **支援前端 UI 線框圖(PlantUML Salt Code-as-Wireframe)**:
|
|
735
|
+
- **純文字代碼化線框圖**:在 `uml/` 目錄新增標準 `uml/wireframe.puml`,使用 PlantUML Salt 語法(`@startsalt ... @endsalt`)以純文字定義頁面排版、輸入欄位、選項與按鈕,可直接在 VS Code 渲染預覽,並可納入 Git 版本追蹤。
|
|
736
|
+
- **AI 開發交接前後閉環**:`srs.md` 與 `handoff.md` 新增「UI / 畫面規格」區塊,前端需求直接引用 `uml/wireframe.puml`,供 OpenSpec / Claude Code 精準產出前端元件;純後端需求則標示「無 UI 介面需求」。
|
|
737
|
+
- **版本升級(`sa-spec upgrade`)既有需求防護**:升級時主動掃描既有需求,若偵測到前端介面描述且缺少 wireframe 則發出補齊提示;已標記無 UI 之純後端需求則略過,不盲目覆蓋既有規格。
|
|
738
|
+
|
|
727
739
|
### v0.2.4
|
|
728
740
|
- **序號重複主動告警與重新定號自癒支援**:
|
|
729
741
|
- **唯一性主動檢驗**:`sa-spec check` 與 `sa-spec reindex` 加入重複序號檢測,遇到衝突時即時發出 WARNING 告警並列出衝突目錄與修復建議。
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -385,7 +385,7 @@ commit (scc) -> 歸檔 -> 本機 Git commit
|
|
|
385
385
|
docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
**鐵律**:只要 Git repository 有設定 remote(例如 `origin`),在 `scp` 建立分支與 `scc` 歸檔合併時,都會**自動執行 `git push` 推送至 remote**。如果 push 失敗,只回報認證或網路問題,不會回滾已完成的文件歸檔與本機 commit。
|
|
389
389
|
|
|
390
390
|
## 多人協作解決方案(Git-Flow 與延遲綁定 ID)
|
|
391
391
|
|
|
@@ -397,12 +397,12 @@ docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
|
|
|
397
397
|
|
|
398
398
|
```mermaid
|
|
399
399
|
flowchart TD
|
|
400
|
-
A["開新需求: scp 或 sa-spec new --branch"] --> B["建立並切換至 feat/cart 分支<br/>以 project/cart/ 建立草稿目錄"]
|
|
400
|
+
A["開新需求: scp 或 sa-spec new --branch"] --> B["建立並切換至 feat/cart 分支<br/>若有 remote 自動推分支至遠端<br/>以 project/cart/ 建立草稿目錄"]
|
|
401
401
|
B --> C["AI 分析與起草: sca<br/>內部使用 {{REQ_ID}} 佔位<br/>自動同步 master 規格防護"]
|
|
402
402
|
C --> D{"使用者確認通過<br/>執行 scc 或 finalize"}
|
|
403
|
-
D --> E["
|
|
403
|
+
D --> E["先推分支至 remote 並同步遠端狀態<br/>再查詢主分支最新序號 N"]
|
|
404
404
|
E --> F["自動定號為 project/REQ-N+1-cart/<br/>批次置換 {{REQ_ID}} 並建立 commit"]
|
|
405
|
-
F --> G["自動合併至 master
|
|
405
|
+
F --> G["自動合併至 master 主分支並推上 remote<br/>動態重新生成 project/index.md"]
|
|
406
406
|
G --> H["完成閉環:零衝突、序號永遠連續!"]
|
|
407
407
|
```
|
|
408
408
|
|
|
@@ -415,7 +415,7 @@ flowchart TD
|
|
|
415
415
|
```text
|
|
416
416
|
scp 購物車結帳需求
|
|
417
417
|
```
|
|
418
|
-
AI 收到後,會**自動在背景執行 `git checkout -b feat/cart-checkout`
|
|
418
|
+
AI 收到後,會**自動在背景執行 `git checkout -b feat/cart-checkout` 建立並切換分支**,檢查若有設定 Git remote 則自動將分支推上遠端(`git push -u origin feat/cart-checkout`),並在 `project/cart-checkout/` 建立草稿目錄!
|
|
419
419
|
* **方式 B(CLI 終端指令)**:
|
|
420
420
|
```bash
|
|
421
421
|
sa-spec new --name cart-checkout --branch
|
|
@@ -425,7 +425,7 @@ flowchart TD
|
|
|
425
425
|
#### 2. 分析與衝突檢查(規格基線同步)
|
|
426
426
|
在分支上執行 `spec:analyze`(或 `sca`)前,工具會確認已取得 `master`(或 `origin/master`)的最新規格,確保是以全專案最新基準進行影響評估,避免因分支落後而漏檢權限、API 或資料表衝突。
|
|
427
427
|
|
|
428
|
-
#### 3.
|
|
428
|
+
#### 3. 確認歸檔與延遲定號(先推分支 + 自動領號 + 自動合併並推上 Remote)
|
|
429
429
|
當需求規格經使用者確認無誤,準備歸檔時:
|
|
430
430
|
|
|
431
431
|
* **方式 A(純 AI 自動化,最推薦)**:在 AI 側邊欄直接輸入:
|
|
@@ -433,15 +433,16 @@ flowchart TD
|
|
|
433
433
|
scc
|
|
434
434
|
```
|
|
435
435
|
AI 收到後會自動完成全自動 Git-Flow 閉環作業:
|
|
436
|
-
1.
|
|
437
|
-
2.
|
|
438
|
-
3.
|
|
439
|
-
4.
|
|
436
|
+
1. **先推分支至 Remote 並同步遠端**:若 Git 有設定 remote,先將目前分支推送至遠端並執行 `git fetch` 同步最新狀態。
|
|
437
|
+
2. **自動向主分支查詢並取得新號**:查詢 master/main(含遠端主分支)目前最大序號(例如最大是 `REQ-005`,自動領取最新號 `REQ-006`),避免號碼競爭。
|
|
438
|
+
3. **自動定名更名**:使用 `git mv` 將目錄重命名為 `project/REQ-006-cart-checkout`,並將目錄內所有檔案的 `{{REQ_ID}}` 批次置換為 `REQ-006`。
|
|
439
|
+
4. **自動建立提交並推送分支**:在 feature 分支自動建立 commit `docs(REQ-006): cart-checkout - 規格確認歸檔`,若有 remote 則同步推送至遠端。
|
|
440
|
+
5. **自動合併至主分支並推送至 Remote**:自動切換至主分支(`git checkout master`),將 feature 分支自動合併回主分支(`git merge feat/cart-checkout`),重新生成主分支的 `project/index.md`,若有 remote 則自動將主分支推送至遠端(`git push origin master`),保證主分支規格最新且永遠不衝突!
|
|
440
441
|
* **方式 B(CLI 終端指令)**:
|
|
441
442
|
```bash
|
|
442
443
|
sa-spec finalize --name cart-checkout
|
|
443
444
|
```
|
|
444
|
-
CLI
|
|
445
|
+
CLI 同樣會先推分支至 remote、查詢主分支最新序號定號、置換佔位符、完成提交、自動合併回 master 並推送至 remote!若想保留在當前分支手動處理,可加上 `--no-merge` 參數。
|
|
445
446
|
|
|
446
447
|
#### 4. 消除索引合併衝突(`sa-spec reindex`)
|
|
447
448
|
`project/index.md` 改為由目錄動態生成的「衍生清單」,不再依賴脆弱的手動 append:
|
|
@@ -702,7 +703,7 @@ git status
|
|
|
702
703
|
git log -1 --oneline
|
|
703
704
|
```
|
|
704
705
|
|
|
705
|
-
|
|
706
|
+
若 Git 有設定 remote,AI 與 CLI 會在建立分支與歸檔合併時自動執行 `git push` 推送至遠端;若當時尚未設定 remote,事後也可手動執行:
|
|
706
707
|
|
|
707
708
|
```bash
|
|
708
709
|
git push origin main
|
|
@@ -719,11 +720,22 @@ git push origin master
|
|
|
719
720
|
- 未經使用者確認,不得標示為 `已審核`。
|
|
720
721
|
- `spec:analyze` 發現衝突時不得產出最終文件,也不得修改既有需求文件。
|
|
721
722
|
- `project/system-spec.md` 只能在 `spec:commit` 依使用者確認內容更新。
|
|
722
|
-
-
|
|
723
|
+
- **鐵律**:只要 Git 有設定 remote,`scp` 與 `scc` 都會自動將分支與主分支推送至 remote。
|
|
723
724
|
- 一次最多問 3 個待確認問題,優先詢問會影響範圍、資料、權限、API、DB 或驗收的問題。
|
|
724
725
|
|
|
725
726
|
## 更新紀錄
|
|
726
727
|
|
|
728
|
+
### v0.2.6
|
|
729
|
+
- **Git Remote 自動推送鐵律(Remote Auto-Push)**:
|
|
730
|
+
- **`scp` 建立分支自動推上遠端**:執行 `spec:propose`(`scp`)或 `sa-spec new --branch` 建立 feature 分支後,自動偵測是否有設定 Git remote;若有則立即將新分支推送至遠端(`git push -u <remote> feat/<name>`)。
|
|
731
|
+
- **`scc` 先推分支再領號與主分支自動推送**:執行 `spec:commit`(`scc`)或 `sa-spec finalize` 時,若有設定 Git remote,會**先將目前分支推送至 remote 並同步遠端狀態**,接著才查詢主分支(`master`/`main`)最新可用序號定號,完成 feature 分支提交與推送、自動合併回主分支後,**自動將主分支推送至 remote**。
|
|
732
|
+
|
|
733
|
+
### v0.2.5
|
|
734
|
+
- **支援前端 UI 線框圖(PlantUML Salt Code-as-Wireframe)**:
|
|
735
|
+
- **純文字代碼化線框圖**:在 `uml/` 目錄新增標準 `uml/wireframe.puml`,使用 PlantUML Salt 語法(`@startsalt ... @endsalt`)以純文字定義頁面排版、輸入欄位、選項與按鈕,可直接在 VS Code 渲染預覽,並可納入 Git 版本追蹤。
|
|
736
|
+
- **AI 開發交接前後閉環**:`srs.md` 與 `handoff.md` 新增「UI / 畫面規格」區塊,前端需求直接引用 `uml/wireframe.puml`,供 OpenSpec / Claude Code 精準產出前端元件;純後端需求則標示「無 UI 介面需求」。
|
|
737
|
+
- **版本升級(`sa-spec upgrade`)既有需求防護**:升級時主動掃描既有需求,若偵測到前端介面描述且缺少 wireframe 則發出補齊提示;已標記無 UI 之純後端需求則略過,不盲目覆蓋既有規格。
|
|
738
|
+
|
|
727
739
|
### v0.2.4
|
|
728
740
|
- **序號重複主動告警與重新定號自癒支援**:
|
|
729
741
|
- **唯一性主動檢驗**:`sa-spec check` 與 `sa-spec reindex` 加入重複序號檢測,遇到衝突時即時發出 WARNING 告警並列出衝突目錄與修復建議。
|
package/src/cli.js
CHANGED
|
@@ -306,6 +306,12 @@ function createReqTemplate(args, label = "new") {
|
|
|
306
306
|
} else {
|
|
307
307
|
console.log(`提示: 分支切換略過 (${(branchRes.stderr || "").trim() || "可能是已有同名分支或未在 git 目錄"})`);
|
|
308
308
|
}
|
|
309
|
+
|
|
310
|
+
const remote = getDefaultRemote();
|
|
311
|
+
const activeBranch = getCurrentBranch() || branchName;
|
|
312
|
+
if (remote && activeBranch) {
|
|
313
|
+
pushBranchToRemote(remote, activeBranch);
|
|
314
|
+
}
|
|
309
315
|
}
|
|
310
316
|
|
|
311
317
|
const reqDir = path.join("project", slug);
|
|
@@ -316,6 +322,7 @@ function createReqTemplate(args, label = "new") {
|
|
|
316
322
|
ensureDir(umlDir),
|
|
317
323
|
ensureFileFromTemplate(path.join("project", "req", "srs.md"), path.join(reqDir, "srs.md"), replacements),
|
|
318
324
|
ensureFileFromTemplate(path.join("project", "req", "uml", "main.puml"), path.join(umlDir, "main.puml"), replacements),
|
|
325
|
+
ensureFileFromTemplate(path.join("project", "req", "uml", "wireframe.puml"), path.join(umlDir, "wireframe.puml"), replacements),
|
|
319
326
|
ensureFileFromTemplate(path.join("project", "req", "openapi.yaml"), path.join(reqDir, "openapi.yaml"), replacements),
|
|
320
327
|
ensureFileFromTemplate(path.join("project", "req", "db-schema.md"), path.join(reqDir, "db-schema.md"), replacements),
|
|
321
328
|
ensureFileFromTemplate(path.join("project", "req", "handoff.md"), path.join(reqDir, "handoff.md"), replacements),
|
|
@@ -337,6 +344,7 @@ function createReqTemplate(args, label = "new") {
|
|
|
337
344
|
ensureDir(umlDir),
|
|
338
345
|
ensureFileFromTemplate(path.join("project", "req", "srs.md"), path.join(reqDir, "srs.md"), replacements),
|
|
339
346
|
ensureFileFromTemplate(path.join("project", "req", "uml", "main.puml"), path.join(umlDir, "main.puml"), replacements),
|
|
347
|
+
ensureFileFromTemplate(path.join("project", "req", "uml", "wireframe.puml"), path.join(umlDir, "wireframe.puml"), replacements),
|
|
340
348
|
ensureFileFromTemplate(path.join("project", "req", "openapi.yaml"), path.join(reqDir, "openapi.yaml"), replacements),
|
|
341
349
|
ensureFileFromTemplate(path.join("project", "req", "db-schema.md"), path.join(reqDir, "db-schema.md"), replacements),
|
|
342
350
|
ensureFileFromTemplate(path.join("project", "req", "handoff.md"), path.join(reqDir, "handoff.md"), replacements),
|
|
@@ -347,6 +355,32 @@ function createReqTemplate(args, label = "new") {
|
|
|
347
355
|
printResultList(label, results);
|
|
348
356
|
}
|
|
349
357
|
|
|
358
|
+
function getDefaultRemote() {
|
|
359
|
+
const res = spawnSync("git", ["remote"], { cwd, encoding: "utf8" });
|
|
360
|
+
if (res.status === 0 && res.stdout) {
|
|
361
|
+
const remotes = res.stdout
|
|
362
|
+
.split("\n")
|
|
363
|
+
.map((r) => r.trim())
|
|
364
|
+
.filter(Boolean);
|
|
365
|
+
if (remotes.includes("origin")) return "origin";
|
|
366
|
+
if (remotes.length > 0) return remotes[0];
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function pushBranchToRemote(remote, branch) {
|
|
372
|
+
if (!remote || !branch) return false;
|
|
373
|
+
console.log(`[Git] 偵測到遠端 (${remote}),正在將分支 ${branch} 推送至 ${remote}/${branch}...`);
|
|
374
|
+
const pushRes = spawnSync("git", ["push", "-u", remote, branch], { cwd, encoding: "utf8" });
|
|
375
|
+
if (pushRes.status === 0) {
|
|
376
|
+
console.log(`[Git] 已成功將分支 ${branch} 推送至 ${remote}/${branch}`);
|
|
377
|
+
return true;
|
|
378
|
+
} else {
|
|
379
|
+
console.warn(`[Git 警告] 推送分支 ${branch} 至 ${remote} 失敗: ${(pushRes.stderr || pushRes.stdout || "").trim()}`);
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
350
384
|
function detectMainBranch() {
|
|
351
385
|
const branches = ["main", "master"];
|
|
352
386
|
for (const b of branches) {
|
|
@@ -365,7 +399,7 @@ function getCurrentBranch() {
|
|
|
365
399
|
return null;
|
|
366
400
|
}
|
|
367
401
|
|
|
368
|
-
function getLatestMaxReqId(projectDir, mainBranch) {
|
|
402
|
+
function getLatestMaxReqId(projectDir, mainBranch, remoteName = "origin") {
|
|
369
403
|
let maxIdNum = 0;
|
|
370
404
|
// 1. 掃描本地工作目錄既有 REQ-xxx
|
|
371
405
|
if (fs.existsSync(projectDir)) {
|
|
@@ -398,7 +432,8 @@ function getLatestMaxReqId(projectDir, mainBranch) {
|
|
|
398
432
|
}
|
|
399
433
|
|
|
400
434
|
// 3. 掃描遠端主分支 (若有設定 remote)
|
|
401
|
-
const
|
|
435
|
+
const targetRemote = remoteName || "origin";
|
|
436
|
+
const gitRemoteLs = spawnSync("git", ["ls-tree", `${targetRemote}/${mainBranch}:project`], { cwd, encoding: "utf8" });
|
|
402
437
|
if (gitRemoteLs.status === 0 && gitRemoteLs.stdout) {
|
|
403
438
|
for (const line of gitRemoteLs.stdout.split("\n")) {
|
|
404
439
|
const parts = line.split("\t");
|
|
@@ -462,10 +497,17 @@ function finalizeReq(args) {
|
|
|
462
497
|
return;
|
|
463
498
|
}
|
|
464
499
|
|
|
465
|
-
// 1.
|
|
500
|
+
// 1. 先檢查是否有 remote,若有則先將目前分支推上 remote 並同步遠端狀態,接著才查詢主分支最新 REQ 序號
|
|
501
|
+
const remote = getDefaultRemote();
|
|
466
502
|
const mainBranch = detectMainBranch();
|
|
467
503
|
const currentBranch = getCurrentBranch();
|
|
468
|
-
|
|
504
|
+
|
|
505
|
+
if (remote && currentBranch) {
|
|
506
|
+
pushBranchToRemote(remote, currentBranch);
|
|
507
|
+
spawnSync("git", ["fetch", remote], { cwd, encoding: "utf8" });
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const maxIdNum = getLatestMaxReqId(projectDir, mainBranch, remote);
|
|
469
511
|
|
|
470
512
|
const nextIdNum = maxIdNum + 1;
|
|
471
513
|
const nextId = `REQ-${String(nextIdNum).padStart(3, "0")}`;
|
|
@@ -516,14 +558,17 @@ function finalizeReq(args) {
|
|
|
516
558
|
|
|
517
559
|
console.log(`\n 需求已成功定號歸檔為: ${nextId} (${finalDirName})`);
|
|
518
560
|
|
|
519
|
-
// 5.
|
|
561
|
+
// 5. 自動提交、自動合併回主分支與自動推送至 remote (Git-Flow 閉環)
|
|
520
562
|
const shouldAutoMerge = !args.includes("--no-merge");
|
|
521
563
|
if (currentBranch && mainBranch && currentBranch !== mainBranch) {
|
|
522
564
|
console.log(`[Git] 正在為分支 ${currentBranch} 建立歸檔 commit...`);
|
|
523
565
|
spawnSync("git", ["add", "project/"], { cwd, encoding: "utf8" });
|
|
524
|
-
const commitRes = spawnSync("git", ["commit", "-m", `docs(${nextId}): ${
|
|
566
|
+
const commitRes = spawnSync("git", ["commit", "-m", `docs(${nextId}): ${rawName} - 規格確認歸檔`], { cwd, encoding: "utf8" });
|
|
525
567
|
if (commitRes.status === 0) {
|
|
526
|
-
console.log(`[Git] 分支 ${currentBranch} 提交完成: docs(${nextId}): ${
|
|
568
|
+
console.log(`[Git] 分支 ${currentBranch} 提交完成: docs(${nextId}): ${rawName} - 規格確認歸檔`);
|
|
569
|
+
}
|
|
570
|
+
if (remote) {
|
|
571
|
+
pushBranchToRemote(remote, currentBranch);
|
|
527
572
|
}
|
|
528
573
|
|
|
529
574
|
if (shouldAutoMerge) {
|
|
@@ -544,7 +589,10 @@ function finalizeReq(args) {
|
|
|
544
589
|
spawnSync("git", ["add", "project/index.md"], { cwd, encoding: "utf8" });
|
|
545
590
|
spawnSync("git", ["commit", "-m", `chore: update project/index.md for ${nextId}`], { cwd, encoding: "utf8" });
|
|
546
591
|
}
|
|
547
|
-
|
|
592
|
+
if (remote) {
|
|
593
|
+
pushBranchToRemote(remote, mainBranch);
|
|
594
|
+
}
|
|
595
|
+
console.log(` 全部歸檔流程完成!已自動領取新號 ${nextId} 並自動合併回主分支 ${mainBranch}${remote ? ` 且推送至 ${remote}` : ""}。`);
|
|
548
596
|
} else {
|
|
549
597
|
console.error(`[Git 警告] 合併至 ${mainBranch} 發生衝突,請手動確認衝突狀況:\n${(mergeRes.stderr || mergeRes.stdout || "").trim()}`);
|
|
550
598
|
}
|
|
@@ -554,12 +602,15 @@ function finalizeReq(args) {
|
|
|
554
602
|
}
|
|
555
603
|
} else if (currentBranch && currentBranch === mainBranch) {
|
|
556
604
|
spawnSync("git", ["add", "project/"], { cwd, encoding: "utf8" });
|
|
557
|
-
spawnSync("git", ["commit", "-m", `docs(${nextId}): ${
|
|
605
|
+
spawnSync("git", ["commit", "-m", `docs(${nextId}): ${rawName} - 規格確認歸檔`], { cwd, encoding: "utf8" });
|
|
558
606
|
console.log(`[Git] 已直接於主分支 ${mainBranch} 建立提交完成。`);
|
|
607
|
+
if (remote) {
|
|
608
|
+
pushBranchToRemote(remote, mainBranch);
|
|
609
|
+
}
|
|
559
610
|
} else {
|
|
560
611
|
console.log(`建議接下來執行:`);
|
|
561
612
|
console.log(` git add project/`);
|
|
562
|
-
console.log(` git commit -m "docs(${nextId}): ${
|
|
613
|
+
console.log(` git commit -m "docs(${nextId}): ${rawName} - 規格確認歸檔"`);
|
|
563
614
|
}
|
|
564
615
|
}
|
|
565
616
|
|
|
@@ -846,15 +897,70 @@ function upgradeProject(args = []) {
|
|
|
846
897
|
const handoffRelPath = path.join(reqRelDir, "handoff.md");
|
|
847
898
|
const handoffAbsPath = path.join(cwd, handoffRelPath);
|
|
848
899
|
if (fs.existsSync(handoffAbsPath)) {
|
|
849
|
-
|
|
900
|
+
let content = fs.readFileSync(handoffAbsPath, "utf8");
|
|
901
|
+
let updatedHandoff = false;
|
|
850
902
|
if (content.includes("uml.puml")) {
|
|
903
|
+
content = content.replace(/uml\.puml/g, "uml/");
|
|
904
|
+
updatedHandoff = true;
|
|
905
|
+
}
|
|
906
|
+
if (!content.includes("## UI") && !content.includes("畫面規格")) {
|
|
907
|
+
const uiSection = `\n## UI / 畫面規格\n待補充;若有前端介面需求,參照 \`uml/wireframe.puml\`;若無 UI 需求,明確標示「無 UI 介面需求」。\n`;
|
|
908
|
+
if (content.includes("## 驗收條件")) {
|
|
909
|
+
content = content.replace("## 驗收條件", `${uiSection}\n## 驗收條件`);
|
|
910
|
+
} else {
|
|
911
|
+
content = `${content.trimEnd()}\n${uiSection}`;
|
|
912
|
+
}
|
|
913
|
+
updatedHandoff = true;
|
|
914
|
+
}
|
|
915
|
+
if (updatedHandoff) {
|
|
851
916
|
if (!dryRun) {
|
|
852
|
-
fs.writeFileSync(handoffAbsPath, content
|
|
917
|
+
fs.writeFileSync(handoffAbsPath, content, "utf8");
|
|
853
918
|
}
|
|
854
919
|
results.push({
|
|
855
920
|
action: "update",
|
|
856
921
|
target: handoffRelPath,
|
|
857
|
-
message: "
|
|
922
|
+
message: "更新來源參照與補全 UI/畫面規格章節"
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// 檢查既有需求是否需要 wireframe
|
|
928
|
+
const wireframeRelPath = path.join(newUmlRelDir, "wireframe.puml");
|
|
929
|
+
const wireframeAbsPath = path.join(cwd, wireframeRelPath);
|
|
930
|
+
const srsRelPath = path.join(reqRelDir, "srs.md");
|
|
931
|
+
const srsAbsPath = path.join(cwd, srsRelPath);
|
|
932
|
+
|
|
933
|
+
let explicitNoUi = false;
|
|
934
|
+
let likelyHasUi = false;
|
|
935
|
+
|
|
936
|
+
const inspectUiText = (text) => {
|
|
937
|
+
if (/無\s*UI/i.test(text) || /純後端/i.test(text) || /無介面/i.test(text)) {
|
|
938
|
+
explicitNoUi = true;
|
|
939
|
+
}
|
|
940
|
+
if (/畫面|介面|UI|前端|按鈕|表單|點擊|頁面|Page|Screen|View|Modal/i.test(text)) {
|
|
941
|
+
likelyHasUi = true;
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
if (fs.existsSync(handoffAbsPath)) {
|
|
946
|
+
inspectUiText(fs.readFileSync(handoffAbsPath, "utf8"));
|
|
947
|
+
}
|
|
948
|
+
if (fs.existsSync(srsAbsPath)) {
|
|
949
|
+
inspectUiText(fs.readFileSync(srsAbsPath, "utf8"));
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
if (!fs.existsSync(wireframeAbsPath)) {
|
|
953
|
+
if (explicitNoUi) {
|
|
954
|
+
results.push({
|
|
955
|
+
action: "skip",
|
|
956
|
+
target: wireframeRelPath,
|
|
957
|
+
message: "已標記為無 UI 需求,略過 wireframe"
|
|
958
|
+
});
|
|
959
|
+
} else if (likelyHasUi) {
|
|
960
|
+
results.push({
|
|
961
|
+
action: "warn",
|
|
962
|
+
target: wireframeRelPath,
|
|
963
|
+
message: "偵測到包含前端介面描述,建議透過 AI (sca) 補齊 PlantUML Salt 線框圖"
|
|
858
964
|
});
|
|
859
965
|
}
|
|
860
966
|
}
|
package/templates/AGENTS.md
CHANGED
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
| 指令 | 簡寫 | 用途 | 規則 |
|
|
21
21
|
|---|---|---|---|
|
|
22
22
|
| `spec:init` | `sci` | 初始化 | 載入並遵守 `AGENTS.md`、`skills/system-analysis/SKILL.md` 與必要規則,確認 `project/` 結構是否存在。 |
|
|
23
|
-
| `spec:propose` | `scp` | 提出需求 | 使用者提出需求後,自動依需求名稱建立並切換至專屬 feature 分支(`feat/<name>`,若已在 feature branch
|
|
23
|
+
| `spec:propose` | `scp` | 提出需求 | 使用者提出需求後,自動依需求名稱建立並切換至專屬 feature 分支(`feat/<name>`,若已在 feature branch 則沿用),檢查是否有設定 Git remote,若有則自動將分支推上 remote(`git push -u <remote> feat/<name>`),並建立草稿目錄(內部使用 `{{REQ_ID}}` 佔位),整理需求摘要、目標、初步流程與待確認事項,不歸檔、不修改既有需求。 |
|
|
24
24
|
| `spec:analyze` | `sca` | 分析與起草 | 先檢查新需求是否與 `project/` 內所有既有需求衝突;無衝突才產出 SRS、UML、OpenAPI、DB Schema 草稿;有衝突則只列出衝突與待釐清問題,待使用者釐清後再次執行 `spec:analyze`(或 `sca`)。 |
|
|
25
|
-
| `spec:commit` | `scc` | 確認歸檔 |
|
|
25
|
+
| `spec:commit` | `scc` | 確認歸檔 | 只把使用者已確認的版本歸檔到該需求資料夾;若有 Git remote 則先將目前分支推上 remote 並同步遠端狀態,接著才查詢主分支(`master`/`main`)最新可用序號定號(`REQ-xxx`)、替換佔位符,更新 `project/index.md`、`project/system-spec.md` 與 `history.md`,建立 Git commit(若有 remote 則推送分支),再自動切換回主分支完成合併並推送到 remote。 |
|
|
26
26
|
|
|
27
27
|
# 重要限制
|
|
28
28
|
|
|
@@ -42,12 +42,16 @@
|
|
|
42
42
|
- `spec:commit` 只能套用已由 `spec:analyze` 產出的、且使用者已確認的無衝突版本。
|
|
43
43
|
- `handoff.md` 只能根據已確認的 SRS、UML、OpenAPI、DB Schema 與限制整理,不得新增未確認的開發假設。
|
|
44
44
|
- 交給 OpenSpec 或其他 AI 開發工具時,必須指定它先閱讀 `handoff.md`,並以 `handoff.md` 作為開發入口與限制摘要;其他規格文件作為詳細來源。
|
|
45
|
+
- **鐵律(Git Remote 自動推送強制規範)**:只要 Git repository 有設定 remote(例如 `origin`),所有分支建立與提交變更**都必須自動推送(`git push`)到 remote**,無需等待使用者額外指示;若 push 失敗時只回報認證或網路問題,不得回滾已完成的文件歸檔與本機 commit。
|
|
45
46
|
- `spec:commit` 完成文件歸檔後,必須自動建立本機 Git commit;commit message 以需求編號與需求名稱為主,並加上簡短需求說明,格式為 `docs(REQ-001): 需求名稱 - 簡短需求說明`。
|
|
46
|
-
- `spec:commit`
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
- `spec:commit` 歸檔與自動合併閉環流程(含 Remote 同步順序):
|
|
48
|
+
1. **先推分支至 Remote**:執行 `spec:commit`(或 `scc`)時,若檢查到 Git 有設定 remote,必須**先將目前分支推送至 remote**(`git push -u <remote> <branch>`)並同步遠端最新狀態(`git fetch <remote>`)。
|
|
49
|
+
2. **再查主分支最新版號**:接著才向主分支(`main` / `master` 及遠端主分支)查詢最新已使用序號,決定下一個可用序號(`REQ-xxx`)。
|
|
50
|
+
3. **定號歸檔與提交**:將草稿目錄重命名為正式 `project/REQ-xxx-<name>`、替換內部 `{{REQ_ID}}` 佔位符、更新索引與規格後,在 feature 分支建立 commit;若有 remote 則同步推送該 feature 分支至 remote。
|
|
51
|
+
4. **自動合併回主分支並推送**:若目前處於 feature 分支(`feat/<name>`),AI 必須自動切換回主分支(優先偵測 `main` 或 `master`),拉取/檢查最新狀態並自動合併該 feature 分支 (`git checkout master && git merge feat/<name>`),隨後在主分支重新生成 `project/index.md` 索引;若有設定 remote,**必須自動將主分支推送至 remote**(`git push <remote> <mainBranch>`)。
|
|
52
|
+
- 多人協作與 Git-Flow 模式(延遲綁定序號與自動合併):支援多人平行開發。執行 `spec:propose`(或 `scp`)時,若目前處於 master/main 分支,AI 必須自動依需求名稱建立並切換至專屬 feature branch(如 `feat/<name>`),檢查若有設定 Git remote 則立即將新分支推上 remote(`git push -u <remote> feat/<name>`),並在 `project/<name>/` 建立草稿目錄,內部使用 `{{REQ_ID}}` 佔位,無需使用者手動敲 CLI;執行 `spec:analyze` 前應先確保取得 master 最新規格以防漏檢衝突;執行 `spec:commit` 歸檔時先推分支到 remote,再向 master 確認最新可用序號定號,自動將目錄定名為正式 `REQ-xxx`、替換內部佔位符、完成提交、自動合併回 master 並推上 remote,避免多人合併時的序號競爭與索引衝突。
|
|
49
53
|
- 文件未經使用者確認,不得標示為 `已審核`。
|
|
50
|
-
- `uml/` 內的 UML 圖不限單一 UML 圖型;`spec:analyze`
|
|
54
|
+
- `uml/` 內的 UML 圖不限單一 UML 圖型;`spec:analyze` 必須依需求選擇最能說明流程、互動、狀態、資料關係或介面佈局的圖表,例如活動圖、循序圖、使用案例圖、狀態圖、類別圖;**若需求涉及前端 UI 或使用者操作畫面,必須在 `uml/wireframe.puml` 產出線框圖(使用 PlantUML Salt 語法:`@startsalt ... @endsalt`)**;純後端需求則在 `handoff.md` 明確標記「無 UI 介面需求」。**嚴禁將多張圖混在同一個檔案中**,必須在需求資料夾下的 `uml/` 目錄拆分成獨立的 `.puml` 檔案(例如 `uml/main.puml`、`uml/sequence.puml`、`uml/wireframe.puml`),且每個檔案只能包含一組 `@start...` 與 `@end...`,以避免 PlantUML 渲染或預覽失敗。
|
|
51
55
|
- 一次最多問 3 個待確認問題,優先詢問會影響範圍、資料、權限、API、DB 或驗收的問題。
|
|
52
56
|
|
|
53
57
|
# 衝突檢查重點
|
|
@@ -74,12 +78,12 @@
|
|
|
74
78
|
# 狀態機
|
|
75
79
|
|
|
76
80
|
```text
|
|
77
|
-
init (sci) -> propose (scp) -> analyze (sca)
|
|
81
|
+
init (sci) -> propose (scp, 建分支並推至 remote) -> analyze (sca)
|
|
78
82
|
|
|
79
83
|
analyze 無衝突 -> 產出待確認版本 -> commit (scc)
|
|
80
84
|
analyze 有衝突 -> 釐清問題 -> analyze (sca)
|
|
81
85
|
|
|
82
|
-
commit (scc) ->
|
|
86
|
+
commit (scc) -> 先推分支至 remote -> 查 master 最新版號定號 -> 歸檔 commit -> 合併回主分支並推至 remote
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
# 歸檔結構
|
package/templates/readme.md
CHANGED
|
@@ -385,7 +385,7 @@ commit (scc) -> 歸檔 -> 本機 Git commit
|
|
|
385
385
|
docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
**鐵律**:只要 Git repository 有設定 remote(例如 `origin`),在 `scp` 建立分支與 `scc` 歸檔合併時,都會**自動執行 `git push` 推送至 remote**。如果 push 失敗,只回報認證或網路問題,不會回滾已完成的文件歸檔與本機 commit。
|
|
389
389
|
|
|
390
390
|
## 多人協作解決方案(Git-Flow 與延遲綁定 ID)
|
|
391
391
|
|
|
@@ -397,12 +397,12 @@ docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
|
|
|
397
397
|
|
|
398
398
|
```mermaid
|
|
399
399
|
flowchart TD
|
|
400
|
-
A["開新需求: scp 或 sa-spec new --branch"] --> B["建立並切換至 feat/cart 分支<br/>以 project/cart/ 建立草稿目錄"]
|
|
400
|
+
A["開新需求: scp 或 sa-spec new --branch"] --> B["建立並切換至 feat/cart 分支<br/>若有 remote 自動推分支至遠端<br/>以 project/cart/ 建立草稿目錄"]
|
|
401
401
|
B --> C["AI 分析與起草: sca<br/>內部使用 {{REQ_ID}} 佔位<br/>自動同步 master 規格防護"]
|
|
402
402
|
C --> D{"使用者確認通過<br/>執行 scc 或 finalize"}
|
|
403
|
-
D --> E["
|
|
403
|
+
D --> E["先推分支至 remote 並同步遠端狀態<br/>再查詢主分支最新序號 N"]
|
|
404
404
|
E --> F["自動定號為 project/REQ-N+1-cart/<br/>批次置換 {{REQ_ID}} 並建立 commit"]
|
|
405
|
-
F --> G["自動合併至 master
|
|
405
|
+
F --> G["自動合併至 master 主分支並推上 remote<br/>動態重新生成 project/index.md"]
|
|
406
406
|
G --> H["完成閉環:零衝突、序號永遠連續!"]
|
|
407
407
|
```
|
|
408
408
|
|
|
@@ -415,7 +415,7 @@ flowchart TD
|
|
|
415
415
|
```text
|
|
416
416
|
scp 購物車結帳需求
|
|
417
417
|
```
|
|
418
|
-
AI 收到後,會**自動在背景執行 `git checkout -b feat/cart-checkout`
|
|
418
|
+
AI 收到後,會**自動在背景執行 `git checkout -b feat/cart-checkout` 建立並切換分支**,檢查若有設定 Git remote 則自動將分支推上遠端(`git push -u origin feat/cart-checkout`),並在 `project/cart-checkout/` 建立草稿目錄!
|
|
419
419
|
* **方式 B(CLI 終端指令)**:
|
|
420
420
|
```bash
|
|
421
421
|
sa-spec new --name cart-checkout --branch
|
|
@@ -425,7 +425,7 @@ flowchart TD
|
|
|
425
425
|
#### 2. 分析與衝突檢查(規格基線同步)
|
|
426
426
|
在分支上執行 `spec:analyze`(或 `sca`)前,工具會確認已取得 `master`(或 `origin/master`)的最新規格,確保是以全專案最新基準進行影響評估,避免因分支落後而漏檢權限、API 或資料表衝突。
|
|
427
427
|
|
|
428
|
-
#### 3.
|
|
428
|
+
#### 3. 確認歸檔與延遲定號(先推分支 + 自動領號 + 自動合併並推上 Remote)
|
|
429
429
|
當需求規格經使用者確認無誤,準備歸檔時:
|
|
430
430
|
|
|
431
431
|
* **方式 A(純 AI 自動化,最推薦)**:在 AI 側邊欄直接輸入:
|
|
@@ -433,15 +433,16 @@ flowchart TD
|
|
|
433
433
|
scc
|
|
434
434
|
```
|
|
435
435
|
AI 收到後會自動完成全自動 Git-Flow 閉環作業:
|
|
436
|
-
1.
|
|
437
|
-
2.
|
|
438
|
-
3.
|
|
439
|
-
4.
|
|
436
|
+
1. **先推分支至 Remote 並同步遠端**:若 Git 有設定 remote,先將目前分支推送至遠端並執行 `git fetch` 同步最新狀態。
|
|
437
|
+
2. **自動向主分支查詢並取得新號**:查詢 master/main(含遠端主分支)目前最大序號(例如最大是 `REQ-005`,自動領取最新號 `REQ-006`),避免號碼競爭。
|
|
438
|
+
3. **自動定名更名**:使用 `git mv` 將目錄重命名為 `project/REQ-006-cart-checkout`,並將目錄內所有檔案的 `{{REQ_ID}}` 批次置換為 `REQ-006`。
|
|
439
|
+
4. **自動建立提交並推送分支**:在 feature 分支自動建立 commit `docs(REQ-006): cart-checkout - 規格確認歸檔`,若有 remote 則同步推送至遠端。
|
|
440
|
+
5. **自動合併至主分支並推送至 Remote**:自動切換至主分支(`git checkout master`),將 feature 分支自動合併回主分支(`git merge feat/cart-checkout`),重新生成主分支的 `project/index.md`,若有 remote 則自動將主分支推送至遠端(`git push origin master`),保證主分支規格最新且永遠不衝突!
|
|
440
441
|
* **方式 B(CLI 終端指令)**:
|
|
441
442
|
```bash
|
|
442
443
|
sa-spec finalize --name cart-checkout
|
|
443
444
|
```
|
|
444
|
-
CLI
|
|
445
|
+
CLI 同樣會先推分支至 remote、查詢主分支最新序號定號、置換佔位符、完成提交、自動合併回 master 並推送至 remote!若想保留在當前分支手動處理,可加上 `--no-merge` 參數。
|
|
445
446
|
|
|
446
447
|
#### 4. 消除索引合併衝突(`sa-spec reindex`)
|
|
447
448
|
`project/index.md` 改為由目錄動態生成的「衍生清單」,不再依賴脆弱的手動 append:
|
|
@@ -702,7 +703,7 @@ git status
|
|
|
702
703
|
git log -1 --oneline
|
|
703
704
|
```
|
|
704
705
|
|
|
705
|
-
|
|
706
|
+
若 Git 有設定 remote,AI 與 CLI 會在建立分支與歸檔合併時自動執行 `git push` 推送至遠端;若當時尚未設定 remote,事後也可手動執行:
|
|
706
707
|
|
|
707
708
|
```bash
|
|
708
709
|
git push origin main
|
|
@@ -719,11 +720,22 @@ git push origin master
|
|
|
719
720
|
- 未經使用者確認,不得標示為 `已審核`。
|
|
720
721
|
- `spec:analyze` 發現衝突時不得產出最終文件,也不得修改既有需求文件。
|
|
721
722
|
- `project/system-spec.md` 只能在 `spec:commit` 依使用者確認內容更新。
|
|
722
|
-
-
|
|
723
|
+
- **鐵律**:只要 Git 有設定 remote,`scp` 與 `scc` 都會自動將分支與主分支推送至 remote。
|
|
723
724
|
- 一次最多問 3 個待確認問題,優先詢問會影響範圍、資料、權限、API、DB 或驗收的問題。
|
|
724
725
|
|
|
725
726
|
## 更新紀錄
|
|
726
727
|
|
|
728
|
+
### v0.2.6
|
|
729
|
+
- **Git Remote 自動推送鐵律(Remote Auto-Push)**:
|
|
730
|
+
- **`scp` 建立分支自動推上遠端**:執行 `spec:propose`(`scp`)或 `sa-spec new --branch` 建立 feature 分支後,自動偵測是否有設定 Git remote;若有則立即將新分支推送至遠端(`git push -u <remote> feat/<name>`)。
|
|
731
|
+
- **`scc` 先推分支再領號與主分支自動推送**:執行 `spec:commit`(`scc`)或 `sa-spec finalize` 時,若有設定 Git remote,會**先將目前分支推送至 remote 並同步遠端狀態**,接著才查詢主分支(`master`/`main`)最新可用序號定號,完成 feature 分支提交與推送、自動合併回主分支後,**自動將主分支推送至 remote**。
|
|
732
|
+
|
|
733
|
+
### v0.2.5
|
|
734
|
+
- **支援前端 UI 線框圖(PlantUML Salt Code-as-Wireframe)**:
|
|
735
|
+
- **純文字代碼化線框圖**:在 `uml/` 目錄新增標準 `uml/wireframe.puml`,使用 PlantUML Salt 語法(`@startsalt ... @endsalt`)以純文字定義頁面排版、輸入欄位、選項與按鈕,可直接在 VS Code 渲染預覽,並可納入 Git 版本追蹤。
|
|
736
|
+
- **AI 開發交接前後閉環**:`srs.md` 與 `handoff.md` 新增「UI / 畫面規格」區塊,前端需求直接引用 `uml/wireframe.puml`,供 OpenSpec / Claude Code 精準產出前端元件;純後端需求則標示「無 UI 介面需求」。
|
|
737
|
+
- **版本升級(`sa-spec upgrade`)既有需求防護**:升級時主動掃描既有需求,若偵測到前端介面描述且缺少 wireframe 則發出補齊提示;已標記無 UI 之純後端需求則略過,不盲目覆蓋既有規格。
|
|
738
|
+
|
|
727
739
|
### v0.2.4
|
|
728
740
|
- **序號重複主動告警與重新定號自癒支援**:
|
|
729
741
|
- **唯一性主動檢驗**:`sa-spec check` 與 `sa-spec reindex` 加入重複序號檢測,遇到衝突時即時發出 WARNING 告警並列出衝突目錄與修復建議。
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
- Sequence Diagram:用於描述角色、系統、服務或 API 之間的互動順序。
|
|
21
21
|
- Class Diagram:用於描述主要資料物件、屬性與關聯。
|
|
22
22
|
- State Diagram:用於描述有明確生命週期的物件狀態。
|
|
23
|
+
- Wireframe / Mockup (PlantUML Salt):用於描述前端介面佈局、表單欄位、按鈕與操作畫面,獨立存放於 `uml/wireframe.puml`(使用 `@startsalt` 與 `@endsalt`)。若需求涉及前端 UI 或使用者操作畫面時按需產出;純後端需求則在 `handoff.md` 標示「無 UI 介面需求」。
|
|
23
24
|
|
|
24
25
|
## 圖表說明
|
|
25
26
|
每張 UML 圖旁邊或同一文件內需補充:
|
|
@@ -21,9 +21,9 @@ description: 用 init、propose、analyze、commit 四段流程整理需求,
|
|
|
21
21
|
| 指令 | 簡寫 | 用途 | 執行規則 |
|
|
22
22
|
|---|---|---|---|
|
|
23
23
|
| `spec:init` | `sci` | 初始化 | 載入並遵守 `AGENTS.md`、本 skill 與必要規則,確認 `project/` 結構是否存在。 |
|
|
24
|
-
| `spec:propose` | `scp` | 提出需求 | 使用者提出需求後,自動依需求名稱建立並切換至專屬 feature 分支(`feat/<name>`,若已在 feature branch
|
|
24
|
+
| `spec:propose` | `scp` | 提出需求 | 使用者提出需求後,自動依需求名稱建立並切換至專屬 feature 分支(`feat/<name>`,若已在 feature branch 則沿用),檢查是否有設定 Git remote,若有則自動將分支推上 remote(`git push -u <remote> feat/<name>`),並建立草稿目錄(內部使用 `{{REQ_ID}}` 佔位),整理需求摘要、目標、初步流程與待確認事項;不歸檔、不修改既有需求。 |
|
|
25
25
|
| `spec:analyze` | `sca` | 分析與起草 | 先檢查新需求是否與 `project/` 內所有既有需求衝突;無衝突才產出 SRS、UML、OpenAPI、DB Schema 草稿;有衝突則只列出衝突與待釐清問題,待使用者釐清後再次執行 `spec:analyze`(或 `sca`)。 |
|
|
26
|
-
| `spec:commit` | `scc` | 確認歸檔 |
|
|
26
|
+
| `spec:commit` | `scc` | 確認歸檔 | 只把使用者已確認的版本歸檔到該需求資料夾;若有 Git remote 則先將目前分支推上 remote 並同步遠端狀態,接著才查詢主分支(`master`/`main`)最新可用序號定號(`REQ-xxx`)、替換佔位符,更新 `project/index.md`、`project/system-spec.md` 與 `history.md`,建立 Git commit(若有 remote 則推送分支),再自動切換回主分支完成合併並推送到 remote。 |
|
|
27
27
|
|
|
28
28
|
## 硬性限制
|
|
29
29
|
|
|
@@ -46,12 +46,16 @@ description: 用 init、propose、analyze、commit 四段流程整理需求,
|
|
|
46
46
|
- `spec:commit` 只能套用已由 `spec:analyze` 產出的、且使用者已確認的無衝突版本。
|
|
47
47
|
- `handoff.md` 只能根據已確認的 SRS、UML、OpenAPI、DB Schema 與限制整理,不得新增未確認的開發假設。
|
|
48
48
|
- 交給 OpenSpec 或其他 AI 開發工具時,必須指定它先閱讀 `handoff.md`,並以 `handoff.md` 作為開發入口與限制摘要;其他規格文件作為詳細來源。
|
|
49
|
+
- **鐵律(Git Remote 自動推送強制規範)**:只要 Git repository 有設定 remote(例如 `origin`),所有分支建立與提交變更**都必須自動推送(`git push`)到 remote**,無需等待使用者額外指示;若 push 失敗時只回報認證或網路問題,不得回滾已完成的文件歸檔與本機 commit。
|
|
49
50
|
- `spec:commit` 完成文件歸檔後,必須自動建立本機 Git commit;commit message 以需求編號與需求名稱為主,並加上簡短需求說明,格式為 `docs(REQ-001): 需求名稱 - 簡短需求說明`。
|
|
50
|
-
- `spec:commit`
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
- `spec:commit` 歸檔與自動合併閉環流程(含 Remote 同步順序):
|
|
52
|
+
1. **先推分支至 Remote**:執行 `spec:commit`(或 `scc`)時,若檢查到 Git 有設定 remote,必須**先將目前分支推送至 remote**(`git push -u <remote> <branch>`)並同步遠端最新狀態(`git fetch <remote>`)。
|
|
53
|
+
2. **再查主分支最新版號**:接著才向主分支(`main` / `master` 及遠端主分支)查詢最新已使用序號,決定下一個可用序號(`REQ-xxx`)。
|
|
54
|
+
3. **定號歸檔與提交**:將草稿目錄重命名為正式 `project/REQ-xxx-<name>`、替換內部 `{{REQ_ID}}` 佔位符、更新索引與規格後,在 feature 分支建立 commit;若有 remote 則同步推送該 feature 分支至 remote。
|
|
55
|
+
4. **自動合併回主分支並推送**:若目前處於 feature 分支(`feat/<name>`),AI 必須自動切換回主分支(優先偵測 `main` 或 `master`),拉取/檢查最新狀態並自動合併該 feature 分支 (`git checkout master && git merge feat/<name>`),隨後在主分支重新生成 `project/index.md` 索引;若有設定 remote,**必須自動將主分支推送至 remote**(`git push <remote> <mainBranch>`)。
|
|
56
|
+
- 多人協作與 Git-Flow 模式(延遲綁定序號與自動合併):支援多人平行開發。執行 `spec:propose`(或 `scp`)時,若目前處於 master/main 分支,AI 必須自動依需求名稱建立並切換至專屬 feature branch(如 `feat/<name>`),檢查若有設定 Git remote 則立即將新分支推上 remote(`git push -u <remote> feat/<name>`),並在 `project/<name>/` 建立草稿目錄,內部使用 `{{REQ_ID}}` 佔位,無需使用者手動敲 CLI;執行 `spec:analyze` 前應先確保取得 master 最新規格以防漏檢衝突;執行 `spec:commit` 歸檔時先推分支到 remote,再向 master 確認最新可用序號定號,自動將目錄定名為正式 `REQ-xxx`、替換內部佔位符、完成提交、自動合併回 master 並推上 remote,避免多人合併時的序號競爭與索引衝突。
|
|
53
57
|
- 文件未經使用者確認,不得標示為 `已審核`。
|
|
54
|
-
- `uml/` 內的 UML 圖不限單一 UML 圖型;`spec:analyze`
|
|
58
|
+
- `uml/` 內的 UML 圖不限單一 UML 圖型;`spec:analyze` 必須依需求選擇最能說明流程、互動、狀態、資料關係或介面佈局的圖表,例如活動圖、循序圖、使用案例圖、狀態圖、類別圖;**若需求涉及前端 UI 或使用者操作畫面,必須在 `uml/wireframe.puml` 產出線框圖(使用 PlantUML Salt 語法:`@startsalt ... @endsalt`)**;純後端需求則在 `handoff.md` 明確標記「無 UI 介面需求」。**嚴禁將多張圖混在同一個檔案中**,必須在需求資料夾下的 `uml/` 目錄拆分成獨立的 `.puml` 檔案(例如 `uml/main.puml`、`uml/sequence.puml`、`uml/wireframe.puml`),且每個檔案只能包含一組 `@start...` 與 `@end...`,以避免 PlantUML 渲染或預覽失敗。
|
|
55
59
|
- 一次最多問 3 個待確認問題,優先詢問會影響範圍、資料、權限、API、DB 或驗收的問題。
|
|
56
60
|
|
|
57
61
|
## analyze 衝突檢查
|
|
@@ -137,15 +141,15 @@ project/
|
|
|
137
141
|
docs(REQ-001): 需求名稱 - 簡短需求說明
|
|
138
142
|
```
|
|
139
143
|
|
|
140
|
-
|
|
144
|
+
只要 Git repository 有設定 remote(例如 `origin`),在 `spec:commit` 歸檔時必須先將目前分支推送至 remote 並同步遠端狀態,接著查詢主分支最新版號、完成定號歸檔與 commit、合併回主分支後,自動將主分支推送至 remote。若 push 失敗,只回報認證或網路問題,不得回滾已完成的文件歸檔與本機 commit。
|
|
141
145
|
|
|
142
146
|
## 狀態機
|
|
143
147
|
|
|
144
148
|
```text
|
|
145
|
-
init (sci) -> propose (scp) -> analyze (sca)
|
|
149
|
+
init (sci) -> propose (scp, 建分支並推至 remote) -> analyze (sca)
|
|
146
150
|
|
|
147
151
|
analyze 無衝突 -> 產出待確認版本 -> commit (scc)
|
|
148
152
|
analyze 有衝突 -> 釐清問題 -> analyze (sca)
|
|
149
153
|
|
|
150
|
-
commit (scc) ->
|
|
154
|
+
commit (scc) -> 先推分支至 remote -> 查 master 最新版號定號 -> feature commit -> 自動合併至主分支並推至 remote
|
|
151
155
|
```
|