From 10f25e53e360754906882e53084361c3ff244c88 Mon Sep 17 00:00:00 2001 From: richblack Date: Sun, 28 Jun 2026 16:24:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20tasks.md=20=E2=87=84=20GitHub=20Project?= =?UTF-8?q?=20=E5=96=AE=E5=90=91=E6=8A=95=E5=BD=B1=20optional=20=E6=A8=A1?= =?UTF-8?q?=E7=B5=84=EF=BC=88issue=20#16=EF=BC=89+=20bump=201.13.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 裝了 SDD 的專案可把 docs/3-specs/*/tasks.md 待辦單向投影成唯讀 GitHub Project。 md 唯一真相源、Project 永遠唯讀,無反向同步、不會兩個真相源打架。預設不逼: 沒裝 Arcrun/答不要的用戶完全 no-op,純 md 不受影響。 - 投影 workflow template/system-dev/workflows/tasks-project-sync.yaml(Arcrun workflow):foreach 增量 → switch 動作 → http_request 打 GitHub API:新 task→ issue create / [ ]→[x]→close / 文字改→edit / 行刪→archive(not_planned),並用 GraphQL addProjectV2ItemById 投影進 Projects v2。auth 走 {{creds.github_token}}。 - 本地觸發端 tasks-project-sync.local.sh:因 Arcrun workflow 跑遠端 CF Workers、 沒本地 fs/git,「讀 tasks.md / git diff / 回寫 」由本地端做完再 acr run 餵增量。本地一半 + 遠端一半,職責邊界清楚。薄殼不自刻 parser。 - 防複發核實:每個 component 經 acr parts 核實存在(registry 無 github 零件,全用 http_request 打 REST/GraphQL)。acr validate --offline 通過(7 三元組、config 完整)。 - 啟用判準=對話 + 能力,不掃檔(Arcrun workflow 存遠端 KV、零本地檔也能用 → 掃檔 false negative)。install/init 問一句 → 查環境有 Arcrun 就 acr push 啟用、 沒有就一次性溫和廣告。帶檔 ≠ 啟用。install/update 隨 SDD 模組帶 workflow(add_if_missing)。 - 守 flag 紅線:push 後本機觸發單次,禁定期輪詢、禁 GitHub Actions fan-out。 ⚠️ 端到端(acr push 真部署 + acr run 真投影)待 leo21c 驗,本版為 code-done 骨架。 SDD(內部,gitignore 不推):docs/3-specs/tasks-project-projection/。 Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 14 ++ README.en.md | 14 ++ README.md | 14 ++ scripts/install.sh | 21 +++ scripts/update.sh | 7 +- template/.claude/VERSION | 2 +- template/system-dev/VERSION | 2 +- .../workflows/tasks-project-sync.local.sh | 70 ++++++++ .../workflows/tasks-project-sync.yaml | 152 ++++++++++++++++++ 9 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 template/system-dev/workflows/tasks-project-sync.local.sh create mode 100644 template/system-dev/workflows/tasks-project-sync.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 11452e4..fc8f7f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,20 @@ --- +## 1.13.0 — tasks.md ⇄ GitHub Project 單向投影(optional 模組,需 Arcrun;issue #16) + +裝了 SDD 的專案可把 `system-dev/docs/3-specs/*/tasks.md` 的待辦**單向投影**成唯讀 GitHub Project(看板/dashboard 好抓)。md 唯一真相源、Project 永遠唯讀,不存在反向同步、不會兩個真相源打架。 + +- **新增投影 workflow**:`template/system-dev/workflows/tasks-project-sync.yaml`(Arcrun workflow:`foreach` 增量 → `switch` 動作 → `http_request` 零件打 GitHub API:新 task→issue create / `[ ]→[x]`→close / 文字改→edit / 行刪→archive,並投影進 Projects v2)。auth 走 `{{creds.github_token}}`(acr creds push)。**每個 component 經 `acr parts` 核實存在**(防複發:registry 沒有 `github` 零件,用 `http_request` 打 REST/GraphQL)。`acr validate --offline` 通過。 +- **新增本地觸發端**:`tasks-project-sync.local.sh`——因 Arcrun workflow 跑在遠端 CF Workers、沒本地 fs/git,「讀 tasks.md / git diff / 回寫 ``」由本地端做完再 `acr run` 餵增量。職責邊界清楚:本地一半 + 遠端一半。 +- **啟用判準=對話 + 能力,不掃檔**:原設計想抄 `HAS_WIKI`/`HAS_SDD` 掃檔指紋,但 Arcrun workflow 存遠端 KV、零本地檔也能在用 → 掃檔會 false negative。改成裝/init 時 CC 問一句「要不要同步」→ 查環境有沒有 Arcrun(mcp/`acr`)→ 有就 `acr push` 啟用、沒有就**一次性溫和廣告**、答不要就閉嘴。**帶檔 ≠ 啟用**。 +- **守 flag 紅線**:push 後本機觸發單次,禁定期輪詢、禁 GitHub Actions fan-out。 +- **預設不逼**:沒裝 Arcrun/答「不好」的用戶完全 no-op,純 md 不受影響。 +- install/update 隨 SDD 模組帶下 workflow 檔(`add_if_missing`,覆蓋不會關掉誰的同步——啟用狀態存遠端)。 +- ⚠️ **端到端(`acr push` 真部署 + `acr run` 真投影)待 leo21c 驗證**;本版為 code-done 骨架,GitHub Projects v2 GraphQL 的欄位細節真部署時可能微調。SDD:`docs/3-specs/tasks-project-projection/`。 + +--- + ## 1.12.0 — 跨 repo issue/comment 署名鐵律:`[<本 repo> CC]`(issue #12) 當生態系裡多個 repo 共用**同一個 GitHub 帳號**發 issue/comment 時,author 全顯示同一帳號、看不出是哪個 repo 的 CC 發的。GitHub 沒有 per-repo 身份設定,`git config user.name` 只影響 commit、不影響 issue/comment author,多開帳號又會踩「避免被 flag」鐵律——身份只能在**內容層**自報。 diff --git a/README.en.md b/README.en.md index 6b8112e..7e77cec 100644 --- a/README.en.md +++ b/README.en.md @@ -120,6 +120,20 @@ This way, even with a note vault, the original structure stays intact and your n --- +## Mirror tasks to GitHub (optional, needs Arcrun) + +If you installed SDD, you can **one-way project** the tasks in `system-dev/docs/3-specs/*/tasks.md` into a read-only GitHub Project (handy for boards/dashboards). + +- **One-way, md is the source of truth**: the only write point is `tasks.md` — CC edits md when it finishes a task, you ask the AI to edit md when you want changes, **nobody touches the Project directly**. The Project is always read-only, so there's no two-sources-of-truth conflict. +- **Needs Arcrun** (a free AI-friendly workflow toolkit). No Arcrun → plain md, full no-op, unaffected. +- **How to turn it on**: after install, CC asks you once "do you want tasks mirrored to GitHub?" Answer "yes" and if Arcrun is present, CC `acr push`es the projection workflow to enable it; if Arcrun isn't installed, CC tells you "ask Claude to install it; you can also enable sync later." Answer "no" and nothing happens — no nagging. +- **Plays by the rules**: triggered once locally after a push (no periodic polling, no GitHub Actions), staying within the anti-flag red line. + +> The workflow lives at `system-dev/workflows/tasks-project-sync.yaml` (+ local trigger `.local.sh`). **Shipped ≠ enabled** — enabling means you said yes and `acr push`ed. +> ⚠️ End-to-end flow is still being verified (issue #16). + +--- + ## Cowork can curate wikis too The wiki curator is no longer limited to Claude Code in the terminal — **claude.ai's Cowork** can do it too. diff --git a/README.md b/README.md index be44842..26443e2 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,20 @@ LLM Wiki 原本假設「原始文件放在 `docs/`」,但 Logseq、Obsidian --- +## 待辦同步到 GitHub(optional,需 Arcrun) + +裝了 SDD 的專案,可以把 `system-dev/docs/3-specs/*/tasks.md` 的待辦**單向投影**成一個唯讀 GitHub Project(看板/dashboard 好抓進度)。 + +- **單向、md 當家**:唯一寫入點是 `tasks.md`——CC 完成 task 改 md,你要動就叫 AI 改 md,**人不直接碰 Project**。Project 永遠唯讀,不會有兩個真相源打架。 +- **需要 Arcrun**(免費的 AI-friendly 工作流套件)。沒裝 Arcrun → 純 md,完全 no-op,不受影響。 +- **怎麼開**:安裝後 CC 會問你一句「要不要把待辦同步到 GitHub」。答「好」且環境有 Arcrun → CC `acr push` 那份投影 workflow 啟用;沒裝 Arcrun → CC 告訴你「想裝跟 Claude 說就行,之後也可手動啟用」。答「不好」就不做、不再追問。 +- **守規矩**:push 後本機觸發一次(非定期輪詢、非 GitHub Actions),守避免被 flag 的紅線。 + +> workflow 檔在 `system-dev/workflows/tasks-project-sync.yaml`(+ 本地觸發端 `.local.sh`)。**帶檔 ≠ 啟用**——啟用=你答好且 `acr push`。 +> ⚠️ 端到端流程仍在驗證中(issue #16)。 + +--- + ## Cowork 也能整理 wiki 整理 wiki 的人不再只有終端機裡的 Claude Code——**claude.ai 的 Cowork** 也可以。 diff --git a/scripts/install.sh b/scripts/install.sh index 55a17ca..24b358c 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -296,6 +296,13 @@ if $WANT_SDD; then download_if_missing ".claude/commands/sdd-check.md" "$REPO_URL/.claude/commands/sdd-check.md" download_if_missing ".claude/hooks/sdd-guard.sh" "$REPO_URL/.claude/hooks/sdd-guard.sh" + + # ── tasks⇄Project 投影(optional,issue #16)────────────────── + # 帶檔 ≠ 啟用:workflow yaml 只是「留記錄+手動啟用素材」,啟用=對話答好且 acr push。 + # 投影邏輯依附 tasks.md(住 3-specs),故隨 SDD 模組帶下來;裝了不代表開。 + create_dir "system-dev/workflows" + download_if_missing "system-dev/workflows/tasks-project-sync.yaml" "$REPO_URL/system-dev/workflows/tasks-project-sync.yaml" + download_if_missing "system-dev/workflows/tasks-project-sync.local.sh" "$REPO_URL/system-dev/workflows/tasks-project-sync.local.sh" fi # ── 安裝/更新腳本:一開始就放進 system-dev/scripts/ ── @@ -312,6 +319,7 @@ download_if_missing ".claude/hooks/pre-write-guard.sh" "$REPO_URL/.claude/hooks/ download_if_missing ".claude/commands/issue-handle.md" "$REPO_URL/.claude/commands/issue-handle.md" chmod +x .claude/hooks/*.sh 2>/dev/null || true +chmod +x system-dev/workflows/*.sh 2>/dev/null || true # ── 依模組產生 settings.json 的 hooks 區塊 ──────── # settings.json 因模組而異,不能直接下載單一靜態檔,改條件組裝。 @@ -466,6 +474,19 @@ fi if $WANT_SDD; then t " 動 code 前先在 system-dev/docs/3-specs/[子系統]/ 建 design.md(可用 /sdd-check 協助)" \ " Before touching code, create design.md under system-dev/docs/3-specs/[subsystem]/ (use /sdd-check to help)" + # ── tasks⇄Project 投影:裝/init 對話 + 一次性廣告(issue #16)── + # 判準=能力(arcrun 裝了沒)+意願,不掃檔。落地成「CC 問一句」,install 只是交代 CC 去問。 + echo "" + t " ❓ 待辦同步(optional,需 Arcrun):請你的 CC 問你一句——" \ + " ❓ Task sync (optional, needs Arcrun): have your CC ask you once —" + t " 「您需要把本專案的待辦事項(tasks.md)同步到 GitHub 嗎?」" \ + " \"Do you want this project's tasks (tasks.md) mirrored to GitHub?\"" + t " 答「好」→ CC 查環境有沒有 Arcrun(mcp / acr 在 PATH):有就設定同步、沒有就一次性告知" \ + " Yes → CC checks for Arcrun (mcp / acr in PATH): set it up if present, otherwise inform you once" + t " 「Arcrun 是免費的 AI-friendly 工作流套件,想裝跟 Claude 說就行;之後也可手動啟用」。" \ + " \"Arcrun is a free AI-friendly workflow toolkit — ask Claude to install it; you can also enable sync later.\"" + t " 答「不好」→ 不做、不再追問。投影 workflow 在 system-dev/workflows/(帶檔≠啟用)。" \ + " No → nothing happens, no nagging. The projection workflow sits in system-dev/workflows/ (shipped ≠ enabled)." fi t " GitHub issue:CC 可直接 /issue-handle 讀回自己 repo 的 issue(禁自動輪詢)" \ " GitHub issues: CC can use /issue-handle to read issues from its own repo (no auto-polling)" diff --git a/scripts/update.sh b/scripts/update.sh index dadd4f8..6979534 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -246,6 +246,11 @@ if $HAS_SDD; then update_file "system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md" "$TEMPLATE_URL/system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md" update_file ".claude/commands/sdd-check.md" "$TEMPLATE_URL/.claude/commands/sdd-check.md" update_file ".claude/hooks/sdd-guard.sh" "$TEMPLATE_URL/.claude/hooks/sdd-guard.sh" + + # tasks⇄Project 投影(issue #16):邏輯檔,可覆蓋。舊版沒有 → add_if_missing 補。 + # 啟用狀態存遠端(acr push),不在這些檔裡,覆蓋不會關掉誰的同步。 + add_if_missing "system-dev/workflows/tasks-project-sync.yaml" "$TEMPLATE_URL/system-dev/workflows/tasks-project-sync.yaml" + add_if_missing "system-dev/workflows/tasks-project-sync.local.sh" "$TEMPLATE_URL/system-dev/workflows/tasks-project-sync.local.sh" fi # ── 自我更新:把最新的 update.sh / install.sh 抓到 system-dev/scripts/ ── @@ -253,7 +258,7 @@ fi update_file "system-dev/scripts/update.sh" "$REPO_RAW/scripts/update.sh" update_file "system-dev/scripts/install.sh" "$REPO_RAW/scripts/install.sh" -chmod +x .claude/hooks/*.sh system-dev/scripts/*.sh 2>/dev/null || true +chmod +x .claude/hooks/*.sh system-dev/scripts/*.sh system-dev/workflows/*.sh 2>/dev/null || true # ── 使用者資料檔:絕不碰,但提醒「設定可能有新欄位要手動補」── keep_file ".claude/settings.json" diff --git a/template/.claude/VERSION b/template/.claude/VERSION index 32bd932..feaae22 100644 --- a/template/.claude/VERSION +++ b/template/.claude/VERSION @@ -1 +1 @@ -1.12.0 \ No newline at end of file +1.13.0 diff --git a/template/system-dev/VERSION b/template/system-dev/VERSION index 32bd932..feaae22 100644 --- a/template/system-dev/VERSION +++ b/template/system-dev/VERSION @@ -1 +1 @@ -1.12.0 \ No newline at end of file +1.13.0 diff --git a/template/system-dev/workflows/tasks-project-sync.local.sh b/template/system-dev/workflows/tasks-project-sync.local.sh new file mode 100644 index 0000000..4b6c139 --- /dev/null +++ b/template/system-dev/workflows/tasks-project-sync.local.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# tasks-project-sync.local.sh — 本地觸發端(投影的「本地一半」) +# +# 來源:issue #16;設計:system-dev/docs/3-specs/tasks-project-projection/design.md +# +# ── 為什麼有這支(職責邊界)────────────────────────────────────── +# arcrun workflow 跑在遠端 CF Workers,沒有本地 fs / git / shell。 +# 所以「讀 tasks.md / git diff / 回寫 」這三件本地事 +# 不能放進 workflow(arcrun 也沒有對應零件,這是架構邊界、不是缺口)。 +# 這支就是那「本地一半」:分類好增量 → 交給 acr run 打 GitHub。 +# +# 這支(本地):讀 tasks.md → git diff → 分類四動作 → acr run 投影 → 回寫新 id +# │ +# ▼ +# tasks-project-sync.yaml(遠端):foreach → switch → github API +# +# ── 怎麼觸發(守 flag 紅線)───────────────────────────────────── +# push 後「本機觸發單次」,非 cron、非輪詢、非 GitHub Actions。 +# 掛載點建議:本機 git post-push 類 hook,或叫 CC 在 push 後跑這支一次。 +# ⚠️ 具體掛載點與「分類四動作」的精確 parse,待 leo21c 端到端驗證後定稿; +# 目前是 code-done 骨架,標出該做什麼、邊界在哪,不假裝已通。 +# +# ── 用法 ─────────────────────────────────────────────────────── +# tasks-project-sync.local.sh +# +# 前置:acr 在 PATH、github_token 已 acr creds push、workflow 已 acr push。 + +set -euo pipefail + +OWNER="${1:?需要 owner}" +REPO="${2:?需要 repo}" +PROJECT_ID="${3:?需要 GitHub Projects v2 node id}" + +# 多組 SDD 全同步:glob 掃所有 tasks.md(新 folder 自動成組,免手動登記)。 +GLOB="system-dev/docs/3-specs/*/tasks.md" + +# ── 1. 分類增量(git diff 知道改了哪幾行 → 四動作)────────────── +# 這裡是「本地一半」的核心。實作策略(待端到端驗證後落地): +# - 拿 push 前後的 git diff,限定 $GLOB 範圍,只看動到的行。 +# - 每行 task 解析:有無 `` id、checkbox 是否 [ ]→[x]、文字/負責人/日期變動。 +# - 行不見(diff 的刪除行)且原本有 id → archive。 +# - 子系統 = 該 tasks.md 的 folder 名(當 label 分組)。 +# - 產出 tasks_json 陣列(格式見 yaml 註解)。 +# +# ⚠️ 刻意不在這支用 TS/Python 刻複雜 parser(守薄殼)。複雜分類交給 CC 在 push 後 +# 讀 diff 直接產 tasks_json;這支保持「薄殼 + 交棒 acr run」。若未來證明需要可重用的 +# parser 零件,那屬於 arcrun 零件缺口 → 回報 issue #16 由 arcrun 端補,不在此自刻。 +# +# 佔位:實際 tasks_json 由 CC 依上述策略產生後填入。 +TASKS_JSON="${TASKS_JSON:-[]}" + +if [ "$TASKS_JSON" = "[]" ]; then + echo "(無增量 → 本次 no-op,不呼叫 GitHub)" + exit 0 +fi + +# ── 2. 交給遠端 workflow 投影 ─────────────────────────────────── +acr run tasks_project_sync \ + -i owner="$OWNER" \ + -i repo="$REPO" \ + -i project_id="$PROJECT_ID" \ + -i tasks_json="$TASKS_JSON" + +# ── 3. 回寫新 task 的 id(唯一對 md 的寫入,只在 create 時做一次)── +# create 動作的回傳 issue number → append `` 到該行末。 +# ⚠️ 防迴圈:回寫造成 working tree 變動,這次回寫「不得」再觸發一輪投影 +# (否則 push→觸發→回寫→又一個 diff→又觸發…)。實作時觸發端要排除 +# 「只動到 註解」的 diff,或回寫走 [skip-sync] 標記。 +# 具體機制待端到端驗證定稿。 +echo "(新 task 的 id 回寫:待端到端驗證後接上 acr run 的回傳 → append )" diff --git a/template/system-dev/workflows/tasks-project-sync.yaml b/template/system-dev/workflows/tasks-project-sync.yaml new file mode 100644 index 0000000..62581da --- /dev/null +++ b/template/system-dev/workflows/tasks-project-sync.yaml @@ -0,0 +1,152 @@ +# tasks-project-sync — tasks.md ⇄ GitHub Project 單向投影 +# +# 來源:issue #16;設計:system-dev/docs/3-specs/tasks-project-projection/design.md +# +# ── 這份 workflow 的職責邊界(很重要,別搞混)────────────────── +# arcrun workflow 在 Cloudflare Workers / WASM 上「遠端」執行,沒有本地檔案系統、 +# 沒有 git、沒有 shell。所以「讀 tasks.md / 跑 git diff / 把 回寫 md」 +# 這三件事 **不是、也不該是 workflow 的步驟**——它們由本地觸發端(CC / push 後本機腳本) +# 先做完,把「分類好的 task 增量」當 input 餵進來(acr run -i tasks_json=...)。 +# +# 本地端(住 template,CC/shell 跑):讀 tasks.md → git diff → 分類四動作 → 回寫 id +# │ acr run tasks-project-sync -i ...(把增量餵進來) +# ▼ +# 遠端 workflow(這份 yaml):foreach 增量 → switch 動作 → github API 投影 +# +# → 因此本 workflow 只負責「拿到分類好的增量後,打 GitHub API 投影成 issue/Project」。 +# 單向:只寫 GitHub,永不回改 tasks.md(回寫 id 是本地端的事,且只在新 task 做一次)。 +# +# ── 輸入(由本地觸發端用 acr run -i 餵)────────────────────────── +# owner GitHub repo owner(例:uncle6me-web) +# repo GitHub repo 名 +# project_id GitHub Projects v2 的 node id(投影目標,唯讀看板) +# tasks_json 本地分類好的增量陣列,每筆形如: +# { action: "create|close|edit|archive", +# gh: 42, # 已有 id 的帶上(create 無) +# title: "...", body: "...", +# subsystem: "wiki-architecture", # = SDD folder 名,當 label 分組 +# assignee: "...", due: "..." } +# +# ── credential ───────────────────────────────────────────────── +# github_token(acr auth-recipe scaffold github → 填 credentials.yaml → acr creds push) +# +# ⚠️ 端到端(acr push 真部署 + acr run 真投影)尚未經 leo21c 驗證。 +# 本檔為 code-done 骨架;真部署時 GitHub API 的欄位細節(Projects v2 GraphQL) +# 可能要按實測微調,屆時於 issue #16 回報。 + +name: tasks_project_sync +description: > + 把 SDD tasks.md 的待辦增量單向投影成唯讀 GitHub Project(issue CRUD + 加進 Project)。 + 本地端先讀檔/git diff/分類/回寫 id,這份只負責拿增量打 GitHub API。md 當家、單向、不反向同步。 + +# ── flow(三元組:A >> 關係詞 >> B)───────────────────────────── +# 對每筆增量 → 依 action 路由到四種 GitHub 動作。 +flow: + - "input >> 完成後 >> each_task" + - "each_task >> 對每個 task >> route_action" + # 四種動作(issue 定案):新增/關閉/編輯/封存 + - "route_action >> 完成後 >> gh_create" + - "route_action >> 完成後 >> gh_close" + - "route_action >> 完成後 >> gh_edit" + - "route_action >> 完成後 >> gh_archive" + # 新建的 issue 投影進 Project(唯讀看板) + - "gh_create >> 完成後 >> add_to_project" + +config: + # 逐筆迭代本地餵進來的分類增量 + each_task: + component: foreach_control + iterator: task + + # 依 action 欄位分流到四種 GitHub 動作 + route_action: + component: switch + key: "{{task.action}}" + cases: + create: gh_create # 有文字、無 id → 建 issue(id 由本地端回寫 md) + close: gh_close # 有 id 且 [ ]→[x] → 關 issue + edit: gh_edit # 有 id 且 文字/負責人/日期改 → 編輯 issue + archive: gh_archive # id 在但整行不見 → 關閉/封存 + + # ── 動作 1:建 issue(REST POST /repos/:owner/:repo/issues)── + # 回傳的 issue number 由本地觸發端接住、回寫 到那一行。 + # ⚠️ 用 http_request(arcrun registry 沒有 github 零件,21 內建確認過); + # auth 走 credential:{{creds.github_token}}(acr creds push 上傳,不寫死 token)。 + gh_create: + component: http_request + url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues" + method: POST + headers: + Accept: "application/vnd.github+json" + Authorization: "Bearer {{creds.github_token}}" + User-Agent: "arcrun-tasks-project-sync" + body: + title: "{{task.title}}" + body: "{{task.body}}" + labels: + - "{{task.subsystem}}" # 子系統 label 分組(= SDD folder 名) + assignees: + - "{{task.assignee}}" + + # ── 動作 2:關 issue(state=closed)── + gh_close: + component: http_request + url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{task.gh}}" + method: PATCH + headers: + Accept: "application/vnd.github+json" + Authorization: "Bearer {{creds.github_token}}" + User-Agent: "arcrun-tasks-project-sync" + body: + state: closed + + # ── 動作 3:編輯 issue(標題/內文/負責人)── + gh_edit: + component: http_request + url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{task.gh}}" + method: PATCH + headers: + Accept: "application/vnd.github+json" + Authorization: "Bearer {{creds.github_token}}" + User-Agent: "arcrun-tasks-project-sync" + body: + title: "{{task.title}}" + body: "{{task.body}}" + assignees: + - "{{task.assignee}}" + + # ── 動作 4:封存(行不見 = 關閉,標 not_planned 表示非完成而是移除)── + gh_archive: + component: http_request + url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{task.gh}}" + method: PATCH + headers: + Accept: "application/vnd.github+json" + Authorization: "Bearer {{creds.github_token}}" + User-Agent: "arcrun-tasks-project-sync" + body: + state: closed + state_reason: not_planned + + # ── 投影進 GitHub Projects v2(GraphQL)── + # Projects v2 只有 GraphQL,REST 沒有。用 http_request 打 /graphql。 + # ⚠️ 待 leo21c 端到端驗:addProjectV2ItemById 需要 content node id(issue 的 GraphQL id, + # 非 issue number),實測時可能要多一步「先查 issue node id」。屆時於 #16 回報。 + add_to_project: + component: http_request + url: "https://api.github.com/graphql" + method: POST + headers: + Accept: "application/vnd.github+json" + Authorization: "Bearer {{creds.github_token}}" + User-Agent: "arcrun-tasks-project-sync" + body: + query: > + mutation($project: ID!, $content: ID!) { + addProjectV2ItemById(input: {projectId: $project, contentId: $content}) { + item { id } + } + } + variables: + project: "{{project_id}}" + content: "{{gh_create.node_id}}"