--- 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 ] [--base ] [--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 ] [--base ] [--no-pr] [--yes]` - `--schedule on|off`:`on` 建立/更新排程,`off` 移除排程。省略時不動排程。 - `--run`:立即執行一次 `TARGET.md`(排程條目帶的就是這個)。 - `--project-dir <專案根目錄>`:目標專案根目錄,**省略時取目前工作目錄**(會先 `git rev-parse --show-toplevel` 正規化成 repo 根)。`TARGET.md` 固定讀**專案根目錄**的那一份。 - `--cli `:排程條目要用哪個助理的 headless 指令。省略時用**目前正在執行本 skill 的助理**;判斷不出來且未帶此參數 → 詢問,不猜測。 - `--base `: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]`,並在該行**行尾**補上 `( 完成)`(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}' && >> '${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 也寫成絕對路徑。 **schtasks**(Windows): ```powershell $task = "jsc-code-target-<專案名>" # 專案名重複時附加路徑短碼,確保唯一 schtasks /Create /TN "$task" /SC DAILY /ST 00:00 /F ` /TR "cmd /c cd /d ""<專案絕對路徑>"" && >> """" 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]` 並於行尾補 `( 完成)`;有子項目則子項目全部完成後才勾選上層。 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): 每日待辦`(有明確主軸時可改成該主軸的一句總結)。 - **描述**:本次完成的項目清單(✅/⏭️ 各自列出+待人工處理原因)、變更摘要與影響範圍、本次的 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」)自動觸發 |