@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 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["Auto query latest sequential ID N from master"]
109
- E --> F["Auto assign project/REQ-N+1-cart/<br/>Replace {{REQ_ID}} and commit on feature branch"]
110
- F --> G["Auto merge into master branch<br/>Dynamically rebuild project/index.md"]
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 & Auto-Merge**: Running `scc` in AI chat (or `sa-spec finalize --name checkout`) automatically inspects master's latest ID, assigns `REQ-xxx`, replaces placeholders, commits, and **automatically merges into master** (`git checkout master && git merge feat/checkout`), then updates `project/index.md`.
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 から最新の利用可能番号 N を自動取得"]
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 ブランチへ自動マージ<br/>project/index.md を動的に再生成"]
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}}` を使って作業します。途中で要件を破棄する場合も、ブランチを削除するだけで済み、欠番(ゴーストID)を残しません。
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. **自動採番と主ブランチへの自動マージ**: `scc` または `sa-spec finalize` を実行すると、**master から次の番号を自動取得して採番・置換・コミット**し、**master ブランチへ自動切り替え&自動マージ**を行い、`project/index.md` を最新状態に再生成します。
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에서 최신 사용 가능 번호 N 자동 확인"]
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 브랜치로 자동 머지<br/>project/index.md 동적 재생성"]
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. **자동 신규 번호 채번 및 메인 브랜치 자동 머지**: `scc` 또는 `sa-spec finalize` 실행 시 **master에서 다음 번호를 자동 조회하여 채번·치환·커밋**하고, **master 브랜치로 자동 전환 후 자동 머지**를 수행하며 `project/index.md`를 최신 상태로 정렬 재생성합니다.
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["自动向主分支查询最新可用序号 N"]
108
+ D --> E["先推分支至 remote 并同步远端状态<br/>再向主分支查询最新可用序号 N"]
109
109
  E --> F["自动定号为 project/REQ-N+1-cart/<br/>批量替换 {{REQ_ID}} 并建立提交"]
110
- F --> G["自动合并至 master 主分支<br/>动态重新生成 project/index.md"]
110
+ F --> G["自动合并至 master 主分支并推上 remote<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`,建立 `feat/cart`(若配置了 Git remote 则自动推送分支至远端)以及 `project/cart/` 与 `{{REQ_ID}}` 占位符。多人同时提出需求互不冲突。如果需求放弃,直接删除分支,**绝不遗留幽灵跳号**。
115
115
  2. **基线同步防漏检**:执行 `spec:analyze` 前先确认同步远端 master 规格,确保以全系统最新状态进行冲突检查。
116
- 3. **自动拿新号与自动合并**:执行 `scc`(或 `sa-spec finalize --name cart`)时,系统**自动向 master 申请下一个新号定号**、批量替换占位符、完成提交,并**自动切换回 master 并合并该 feature 分支**,随后自动重建 `project/index.md`。
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
- 只有在使用者明確要求推送 remote,或專案設定啟用 auto-push 時,才會執行 `git push`。如果 push 失敗,只回報認證或網路問題,不會回滾已完成的文件歸檔與本機 commit。
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["自動查詢主分支最新序號 N"]
403
+ D --> E["先推分支至 remote 並同步遠端狀態<br/>再查詢主分支最新序號 N"]
404
404
  E --> F["自動定號為 project/REQ-N+1-cart/<br/>批次置換 {{REQ_ID}} 並建立 commit"]
405
- F --> G["自動合併至 master 主分支<br/>動態重新生成 project/index.md"]
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` 建立並切換分支**,並在 `project/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. **自動向主分支查詢並取得新號**:查詢 master/main 目前最大序號(例如最大是 `REQ-005`,自動領取最新號 `REQ-006`),避免號碼競爭。
437
- 2. **自動定名更名**:使用 `git mv` 將目錄重命名為 `project/REQ-006-cart-checkout`,並將目錄內所有檔案的 `{{REQ_ID}}` 批次置換為 `REQ-006`。
438
- 3. **自動建立本機提交**:在 feature 分支自動建立 commit `docs(REQ-006): cart-checkout - 規格確認歸檔`。
439
- 4. **自動合併至主分支**:自動切換至主分支(`git checkout master`),將 feature 分支自動合併回主分支(`git merge feat/cart-checkout`),並重新生成主分支的 `project/index.md`,保證主分支規格最新且永遠不衝突!
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 同樣會自動查詢主分支最新序號定號、置換佔位符、完成提交並自動合併回 master!若想保留在當前分支手動處理,可加上 `--no-merge` 參數。
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
- 若要推送到 remote,需要明確要求 AI 執行 push,或自行執行:
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
- - `spec:commit` 會自動建立本機 Git commit;remote push 需使用者明確要求或啟用 auto-push。
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loviusc/sa-spec",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Personal system analysis documentation workspace CLI",
5
5
  "publishConfig": {
6
6
  "access": "public",
package/readme.md CHANGED
@@ -385,7 +385,7 @@ commit (scc) -> 歸檔 -> 本機 Git commit
385
385
  docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
386
386
  ```
387
387
 
388
- 只有在使用者明確要求推送 remote,或專案設定啟用 auto-push 時,才會執行 `git push`。如果 push 失敗,只回報認證或網路問題,不會回滾已完成的文件歸檔與本機 commit。
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["自動查詢主分支最新序號 N"]
403
+ D --> E["先推分支至 remote 並同步遠端狀態<br/>再查詢主分支最新序號 N"]
404
404
  E --> F["自動定號為 project/REQ-N+1-cart/<br/>批次置換 {{REQ_ID}} 並建立 commit"]
405
- F --> G["自動合併至 master 主分支<br/>動態重新生成 project/index.md"]
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` 建立並切換分支**,並在 `project/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. **自動向主分支查詢並取得新號**:查詢 master/main 目前最大序號(例如最大是 `REQ-005`,自動領取最新號 `REQ-006`),避免號碼競爭。
437
- 2. **自動定名更名**:使用 `git mv` 將目錄重命名為 `project/REQ-006-cart-checkout`,並將目錄內所有檔案的 `{{REQ_ID}}` 批次置換為 `REQ-006`。
438
- 3. **自動建立本機提交**:在 feature 分支自動建立 commit `docs(REQ-006): cart-checkout - 規格確認歸檔`。
439
- 4. **自動合併至主分支**:自動切換至主分支(`git checkout master`),將 feature 分支自動合併回主分支(`git merge feat/cart-checkout`),並重新生成主分支的 `project/index.md`,保證主分支規格最新且永遠不衝突!
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 同樣會自動查詢主分支最新序號定號、置換佔位符、完成提交並自動合併回 master!若想保留在當前分支手動處理,可加上 `--no-merge` 參數。
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
- 若要推送到 remote,需要明確要求 AI 執行 push,或自行執行:
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
- - `spec:commit` 會自動建立本機 Git commit;remote push 需使用者明確要求或啟用 auto-push。
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 gitRemoteLs = spawnSync("git", ["ls-tree", `origin/${mainBranch}:project`], { cwd, encoding: "utf8" });
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. 自動向本地與主分支查詢最新已使用的最大 REQ 序號
500
+ // 1. 先檢查是否有 remote,若有則先將目前分支推上 remote 並同步遠端狀態,接著才查詢主分支最新 REQ 序號
501
+ const remote = getDefaultRemote();
466
502
  const mainBranch = detectMainBranch();
467
503
  const currentBranch = getCurrentBranch();
468
- const maxIdNum = getLatestMaxReqId(projectDir, mainBranch);
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. 自動提交與自動合併回主分支 (Git-Flow 閉環)
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}): ${name} - 規格確認歸檔`], { cwd, encoding: "utf8" });
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}): ${name} - 規格確認歸檔`);
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
- console.log(` 全部歸檔流程完成!已自動領取新號 ${nextId} 並自動合併回主分支 ${mainBranch}。`);
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}): ${name} - 規格確認歸檔`], { cwd, encoding: "utf8" });
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}): ${name} - 規格確認歸檔"`);
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
- const content = fs.readFileSync(handoffAbsPath, "utf8");
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.replace(/uml\.puml/g, "uml/"), "utf8");
917
+ fs.writeFileSync(handoffAbsPath, content, "utf8");
853
918
  }
