Skip to content

feat(voicetranser): add the voicetranser push-to-talk voice input plugin (1.0.3) - #149

Open
Lumos-789 wants to merge 5 commits into
zai-org:mainfrom
Lumos-789:feat/voicetranser
Open

Lumos-789 wants to merge 5 commits into
zai-org:mainfrom
Lumos-789:feat/voicetranser

Conversation

@Lumos-789

@Lumos-789 Lumos-789 commented Nov 1, 2026 •

Copy link
Copy Markdown

Plugin type (required) / 插件类型(必填)

  • UI Plugin / 是 UI 插件 — provides MCP Apps interactive pages / 提供 MCP Apps 交互页面
  • Standard plugin / 普通插件(非 UI) — does not provide MCP Apps interactive pages / 不提供 MCP Apps 交互页面
  • Not applicable / 不适用 — repository-only changes; no plugin content changed / 仅仓库级改动,不涉及插件内容

Affected plugin name(s) / 涉及的插件名称:voicetranser

What / 改动内容

EN — Adds voicetranser, a skill that installs, configures and troubleshoots VoiceTranser, a fully local push-to-talk voice-input app for macOS: hold a global hotkey, speak, release — the transcription is pasted at the cursor. Local-first STT (Qwen3-ASR 0.6B 4bit on MLX/Metal by default, with SenseVoice / mlx-whisper fallbacks) and zero external APIs.

  • The payload is the skill plus a bilingual README: external_plugins/voicetranser/ holds plugin.json, README.md / README_CN.md and skills/voicetranser/SKILL.md.
  • The app itself is cloned and installed from its own repository, so the plugin package stays small and the app can be updated independently.
  • 1.0.2 fixes the installer's self-check: tests/diagnose.py used to open an input stream regardless of microphone permission, which blocked on a macOS TCC dialog. It now reads the authorization status read-only first, only opens a stream when that says authorized, and kills the probe after 3 s in a child process; --skip-audio is the escape hatch, and a skipped check counts as not verified so it can never look green.

中文 — 新增 voicetranser:安装、配置并排障 VoiceTranser 的 skill —— 一个完全本地的 macOS 按住说话输入工具(按住全局热键说话,松开即转写并粘贴到光标处),纯本地 STT(Qwen3-ASR MLX,SenseVoice / mlx-whisper 兜底),零外部 API。载荷只有 skill + 中英 README,应用本体从自己的仓库安装;1.0.2 修掉了诊断脚本会弹授权框并卡住的问题。

Visible behavior and testing / 可见行为与测试

  • Product repository: python3 -m unittest discover -s tests → 52 passed in the project venv (macOS 27.0.1 arm64, Python 3.12). On a bare Python 3.14 without the audio dependency installed, the recorder-stream test errors at import sounddevice — that is the environment, not the suite.
  • Repository checks on this branch: python3 scripts/validate.py → OK: 53 plugin(s) validated; the plugin payload is stdlib text only (4 files, 13 KiB).
  • 1.0.2 diagnosis on a real machine: 8/8 checks passed, exit 0, returned in seconds, and no TCC prompt appeared (this is the behaviour 1.0.2 was written to guarantee; it was verified in the 1.0.2 round and is not re-run in this metadata pass).
  • State machine observed end to end: idle → recording → processing → idle; a silent take returns No speech detected instead of a bogus transcript.

Not covered by this round / 本轮未覆盖:

  • The physical global hotkey and the one-time Accessibility/Microphone grants need a human at the keyboard; they cannot be verified by an agent session and were not re-checked in this round.
  • Only macOS is supported by the app; nothing else was tested.

Version and marketplace registration / 版本与市场注册

  • New plugin directory external_plugins/voicetranser/ (4 files, 13 KiB), .zcode-plugin/plugin.json and the marketplace.json entry both at 1.0.2.
  • Category productivity; the icon lives at the repo-root path the entry uses (assets/voicetranser/icon.png, 512×512).
  • description_i18n carries en and zh-CN, identical in both files; README.md / README_CN.md both present.

Dependencies, network, permissions, side effects / 依赖、网络、权限与副作用

  • macOS with Python 3.12+ for the app; the skill installs it from https://github.com/Lumos-789/VoiceTranser.
  • Speech models are downloaded on first use (Qwen3-ASR 0.6B 4bit by default) — this is the only network access, and the READMEs document it. Transcription itself runs locally; no audio leaves the machine.
  • Writes the app checkout, its Python environment and models under the user's data directory, plus a launchd agent for the resident service. The installer generates the plist from the user's own checkout instead of shipping one.
  • Needs Microphone and Accessibility permissions, which the user grants through macOS; the diagnose command checks and reports them without prompting.

Licensing / provenance / 许可与来源

  • The plugin and the app are MIT (LICENSE in the product repository); the skill text is written for this submission.
  • No third-party code or assets are bundled; models are downloaded at run time under their own licences.

