From 5873cfa30f09f2d0f0b64cdaee580e1bbaf36821 Mon Sep 17 00:00:00 2001 From: Alex J Lennon Date: Mon, 10 Aug 2026 11:49:10 +0100 Subject: [PATCH] Release 0.2.0: Nebula light, action_class chrome, Confirm UX docs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document band colours and themes for agents; changelog covers the post-0.1.0 MCQ polish (banner, · split, images, audio defaults). Co-authored-by: Cursor --- CHANGELOG.md | 23 +++++++++++++++++++++++ README.md | 3 +++ docs/AGENTS.md | 5 +++++ pyproject.toml | 2 +- uv.lock | 26 +++++++++++++------------- 5 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..234263e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,23 @@ +# Changelog + +## [0.2.0] — 2026-08-10 + +### Added +- Nebula **light** theme alongside glass dark (`ASK_QUESTION_THEME` / prefs `theme`) +- `action_class` band chrome: `file` · `secrets` · `comms` · `destructive` · `policy` +- Optional `image` / `images` preview (Linux Gtk + Nebula; carousel for multi) +- Windows Nebula WebView2 MCQ path (glass default) + +### Fixed +- Dense ` · `-packed Confirm questions split into lead + detail (Gtk parity) +- Policy/dangerous banner no longer repeats the full question under the band label +- Linux Nebula known-goods: window drag, ↑/↓+Enter, audio checkbox vs env mute +- Confirm body clipping, footer Cancel/OK visibility, image dialog sizing + +### Changed +- Default MCQ audio off until the human opts in +- TTS/STT URLs remain optional; text-only is the lean default + +## [0.1.0] — 2026-07-26 + +First public release — Gtk4/Adw `ask_multiple_choice`, text-first, optional voice. diff --git a/README.md b/README.md index 5689ec4..6b2b820 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ dialog (`ask_multiple_choice`) on any compatible host. **Works text-only** [Demo](https://www.youtube.com/watch?v=5wVKCIXAfi4) · [SETUP](SETUP.md) · +[Changelog](CHANGELOG.md) · [Dependencies](DEPENDENCIES.md) · [Security](SECURITY.md) (3-year fix window) · [Maintainers](MAINTAINERS.md) @@ -98,6 +99,8 @@ Full env / prefs: [SETUP.md](SETUP.md). Never commit tokens. returned as MCP image blocks (max 4, no lasting files) - **Idle timeout hold:** default `timeout_sec=0` (waits). If a timeout is set, typing / paste / select cancels auto-close until OK/Cancel +- **`action_class`** band chrome: `file` · `secrets` · `comms` · `destructive` · + `policy` (COMMS wording only for real outbound messages) - Linux aesthetic: **Nebula** glass (dark default) + **light** daylight companion (`ASK_QUESTION_THEME` / prefs `theme`: `glass` | `light` | `ink` | `signal` | `hybrid`) - Remembers last dialog size (`prefs.window`; position on Windows; size-only diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 0021978..9d6097e 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -73,6 +73,7 @@ skill via `ask-question-install --skill` (`~/.cursor/skills/ask-multiple-choice` | `allow_multiple` | bool | no | default `false` (radio); `true` = checklist | | `allow_other` | bool | no | **Ignored** — Something else is always appended when missing | | `dangerous` | bool | no | Danger chrome; OK/Enter armed ~1s (`ASK_QUESTION_DANGER_ARM_MS`, same default as normal). Normal MCQs arm ~1s (`ASK_QUESTION_ARM_MS`). | +| `action_class` | string \| null | no | Band colour: `file` \| `secrets` \| `comms` \| `destructive` \| `policy`. Use **COMMS** only for real outbound messages (never “send this” for file/secrets/policy). Bare `dangerous=true` maps to destructive chrome. | | `speak` | bool | no | default `true` (honours mute env / missing TTS) | | `title` | string | no | default `"Decide"` — short noun phrase | | `agent` | string \| null | **strongly yes** | Window title prefix `[agent]` | @@ -151,6 +152,7 @@ Routine forks stay short (no referent dump): "title": "Force push", "agent": "release-agent", "dangerous": true, + "action_class": "destructive", "recommended_id": "abort", "options": [ { "id": "abort", "label": "Abort (recommended)" }, @@ -159,6 +161,9 @@ Routine forks stay short (no referent dump): } ``` +**Theme (Nebula):** env `ASK_QUESTION_THEME` or prefs `theme` — +`glass` (default dark) · `light` · `ink` · `signal` · `hybrid`. + OK and Enter stay locked briefly after open (countdown on OK): **~1s** for both normal (`ASK_QUESTION_ARM_MS`) and `dangerous` (`ASK_QUESTION_DANGER_ARM_MS`). (Dangerous used to be ~4s; shortened 2026-08-01.) Set either env to `0` to diff --git a/pyproject.toml b/pyproject.toml index 0739489..e01d182 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ask-question-mcp" -version = "0.1.0" +version = "0.2.0" description = "Stdio MCP desktop multiple-choice (Gtk/tk); works text-only, optional TTS/STT" readme = "README.md" requires-python = ">=3.12" diff --git a/uv.lock b/uv.lock index 3d6eb72..d6f7be9 100644 --- a/uv.lock +++ b/uv.lock @@ -41,7 +41,7 @@ wheels = [ [[package]] name = "ask-question-mcp" -version = "0.1.0" +version = "0.2.0" source = { editable = "." } dependencies = [ { name = "mcp", extra = ["cli"] }, @@ -183,7 +183,7 @@ name = "clr-loader" version = "0.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi" }, + { name = "cffi", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/46/7eea92b6aa2d68af78e049cbecec5f757f1aad44ecdecdc16bbad7eead51/clr_loader-0.3.1.tar.gz", hash = "sha256:2e073e9aaf49d1ae2f56ecba27987ad5fb68be4bcd9dd34a5bed8f0e4e128366", size = 86805, upload-time = "2026-04-18T17:49:44.287Z" } wheels = [ @@ -554,7 +554,7 @@ name = "pyobjc-framework-cocoa" version = "12.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/51/34/fbe38a204643aa4e1b91391cdce07a34da565a69171ebcad08de7438a556/pyobjc_framework_cocoa-12.2.1.tar.gz", hash = "sha256:b94b37fe5730e5ae1fb0052912cd174e6ec329b0bfba4a012ae5db1014b5864b", size = 3125751, upload-time = "2026-06-19T16:20:05.159Z" } wheels = [ @@ -572,8 +572,8 @@ name = "pyobjc-framework-quartz" version = "12.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3b/f6/2a8b84dbf1fe7c04dd96ea73d991678d4e09a909f51971ecc51629bb2ab4/pyobjc_framework_quartz-12.2.1.tar.gz", hash = "sha256:b3b8b6f71e66147f8ff9e6213864cc8527e3a0b1ee90835b93ce221f4802d9b0", size = 3215521, upload-time = "2026-06-19T16:21:30.199Z" } wheels = [ @@ -591,8 +591,8 @@ name = "pyobjc-framework-security" version = "12.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/b8/4267b802d8dba6de468e7d0765b05cc4e146fa376ed9f55e0b6461016bef/pyobjc_framework_security-12.2.1.tar.gz", hash = "sha256:d7831b1537f4346892e7f2f0e2b09d79bee98919b0767f4061278d0e03028f2d", size = 181065, upload-time = "2026-06-19T16:21:40.151Z" } wheels = [ @@ -610,8 +610,8 @@ name = "pyobjc-framework-uniformtypeidentifiers" version = "12.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/a1/108fa1e5a3dd8aff626f98fb97de370323b290404b04ffa2ef9420665ed3/pyobjc_framework_uniformtypeidentifiers-12.2.1.tar.gz", hash = "sha256:1fb89d13aa3c2df8e6d6536f6df3493fe5a6caefd2a5adebf17c5af3b29ed4a2", size = 20679, upload-time = "2026-06-19T16:21:55.739Z" } wheels = [ @@ -623,8 +623,8 @@ name = "pyobjc-framework-webkit" version = "12.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/d2/b230c594f70ecb970b4cef67bae2648d1bfa5b381e9b7e3710bf24ec8887/pyobjc_framework_webkit-12.2.1.tar.gz", hash = "sha256:a56acae55b50d549b20dff2921ad1099add8fbc377d0de09ddc2ba50957f7def", size = 332374, upload-time = "2026-06-19T16:22:01.988Z" } wheels = [ @@ -660,7 +660,7 @@ name = "pythonnet" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "clr-loader" }, + { name = "clr-loader", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/05/57/da1992e44663b71365c6e842c8d7fa453d4ec45fb99a68cfee5b7e944d3c/pythonnet-3.1.0.tar.gz", hash = "sha256:7b34c382905d10a371509ffafd64cae0416305c28817738a9cd138336f4e9991", size = 250599, upload-time = "2026-05-23T20:30:21.578Z" } wheels = [ @@ -714,7 +714,7 @@ name = "qtpy" version = "2.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "packaging" }, + { name = "packaging", marker = "sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/70/01/392eba83c8e47b946b929d7c46e0f04b35e9671f8bb6fc36b6f7945b4de8/qtpy-2.4.3.tar.gz", hash = "sha256:db744f7832e6d3da90568ba6ccbca3ee2b3b4a890c3d6fbbc63142f6e4cdf5bb", size = 66982, upload-time = "2025-02-11T15:09:25.759Z" } wheels = [