From 08e1b0e9e1bd2caf9e0f6f3472706d1cdc8e87e2 Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Fri, 7 Aug 2026 19:57:40 +0800 Subject: [PATCH] emrg: GitHub PAT auth in GUI settings + gh auth setup-git (GCM rant Stage 2) Windows GCM rant (2026-08-07T10:17:27) acceptance items 4/5 (PAT fallback + setup-git) + settings-page auth section groundwork. Daemon (emrg/server/daemon.py): - github_connect command: gh auth login --with-token (token via stdin, never argv) + gh auth setup-git so git uses gh as credential helper and push/pull/fetch never falls back to GCM popups; re-verifies via the github_status parser; never raises. - github_disconnect command: gh auth logout --hostname github.com. - Both dispatch to github_connect_result / github_disconnect_result frames. GUI: - Settings dialog gains a 'GitHub connection' section: live status from github_status, PAT input + Connect / Disconnect buttons, zh/en i18n. - daemon_client RESPONSE_TYPES: github_connect / github_disconnect maps. - main.js IPC handlers (emrg:githubStatus/Connect/Disconnect) + preload bridge exposure. Tests: +8 Python (dispatch, empty-token, gh-missing, PAT stdin delivery, login failure, setup-git failure, disconnect); GUI RESPONSE_TYPES test covers the two new mappings. Docs synced 534 -> 542 (doc-count guard). --- Agent.md | 2 +- README.cn.md | 2 +- README.md | 2 +- emrg/gui/daemon_client.js | 2 + emrg/gui/main.js | 18 +++ emrg/gui/preload.js | 3 + emrg/gui/renderer/index.html | 10 ++ emrg/gui/renderer/js/app.js | 1 + emrg/gui/renderer/js/dialogs.js | 65 ++++++++++ emrg/gui/renderer/js/i18n.js | 32 +++++ emrg/gui/test/daemon_client.test.js | 14 +++ emrg/server/daemon.py | 99 +++++++++++++++ tests/test_daemon.py | 184 ++++++++++++++++++++++++++++ 13 files changed, 431 insertions(+), 3 deletions(-) diff --git a/Agent.md b/Agent.md index 4ab533c5..d82b0022 100644 --- a/Agent.md +++ b/Agent.md @@ -93,7 +93,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design: pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.port; python -m emrg ``` -Python: `uv run pytest tests/ -v` (534) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (542) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (91: 22 daemon_client + 22 app-commands + 22 renderer smoke + 15 i18n + 7 integration + 3 commands) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` CI: `uv run pytest` + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文) Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响) diff --git a/README.cn.md b/README.cn.md index 9cdda4c7..39828c69 100644 --- a/README.cn.md +++ b/README.cn.md @@ -274,7 +274,7 @@ EMRG 不只是追赶——它自己追上来。 git clone https://github.com/argszero/emrg.git cd emrg uv sync # 安装依赖 -uv run pytest tests/ -v # 跑测试(当前 534 项) +uv run pytest tests/ -v # 跑测试(当前 542 项) uv run python -m emrg # 启动 TUI # CI 含 actionlint workflow 门禁(#444):workflow 解析错误在 PR 即失败 diff --git a/README.md b/README.md index eefb54f0..6d8fe2c7 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ EMRG doesn't just keep up — it catches up on its own. git clone https://github.com/argszero/emrg.git cd emrg uv sync # install deps -uv run pytest tests/ -v # run tests (currently 534 items) +uv run pytest tests/ -v # run tests (currently 542 items) uv run python -m emrg # launch TUI # CI includes actionlint workflow gate (#444): workflow parse errors fail PR CI diff --git a/emrg/gui/daemon_client.js b/emrg/gui/daemon_client.js index 76a48495..dd27983a 100644 --- a/emrg/gui/daemon_client.js +++ b/emrg/gui/daemon_client.js @@ -45,6 +45,8 @@ const RESPONSE_TYPES = { rewind_session: "rewind_result", // 补缺:daemon.py:955 rewind_result read_memory: "memory_content", // 补缺:daemon.py:771/778 memory_content evolution_summary: "evolution_summary", // WorkBuddy P3:自进化可见化 + github_connect: "github_connect_result", // Windows GCM rant Stage 2:PAT 授权(daemon.py github_connect) + github_disconnect: "github_disconnect_result", // Windows GCM rant Stage 2:断开(daemon.py github_disconnect) }; class DaemonClient { diff --git a/emrg/gui/main.js b/emrg/gui/main.js index 0b20c7eb..06404e5a 100644 --- a/emrg/gui/main.js +++ b/emrg/gui/main.js @@ -442,6 +442,24 @@ vision = false return { count: frame.count ?? 0, recent: frame.recent || [] }; }); + ipcMain.handle("emrg:githubStatus", async () => { + // Windows GCM rant Stage 2:设置页 GitHub 连接状态(daemon github_status) + const frame = await client.sendCommandAndWait("github_status", {}, 10000); + return { authenticated: Boolean(frame.authenticated), user: frame.user || null }; + }); + + ipcMain.handle("emrg:githubConnect", async (_e, { token }) => { + // Windows GCM rant Stage 2:PAT 授权 + setup-git(daemon github_connect) + const frame = await client.sendCommandAndWait("github_connect", { token: String(token || "").trim() }, 40000); + return { ok: Boolean(frame.ok), user: frame.user || null, error: frame.error || null }; + }); + + ipcMain.handle("emrg:githubDisconnect", async () => { + // Windows GCM rant Stage 2:断开 GitHub(daemon github_disconnect) + const frame = await client.sendCommandAndWait("github_disconnect", {}, 40000); + return { ok: Boolean(frame.ok), error: frame.error || null }; + }); + ipcMain.handle("emrg:setModel", async (_e, { model }) => { await client.sendCommandAndWait("set_model", { model }, 5000); return { ok: true }; diff --git a/emrg/gui/preload.js b/emrg/gui/preload.js index 197b2bef..945225e8 100644 --- a/emrg/gui/preload.js +++ b/emrg/gui/preload.js @@ -27,6 +27,9 @@ const api = { triggerTask: (payload) => ipcRenderer.invoke("emrg:triggerTask", payload), sendRant: (payload) => ipcRenderer.invoke("emrg:sendRant", payload), evolutionSummary: (payload) => ipcRenderer.invoke("emrg:evolutionSummary", payload), + githubStatus: () => ipcRenderer.invoke("emrg:githubStatus"), + githubConnect: (payload) => ipcRenderer.invoke("emrg:githubConnect", payload), + githubDisconnect: () => ipcRenderer.invoke("emrg:githubDisconnect"), listModels: () => ipcRenderer.invoke("emrg:listModels"), openFile: (payload) => ipcRenderer.invoke("emrg:openFile", payload), saveSettings: (payload) => ipcRenderer.invoke("emrg:saveSettings", payload), diff --git a/emrg/gui/renderer/index.html b/emrg/gui/renderer/index.html index 97152526..166739ea 100644 --- a/emrg/gui/renderer/index.html +++ b/emrg/gui/renderer/index.html @@ -123,6 +123,16 @@

设置

+
+
GitHub 连接
+
+
+ + + +
+
用于自进化推送 PR;授权后自动执行 gh auth setup-git,git 操作不再弹 GCM
+
外观