排程器代理管理指南
在單一畫面中管理依專案(CSN)註冊的自動化執行器(gissue 排程器等背景代理):線上/離線狀態、執行狀態與歷史記錄,以及即時日誌。
🤖 讓 AI 幫你建立 Gissue 排程器
把本文件交給 AI,AI 會 clone 或更新 giip-fde-agent 儲存庫(https://github.com/LowyShin/giip-fde-agent.git),然後自動在這台 PC 上完成 gissue 處理排程器的安裝、註冊和驗證。不要從零開始寫腳本,使用此步驟。
提示詞(複製後直接使用):
讀取本文件(/help/catquest-schedulers.zh-TW.md),並按照下面的「安裝步驟」在此 PC 上安裝 gissue 排程器。
如果沒有 giip-fde-agent 就 clone,如果有就執行 git pull --ff-only 更新。如果有本地變更,不要覆蓋,先停止並報告。
目標 CSN 指定為 <CSN>,工作資料夾指定為 <路徑>。
從 giipAgent.cnf(或 giipAgent.cfg)讀取 sk= 的值,不要向使用者詢問。
報告每個步驟的確認結果。
安裝步驟
- 預檢 — 執行 →
git --version、node --version、claude --version,Windows 執行powershell -Command $PSVersionTable.PSVersion,Linux 執行pwsh --version。全部在 PATH 中後才能進入下一步。 - 取得 giip-fde-agent — 執行 → 沒有則
git clone https://github.com/LowyShin/giip-fde-agent.git,有則git pull --ff-only。如有本地變更則停止並報告。 - 讀取規範文件 — 讀取
docs/60-operations/hourly-issue-scheduler.md§4~§5,確認 CSN→workdir 對應、心跳區塊和 SK 位置。 - 撰寫 csn-projects.json — 將
scripts/gissue/csn-projects.json.example複製為csn-projects.json。填寫目標 CSN 的workdir/enabled: true,並在頂層heartbeat區塊中必須指定lssn(伺服器編號)/hostname(本機識別符)/skFile(sk= 格式檔案路徑)。缺失則此畫面上不會顯示該列。 - 準備密鑰 — 從上層資料夾的
giipAgent.cnf(或giipAgent.cfg)讀取sk=值。不向使用者詢問,也不記錄到輸出中。同時準備好slack-bot/.secrets/giip-accounts.json(從 .sample.json 複製)。 - 試執行 — 執行
scripts/gissue/manage-gissue-scheduler.ps1 -Action DryRun -OnlyCsn <CSN>→ 如果結束無[PREFLIGHT-FAIL]日志則成功。 - 註冊
- Windows —
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\register-hourly-issue-scheduler.ps1 -Action Register -RepoRoot <giip-fde-agent 根目錄> - Linux — 沒有專用註冊腳本,用類似
/etc/cron.d/gissue-scheduler的一行 cron 註冊(與實際 docker 部署格式相同):7,27,47 * * * * <普通使用者> cd <根目錄> && pwsh -NoProfile -NonInteractive -File "<根目錄>/scripts/gissue/run-gissue-claude.ps1" -OnlyCsn <CSN> >> <根目錄>/scripts/gissue/logs/cron.log 2>&1。必須以普通使用者註冊,不能用 root(claude 在 root 下會拒絕--dangerously-skip-permissions,導致所有 issue 均失敗)。該使用者的 claude 登入資訊也必須提供。 - Docker 執行個體 — 容器啟動時
docker/entrypoint.sh會自動註冊上述 cron(GIIP_ENABLE_SCHEDULER預設為 true,-OnlyCsn從csn-projects.json衍生)。此時步驟 7 已完成,只需確認/etc/cron.d/gissue-scheduler存在,並用scripts/bootstrap-instance.sh檢查環境(pwsh 連結等)。
- Windows —
- 驗證 — 執行
manage-gissue-scheduler.ps1 -Action RunOnce -OnlyCsn <CSN>一次,或等待下一個 :07,然後重新整理本畫面 → 如果gissue_csn<CSN>列顯示 online 且 History 有執行記錄則成功。若未顯示,檢查scripts/gissue/logs/gissue_csn<CSN>.log中的[WARN][SchedulerState-...]列。
AI 不得做的事
- 不得新建 giip-fde-agent 的 runner(
run-gissue-claude.ps1) - 不得另行編寫直接呼叫 SP 的程式碼(已安裝的 runner 會處理)
- 不得在文件或日誌中留下 SK 值
- 不得修改 giip-fde-agent 程式碼本身
📋 概覽
排程器代理管理 顯示目前所選專案(CSN)下註冊的所有自動化代理 —— 例如 gissue 的每小時排程器、互動式 Claude Code 工作階段等。與將 giip 問題 視覺化為貓咪的 /admin/catquest 不同,本畫面是用來管理 執行自動化工作的代理本身 的維運儀表板:檢視每個代理是否存活、目前執行是否正常、以及在哪裡可以查看其日誌。
🎨 狀態顏色
每個代理會顯示兩個彼此獨立的狀態訊號——請勿混淆。
身分狀態(代理名稱旁的小圓點)
表示代理程序本身是否可連線(tSchedulerAgent.status),與單次執行無關。
| 顏色 | 狀態 | 意義 |
|---|---|---|
| 🟢 綠色 | online | 代理可連線且正常回報中 |
| 🔴 紅色 | error | 代理回報了錯誤狀態 |
| ⚪ 灰色(slate-400) | offline | 目前無法連線至代理 |
| ⚪ 淺灰色(slate-300) | unknown | 尚未回報任何狀態 |
執行狀態(Status 欄位徽章)
反映最近一次排程器 執行(run) 的狀態(currentStatus),以及 stale(停滯)偵測結果。
| 顏色 | 顯示標籤 | 條件 | 意義 |
|---|---|---|---|
| 🟢 綠色 | RUNNING | currentStatus = RUNNING 且未 stale | 正常執行中 |
| 🔴 紅色 | STALE | currentStatus = RUNNING 且 isStale = true | 標記為執行中,但心跳長時間無回應 —— 看起來像卡住/殭屍執行 |
| 🟠 橙色 | STALE | currentStatus = STALE(明確值) | 後端將此次執行本身標記為 stale |
| ⚪ 灰色 | ENDED | currentStatus = ENDED | 已結束(正常完成或受控停止) |
| ⚪ 灰色 | (原始值) | 其他情況 / 尚無執行紀錄 | 未知 / 無資料 |
在下方的執行歷史彈窗中,已完成的執行也可能以紅色的 FAILED 顯示——這是以錯誤結束的執行,與 ENDED(正常結束)或 stale/逾時不同。
🔍 畫面結構
1. 頂部標題列
- 返回
/admin/catquest的箭頭(←)。 - Refresh:重新載入目前 CSN 的代理清單。
2. Open Interactive Sessions
僅當至少存在一個活躍的 claude_interactive_session 代理時(即目前在某主機上註冊為執行中的互動式 Claude Code 工作階段),才會單獨顯示此卡片。每一列顯示工作階段名稱、主機、最後通訊時間,以及當該代理的 capabilities 中已註冊工作階段 URL 時顯示的 「Open session」 連結。
3. 代理清單(表格)
每個排程器代理占一列,包含:
- Name —— 身分狀態圓點、代理名稱、作業系統/代理類型/版本徽章、
lssn(關聯伺服器)、截斷顯示的 capabilities 摘要,以及最近記錄的錯誤(若有)。 - Host ——
hostIdentifier。 - Windows Task —— 若適用,執行該代理的 Windows 工作排程器工作名稱。
- Project —— 專案名稱。
- Active —— ON/OFF 徽章(
isActive)。 - Last Comm —— 最後一次心跳/通訊時間戳記。
- Status —— 上述執行狀態徽章,以及(若有回報)目前階段(phase)文字。
底部統計列彙總清單中所有代理的 已處理(Processed)/ 已略過(Skipped)/ 失敗(Failed) 計數。
4. 執行歷史(Run History)
表格下方的「View History」卡片會再次列出所有代理;點擊某列的 History 按鈕會開啟彈窗,顯示該代理最近的執行記錄——執行模式、狀態(含 FAILED)、開始/結束時間、耗時、已處理/已略過/失敗計數、階段、以及摘要。
5. 即時日誌檢視器(Live Log Viewer)
雙欄即時追蹤畫面:
- 左側(代理 → 日誌串流樹):代理依群組顯示,展開後可看到已知的日誌串流清單(日誌串流以
streamKey識別,具有streamType與輪替世代編號)。代理會依最近通訊時間顯示 online/offline。 - 右側(日誌串流卡片):選取某個日誌串流後,會顯示其最近的日誌行,並持續更新以實現即時追蹤。
➕ 新增其他主機
本畫面沒有手動「新增」主機的按鈕或表單——清單完全由下方兩種自動註冊路徑產生。兩種路徑都是使用**依 CSN(專案)核發的密鑰(SK)**呼叫 giipApiSk4 端點,將自身 upsert 到 tSchedulerAgent/tSchedulerAgentRun 中;若沒有目標 CSN 的有效 SK,呼叫本身就會以 401 Unauthorized 失敗,因此即使知道下方步驟,也無法擅自向他人的專案註冊假代理。
⚠️ 下方出現的 SK/AK 值一律為占位符。切勿將真實值寫死在文件或程式碼中,核發後的值請各自以安全方式保管(密鑰檔案、環境變數、密鑰管理器等)。
共通前提條件
| 項目 | 說明 |
|---|---|
| 目標 CSN | 要註冊代理的專案編號。本頁依工作階段目前的 CSN 顯示清單。 |
| SK(密鑰) | 對該 CSN 具有寫入(註冊)權限的密鑰。請向專案管理員申請核發該 CSN 的 SK——無法透過本畫面或 API 自行核發。 |
| 註冊端點 | https://giipfaw.azurewebsites.net/api/giipApiSk4(匿名驗證——不需要 Function key,透過請求表單中的 SK 權杖進行驗證) |
將主控台註冊到此頁面 — 原樣複製並貼到主控台
如果此頁面的 "Open Interactive Sessions" 中看不到您正在使用的 Claude Code 主控台,請把下面的請求文原樣貼到主控台(Claude Code)。主控台僅依據下方「方法 A」的規範(agentKey 規則、SP 呼叫)完成註冊,因此不需要額外腳本或其他儲存庫。請把 <CSN> 替換為要註冊的專案編號。
前提條件:目標 CSN 的 SK 必須以
sk=的形式存在於這台 PC 上層資料夾的giipAgent.cnf(或giipAgent.cfg)中(沒有的話,請專案管理員為該 CSN 核發 SK)。主控台會從該檔案讀取 SK,不會向使用者反問。
請求文 1 — 一次性註冊目前開啟的這個主控台
請把我目前開啟的這個主控台工作階段,作為 CSN <CSN> 的互動式工作階段,一次性註冊到 giip 排程器代理頁面(/zh-TW/admin/catquest/schedulers)。
請閱讀本文件(/help/catquest-schedulers.zh-TW.md)中的「方法 A —— 註冊互動式 Claude Code 工作階段」,並嚴格依其規範執行。請假定不存在 register-interactive-session.ps1 之類的獨立腳本,直接執行文件中寫明的 giipApiSk4 呼叫(HTTP POST,表單欄位 text/token/jsondata)。
1. agentKey:依文件「agentKey 產生規則」的 5 個步驟產生。原始 ID 優先使用本工作階段的 session_id(若已知),否則使用 fallback_<COMPUTERNAME>_<PID>。如果沒有 COMPUTERNAME 環境變數,就使用 hostname 指令的結果。
2. SchedulerAgentUpsert:text 為 "SchedulerAgentUpsert agentKey displayName hostIdentifier windowsTaskName projectName scheduleDesc isActive lssn osType agentType version"。jsondata 包含 agentKey、displayName="Claude Interactive Session (<主機名稱>)"、hostIdentifier=<主機名稱>、windowsTaskName/projectName/scheduleDesc 為空字串、isActive="1"、lssn="0"、osType=Windows 或 Linux、agentType="claude_interactive_session"、version=""。如果存在環境變數 CLAUDE_CODE_BRIDGE_SESSION_ID,就在 text 和 jsondata 的最末尾加上 capabilities={"sessionUrl":"https://claude.ai/code/<該值>"};如果不存在,就整個省略 capabilities。不要用其他值捏造 sessionUrl。
3. SchedulerAgentRunStart:text 為 "SchedulerAgentRunStart runIdKey agentKey executionMode totalIssueCount"。runIdKey=<agentKey>_<目前時間 yyyyMMddHHmmss>,executionMode="interactive",totalIssueCount="0"。
4. SK 從上層資料夾中 giipAgent.cnf(沒有則 giipAgent.cfg)的 sk= 值讀取,作為 token 使用。不要向我反問,也不要在螢幕、日誌或任何檔案中輸出或記錄 SK 的值。
5. 確認:用同一個 giipApiSk4 呼叫 text "SchedulerAgentList csn"、jsondata {"csn":"<CSN>"},確認剛建立的 agentKey 對應的資料列 is_active=true 且 current_status=RUNNING。把結果和所用的 agentKey/runIdKey 告訴我(不含 SK)。
請求文 2 — 設定掛鉤,讓之後所有工作階段自動註冊
請設定 SessionStart/SessionEnd 掛鉤,使這台 PC 上每次開啟或關閉 Claude Code 工作階段時,都自動在 giip 排程器代理頁面中註冊/取消註冊。目標 CSN 為 <CSN>。
請閱讀本文件(/help/catquest-schedulers.zh-TW.md)中的「方法 A —— 註冊互動式 Claude Code 工作階段」,僅依據該規範自行實作。不要試圖從其他儲存庫取得腳本。
1. 在使用者家目錄下的某處建立掛鉤處理腳本(例如 ~/.claude/giip-console-hook.ps1)。它接收 Start 或 End 作為引數,並從標準輸入讀取掛鉤事件 JSON。非 Windows 環境下也可以用 pwsh 或 bash 撰寫。
2. 掛鉤註冊依文件中的 JSON,在 ~/.claude/settings.json(全域)的 hooks.SessionStart 和 hooks.SessionEnd 中新增 command 掛鉤。不要加 matcher。不要覆寫既有的 hooks 項目,而是附加到陣列中,並原樣使用文件 JSON 中的 timeout 值。
3. 排除無頭執行:腳本先沿父處理程序往上找,如果 claude 處理程序的命令列中含有 -p 或 --print,就什麼都不做直接結束(文件中的無頭判定)。不要根據 CLAUDE_CODE_BRIDGE_SESSION_ID 是否存在來判定無頭。
4. Start:依文件「agentKey 產生規則」產生 agentKey(原始 ID = stdin 中的 session_id,沒有則 fallback_<COMPUTERNAME>_<PID>),然後呼叫 SchedulerAgentUpsert(agentType="claude_interactive_session",isActive="1",欄位及順序與文件範例相同)和 SchedulerAgentRunStart(executionMode="interactive",totalIssueCount="0")。runIdKey=<agentKey>_<目前時間 yyyyMMddHHmmss>,並儲存到暫存資料夾中的檔案供 End 使用。只有存在 CLAUDE_CODE_BRIDGE_SESSION_ID 時才加入 capabilities.sessionUrl;不存在則省略 capabilities 繼續註冊。
5. End:依同樣規則重新計算 agentKey,呼叫 SchedulerAgentRunEnd(status="ENDED",processedCount/skippedCount/failedCount="0"),然後以 isActive="0" 呼叫 SchedulerAgentUpsert,切換為離線。
6. 所有呼叫都透過 giipApiSk4(text/token/jsondata)進行,並且一律以結束碼 0 結束,避免掛鉤失敗時阻擋工作階段。
7. 不要把 SK 的值寫進腳本,只寫入 giipAgent.cnf(沒有則 giipAgent.cfg)的絕對路徑,每次執行時從中讀取 sk=。不要向我反問,也不要在輸出、日誌或檔案中留下 SK 的值。
8. 完成後,告訴我建立或修改的檔案路徑清單,以及在新工作階段中確認是否已註冊的方法。
- 用請求文 1 註冊的工作階段沒有結束掛鉤,若要在關閉時取消註冊,請對主控台說:「用你告訴我的 agentKey/runIdKey 呼叫 SchedulerAgentRunEnd,再以 isActive=0 呼叫 SchedulerAgentUpsert。」使用掛鉤(請求文 2)則會在結束時自動取消註冊。
- 成功確認:重新整理頁面後,該工作階段會出現在 "Open Interactive Sessions" 卡片和代理清單中。詳細規範請參閱下方的「方法 A」。
方法 A —— 註冊互動式 Claude Code 工作階段
若要讓 Claude Code 這類互動式 AI 程式設計工作階段出現在「Open Interactive Sessions」卡片中,需在該工作階段的 SessionStart/SessionEnd 掛鉤(hook)中設定執行以下步驟。
- 前提條件:上述共通前提條件(目標 CSN 的 SK),以及在執行工作階段的工具(如 Claude Code)中設定 SessionStart/SessionEnd 掛鉤的權限。
- 工作階段開始時(SessionStart)——先呼叫
SchedulerAgentUpsert註冊/更新身分,接著呼叫SchedulerAgentRunStart記錄執行開始。 - 工作階段結束時(SessionEnd)——呼叫
SchedulerAgentRunEnd記錄執行結束,再以isActive=0重新呼叫SchedulerAgentUpsert將代理切換為離線。
agentKey 產生規則(照原樣套用,無需判斷):資料庫中 csn + agentKey 組合是 UNIQUE 限制,因此同一工作階段重新啟動後也必須始終得到相同值(否則每次重新啟動都會新增一列而非更新既有列)。請依下列步驟原樣計算:
- 原始 ID:若掛鉤 stdin 的 JSON 中存在
session_id欄位,則使用該值;若不存在,則使用fallback_<COMPUTERNAME 環境變數的值>_<目前處理程序 PID>作為原始 ID。 - 正規化:從原始 ID 中移除所有非英數字元(
a-z、A-Z、0-9)(正規表示式取代:[^a-zA-Z0-9]→'')。 - 截斷(第一次):若正規化後的值超過24個字元,只保留前24個字元。
- 組合:
agentKey = "claude_interactive_" + <COMPUTERNAME 環境變數的值> + "_" + <步驟3的結果> - 截斷(第二次):若步驟4的結果超過100個字元,只保留前100個字元。將此最終值作為
agentKey。
SessionStart/SessionEnd 掛鉤的註冊位置(可直接貼上的 JSON):以 Claude Code 為例,選擇專案根目錄的 .claude/settings.json(僅對該專案生效)或使用者家目錄的 ~/.claude/settings.json(對所有專案全域生效)其中之一,將下方的 hooks 鍵合併到該檔案的最上層。若檔案中已有 hooks 鍵,則在 SessionStart/SessionEnd 陣列中加入下方物件(請勿覆寫既有項目)。不要加入 matcher 欄位——此掛鉤對所有工作階段全域生效。
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "<工作階段開始時要執行的 command。例如:powershell -NoProfile -ExecutionPolicy Bypass -File \"<註冊指令碼的絕對路徑>\" -Action Start>",
"timeout": 15000
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "<工作階段結束時要執行的 command。例如:powershell -NoProfile -ExecutionPolicy Bypass -File \"<註冊指令碼的絕對路徑>\" -Action End>",
"timeout": 15000
}
]
}
]
}
}
⚠️ 以全域(無 matcher)掛鉤註冊時要留意無頭誤判(giip #1837):上方掛鉤沒有
matcher,因此該主機上執行的所有 claude 處理程序都會觸發它——不僅是互動式工作階段,無人值守排程器以claude -p開啟的每一次無頭執行也會觸發。這代表你的註冊指令碼實際上必須包含「目前這次執行是互動式還是無頭」的判斷邏輯。此時請勿使用$env:CLAUDE_CODE_BRIDGE_SESSION_ID(Remote Control 橋接是否已連接)作為判斷依據——此值僅反映橋接連線狀態,與是否無頭無關;一個真正的互動式工作階段,若尚未執行/連接/remote-control,同樣可能沒有此值(這個具體缺陷已經真實導致互動式工作階段被誤判為無頭而遭靜默略過註冊——giip #1837)。正確的判斷方法:從執行此掛鉤的處理程序本身向上追溯父處理程序,找到真正的claude/claude.exe處理程序,檢查該處理程序的命令列中是否包含-p/function Test-IsHeadlessClaudeInvocation { try { $checkPid = $PID for ($i = 0; $i -lt 6; $i++) { $proc = Get-CimInstance Win32_Process -Filter "ProcessId=$checkPid" -ErrorAction Stop if (-not $proc) { return $false } if ($proc.Name -eq 'claude.exe') { $cmd = $proc.CommandLine if ($cmd -and ($cmd -match '(^|\s)(-p|--print)(\s|$)')) { return $true } return $false } $checkPid = $proc.ParentProcessId if (-not $checkPid -or $checkPid -eq 0) { return $false } } return $false } catch { return $false } }在非 Windows 環境下,請使用該作業系統對應的處理程序查詢方式實作相同的原理(檢查祖先處理程序命令列中是否包含
-p/
該 command 會從標準輸入(stdin)接收掛鉤事件的 JSON(含 session_id 等)。僅憑本文件中記載的 SP 呼叫規格(呼叫慣例、欄位清單、agentKey 產生規則)即可自行完整實作——即使維護本文件的維運者個人有一份參考實作,該儲存庫也是私有的,其他工作階段無法存取,因此請勿試圖從任何地方取得程式碼,僅依本文件的規格自行撰寫。
請注意,agentKey 與 capabilities.sessionUrl 來自兩個不同的 ID——把兩者混為一談,可能會讓你誤以為「沒有工作階段 ID 所以無法建構 URL」,因而放棄整個註冊流程:
agentKey——依掛鉤 stdin 的session_id(工具內部的 UUID,即~/.claude/projects/*/<uuid>.jsonl檔名中使用的值)建構。其唯一用途是讓同一工作階段重新啟動後得到相同的鍵,並非 URL。capabilities.sessionUrl——若存在的話,依$env:CLAUDE_CODE_BRIDGE_SESSION_ID(例如 ULID 風格的值session_01JGmSiTajXu9iZmjVZC27Nt——與掛鉤 stdin 的session_id是不同的 ID)建構為https://claude.ai/code/<該值>。
並非每個工作階段都存在此環境變數——例如從未經過 claude.ai/code 橋接的本機 CLI 工作階段可能沒有它。若 $env:CLAUDE_CODE_BRIDGE_SESSION_ID 不存在,只代表無法建構 sessionUrl,並不代表註冊被卡住——此時直接從呼叫中完全移除 capabilities 欄位,用其餘欄位繼續完成註冊即可(參見下方「無法建構 sessionUrl 時」)。
CLAUDE_CODE_BRIDGE_SESSION_ID 何時會被設定,缺少時事後能否補上(依官方文件 https://code.claude.com/docs/en/remote-control ,以下是可直接照做的步驟):
此環境變數僅在工作階段已連接到 Anthropic 的「Remote Control」功能時才存在。只要下列任一條件不滿足,就從根本上無法取得,這是正常狀態,不是缺陷——此時不要再嘗試其他辦法,直接省略 capabilities 繼續完成註冊即可。
- 無頭(
claude -p)工作階段根本沒有此功能。 Remote Control 僅限互動式工作階段使用,因此像 gissue 排程器那樣以claude -p執行的無人值守處理程序絕不可能擁有此值。 - 使用 API 金鑰(
ANTHROPIC_API_KEY)驗證的工作階段不支援 Remote Control。 需要登入 claude.ai 帳號(執行claude後執行/login)。 - 若經由 Amazon Bedrock / Google Vertex / Microsoft Foundry 接入,或
ANTHROPIC_BASE_URL被設為api.anthropic.com以外的值(LLM 閘道、代理伺服器等),也不受支援。 - 若設定了
DISABLE_TELEMETRY、DO_NOT_TRACK、CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC、DISABLE_GROWTHBOOK其中任一個,也不受支援(若已設定,需要取消該變數)。
若上述條件全部滿足,卻仍是一般互動式工作階段且此變數缺少,那只是 Remote Control 尚未連接而已。無需重新啟動工作階段,在該工作階段內執行以下命令即可立即連接,從那一刻起 $env:CLAUDE_CODE_BRIDGE_SESSION_ID 就會被設定:
/remote-control
(/rc 效果相同)若想讓之後每次工作階段都自動連接,可在工作階段內執行 /config 並開啟「Enable Remote Control for all sessions」,或在使用者主目錄的 ~/.claude/settings.json 中加入以下內容:
{
"remoteControlAtStartup": true
}
這裡同樣絕對禁止(與本指南第147行的原則相同):當因不滿足上述條件(無頭執行、API 金鑰驗證等)而無法取得 CLAUDE_CODE_BRIDGE_SESSION_ID 時,不要用掛鉤 stdin 的 session_id 或 $env:CLAUDE_CODE_SESSION_ID 等其他值來「捏造」sessionUrl——這些值與 claude.ai/code 的實際工作階段毫無關聯,會形成無法開啟(404)的連結。此時唯一正確的做法是省略 capabilities 並繼續完成註冊,不需要嘗試其他辦法。
這個判斷完全是機械式的——絕不詢問使用者。 只需檢查自身處理程序中 $env:CLAUDE_CODE_BRIDGE_SESSION_ID 是否存在即可分支,絕不將「用哪個值」當作選項呈現給使用者或向使用者提問。絕對禁止把掛鉤 stdin 的 session_id(agentKey 的來源)當作 sessionUrl 重複使用——兩者是不同的 ID,會產生失效/404 連結。也禁止用其他任意值(內部工具連結、猜測的 URL 等)替代 sessionUrl——sessionUrl 只能是真正的 claude.ai/code 橋接連結,或者乾脆省略。
如果一定要填入 sessionUrl:執行此次註冊的工作階段「自身」必須已連接到 Remote Control 橋接,$env:CLAUDE_CODE_BRIDGE_SESSION_ID 才會被設定。這是每個工作階段自己具備的狀態,不能依賴其他維運者的電腦設定(例如某台電腦設定了工作階段啟動時自動連接橋接)——別人電腦上的設定對本工作階段沒有任何影響。若尚未連接,請在互動式工作階段內執行 /remote-control 命令,或帶上 claude --remote-control/--rc 參數重新啟動,自行完成連接。在等待連接期間,註冊本身(Upsert/RunStart)仍應繼續進行——請依下方「無法建構 sessionUrl 時(省略 capabilities)」一節的方式操作,不要把整個註冊都延後。
呼叫慣例(giipApiSk4 共通):HTTP POST,3 個 application/x-www-form-urlencoded 表單欄位。
⚠️ 位置參數:這些 SP(如
pApiSchedulerAgentUpsertBySK)會將jsondata中的欄位依序繫結到 SP 的各個位置參數(@p0、@p1、……)——中間的欄位無法略過。若要填到後面的欄位(例如capabilities),就必須連同其前面的所有欄位一起送出,實際不使用的欄位以安全的占位值填入(例如windowsTaskName=''、projectName=''、scheduleDesc=''、lssn='0'、version='')。整數型參數(lssn等)若傳入空字串會導致轉換錯誤,因此必須傳入數字字串。不過capabilities位於此欄位清單的最末端,因此當它沒有值時(即上述$env:CLAUDE_CODE_BRIDGE_SESSION_ID不存在的情況),可以安全地整體省略此欄位——因為其後沒有其他欄位,位置不會偏移。位置參數的限制僅表示不能跳過中間欄位,並不表示末端欄位也必須一律填寫。
| 表單欄位 | 值 |
|---|---|
text | "<SP名稱> <欄位1> <欄位2> ..."(SP 名稱去除 BySK 尾碼,後接此次呼叫要填入的欄位名稱,以空格分隔) |
token | <YOUR_SECRET_KEY>(目標 CSN 的 SK) |
jsondata | 欄位名稱→值的對應 JSON 字串,例如:{"agentKey":"...","displayName":"..."} |
各步驟實際填入的欄位:
| 步驟 | SP 名稱(text 的第一個詞) | 主要欄位 |
|---|---|---|
| 開始——註冊/更新身分 | SchedulerAgentUpsert | agentKey(每台主機+每個工作階段唯一的識別碼)、displayName、hostIdentifier(主機名稱)、windowsTaskName、projectName、scheduleDesc、isActive=1、lssn、osType、agentType(例如 claude_interactive_session)、version、capabilities(JSON 字串,例如 {"sessionUrl":"<可開啟工作階段的 URL>"}) |
| 開始——啟動執行(run) | SchedulerAgentRunStart | runIdKey(本次執行的唯一鍵)、agentKey、executionMode=interactive、totalIssueCount |
| 結束——結束執行(run) | SchedulerAgentRunEnd | runIdKey、agentKey、status=ENDED、processedCount、skippedCount、failedCount |
| 結束——身分切換為離線 | SchedulerAgentUpsert | agentKey、displayName、hostIdentifier、windowsTaskName、projectName、scheduleDesc、isActive=0 |
範例(PowerShell,所有值皆為占位符):
$body = @{
text = 'SchedulerAgentUpsert agentKey displayName hostIdentifier windowsTaskName projectName scheduleDesc isActive lssn osType agentType version capabilities'
token = '<YOUR_SECRET_KEY>'
jsondata = (@{
agentKey = 'claude_interactive_<YOUR_HOST>_<UNIQUE_ID>'
displayName = 'Claude Interactive Session (<YOUR_HOST>)'
hostIdentifier = '<YOUR_HOST>'
windowsTaskName = ''
projectName = ''
scheduleDesc = ''
isActive = '1'
lssn = '0'
osType = 'Windows'
agentType = 'claude_interactive_session'
version = ''
capabilities = (@{ sessionUrl = '<選填的工作階段 URL>' } | ConvertTo-Json -Compress)
} | ConvertTo-Json -Compress)
}
Invoke-WebRequest -Uri 'https://giipfaw.azurewebsites.net/api/giipApiSk4' -Method Post -Body $body
無法建構 sessionUrl 時(省略 capabilities):若 $env:CLAUDE_CODE_BRIDGE_SESSION_ID 不存在,導致無法建構 capabilities,只需從上方範例中移除 text 裡的 capabilities 詞元與 jsondata 中的 capabilities 欄位,其餘11個欄位照常使用即可。沒有 sessionUrl 也能完全正常成功註冊——唯一的差異是「Open Interactive Sessions」卡片中不會出現「Open session」連結(參見下方「疑難排解」)。
$body = @{
text = 'SchedulerAgentUpsert agentKey displayName hostIdentifier windowsTaskName projectName scheduleDesc isActive lssn osType agentType version'
token = '<YOUR_SECRET_KEY>'
jsondata = (@{
agentKey = 'claude_interactive_<YOUR_HOST>_<UNIQUE_ID>'
displayName = 'Claude Interactive Session (<YOUR_HOST>)'
hostIdentifier = '<YOUR_HOST>'
windowsTaskName = ''
projectName = ''
scheduleDesc = ''
isActive = '1'
lssn = '0'
osType = 'Windows'
agentType = 'claude_interactive_session'
version = ''
} | ConvertTo-Json -Compress)
}
Invoke-WebRequest -Uri 'https://giipfaw.azurewebsites.net/api/giipApiSk4' -Method Post -Body $body
若要在其他主機上重現此機制,需要原樣滿足以下兩點(兩者皆為固定要求,沒有裁量空間):(a) 該主機執行工作階段的工具中設定與上方相同的 hooks.SessionStart/hooks.SessionEnd;(b) 擁有要註冊之 CSN 的有效 SK。
SK 保存在何處是(與此流程無關的)純安全判斷事項——僅供參考,此維運者的個人環境(lowyworkenv 儲存庫)將此 SK 保存在名為 slack-bot/.secrets/giip-accounts.json 的 JSON 檔案中(結構為 Slack 頻道 ID → {login_id, sk, csn} 的對應),但這僅是範例結構——並非要求照搬這個特定檔案路徑;其他主機/維運者可各自選擇安全的方式(作業系統憑證儲存區、密鑰管理器、環境變數等)保管 SK。
確認成功:重新整理畫面後,工作階段會出現在「Open Interactive Sessions」卡片中。
方法 B —— 註冊排程器代理(自動化執行器)
註冊背景自動化執行器(如每小時的 gissue 排程器)使用與方法 A 相同的 SP 系列,但不是一次性呼叫,而是**定期(心跳)**更新自身的身分與執行狀態。
標準實作是 giip-fde-agent。 不要從零開始撰寫,遵循上面的「讓 AI 幫你建立 Gissue 排程器」步驟。下面的 SP 規格是 runner 內部使用的呼叫,僅在直接實作時參考。
- 前提條件:上述共通前提條件(目標 CSN 的 SK)。
- 首次註冊/定期身分更新:處理程序啟動時呼叫一次
SchedulerAgentUpsert(欄位與方法 A 相同——agentKey/displayName/hostIdentifier/osType/agentType/version/capabilities等),之後以最長 5 分鐘的間隔(建議:每 2 分鐘)重複呼叫。 - 啟動執行:
SchedulerAgentRunStart(runIdKey、agentKey、executionMode=scheduled、totalIssueCount)。 - 執行期間更新進度(心跳):
SchedulerAgentHeartbeatPut——runIdKey、agentKey、processedCount、skippedCount、failedCount、currentPhase、currentIssueNum、totalIssueCount。每完成一個處理單位(例如處理完一個 issue)呼叫一次;即使處於閒置、沒有可處理項目時,也要以最長 2 分鐘的間隔呼叫——若心跳中斷達到或超過 5 分鐘,畫面會將該執行顯示為 STALE。 - 結束執行:
SchedulerAgentRunEnd(runIdKey、agentKey、status、processedCount、skippedCount、failedCount、exitCode、summary)。status值為SUCCEEDED/TIMED_OUT/FAILED,exitCode為數字字串('0'或'1')。
| SP 名稱 | 驗證方式 | 用途 |
|---|---|---|
SchedulerAgentUpsert | SK | 註冊/更新身分 |
SchedulerAgentRunStart | SK | 記錄執行開始 |
SchedulerAgentHeartbeatPut | SK | 執行期間更新進度/心跳 |
SchedulerAgentRunEnd | SK | 記錄執行結束 |
SchedulerAgentList | AK(登入工作階段) | 本畫面用於取得清單——註冊時不需要 |
位置引數順序(方式 1):
- Upsert 引數順序:
agentKey、displayName、hostIdentifier、windowsTaskName、projectName、scheduleDesc、isActive - RunStart 引數順序:
runIdKey、agentKey、executionMode、totalIssueCount - HeartbeatPut 引數順序:
runIdKey、agentKey、processedCount、skippedCount、failedCount、currentPhase、currentIssueNum
呼叫慣例有兩種方式,均有效。方式 1(runner 內部):giipApiSk2,token=SK,text="SP名稱 '值1' '值2' ..."(SP 參數宣告順序的位置引數,值為單引號字串常值),jsondata 為空。方式 2(直接實作,與方法 A 相同格式):giipApiSk4,token=SK,text 中填欄位名以空格分隔,jsondata 中填 {"欄位名":"值",...} JSON。
備註:本專案所管理的 giipAgentWin/giipAgentLinux(伺服器基礎設施代理)使用與
tSchedulerAgent體系完全不同的註冊機制(以 x-api-key 為基礎的agent-register/agent-heartbeatAPI),與本畫面無關。若要註冊到本畫面(admin/catquest/schedulers),需要自行實作呼叫上述 SP 系列;gissue 每小時排程器的標準實作是 giip-fde-agent 的run-gissue-claude.ps1。
確認成功:下一次心跳/重新整理後,代理會出現在代理清單表格中。
💡 注意事項
- 本畫面為 僅限管理員 使用,需具備
AdminGuard(uLevel ≥ 70)權限。 - 代理清單、執行歷史與日誌目錄皆依工作階段目前的 CSN 範圍取得——如需查看其他專案的代理,請在頂部導覽切換專案。
- 載入資料需要已驗證的工作階段(AK 權杖);若請求開始因驗證錯誤而失敗,請重新登入後按下 Refresh。
- 本頁面與
/admin/catquest是彼此獨立的工具——透過 CatQuest 畫面的導覽進入本頁,並不代表共用 CatQuest 的貓咪視覺化資料或受眾。
疑難排解
| 症狀 | 原因 | 解決方法 |
|---|---|---|
| 已指示互動式工作階段去註冊,但「Open Interactive Sessions」始終沒有出現 | 最有可能的原因是全域掛鉤的無頭判斷邏輯僅憑 $env:CLAUDE_CODE_BRIDGE_SESSION_ID 的有無來判斷,把尚未連接橋接的互動式工作階段誤判為無頭,因而整體略過了註冊(giip #1837) | 請依上方「以全域掛鉤註冊時要留意無頭誤判」提示框中的處理程序命令列檢查方式,替換掉判斷邏輯。 |
| 出現「Authentication required」錯誤 | 找不到 AK/工作階段權杖 | 重新登入後重新整理頁面。 |
| 代理清單為空 | 此 CSN 下沒有已註冊的排程器代理,或所選專案不正確 | 確認頂部導覽中已選擇正確的專案(CSN)。 |
| 明明工作已閒置,某列卻顯示紅色 STALE | 代理在執行過程中停止傳送心跳(isStale = true)且未轉為 ENDED —— 可能是程序當機或被強制終止 | 直接檢查代理所在主機;一旦其重新啟動並再次回報,徽章會自動更新。 |
| Live Log Viewer 顯示「No streams yet.」 | 該代理尚未註冊任何日誌串流,或自上次目錄更新以來沒有新輸出 | 等待代理下一次執行,或確認代理程序確實正在寫入日誌。 |
| Open Interactive Sessions 中缺少「Open session」連結 | 該代理已註冊的 capabilities 中未包含 sessionUrl | 沒有可開啟的項目——該互動式工作階段未註冊可連線的 URL。 |
版本:1.1
最後更新:2026-09-01
來源檔案:giipv3/public/help/catquest-schedulers.zh-TW.md