854
919
  results.push({
855
920
  action: "update",
856
921
  target: handoffRelPath,
857
- message: "更新來源參照 uml.puml -> uml/"
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
  }
@@ -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 則沿用),建立草稿目錄(內部使用 `{{REQ_ID}}` 佔位),整理需求摘要、目標、初步流程與待確認事項,不歸檔、不修改既有需求。 |
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` | 確認歸檔 | 只把使用者已確認的版本歸檔到該需求資料夾,自動向主分支確認最新可用序號定號(`REQ-xxx`)、替換佔位符,更新 `project/index.md`、`project/system-spec.md` 與 `history.md`,建立本機 Git commit 後,自動切換回主分支並完成合併。 |
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` 自動合併到主分支(Git-Flow 閉環):完成 feature 分支 commit 後,若目前處於 feature 分支(`feat/<name>`),AI 必須自動切換回主分支(優先偵測 `main` 或 `master`),拉取/檢查最新狀態並自動合併該 feature 分支 (`git checkout master && git merge feat/<name>`),隨後在主分支重新生成 `project/index.md` 索引,確保主分支規格清單完整且無衝突。
47
- - `spec:commit` 只有在使用者明確要求推送 remote,或專案設定啟用 auto-push 時,才可執行 `git push`;push 失敗時只回報認證或網路問題,不得回滾已完成的文件歸檔與本機 commit。
48
- - 多人協作與 Git-Flow 模式(延遲綁定序號與自動合併):支援多人平行開發。執行 `spec:propose`(或 `scp`)時,若目前處於 master/main 分支,AI 必須自動依需求名稱建立並切換至專屬 feature branch(如 `feat/<name>`),並在 `project/<name>/` 建立草稿目錄,內部使用 `{{REQ_ID}}` 佔位,無需使用者手動敲 CLI;執行 `spec:analyze` 前應先確保取得 master 最新規格以防漏檢衝突;執行 `spec:commit` 歸檔時自動向 master 確認最新可用序號定號,自動將目錄定名為正式 `REQ-xxx`、替換內部佔位符、完成提交並自動合併回 master,避免多人合併時的序號競爭與索引衝突。
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` 必須依需求選擇最能說明流程、互動、狀態或資料關係的 UML 圖,例如活動圖、循序圖、使用案例圖、狀態圖或類別圖,不可為了固定格式硬產生活動圖。**嚴禁將多張圖混在同一個檔案中**,必須在需求資料夾下的 `uml/` 目錄拆分成獨立的 `.puml` 檔案(例如 `uml/main.puml`、`uml/sequence.puml`、`uml/state.puml`),且每個檔案只能包含一組 `@startuml` 與 `@enduml`,以避免 PlantUML 渲染或預覽失敗。
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) -> 歸檔 -> 本機 Git commit
86
+ commit (scc) -> 先推分支至 remote -> 查 master 最新版號定號 -> 歸檔 commit -> 合併回主分支並推至 remote
83
87
  ```
84
88
 
85
89
  # 歸檔結構
@@ -22,6 +22,9 @@
22
22
  ## DB 變更
23
23
  待補充;若無 DB 需求,明確標示「無 DB 需求」。
24
24
 
25
+ ## UI / 畫面規格
26
+ 待補充;若有前端介面需求,參照 `uml/wireframe.puml`(PlantUML Salt 線框圖);若無 UI 需求,明確標示「無 UI 介面需求」。
27
+
25
28
  ## 驗收條件
26
29
  - 待補充。
27
30
 
@@ -16,6 +16,9 @@
16
16
  ## 功能需求
17
17
  - 待補充。
18
18
 
19
+ ## 介面與操作需求
20
+ - 待補充(若涉及前端介面操作,可參照 `uml/wireframe.puml` 線框圖;純後端需求標示「無 UI 介面需求」)。
21
+
19
22
  ## 驗收條件
20
23
  - 待補充。
21
24
 
@@ -0,0 +1,13 @@
1
+ @startsalt
2
+ {+
3
+ {* {{REQ_ID}} {{REQ_NAME}} 介面草稿 }
4
+ --
5
+ {
6
+ 輸入欄位: | "預設內容"
7
+ 選項: | (X) 單選項目 A | ( ) 單選項目 B
8
+ 核取方塊: | [] 核取項目 1 | [] 核取項目 2
9
+ }
10
+ --
11
+ [ 確認送出 ] | [ 取消 ]
12
+ }
13
+ @endsalt
@@ -385,7 +385,7 @@ commit (scc) -> 歸檔 -> 本機 Git commit
385
385
  docs(REQ-001): 番茄時鐘 - 新增專注與休息計時需求
