Files
code/skills/target/SKILL.md
T
jiantw83andClaude Sonnet 5 766142c3ba feat(spec-version-guard): 新增版本檢查 hook 並在 9 個 skill 檔頭引用規範
新建 hooks/hooks.json,PreToolUse 沿用跨 plugin 腳本定位手法呼叫 shared 的
version-guard.mjs(判定仍固定讀自己的 plugin.json,只是腳本檔借用 shared 的);
action-composite/action-docker/action-node/image/issues/nuget/review-resolve/
sync/target 九個 skill 檔頭補上 spec-version-guard。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 14:54:07 +08:00

294 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: target
description: 用專案根目錄的 `TARGET.md` 當每日待辦清單,並以系統排程(Linux/WSL/macOS 用 crontab、Windows 用 schtasks)在每天 00:00 自動跑完它。`--schedule on` 建立或更新排程、`--schedule off` 移除排程、`--run` 立即(或由排程)執行一次:先同步 git 並切到 `develop`(遠端沒有就從預設分支建立),逐項實作 `TARGET.md` 中未勾選的項目、完成一項就勾選並補完成時間,接著把工作區變更依 conventional commit 類型分類提交、push `develop`,最後透過 Gitea API 對**遠端預設分支**發 PR(已有同 head→base 的 open PR 就沿用不重開)。當使用者說把 TARGET.md 排成每天執行、每天半夜自動跑待辦、開啟/關閉每日自動任務、建立每日排程做完 TARGET、移除 TARGET 排程、跑一次 TARGET.md 的項目、讓 AI 每天自動做完待辦並發 PR,或提到 TARGET.md、每日排程、cron 每天 00:00、schtasks 每日任務時觸發。不適用於:解決 AI review findings(用 review-resolve)、實作 Gitea 議題的 TODO(用 issues)、角色記憶的睡眠排程(用 role)。
argument-hint: "[--schedule on|off] [--run] [--project-dir <專案根目錄>] [--cli <claude|codex|agy|opencode|copilot>] [--base <PR 目標分支>] [--no-pr] [--yes]"
---
# target — TARGET.md 每日排程執行、提交、push develop 並發 PR
兩個用途合在一個 skill:**管理排程**(開/關每天 00:00 的系統排程)與**執行一次**(把 `TARGET.md` 的待辦做完並走完 git 流程)。排程觸發時,執行的就是本 skill 的 `--run`。
| 模式 | 觸發 | 動作 |
| --- | --- | --- |
| `--schedule on` | 使用者 | 依 OS 建立/更新「每天 00:00 執行本 skill `--run`」的系統排程(同一專案只會有一筆) |
| `--schedule off` | 使用者 | 移除該專案的排程條目(只動自己那筆,不碰使用者其他排程) |
| `--run` | 排程/使用者 | A Git 同步(切到 develop,沒有就建立)→ B 讀 `TARGET.md` → C 逐項實作並勾選 → D 分類提交 → E push develop → F 對預設分支發 PR |
| 不帶參數 | 使用者 | 只回報現況:排程裝了沒、下次執行時間、`TARGET.md` 還剩幾項未完成 |
`--schedule` 與 `--run` 可同時帶(`--schedule on --run` = 裝好排程並立刻先跑一次)。
---
## 共用規範(必要前置)
先載入 `/jsc-shared:spec-preflight` 並依其流程處理;載入不到即代表 shared plugin 未安裝,
依該 spec 詢問使用者是否安裝 `https://gitea.jsc.idv.tw/plugins/shared.git`,不安裝則中斷本 skill。
本 skill 需要的規範:`spec-version-guard`、`spec-output`、`spec-execution`、`spec-git-safety`、`spec-gitea`、`spec-time-log`、`spec-todo-list`、`spec-conventional-commit`、`spec-git-push`、`spec-pull-request`、`spec-skill-invocation`、`spec-model`
本 skill 特有補充:
- **排程只動自己那一筆**:安裝/移除都以固定標記比對,**絕不覆寫整份 crontab、不刪別人的排程任務**。
- **排程情境沒有人在旁邊**:`--run` 遇到必要決策時**停下來並寫進 log**,不得臆測後硬做;下次執行會再遇到同一個決策點,由使用者處理。
- **必要決策**(會中斷詢問):工作區有未提交變更、`origin` 無法解析、找不到遠端預設分支、`TARGET.md` 項目語意不明無法安全實作、push 憑證皆失敗、無法判斷目前是哪個助理(且未帶 `--cli`)。
---
## 參數
格式:`[--schedule on|off] [--run] [--project-dir <專案根目錄>] [--cli <claude|codex|agy|opencode|copilot>] [--base <PR 目標分支>] [--no-pr] [--yes]`
- `--schedule on|off`:`on` 建立/更新排程,`off` 移除排程。省略時不動排程。
- `--run`:立即執行一次 `TARGET.md`(排程條目帶的就是這個)。
- `--project-dir <專案根目錄>`:目標專案根目錄,**省略時取目前工作目錄**(會先 `git rev-parse --show-toplevel` 正規化成 repo 根)。`TARGET.md` 固定讀**專案根目錄**的那一份。
- `--cli <claude|codex|agy|opencode|copilot>`:排程條目要用哪個助理的 headless 指令。省略時用**目前正在執行本 skill 的助理**;判斷不出來且未帶此參數 → 詢問,不猜測。
- `--base <PR 目標分支>`:PR 的目標分支。**省略時自動取遠端預設分支**(見階段 F),取不到才詢問。
- `--no-pr`:執行到 push 為止,不開 PR。
- `--yes`:全自動,不做確認式詢問(必要決策仍會中斷)。
執行時間固定為**每天 00:00**(本機時區),不提供時間參數;要改時間請直接編輯排程條目。
---
## `TARGET.md` 格式
專案根目錄的 `TARGET.md`,用 Markdown checklist 表示待辦:
```markdown
# TARGET
- [ ] 補上使用者服務的單元測試
- [ ] 把 README 的安裝章節更新成新的 CLI 指令
- [ ] 順便修掉裡面過期的截圖連結
- [x] 移除已停用的舊設定檔(2026/08/02 23:41:07 完成)
```
checklist 語法、已完成略過不重做、子項目連動、標題/說明文字原樣保留、禁止憑空編造等格式規則依 `/jsc-shared:spec-todo-list` 執行。
本 skill 特有:
| 規則 | 說明 |
| --- | --- |
| 待辦 | `- [ ]` 未勾選的項目,**由上而下**依檔案既有順序處理(與 `spec-todo-list` 建立議題 TODO 時「依影響範圍排序」的情境不同,此處沿用 `TARGET.md` 本身的行順序) |
| 檔案不存在 | `--run` 視為「無待辦」正常結束(不建檔、不報錯);`--schedule on` 則提醒尚無 `TARGET.md`,非 `--yes` 時詢問是否仍要建立排程 |
完成一項後就地改成 `- [x]`,並在該行**行尾**補上 `(<yyyy/MM/dd HH:mm:ss> 完成)`(Asia/Taipei,時間格式依 `/jsc-shared:spec-time-log`)。無法安全完成的項目**保持未勾選**,並在該行下方以縮排補一行 `> ⏭️ 待人工處理:<原因>`(已有同樣註記則更新而非重複新增)。
---
## 階段 S:管理排程(`--schedule on|off`)
### S1. 判定 OS 與排程機制
```bash
uname -s # Linux / Darwin / MINGW*|MSYS*|CYGWIN*(後者代表在 Windows 的 git bash)
```
| 環境 | 機制 | 備註 |
| --- | --- | --- |
| Linux、WSL | `crontab` | WSL 的 cron **預設不會自動啟動**,見 S5 |
| macOS | `crontab` | 可用;若使用者偏好 `launchd` 需自行改寫,本 skill 不代為產生 plist |
| Windows(PowerShell/cmd) | `schtasks` | 每日任務 |
判斷不出環境時停止並回報,不臆測。
### S2. 組出排程要執行的指令
```bash
proj="$(cd "<專案根目錄>" && git rev-parse --show-toplevel)" # 絕對路徑
log="$HOME/.jsc/target-$(basename "$proj").log"
```
log **刻意放在專案外面**:放進 repo 會讓每次執行都多出未追蹤檔,污染 D 階段的變更盤點。
各助理的 headless 指令(依 `--cli`):
| `--cli` | 指令 |
| --- | --- |
| `claude` | `claude -p "/jsc-code:target --run --yes"` |
| `codex` | `codex exec '$target --run --yes'`(單引號,避免 `$` 被 shell 展開) |
| `agy` | `agy -p "/jsc-code:target --run --yes"` |
| `opencode` | `opencode run "執行專案根目錄 TARGET.md 的未完成項目,完成後分類提交、push develop 並對預設分支發 PR"` |
| `copilot` | `copilot -p "執行專案根目錄 TARGET.md 的未完成項目,完成後分類提交、push develop 並對預設分支發 PR"` |
> **排程是非互動環境**:助理若跳出工具權限詢問會直接卡住,排程等於沒跑。建立排程前要提醒使用者**先在該專案預先授權**(例如 Claude Code 於專案設定的 `permissions.allow` 列出所需工具,或在指令上加該助理的非互動旗標)。這牽涉安全取捨,**由使用者決定,不代為加上略過權限的旗標**。
### S3. 建立/更新排程(`--schedule on`)
**crontab**(標記寫在行尾,一筆條目就是一行,安裝與移除都靠它比對):
```bash
marker="# jsc-code:target ${proj}"
entry="0 0 * * * cd '${proj}' && <headless 指令> >> '${log}' 2>&1 ${marker}"
mkdir -p "$(dirname "${log}")"
tmp="$(mktemp)"
crontab -l 2>/dev/null | grep -vF "${marker}" > "${tmp}" # 先移除同專案的舊條目(更新用)
printf '%s\n' "${entry}" >> "${tmp}"
crontab "${tmp}"
rm -f "${tmp}"
crontab -l | grep -F "${marker}" # 驗證確實寫進去了
```
- `crontab -l` 在「完全沒有排程」時會回非 0 並印錯誤,所以要 `2>/dev/null`;**不可因此把整份 crontab 當成空的覆寫**——先確認 `crontab -l` 的失敗是「沒有排程」而不是權限問題。
- 指令中若出現 `%`,crontab 會把它當換行,必須寫成 `\%`。
- 條目一律用**絕對路徑**(cron 的 `PATH` 很精簡);若 `command -v <cli>` 得到的不是系統路徑,把 CLI 也寫成絕對路徑。
**schtasks**(Windows):
```powershell
$task = "jsc-code-target-<專案名>" # 專案名重複時附加路徑短碼,確保唯一
schtasks /Create /TN "$task" /SC DAILY /ST 00:00 /F `
/TR "cmd /c cd /d ""<專案絕對路徑>"" && <headless 指令> >> ""<log 絕對路徑>"" 2>&1"
schtasks /Query /TN "$task" # 驗證
```
`/F` 只覆蓋**同名**任務(即本 skill 自己那筆),不影響其他排程。
### S4. 移除排程(`--schedule off`)
```bash
tmp="$(mktemp)"
crontab -l 2>/dev/null | grep -vF "# jsc-code:target ${proj}" > "${tmp}"
crontab "${tmp}"
rm -f "${tmp}"
crontab -l 2>/dev/null | grep -F "# jsc-code:target ${proj}" || echo "已移除"
```
```powershell
schtasks /Delete /TN "jsc-code-target-<專案名>" /F
```
- 找不到條目 → 回報「本來就沒有排程」,視為成功,不報錯。
- **只刪自己標記的那一筆**;其餘 crontab 內容原樣寫回。`TARGET.md`、log 檔、git 分支都不刪。
### S5. 確認排程服務真的在跑(`--schedule on` 後必做)
排程條目寫進去 ≠ 會被執行。安裝後檢查:
```bash
pgrep -x cron >/dev/null || pgrep -x crond >/dev/null || echo "cron 服務未執行"
```
- **WSL 特別注意**:WSL 預設不啟動 cron,需要 `sudo service cron start`,且**重開 WSL 後要再啟動一次**(可寫進 `/etc/wsl.conf` 的 `boot.command` 或啟動腳本)。偵測到未執行時**明確告知使用者這件事**,不要只回報「排程已建立」。
- Windows:`schtasks /Query /TN "<任務名>"` 能查到即可。
---
## 階段 A:Git 同步(`--run`)
### A1. 盤點狀態
```bash
cd "<專案根目錄>"
git rev-parse --show-toplevel
git status --porcelain
git rev-parse --abbrev-ref HEAD
```
- **工作區有未提交變更** → **停止**並回報(排程情境寫入 log)。理由:本 skill 結尾會分類提交所有變更,混入使用者未完成的工作會把它一起提交上去。依 `/jsc-shared:spec-git-safety`「不破壞既有工作」,不得 stash、`reset --hard` 或 `clean` 來清場。
- **detached HEAD** → 停止並回報。
### A2. Fetch 與判定遠端預設分支
```bash
git fetch --all --prune
```
依 `/jsc-shared:spec-git-safety`「工作分支選擇」判定遠端預設分支(`git symbolic-ref refs/remotes/origin/HEAD` → 取不到退而 `git remote show origin` → 兩者皆無則停止詢問,不臆測 `master`/`main`)。**本 skill 特有**:帶 `--base` 時直接採用 `--base` 的值,不再另行判定。
### A3. 切到 `develop`(不存在就從預設分支建立)
依 `/jsc-shared:spec-git-safety`「develop → master 後備分支」與「工作分支選擇」處理:`origin/develop` 存在則切換並 `git pull --ff-only`(分岔失敗 → 停止並回報,不做 merge/rebase 猜測);不存在則從 A2 判定出的遠端預設分支建立 `develop`。
本 skill 特有:**本地已有 `develop` 但遠端沒有** → 沿用本地那條,**不覆蓋、不重建**,並在回報中說明它還沒推上遠端(`git switch develop 2>/dev/null || git switch -c develop --track origin/develop` 的寫法即可自然落在此情形)。新建 `develop` 屬不可忽略的狀態變更,必須在回報與 log 中明講「遠端沒有 develop,已從 `<預設分支>` 建立」。
---
## 階段 B:讀 `TARGET.md` 並盤點待辦
1. 讀 `<專案根目錄>/TARGET.md`(UTF-8)。檔案不存在 → 回報「無 TARGET.md,無待辦」,**正常結束**(不進入 C~F、不 commit、不發 PR)。
2. 解析出所有 `- [ ]` 未勾選項目(含子項目的從屬關係),依**檔案由上而下**的順序排定執行順序。
3. 全部都是 `- [x]` → 回報「TARGET.md 已全部完成」,正常結束。
4. 輸出待辦清單表,除非使用者要求確認,否則直接進入階段 C:
| # | 項目 | 子項目數 | 備註 |
| --- | --- | --- | --- |
若 `TARGET.md` 帶有 `model:` frontmatter,依 `/jsc-shared:spec-model` 的『讀到帶 `model:` frontmatter 的清單檔時的檢查義務』先做模型檢查。
---
## 階段 C:逐項實作並回寫 `TARGET.md`
依 B 的順序,**一次做一項,做完一項就回寫 `TARGET.md`**(中途失敗時已完成的進度不會遺失):
1. 讀懂該項目要什麼;必要時讀相關程式碼與文件確認脈絡。
2. **語意不明、範圍不清、或牽涉設計取捨無法安全決定** → 不硬做。保持未勾選、補上 `> ⏭️ 待人工處理:<原因>`,繼續下一項。
3. 實作最小且合理的變更;能驗證的就驗證(該專案既有的 build/test 指令)。驗證失敗且無法安全修正 → 比照第 2 點標記待人工處理,並**還原**該項目造成的變更,不留半成品。
4. 完成 → 把該行改成 `- [x]` 並於行尾補 `(<yyyy/MM/dd HH:mm:ss> 完成)`;有子項目則子項目全部完成後才勾選上層。
5. 每項結束記錄結果(✅ 完成 / ⏭️ 待人工處理+原因),供階段 G 總結。
`TARGET.md` 一律以 UTF-8(不含 BOM)寫回,結尾保留一個換行;**只改動勾選狀態與完成時間/待人工註記**,其餘內容原樣保留。
---
## 階段 D:分類提交
依 `/jsc-shared:spec-conventional-commit` 執行:以 `git status --porcelain=v1 -uall` 完整盤點所有變更(含未追蹤檔)、依實際異動內容歸入 9 種 commit 類型(每個 type 各一個 commit,訊息格式 `type(範圍): 一句總結`,範圍不得重述 type 本身)、逐組精準 `git add -- <該組檔案...>` 後分別 commit(不用 `git add -A`)。
本 skill 特有:
- `TARGET.md` 本身的勾選更新歸 `chore`,訊息固定用 `chore(TARGET): 更新每日待辦完成狀態`。
- 無任何變更(例如所有項目都待人工處理,只有 `TARGET.md` 的註記異動)→ 仍照常提交 `TARGET.md` 的異動;連 `TARGET.md` 都沒變則跳過 D、E、F,直接進入總結。
---
## 階段 E:Push `develop`
依 `/jsc-shared:spec-git-push` 的三段式流程(認證管理器 → token push → 詢問使用者,前者失敗才換下一個,token 全程遮蔽且不寫進 remote 設定)推送 `develop`。推送前先確認是否有領先遠端的 commit:
```bash
git log --oneline "origin/develop..develop" 2>/dev/null # 領先遠端的 commit;遠端無 develop 時視為全部要推
```
本 skill 特有:無 commit 可推 → 跳過 push,直接進入階段 F(既有遠端分支仍可開 PR);三段皆失敗 → 停止並回報失敗原因(先遮蔽 token),排程情境寫入 log,等使用者處理,不猜測其他憑證。
---
## 階段 F:對預設分支發 PR(`--no-pr` 時略過)
依 `/jsc-shared:spec-pull-request` 執行:目標分支不臆測 → 解析 origin 座標(host/owner/repo)→ 先查有沒有相同 head=`develop` → base=`<目標分支>` 的 open PR,有則沿用不重開(今天新推的 commit 會自動出現在該 PR,可視情況補一則今日進度留言)→ 沒有才以 UTF-8 JSON 檔帶入 body 建立新 PR(換行用實際換行,不可送出字面 `\n`)→ 失敗回報 API 錯誤訊息(先依 `/jsc-shared:spec-gitea` 遮蔽 token)→ 完成後提醒清除對話內文。
本 skill 特有:
- **目標分支**:`--base` 有帶則用它,否則用 A2 判定出的遠端預設分支;若該目標分支就是 `develop`(等於 head=base)→ 不開 PR,回報原因即可。
- **標題**:`chore(TARGET): <yyyy/MM/dd> 每日待辦`(有明確主軸時可改成該主軸的一句總結)。
- **描述**:本次完成的項目清單(✅/⏭️ 各自列出+待人工處理原因)、變更摘要與影響範圍、本次的 commit 一覽。
- **收尾**:push/API 過程可能讓 token 殘留在對話內文;**互動情境**完成後提醒使用者清除對話(Claude Code 用 `/clear`)。**排程情境**沒有互動對話,只寫 log,不輸出 token。
---
## 總結
執行後輸出(排程情境同時以 `[時間][階段][等級]: 訊息` 寫入 log):
| 模式 | 要回報的內容 |
| --- | --- |
| `--schedule on` | 用了哪種機制(crontab/schtasks)、條目內容、log 路徑、排程服務是否在跑(WSL 未啟動 cron 要明講)、下次執行時間 |
| `--schedule off` | 移除了哪一筆、其餘排程未受影響 |
| `--run` | 待辦總數/✅ 完成 N 項/⏭️ 待人工處理 K 項(逐項原因)、develop 是新建還是既有、建立了哪幾個 commit、push 結果與方式、PR 連結(新建或沿用既有)、或為何略過 |
| 無參數 | 排程狀態+下次執行時間、`TARGET.md` 是否存在與剩餘未完成項目數 |
---
## 呼叫方式
依 `/jsc-shared:spec-skill-invocation` 的統一呼叫方式,本 skill 的實際參數格式與範例:
| 助理 | 呼叫 |
| --- | --- |
| Claude Code / Antigravity | `/jsc-code:target --schedule on`、`/jsc-code:target --schedule off`、`/jsc-code:target --run --yes`、`/jsc-code:target --schedule on --run --project-dir ~/work/app` |
| Codex | `$target --schedule on`、`$target --run --yes`,或用 `/skills` 選單 |
| OpenCode | 描述需求(如「幫我把這個專案的 TARGET.md 排成每天 00:00 自動執行,做完分類提交、push develop 並對預設分支發 PR」)自動觸發 |