Merge pull request 'feat(codex): 新增 Codex CLI composite action' (#1) from ai-review-resolve/develop-20260629-115924 into develop

Reviewed-on: composite-actions/codex#1
This commit was merged in pull request #1.
This commit is contained in:
2026-06-29 06:17:22 +00:00
4 changed files with 181 additions and 29 deletions
+24 -9
View File
@@ -1,19 +1,34 @@
name: CI name: CI
on: on:
pull_request: pull_request:
branches-ignore: branches-ignore:
- master - master
types: [opened, synchronize] types: [opened, synchronize]
jobs: jobs:
ai-code-review: release-tag-version:
name: AI Code Review name: Release Tag Version
runs-on: ubuntu runs-on: ubuntu
permissions: outputs:
contents: write version: ${{ steps.release-tag-version.outputs.version }}
pull-requests: write
issues: write
steps: steps:
- name: AI 程式碼審查 by OpenCode - name: 計算版本號
uses: https://gitea.jsc.idv.tw/composite-actions/opencode-code-review@${{ vars.ACTION_OPENCODE_CODE_REVIEW_VERSION }} id: release-tag-version
uses: https://gitea.jsc.idv.tw/composite-actions/release-tag-version@${{ vars.ACTION_RELEASE_TAG_VERSION }}
with: with:
token: ${{ secrets.TOKEN }} is_beta: 'true'
codex:
name: Codex
runs-on: ubuntu
needs: release-tag-version
steps:
- name: 測試工具
id: codex
uses: https://gitea.jsc.idv.tw/composite-actions/codex@v${{ needs.release-tag-version.outputs.version }}
with:
oauth: ${{ secrets.CODEX_OAUTH }}
- name: 檢查輸出
if: ${{ steps.codex.outputs.text != vars.CODEX_EMAIL }}
run: exit 1
+57
View File
@@ -0,0 +1,57 @@
# Codex CLI Composite Action
此 repository 提供一個 Gitea/GitHub Actions composite action,用於安裝 Codex CLI、寫入 OAuth token、執行指定提示詞,並將 CLI 輸出寫入 action output。
## 專案列表
### 專案描述
| 專案名稱 | 專案描述 |
| --- | --- |
| [codex](https://gitea.jsc.idv.tw/composite-actions/codex) | 提供 Codex CLI composite action,讓 workflow 可透過 `oauth``prompt` 輸入執行 CLI,並從 repository variable 讀取模型名稱後取得文字輸出。 |
### 參考專案
| 專案名稱 | 參考專案列表 |
| --- | --- |
| [codex](https://gitea.jsc.idv.tw/composite-actions/codex) | 無 |
### NuGet 套件
| 專案名稱 | NuGet 套件列表 |
| --- | --- |
| [codex](https://gitea.jsc.idv.tw/composite-actions/codex) | 無 |
## 功能列表
此 repository 未包含可列入 README 的 public method、public constructor、public extension method 或 public operator。
## 使用範例
### 在 workflow 中呼叫 Codex CLI
以下範例示範在 workflow step 中呼叫此 composite action,傳入 OAuth token 與提示詞,並在後續步驟讀取 `text` output。模型名稱由 action 直接讀取 `vars.CODEX_MODEL`
```yaml
- name: 執行 Codex CLI
id: codex
uses: https://gitea.jsc.idv.tw/composite-actions/codex@v1
with:
oauth: ${{ secrets.CODEX_OAUTH }}
prompt: "請自我介紹"
- name: 使用輸出文字
run: printf '%s\n' '${{ steps.codex.outputs.text }}'
```
前置條件:
- `secrets.CODEX_OAUTH` 必須是 Codex OAuth token 檔案內容的 base64 字串。
- `vars.CODEX_MODEL` 必須是 Codex CLI 可用的模型名稱。
- runner 必須可透過 npm 安裝 `@openai/codex`
預期結果:
- action 會安裝 `codex` CLI。
- action 會將 OAuth token 寫入 `$HOME/.codex/auth.json` 並設定檔案權限為 `600`
- action 會執行 `codex exec --model "$MODEL" "$PROMPT"`,並把 stdout 寫入 `steps.codex.outputs.text`
+43 -20
View File
@@ -1,33 +1,56 @@
name: 'Composite Action Template' name: 'Codex CLI'
description: 'Composite Action 範本' description: 'Codex CLI 工具'
author: 'Jeffery' author: 'Jeffery'
inputs: inputs:
text: prompt:
description: '輸入的文字' description: '傳給 Codex CLI 的提示詞'
required: false required: false
default: 'Hello, World!' oauth:
description: 'base64 編碼的 Codex OAuth token 檔案內容'
required: true
outputs: outputs:
text: text:
description: '輸出的文字' description: '輸出的文字'
value: ${{ steps.change.outputs.text }} value: ${{ steps.codex.outputs.text }}
runs: runs:
using: 'composite' using: 'composite'
steps: steps:
- name: 交換 - name: 安裝工具
id: change
env: env:
GITEA_SERVER_URL: ${{ gitea.server_url }} OAUTH: ${{ inputs.oauth }}
GITEA_REPOSITORY: ${{ gitea.repository }}
GITEA_TOKEN: ${{ gitea.token }}
TEXT: ${{ inputs.text }}
run: | run: |
echo "Gitea Server Url: $GITEA_SERVER_URL" if [ -z "$OAUTH" ]; then
echo 'oauth input (secrets.CODEX_OAUTH) is required and must not be empty.' >&2
exit 1
fi
echo "Gitea Repository: $GITEA_REPOSITORY" npm install -g @openai/codex
echo "Gitea Token: $GITEA_TOKEN" oauth_file="$HOME/.codex/auth.json"
install -d -m 700 "$(dirname "$oauth_file")"
echo "Text: $TEXT" printf '%s' "$OAUTH" | base64 -d > "$oauth_file"
chmod 600 "$oauth_file"
echo "text=$TEXT" >> "$GITHUB_OUTPUT" shell: bash
shell: bash - name: 執行工具
id: codex
env:
MODEL: ${{ vars.CODEX_MODEL }}
PROMPT: ${{ inputs.prompt }}
run: |
if [ -z "$MODEL" ]; then
echo 'CODEX_MODEL repository variable is required.' >&2
exit 1
fi
if [ -z "$PROMPT" ]; then
email="$(python3 "$GITHUB_ACTION_PATH/app/codex_account.py")"
echo "text=$email" >> "$GITHUB_OUTPUT"
exit 0
fi
text="$(codex exec --skip-git-repo-check -s danger-full-access --model "$MODEL" "$PROMPT")"
printf '%s\n' "$text"
{
echo 'text<<CODEX_OUTPUT'
printf '%s\n' "$text"
echo 'CODEX_OUTPUT'
} >> "$GITHUB_OUTPUT"
shell: bash
+57
View File
@@ -0,0 +1,57 @@
"""透過 codex app-server 的 JSON-RPC account/read 取得目前登入帳號的 email。
這是 TUI `/status` Account 欄位的程式化來源,不解析本地 OAuth token
而是由 codex 自身回報登入帳號。將 email 印到 stdout(取不到時印空字串)。
"""
import json
import subprocess
import time
def read_account_email(timeout_seconds: float = 25.0) -> str:
process = subprocess.Popen(
["codex", "app-server"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
bufsize=1,
)
def send(obj):
process.stdin.write(json.dumps(obj) + "\n")
process.stdin.flush()
send({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {"clientInfo": {"name": "ci", "version": "1.0"}},
})
send({"jsonrpc": "2.0", "method": "initialized", "params": {}})
send({"jsonrpc": "2.0", "id": 2, "method": "account/read", "params": {}})
email = ""
deadline = time.time() + timeout_seconds
try:
while time.time() < deadline:
line = process.stdout.readline()
if not line:
break
try:
message = json.loads(line)
except ValueError:
continue
if message.get("id") == 2:
account = (message.get("result") or {}).get("account") or {}
email = account.get("email") or ""
break
finally:
process.terminate()
return email
if __name__ == "__main__":
print(read_account_email())