From 41b1f444bc07c803410a9a357e2e088a68e1dc66 Mon Sep 17 00:00:00 2001 From: Sergey Afonin Date: Tue, 8 Sep 2026 21:52:58 +0300 Subject: [PATCH 1/2] Add shared Approve and Decline task actions --- CHANGELOG.md | 1 + README.md | 14 +- com.yechan.threaddeck.sdPlugin/en.json | 6 +- com.yechan.threaddeck.sdPlugin/ko.json | 6 +- com.yechan.threaddeck.sdPlugin/manifest.json | 19 +- .../property-inspector/index.html | 23 +- .../property-inspector/property-inspector.js | 104 +- com.yechan.threaddeck.sdPlugin/ru.json | 6 +- docs/CHANGELOG.ko.md | 1 + docs/PROFILE.ko.md | 1 + docs/PROFILE.md | 1 + docs/README.ko.md | 3 +- native/approval-api-context.h | 200 ++++ native/approval-card.h | 979 ++++++++++++++++++ native/approval-shortcuts.h | 636 ++++++++++++ native/keybridge.m | 61 +- native/review-continue.h | 684 ++++++++++++ scripts/audit-release.mjs | 4 +- scripts/sync-localizations.mjs | 3 +- scripts/verify.sh | 4 + src/action-settings.js | 8 +- src/approval-controls.js | 257 +++++ src/approval-shortcuts.js | 100 ++ src/codex-ipc.js | 380 +++++++ src/config.js | 1 + src/i18n.js | 33 + src/ipc-approvals.js | 293 ++++++ src/micro-cdp.js | 37 + src/plugin.js | 700 ++++++++++++- test/action-settings-approval.test.js | 54 + test/approval-controls.test.js | 384 +++++++ test/approval-shortcuts.test.js | 155 +++ test/codex-ipc.test.js | 414 ++++++++ test/domain.test.js | 5 +- test/ipc-approvals.test.js | 329 ++++++ test/micro-cdp.test.js | 40 + test/plugin-verification.test.js | 2 +- test/property-inspector.test.js | 251 ++++- 38 files changed, 6147 insertions(+), 52 deletions(-) create mode 100644 native/approval-api-context.h create mode 100644 native/approval-card.h create mode 100644 native/approval-shortcuts.h create mode 100644 native/review-continue.h create mode 100644 src/approval-controls.js create mode 100644 src/approval-shortcuts.js create mode 100644 src/codex-ipc.js create mode 100644 src/ipc-approvals.js create mode 100644 test/action-settings-approval.test.js create mode 100644 test/approval-controls.test.js create mode 100644 test/approval-shortcuts.test.js create mode 100644 test/codex-ipc.test.js create mode 100644 test/ipc-approvals.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 02fdd43..3a023a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## Unreleased +- Add Approve/Decline to Codex command and the dedicated Task actions selector. Both share explicit task-key IPC targeting and foreground native-card handling, request revalidation, duplicate-delivery prevention, and English/Korean/Russian feedback. No installed profile or approval-policy changes are required. Background IPC is covered by fixtures and read-only live checks; physical background approval remains unverified. - Keep fixture verification offline: mock New Task state reads and permission checks, skip native startup/cleanup in contract modes, and fail verification before any external command, connection, process signal, or file write. - Guard inspector bootstrap against Codex builds that disable `SIGUSR1` activation. ThreadDeck checks the loaded Electron framework's inspector fuse and rechecks the process identity before signaling; disabled or unverifiable builds use the existing safe fallback without sending the signal. Existing process-owned inspector connections remain usable. - Treat failed local turns as errors instead of successful completions. Task keys show review-required safety pauses as yellow **Need input** and other errors in red, preserve the final elapsed time, and do not return to Thinking while a child process is still running. diff --git a/README.md b/README.md index 83623e7..583aa91 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The overview and gesture demos are generated from the plugin's real SVG key rend - **Hardware dictation** — hold a task key to speak and auto-submit a follow-up, or use the dedicated microphone to leave a draft for review. - **Completion feedback** — after a fresh final-turn end is confirmed with no queued continuation, every visible ThreadDeck-owned key acknowledges the first completion frame. The matching task then keeps a slower green pulse until that exact task is successfully opened or viewed frontmost in Codex. Queue edits and dequeue-to-execution transitions never count as completion. - **Workflow controls** — change the current model's reasoning effort, toggle Codex Fast mode, create a task or Side Chat, send, change pages, and optionally show a weekly quota ring. -- **Five focused actions** — choose Current or Top 1–8 from one **Codex task** action, and New task, Side Chat, or Send from one **Codex command** action in the autosaving Property Inspector. +- **Custom controls** — choose Current or Top 1–8 from **Codex task**, and New task, Side Chat, Send, Approve, or Decline from **Codex command**. The dedicated **Task actions** action exposes the same Approve/Decline behavior and target settings. - **Micro-first reliability without restarts** — Effort, Fast, Side Chat, push-to-talk, Send, New Task, and the six native Micro task slots use Codex's own internal commands first. When no persistent renderer endpoint exists, ThreadDeck checks whether the running Codex build supports inspector activation before preparing an authenticated local command socket at startup. It closes an inspector it opened before the first key press. Disabled or unverifiable builds skip activation; Accessibility and shortcuts remain a verified fallback for the eight-task dashboard and unsupported builds. ## Install in 60 seconds @@ -92,6 +92,7 @@ With the Micro bridge connected, these actions use Codex's native internal comma | Codex task: Top 1–8 | Starts opening the configured position in the sorted local, pinned-remote, and Side Chat list | Hold at least **0.55 s** to start dictation in that task; release to transcribe, auto-submit, and verify the draft cleared | | Microphone | Starts dictation in the verified current composer and pauses supported audio-producing media apps | For a brand-new Side Chat, can use its verified right-side composer before a task UUID exists; keep held while speaking, then release to leave a draft **without submitting** and resume media | | Codex command: Send | Verifies the current composer; release before 0.6 s to send Return | Waits for an in-progress task or Side Chat switch; at **0.6 s** the key turns blue, then release to send Command+Return | +| Codex command / Task actions: Approve or Decline | Captures the request for the configured target and shows Checking | Release sends one decision after the request is rechecked; a short tap is sufficient. Blue Sent reports dispatch, not completion of the underlying operation | | Weekly quota | — | Release to refresh CodexBar immediately | | Codex command: New task / Side Chat | — | New Task mirrors Current Task's scope: project tasks create inside that project, standalone tasks stay outside projects. Until Codex assigns an ID, Current Task points to a provisional `New task` composer. ThreadDeck uses native `NEW` when context-aware creation is available, with `⇧⌘O` / `⌥⌘O` fallbacks; Side Chat uses native `PARTY` or `⌥⌘S` and keeps the same protected provisional-composer behavior | | Reasoning + Fast | Release before 0.6 s to move the next-run level (`LIGHT`–`ULTRA`); the track begins a smooth 320 ms transition immediately from the first tap | Rapid taps are folded into the last ping-pong position. After input settles, ThreadDeck sends one exact model/Effort choice through the mounted power controller when exposed; otherwise it opens `Advanced`, scans the live account/model list, and selects only the final requested level. It never replays every intermediate physical-knob step. Direct Codex changes are mirrored with the same animation. An exact Ultra warning selects only `Use Full access`, never `Continue`. At **0.6 s**, the key toggles next-run Fast mode immediately through Codex's native command. When Fast is verified, the level name remains exactly centered and its bolt sits immediately to the left so a pressing finger does not cover it | @@ -101,6 +102,17 @@ The Dashboard's Codex task key is configured as Current and follows the task sel Reasoning and speed have two deliberate timelines. A working task card keeps the exact Effort and Fast/standard setting captured when that turn started; changing the Codex composer or ThreadDeck's combined control does not rewrite an answer already in progress. The combined control instead shows the live setting for the **next run**, including a setting changed directly in Codex. Both tracks animate smoothly when their own trustworthy value changes: the control follows the next-run composer immediately, while a task header moves only when new turn metadata reaches that card. Codex's current queue stores the follow-up content and starts it later through the live composer, so a queued follow-up uses the setting present when it actually begins. Once dequeued, its new turn metadata becomes the task-card header. The amber `+N` remains a queue count rather than pretending every queued item has its own frozen setting. +## Approve and Decline + +Add **Task actions** to any key and choose Approve or Decline, or select the same commands in **Codex command**. Both use the same handler. Existing profiles and keyboard shortcuts are preserved. + +- **Task selected on Stream Deck** (default): press a **Codex task** key first. Its title appears on Approve/Decline, and that exact task stays selected even if you switch tabs manually in Codex. A subsequent approval press uses the running desktop's local IPC and works without focusing Codex or sending a keystroke. Select the task again after restarting the plugin. Only local tasks are supported. +- **Current dialog (foreground)**: keep the intended task and permission card in front. ThreadDeck uses an already-ready Micro connection or activates the verified native approval control. For **Review findings**, review the findings and check the acknowledgment in Codex yourself; Approve can then activate **Continue chat**. Decline does not dismiss that safety review. + +An empty, ambiguous, changed, or unsupported request is not acted on. A task-bound request never falls through to another visible dialog. Decisions are scoped to one request, with no session-wide permission grant, bulk approval, or replay after uncertain delivery. The task-key target is explicit; ThreadDeck does not automatically select the only waiting request across all tasks. + +The local IPC and Micro interfaces are internal and versioned, so a Codex update can make them unavailable. The background IPC route has fixture and read-only live coverage; physical background approval/decline on Neo remains unverified. Blue **Sent** confirms that the desktop accepted dispatch or the native control was activated, not that the backend operation succeeded. + ## Keys with hold gestures ### Task key: open or dictate and submit diff --git a/com.yechan.threaddeck.sdPlugin/en.json b/com.yechan.threaddeck.sdPlugin/en.json index 9eb3bbe..c86fe0c 100644 --- a/com.yechan.threaddeck.sdPlugin/en.json +++ b/com.yechan.threaddeck.sdPlugin/en.json @@ -11,7 +11,11 @@ }, "com.yechan.threaddeck.newthread": { "Name": "Codex command", - "Tooltip": "Choose New task, Side Chat, or Send in the Property Inspector." + "Tooltip": "Choose New task, Side Chat, Send, Approve, or Decline in the Property Inspector." + }, + "com.yechan.threaddeck.taskactions": { + "Name": "Task actions", + "Tooltip": "Choose Approve or Decline and an approval target in the Property Inspector." }, "com.yechan.threaddeck.voice": { "Name": "Codex dictation", diff --git a/com.yechan.threaddeck.sdPlugin/ko.json b/com.yechan.threaddeck.sdPlugin/ko.json index e5730a2..ee9ba84 100644 --- a/com.yechan.threaddeck.sdPlugin/ko.json +++ b/com.yechan.threaddeck.sdPlugin/ko.json @@ -11,7 +11,11 @@ }, "com.yechan.threaddeck.newthread": { "Name": "Codex 명령", - "Tooltip": "속성 검사기에서 새 작업, 사이드챗, 보내기 중 하나를 고릅니다." + "Tooltip": "속성 관리자에서 새 작업, 사이드챗, 보내기, 승인 또는 거절을 선택합니다." + }, + "com.yechan.threaddeck.taskactions": { + "Name": "작업 액션", + "Tooltip": "속성 관리자에서 승인 또는 거절과 승인 대상을 선택합니다." }, "com.yechan.threaddeck.voice": { "Name": "Codex 음성 입력", diff --git a/com.yechan.threaddeck.sdPlugin/manifest.json b/com.yechan.threaddeck.sdPlugin/manifest.json index de76a3e..ecf2842 100644 --- a/com.yechan.threaddeck.sdPlugin/manifest.json +++ b/com.yechan.threaddeck.sdPlugin/manifest.json @@ -47,10 +47,27 @@ "ShowTitle": false } ], - "Tooltip": "Choose New task, Side Chat, or Send in the Property Inspector.", + "Tooltip": "Choose New task, Side Chat, Send, Approve, or Decline in the Property Inspector.", "UserTitleEnabled": false, "UUID": "com.yechan.threaddeck.newthread" }, + { + "Controllers": [ + "Keypad" + ], + "Icon": "images/action", + "Name": "Task actions", + "PropertyInspectorPath": "property-inspector/index.html", + "States": [ + { + "Image": "images/key", + "ShowTitle": false + } + ], + "Tooltip": "Choose Approve or Decline and an approval target in the Property Inspector.", + "UserTitleEnabled": false, + "UUID": "com.yechan.threaddeck.taskactions" + }, { "Controllers": [ "Keypad" diff --git a/com.yechan.threaddeck.sdPlugin/property-inspector/index.html b/com.yechan.threaddeck.sdPlugin/property-inspector/index.html index ed9bb07..1cfbf0d 100644 --- a/com.yechan.threaddeck.sdPlugin/property-inspector/index.html +++ b/com.yechan.threaddeck.sdPlugin/property-inspector/index.html @@ -34,8 +34,29 @@ + + -

Send uses Return on a tap and Command+Return after the key turns blue.

+

Send uses Return on a tap and Command+Return after the key turns blue.

+ + + + +