386
386
  ```
387
387
 
388
- 只有在使用者明確要求推送 remote,或專案設定啟用 auto-push 時,才會執行 `git push`。如果 push 失敗,只回報認證或網路問題,不會回滾已完成的文件歸檔與本機 commit。
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["自動查詢主分支最新序號 N"]
403
+ D --> E["先推分支至 remote 並同步遠端狀態<br/>再查詢主分支最新序號 N"]
404
404
  E --> F["自動定號為 project/REQ-N+1-cart/<br/>批次置換 {{REQ_ID}} 並建立 commit"]
405
- F --> G["自動合併至 master 主分支<br/>動態重新生成 project/index.md"]
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` 建立並切換分支**,並在 `project/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. **自動向主分支查詢並取得新號**:查詢 master/main 目前最大序號(例如最大是 `REQ-005`,自動領取最新號 `REQ-006`),避免號碼競爭。
437
- 2. **自動定名更名**:使用 `git mv` 將目錄重命名為 `project/REQ-006-cart-checkout`,並將目錄內所有檔案的 `{{REQ_ID}}` 批次置換為 `REQ-006`。
438
- 3. **自動建立本機提交**:在 feature 分支自動建立 commit `docs(REQ-006): cart-checkout - 規格確認歸檔`。
439
- 4. **自動合併至主分支**:自動切換至主分支(`git checkout master`),將 feature 分支自動合併回主分支(`git merge feat/cart-checkout`),並重新生成主分支的 `project/index.md`,保證主分支規格最新且永遠不衝突!
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 同樣會自動查詢主分支最新序號定號、置換佔位符、完成提交並自動合併回 master!若想保留在當前分支手動處理,可加上 `--no-merge` 參數。
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
- 若要推送到 remote,需要明確要求 AI 執行 push,或自行執行:
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
- - `spec:commit` 會自動建立本機 Git commit;remote push 需使用者明確要求或啟用 auto-push。
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 則沿用),建立草稿目錄(內部使用 `{{REQ_ID}}` 佔位),整理需求摘要、目標、初步流程與待確認事項;不歸檔、不修改既有需求。 |
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` | 確認歸檔 | 只把使用者已確認的版本歸檔到該需求資料夾,自動向主分支確認最新可用序號定號(`REQ-xxx`)、替換佔位符,更新 `project/index.md`、`project/system-spec.md` 與 `history.md`,建立本機 Git commit 後,自動切換回主分支並完成合併。 |
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` 自動合併到主分支(Git-Flow 閉環):完成 feature 分支 commit 後,若目前處於 feature 分支(`feat/<name>`),AI 必須自動切換回主分支(優先偵測 `main` 或 `master`),拉取/檢查最新狀態並自動合併該 feature 分支 (`git checkout master && git merge feat/<name>`),隨後在主分支重新生成 `project/index.md` 索引,確保主分支規格清單完整且無衝突。
51
- - `spec:commit` 只有在使用者明確要求推送 remote,或專案設定啟用 auto-push 時,才可執行 `git push`;push 失敗時只回報認證或網路問題,不得回滾已完成的文件歸檔與本機 commit。
52
- - 多人協作與 Git-Flow 模式(延遲綁定序號與自動合併):支援多人平行開發。執行 `spec:propose`(或 `scp`)時,若目前處於 master/main 分支,AI 必須自動依需求名稱建立並切換至專屬 feature branch(如 `feat/<name>`),並在 `project/<name>/` 建立草稿目錄,內部使用 `{{REQ_ID}}` 佔位,無需使用者手動敲 CLI;執行 `spec:analyze` 前應先確保取得 master 最新規格以防漏檢衝突;執行 `spec:commit` 歸檔時自動向 master 確認最新可用序號定號,自動將目錄定名為正式 `REQ-xxx`、替換內部佔位符、完成提交並自動合併回 master,避免多人合併時的序號競爭與索引衝突。
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` 必須依需求選擇最能說明流程、互動、狀態或資料關係的 UML 圖,例如活動圖、循序圖、使用案例圖、狀態圖或類別圖,不可為了固定格式硬產生活動圖。**嚴禁將多張圖混在同一個檔案中**,必須在需求資料夾下的 `uml/` 目錄拆分成獨立的 `.puml` 檔案(例如 `uml/main.puml`、`uml/sequence.puml`、`uml/state.puml`),且每個檔案只能包含一組 `@startuml` 與 `@enduml`,以避免 PlantUML 渲染或預覽失敗。
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
- 只有在使用者明確要求推送 remote,或專案設定啟用 auto-push 時,才可執行 `git push`。若 push 失敗,只回報認證或網路問題,不得回滾已完成的文件歸檔與本機 commit。
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) -> 自動拿新號定號 -> feature commit -> 自動合併至主分支 (master/main)
154
+ commit (scc) -> 先推分支至 remote -> 查 master 最新版號定號 -> feature commit -> 自動合併至主分支並推至 remote
151
155
  ```