Self-check / 自查清单

  • Plugin name is unique kebab-case; new external plugin directory is external_plugins/voicetranser/; existing fixes retain ownership / 插件名唯一且 kebab-case,外部新增插件位于 external_plugins/voicetranser/,已有插件修复保留原归属
  • Usage category is set independently of publisher ownership / 用途分类 category 已填写,与维护归属分开:productivity
  • Plugin type and affected names are declared above / 已在上方声明插件类型与涉及的插件名称
  • version bumped in BOTH plugin.json and marketplace.json (artifacts are immutable) / plugin.json 与 marketplace.json 两处版本号已同步升级:1.0.2
  • README.md (EN) and README_CN.md (中文) both updated and equivalent / 中英文 README 均已更新且语义一致
  • description_i18n has both en and zh-CN / description_i18n 包含 en 与 zh-CN
  • No secrets, machine-specific paths, or private dependencies / 不含密钥、机器专属路径或私有依赖
  • Model/API/network dependencies documented / 模型、API、网络依赖已写明(见上方依赖小节与两个 README)
  • python3 scripts/validate.py passes on this branch, and the plugin artifact was built through the same build_zip() code path CI uses (size and sha256 in the comment below). The full python3 scripts/build_dist.py needs the repo's UI-plugin pnpm build and fails identically on upstream main (excalidraw: incomplete build), so CI runs it here — see the note above. / 本地 validate.py 通过,本插件产物用 CI 同一条 build_zip() 路径打出(体积与 sha256 见下方评论);完整 build_dist.py 依赖仓库自带 UI 插件的 pnpm build,在 main 上同样失败,交由 CI 执行

Skill-based installer/troubleshooter for the open-source VoiceTranser tool.
Source: https://github.com/Lumos-789/VoiceTranser
@panda920

panda920 commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

✅ Internal validation passed. A ZCode maintainer will review the change next; after acceptance, release checks run separately and this PR is closed automatically.

…ent checkout

Stop copying the author's hardcoded plist. install_launchd.py builds the plist from the user's own checkout path; diagnose aligns with the active engine and service label; three-engine docs refreshed.
@panda920

panda920 commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

✅ Internal validation passed. A ZCode maintainer will review the change next; after acceptance, release checks run separately and this PR is closed automatically.

@Lumos-789

Copy link
Copy Markdown
Author

1.0.1 — verification (2026-11-04)

Environment: ZCode CLI 0.17.1, macOS 27.0.1 arm64, Python 3.14.4 (app venv: 3.12.13).

Payload checks for external_plugins/voicetranser/ at this head: plugin.json well-formed, marketplace.json entry matches the plugin manifest verbatim (name / version / description / description_i18n), skill frontmatter valid, icon present. plugin_acceptance.py → PASS voicetranser@1.0.1.

Main repo (Lumos-789/VoiceTranser, 1.0.1) test suite: 29 passed, 1 deselected. The deselected case (test_stream_create_start_stop_all_guarded) imports sounddevice, which is installed only in the project's .venv (that interpreter has no pytest), so it was skipped rather than faked.

Not covered, and worth saying plainly: the actual product behaviour — global hotkey registration, macOS Accessibility/Microphone grants, and transcription on a clean machine — is a manual GUI checklist, not something this environment can assert. The bundled skill is install-and-troubleshoot guidance; it cannot prove the app runs.

…e mic

The diagnostic probes the microphone through a non-prompting authorization check and a 3s child-process timeout, so it always returns a verdict; the port has one source of truth (9877) and diagnose resolves it from the installed launchd plist, warning when it disagrees with the default.
@Lumos-789

Copy link
Copy Markdown
Author

Third round — review & simplification (2026-11-05)

No new features. The two substantive items:

1. The skill text existed twice and the copies had drifted. The ZCode payload carried its own SKILL.md while the product repo carried a different one — the payload copy told readers to run uv run python tests/diagnose.py, the repo copy said .venv/bin/python. Two documents, one of them wrong, depending on which you installed. The payload no longer keeps a copy: push_fork.py now reads the skill from the product repo, so there is one source of truth. (The payload's READMEs are intentionally different — they describe the plugin, not the tool.)

2. The repo now passes the public-release gate on the current tree — it had 6 findings, all from files that should not have been there:

  • com.voicetranser-sense.plist, the author's own launchd plist with absolute paths baked in. No code read it (install_launchd.py generates a per-user one), and the skill already warned readers not to copy it. A warning about a file is worse than no file.
  • voicetranser/hotkey.py, the pynput push-to-talk module replaced by the HTTP server. Zero references, pynput is not a dependency, and two documents each carried a line saying "deprecated, do not use".
  • PACKAGE.md (466 lines) was mostly a second copy of the README: install steps, hotkey, launchd, HTTP table, tech stack, troubleshooting — all already in README.md or the skill. What was unique (the architecture diagram, the three-state machine, the module responsibility table) moved to docs/architecture.md; the README gained the troubleshooting and uninstall sections it had been missing.
  • The machine-specific history in AGENTS.md (which instance is loaded, which plist was fixed on which date) moved to a gitignored .agents/ file, and the stale /Users/... line went with it.
  • .env.example still suggested SERVER_PORT=9876 after the port was unified on 9877; a stray .DS_Store was tracked.

Verification: 52 tests pass (re-run), public_release_gate repo reports 0 blocking findings (was 6), and the payload's four blobs match their sources byte-for-byte.

Not verified this round: the hotkey / accessibility flow and a fresh-user machine — the same gap as before. Nothing in this round touched the audio path.

Note on history: the --history audit still reports commits from before this round; rebuilding that history is a separate, destructive decision and has not been made.

@Lumos-789

Copy link
Copy Markdown
Author

Real-machine check of the 1.0.2 diagnose fix (2026-11-05)

The diagnostic used to be the riskiest part of this plugin — it opened an input stream regardless of microphone permission, so on a machine that had never granted it the check blocked on a macOS permission dialog. Verified live on macOS 27.0.1 / arm64:

Check Result
tests/diagnose.py --skip-audio 7/8 pass, 0 fail, 1 skipped, exit 1 — a skipped check cannot masquerade as green
tests/diagnose.py (full) 8/8 pass, 0 skipped, exit 0, returned in seconds — the audio probe ran inside its 3 s child-process bound and did not prompt
launchd service running (com.voicetranser-sense, pid present), GET /status → {"status": "idle"}
state machine over HTTP /start → recording → /stop → processing → idle
real transcription path Qwen3-ASR loaded and ran; a 2 s silent capture correctly returned No speech detected

Still not verified: the physical hotkey (press-and-hold via Karabiner) and a fresh-user machine — both need a human at the keyboard.

@panda920

panda920 commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

✅ Internal validation passed. A ZCode maintainer will review the change next; after acceptance, release checks run separately and this PR is closed automatically.

The marketplace entry named a relative icon path while every icon-bearing
entry in the catalogue uses the absolute CDN URL of assets/<name>/icon.png;
the file is now uploaded with the branch so the entry cannot dangle.
@Lumos-789 Lumos-789 changed the title feat: add voicetranser plugin (local push-to-talk voice input for macOS) feat(voicetranser): add the voicetranser push-to-talk voice input plugin (1.0.2) Nov 5, 2026
@Lumos-789

Copy link
Copy Markdown
Author

Re-pushed this branch as faa98274 and fixed two classes of defect that were ours, not the repository's. Nothing about the plugin's behaviour changed.

1. The PR now follows .github/PULL_REQUEST_TEMPLATE.md. The body had drifted into hand-written prose and lost the two parts a reviewer checks first: the Plugin type declaration and the Self-check list. Both are back, the five sections CONTRIBUTING asks for are filled in (problem / visible behaviour and testing / version and marketplace registration / dependencies and side effects / licensing), and the title carries the (<plugin-name>) scope the template requires for the squash commit on main.

2. The entry now uses the same absolute CDN form as every other icon-bearing entry in marketplace.json (https://cdn-zcode.z.ai/.../assets/voicetranser/icon.png); the file at assets/voicetranser/icon.png (512×512) is committed with the branch.

Re-verified against the branch itself (not a local checkout):

check result
python3 scripts/validate.py @ faa98274 OK: 53 plugin(s) validated
plugin artifact via build_zip() — the same code path CI runs 7521 B, sha256 f4005fa3b3faef2140a1f68beeec2770d7e788cc54326176f65cec89f2404bc3
assets/voicetranser/icon.png present, 512×512
README.md + README_CN.md in the payload both present

Request: the earlier validate status was bound to 1d55ab28, so it is stale after this push. Could you re-run the external validation on faa98274? The full build_dist.py still needs the repository's UI-plugin pnpm build and fails identically on main (excalidraw: incomplete build; run pnpm build first), which is why I am relying on CI for that step.

中文摘要:本轮只补元数据与载荷完整性 —— 恢复了模板要求的插件类型声明与自查清单、标题加上 (插件名) scope(模板说明该标题会成为 main 上的 squash commit)、把条目引用的根级图标真正提交并以 CDN 绝对地址引用。分支上 validate.py 通过,插件产物按 CI 同一代码路径打包成功(体积与 sha256 见上表)。旧的 validate 状态绑定在 1d55ab28 上已失效,请在 faa98274 上重跑一次校验。

The marketplace entry named a relative icon path while every icon-bearing
entry in the catalogue uses the absolute CDN URL of assets/<name>/icon.png;
the file is now uploaded with the branch so the entry cannot dangle.
@Lumos-789 Lumos-789 changed the title feat(voicetranser): add the voicetranser push-to-talk voice input plugin (1.0.2) feat(voicetranser): add the voicetranser push-to-talk voice input plugin (1.0.3) Nov 8, 2026
@Lumos-789

Copy link
Copy Markdown
Author

Update: payload bumped to 1.0.3 (head 72efa5c). Payload refreshed to the current main repo (byte-identical, verified MATCH). This round is a behavior-preserving cleanup: redundant comments and dead code removed, docs re-aligned with the code. Full test suite, packaging gates (plugin acceptance / simplify / public release) and the install lifecycle matrix all pass locally.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants