From 8d79d083be288b00680d65f3a260398877668214 Mon Sep 17 00:00:00 2001 From: Eason WaveKat Date: Sat, 15 Aug 2026 21:14:34 +1200 Subject: [PATCH 01/15] docs: spec Windows downloads across the three repos Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01P1W6SyAGqXSQUbDN4fHfUi --- docs/05-windows-downloads.md | 228 +++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 docs/05-windows-downloads.md diff --git a/docs/05-windows-downloads.md b/docs/05-windows-downloads.md new file mode 100644 index 0000000..395f85f --- /dev/null +++ b/docs/05-windows-downloads.md @@ -0,0 +1,228 @@ +# 05 — Windows downloads + +Offer the Windows installers we already build, pick the right architecture for +the machine asking, and stop telling readers — and answer engines — that +WaveKat Voice is Mac and Linux only. + +## 1. Where this starts + +We have been building a Windows client on every release for months. It is +packaged, uploaded, and published to an R2 update feed by the same workflow +that ships Mac and Linux, and `wavekat-voice/docs/site/installation.md` walks a +Windows reader through installing it. `wavekat-voice` `docs/54` puts the +resulting state plainly: + +> We already pay ~100% of the engineering and CI cost of a Windows client, and +> capture ~0% of the revenue, because the website will not offer a Windows +> visitor the installer we built for them twenty minutes ago. + +A Windows visitor to `/voice/download/` is handed a `.dmg`. This doc is that +document's Phase 1a and Phase 4, done together: offer the build, and say we +offer it. + +Two things changed recently that make this cheap: + +- **The platform already resolves Windows.** `docs/04` moved every download to + `platform.wavekat.com/api/voice/download/latest/{platform}`, and + `lib/downloads/latest.ts` shipped with `windows` in `PUBLISHED` + (`voice/latest.yml`, ext `exe`) and a comment saying which platforms get a + button is the site's decision. So the API side of the button already works. +- **Windows became two installers.** wavekat-voice `a3bc34c` added a native + Windows-on-ARM build: one electron-builder run now emits + `WaveKat Voice Setup -x64.exe` and `…-arm64.exe`, both listed in a + single `latest.yml`. + +That second change is what stops this from being a one-line site edit. + +## 2. The architecture problem + +`installerFromFeed()` picks the installer by extension: + +```ts +const name = files.find((f) => f.toLowerCase().endsWith(suffix)); +``` + +With one `.exe` in the feed that is correct. With two it is whichever +electron-builder happened to list first. An x64 visitor handed `arm64.exe` does +not get a slow download — they get a file Windows refuses to run. + +So the resolver has to name an architecture, and something has to decide which +one a given visitor wants. **We do not detect the chip.** The honest options +were a `navigator.userAgentData` probe (Chromium-only, async, and wrong on +every browser that doesn't implement it) or asking. We ask. + +## 3. Platform — targets instead of platforms + +`Published` stops meaning "operating system" and starts meaning "a thing you +can download": + +```ts +export type Published = 'mac' | 'linux' | 'windows-x64' | 'windows-arm64'; + +export const PUBLISHED: Record = { + mac: { feedKey: 'voice/latest-mac.yml', ext: 'dmg' }, + linux: { feedKey: 'voice/latest-linux.yml', ext: 'deb' }, + 'windows-x64': { feedKey: 'voice/latest.yml', ext: 'exe', arch: 'x64' }, + 'windows-arm64': { feedKey: 'voice/latest.yml', ext: 'exe', arch: 'arm64' }, +}; +``` + +Selection filters on extension **and** architecture, read through `classify()` +— which already parses `-x64` / `-arm64` out of a filename, and is the same +function that dimensions the row the download is logged on. Order in the feed +stops mattering, which is the point. + +### 3.1 The legacy-feed rule + +Every Windows release before `a3bc34c` was named `WaveKat Voice Setup 0.0.46.exe` +— no arch token, because electron-builder's arch suffix is empty for the +default arch. `classify()` reads that as `arch: null`. + +`windows-x64` therefore accepts `x64` **or** `null`: an unsuffixed Windows +installer has always meant x64. `windows-arm64` requires an exact match and +resolves to nothing until the first release built with the new `artifactName` +publishes. + +Without this rule the Windows button 404s on the currently-published feed, and +it would 404 quietly — the failure arrives at the visitor, not at us. + +### 3.2 `windows` stays as an alias + +`adminVoiceDownloads.ts` builds `latestUrl` from `classify()`'s platform, which +is still `mac | linux | windows`, so the admin artifacts page links at +`/download/latest/windows`. The download route normalises `windows` → +`windows-x64` before resolving. One line, and the alternative is an admin page +that 404s on a link nobody would think to test. + +`classify()`'s own `Platform` type is untouched. A download's *platform* is +still `windows`; only the *target you can ask for* is finer-grained. + +### 3.3 `GET /api/voice/releases/latest` + +Emits the four target keys, each with its own size: + +```json +{ "mac": { "version": "0.0.46", "sizeBytes": 126241228 }, + "linux": { "version": "0.0.46", "sizeBytes": 106304532 }, + "windows-x64": { "version": "0.0.46", "sizeBytes": 99000000 }, + "windows-arm64": { "version": "0.0.46", "sizeBytes": 97000000 } } +``` + +Per-target rather than per-platform because the two Windows installers differ +in size and the menu prints the size next to each choice. A platform that +cannot be resolved is still nulled rather than failing the response, so an +arm64 entry that does not exist yet costs nothing. + +## 4. Site — a primary button that asks + +### 4.1 `src/lib/voice-download.ts` + +`PlatformKey` gains both Windows targets, and the two named getters collapse +into `getDownload(key)`. The fallback constants keep one entry per target. + +### 4.2 `src/components/VoiceDownload.astro` + +Mac and Linux keep their one-click behaviour. Windows cannot have it — there +are two files and we refuse to guess — so the Windows primary is a ` ))} - {/* Other platforms — native
so it works without JS. */} -
- - {ui.dlOther} - + {/* Primary control for Windows: the same pill, but it opens the choice + between the two installers rather than downloading one of them. */} +
+ + + {windowsGroup.label} + -
+ + {/* Other platforms — native
so it works without JS. Each + group is WRAPPED, so promoting a platform toggles the wrapper while + a row's own hidden state stays about whether that file exists. Two + independent reasons to hide, on one element, is the bug this + avoids. */} +
+ + {ui.dlOther} + + +
+ {groups.map((g) => ( +
+ {g.rows.map((r) => ( + + ))} + {g.windows && ( +

+ {ui.dlWindowsUnsigned}{' '} + {ui.dlWindowsUnsignedLink} +

+ )} +
+ ))}
@@ -105,15 +238,15 @@ const primaryCls = honest for crawlers and the handful of readers without scripting. */} @@ -122,10 +255,10 @@ const primaryCls = From 2b861423b13f93a2e6a92a033e6898046985bb57 Mon Sep 17 00:00:00 2001 From: Eason WaveKat Date: Sun, 16 Aug 2026 13:10:31 +1200 Subject: [PATCH 14/15] fix(blog): posts that still say two platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two statements survived the Windows promotion sweep and now contradict the ones next to them. `click-to-call-phone-links` had its platforms FAQ rewritten to "Mac, Windows and Linux, the three platforms" but kept the following clause — "and it works on both" — in all nine locales. One sentence, two counts. The other four posts in that sweep say "all three"; this one was missed. `place-calls-from-the-command-line` opens with "It's built into the app today on Mac and Linux" while its own FAQ, three screens down, answers "Mac, Windows and Linux". The lead is the passage an answer engine lifts, so it was the wrong half to leave stale. Upstream `docs/voice/installation.md` calls Windows a supported platform and the automation doc limits the CLI to nothing, so "all three" is the true claim. Also drops a JSDoc line describing a design that didn't ship: `dlWindows` labels a button that downloads x64, not one that opens a choice. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01P1W6SyAGqXSQUbDN4fHfUi --- src/content/blog/click-to-call-phone-links.md | 2 +- src/content/blog/de/click-to-call-phone-links.md | 2 +- src/content/blog/de/place-calls-from-the-command-line.md | 2 +- src/content/blog/es/click-to-call-phone-links.md | 2 +- src/content/blog/es/place-calls-from-the-command-line.md | 2 +- src/content/blog/fr/click-to-call-phone-links.md | 2 +- src/content/blog/fr/place-calls-from-the-command-line.md | 2 +- src/content/blog/it/click-to-call-phone-links.md | 2 +- src/content/blog/it/place-calls-from-the-command-line.md | 2 +- src/content/blog/ja/click-to-call-phone-links.md | 2 +- src/content/blog/ja/place-calls-from-the-command-line.md | 2 +- src/content/blog/ko/click-to-call-phone-links.md | 2 +- src/content/blog/ko/place-calls-from-the-command-line.md | 2 +- src/content/blog/place-calls-from-the-command-line.md | 2 +- src/content/blog/zh-hant/click-to-call-phone-links.md | 2 +- src/content/blog/zh-hant/place-calls-from-the-command-line.md | 2 +- src/content/blog/zh/click-to-call-phone-links.md | 2 +- src/content/blog/zh/place-calls-from-the-command-line.md | 2 +- src/lib/i18n.ts | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/content/blog/click-to-call-phone-links.md b/src/content/blog/click-to-call-phone-links.md index 43f721d..e688033 100644 --- a/src/content/blog/click-to-call-phone-links.md +++ b/src/content/blog/click-to-call-phone-links.md @@ -51,7 +51,7 @@ No, not unless you ask it to. By default WaveKat Voice fills in the number and w ### Which platforms support click-to-call? -Mac, Windows and Linux, the three platforms WaveKat Voice runs on. Turn on Phone links in Settings → General and it works on both. +Mac, Windows and Linux, the three platforms WaveKat Voice runs on. Turn on Phone links in Settings → General and it works on all three. ### Does it work with sip: links too, or only tel: numbers? diff --git a/src/content/blog/de/click-to-call-phone-links.md b/src/content/blog/de/click-to-call-phone-links.md index 57f2782..36522a7 100644 --- a/src/content/blog/de/click-to-call-phone-links.md +++ b/src/content/blog/de/click-to-call-phone-links.md @@ -52,7 +52,7 @@ Nein, nur wenn Sie es so einstellen. Standardmäßig trägt WaveKat Voice die Nu ### Welche Plattformen unterstützen Click-to-call? -Mac, Windows und Linux, die drei Plattformen, auf denen WaveKat Voice läuft. Schalten Sie Telefon-Links unter Einstellungen → Allgemein ein, und es funktioniert auf beiden. +Mac, Windows und Linux, die drei Plattformen, auf denen WaveKat Voice läuft. Schalten Sie Telefon-Links unter Einstellungen → Allgemein ein, und es funktioniert auf allen dreien. ### Funktioniert es auch mit `sip:`-Links oder nur mit `tel:`-Nummern? diff --git a/src/content/blog/de/place-calls-from-the-command-line.md b/src/content/blog/de/place-calls-from-the-command-line.md index a992e8b..ba1bce0 100644 --- a/src/content/blog/de/place-calls-from-the-command-line.md +++ b/src/content/blog/de/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [Sprach-KI, Automatisierung, KI-Agenten] lang: "de" --- -WaveKat Voice liefert jetzt ein Kommandozeilenwerkzeug, sodass ein Programm, dem Sie vertrauen — darunter ein KI-Assistent wie Claude — echte Telefonanrufe für Sie tätigen und verwalten kann. Bitten Sie Ihren Assistenten, „die Zahnarztpraxis anzurufen und zu warten, bis jemand abnimmt", und er wählt über die App, die Sie bereits geöffnet haben, verfolgt den Anruf und teilt Ihnen mit, wie er verlaufen ist. Es ist heute auf Mac und Linux in die App eingebaut und bleibt ausgeschaltet, bis Sie es aktivieren. +WaveKat Voice liefert jetzt ein Kommandozeilenwerkzeug, sodass ein Programm, dem Sie vertrauen — darunter ein KI-Assistent wie Claude — echte Telefonanrufe für Sie tätigen und verwalten kann. Bitten Sie Ihren Assistenten, „die Zahnarztpraxis anzurufen und zu warten, bis jemand abnimmt", und er wählt über die App, die Sie bereits geöffnet haben, verfolgt den Anruf und teilt Ihnen mit, wie er verlaufen ist. Es ist heute auf Mac, Windows und Linux in die App eingebaut und bleibt ausgeschaltet, bis Sie es aktivieren. Das ist der nächste Schritt hin zu dem, worauf wir immer wieder zurückkommen: [jedem kleinen Unternehmen die Stimme eines großen zu geben](/de/blog/hello-world/). Ein großes Unternehmen hat eine Telefonzentrale und Software, die sie steuert. Jetzt können Ihr Computer — und der darauf laufende Assistent — diese Telefonzentrale sein. diff --git a/src/content/blog/es/click-to-call-phone-links.md b/src/content/blog/es/click-to-call-phone-links.md index 5968072..334ac7e 100644 --- a/src/content/blog/es/click-to-call-phone-links.md +++ b/src/content/blog/es/click-to-call-phone-links.md @@ -52,7 +52,7 @@ No, salvo que se lo pidas. Por defecto WaveKat Voice escribe el número y espera ### ¿Qué plataformas admiten el clic para llamar? -Mac, Windows y Linux, las tres plataformas en las que funciona WaveKat Voice. Activa Enlaces de teléfono en Ajustes → General y funciona en ambas. +Mac, Windows y Linux, las tres plataformas en las que funciona WaveKat Voice. Activa Enlaces de teléfono en Ajustes → General y funciona en las tres. ### ¿Funciona también con enlaces sip:, o solo con números tel:? diff --git a/src/content/blog/es/place-calls-from-the-command-line.md b/src/content/blog/es/place-calls-from-the-command-line.md index 9b71ffa..f40ff88 100644 --- a/src/content/blog/es/place-calls-from-the-command-line.md +++ b/src/content/blog/es/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [voz-ia, automatización, agentes-ia] lang: "es" --- -WaveKat Voice ahora incluye una herramienta de línea de comandos, para que un programa de su confianza —incluido un asistente de IA como Claude— pueda realizar y gestionar llamadas telefónicas reales por usted. Pídale a su asistente que "llame al dentista y espere hasta que alguien conteste", y marcará a través de la aplicación que ya tiene abierta, seguirá la llamada y le dirá cómo fue. Hoy está integrado en la aplicación en Mac y Linux, y permanece desactivado hasta que usted lo active. +WaveKat Voice ahora incluye una herramienta de línea de comandos, para que un programa de su confianza —incluido un asistente de IA como Claude— pueda realizar y gestionar llamadas telefónicas reales por usted. Pídale a su asistente que "llame al dentista y espere hasta que alguien conteste", y marcará a través de la aplicación que ya tiene abierta, seguirá la llamada y le dirá cómo fue. Hoy está integrado en la aplicación en Mac, Windows y Linux, y permanece desactivado hasta que usted lo active. Este es el siguiente paso hacia aquello a lo que siempre volvemos: [darle a cada pequeña empresa la voz de una grande](/es/blog/hello-world/). Una gran empresa tiene una centralita y el software que la maneja. Ahora su computadora —y el asistente que se ejecuta en ella— puede ser esa centralita. diff --git a/src/content/blog/fr/click-to-call-phone-links.md b/src/content/blog/fr/click-to-call-phone-links.md index 28ff3a6..a40cf48 100644 --- a/src/content/blog/fr/click-to-call-phone-links.md +++ b/src/content/blog/fr/click-to-call-phone-links.md @@ -52,7 +52,7 @@ Non, pas à moins que vous le demandiez. Par défaut, WaveKat Voice remplit le n ### Quelles plateformes prennent en charge le clic-pour-appeler ? -Mac, Windows et Linux, les trois plateformes sur lesquelles WaveKat Voice fonctionne. Activez les Liens téléphoniques dans Réglages → Général et ça fonctionne sur les deux. +Mac, Windows et Linux, les trois plateformes sur lesquelles WaveKat Voice fonctionne. Activez les Liens téléphoniques dans Réglages → Général et ça fonctionne sur les trois. ### Est-ce que ça marche aussi avec les liens sip:, ou seulement les numéros tel: ? diff --git a/src/content/blog/fr/place-calls-from-the-command-line.md b/src/content/blog/fr/place-calls-from-the-command-line.md index 0569bf6..3928f13 100644 --- a/src/content/blog/fr/place-calls-from-the-command-line.md +++ b/src/content/blog/fr/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [ia-vocale, automatisation, agents-ia] lang: "fr" --- -WaveKat Voice est désormais livré avec un outil en ligne de commande, pour qu'un programme en qui vous avez confiance — y compris un assistant IA comme Claude — puisse passer et gérer de vrais appels téléphoniques à votre place. Demandez à votre assistant d'« appeler le dentiste et d'attendre que quelqu'un décroche », et il compose le numéro via l'application que vous avez déjà ouverte, suit l'appel et vous dit comment il s'est déroulé. C'est intégré à l'application dès aujourd'hui sur Mac et Linux, et c'est désactivé jusqu'à ce que vous l'activiez. +WaveKat Voice est désormais livré avec un outil en ligne de commande, pour qu'un programme en qui vous avez confiance — y compris un assistant IA comme Claude — puisse passer et gérer de vrais appels téléphoniques à votre place. Demandez à votre assistant d'« appeler le dentiste et d'attendre que quelqu'un décroche », et il compose le numéro via l'application que vous avez déjà ouverte, suit l'appel et vous dit comment il s'est déroulé. C'est intégré à l'application dès aujourd'hui sur Mac, Windows et Linux, et c'est désactivé jusqu'à ce que vous l'activiez. C'est la prochaine étape vers ce à quoi nous revenons sans cesse : [donner à chaque petite entreprise la voix d'une grande](/fr/blog/hello-world/). Une grande entreprise dispose d'un standard téléphonique et d'un logiciel qui le pilote. Désormais, votre ordinateur — et l'assistant qui s'y exécute — peut être ce standard. diff --git a/src/content/blog/it/click-to-call-phone-links.md b/src/content/blog/it/click-to-call-phone-links.md index 6967da6..e93d20a 100644 --- a/src/content/blog/it/click-to-call-phone-links.md +++ b/src/content/blog/it/click-to-call-phone-links.md @@ -52,7 +52,7 @@ No, non a meno che tu non glielo chieda. Di default WaveKat Voice inserisce il n ### Quali piattaforme supportano il click-to-call? -Mac, Windows e Linux, le tre piattaforme su cui gira WaveKat Voice. Attiva i Link telefonici in Impostazioni → Generali e funziona su entrambe. +Mac, Windows e Linux, le tre piattaforme su cui gira WaveKat Voice. Attiva i Link telefonici in Impostazioni → Generali e funziona su tutte e tre. ### Funziona anche con i link sip:, o solo con i numeri tel:? diff --git a/src/content/blog/it/place-calls-from-the-command-line.md b/src/content/blog/it/place-calls-from-the-command-line.md index c3f6f0e..962fd18 100644 --- a/src/content/blog/it/place-calls-from-the-command-line.md +++ b/src/content/blog/it/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [voice-ai, automazione, ai-agents] lang: "it" --- -WaveKat Voice ora include uno strumento da riga di comando, così un programma di cui ti fidi — incluso un assistente AI come Claude — può effettuare e gestire vere telefonate per te. Chiedi al tuo assistente di "chiamare il dentista e aspettare finché qualcuno non risponde", e comporrà il numero attraverso l’app che hai già aperta, seguirà la chiamata e ti dirà com’è andata. Oggi è integrato nell’app su Mac e Linux, ed è disattivato finché non lo attivi. +WaveKat Voice ora include uno strumento da riga di comando, così un programma di cui ti fidi — incluso un assistente AI come Claude — può effettuare e gestire vere telefonate per te. Chiedi al tuo assistente di "chiamare il dentista e aspettare finché qualcuno non risponde", e comporrà il numero attraverso l’app che hai già aperta, seguirà la chiamata e ti dirà com’è andata. Oggi è integrato nell’app su Mac, Windows e Linux, ed è disattivato finché non lo attivi. Questo è il passo successivo verso ciò a cui torniamo sempre: [dare a ogni piccola impresa la voce di una grande](/it/blog/hello-world/). Una grande azienda ha un centralino e il software che lo guida. Ora il tuo computer — e l’assistente che ci gira sopra — può essere quel centralino. diff --git a/src/content/blog/ja/click-to-call-phone-links.md b/src/content/blog/ja/click-to-call-phone-links.md index 42abaa0..f7c0ea8 100644 --- a/src/content/blog/ja/click-to-call-phone-links.md +++ b/src/content/blog/ja/click-to-call-phone-links.md @@ -52,7 +52,7 @@ WaveKat Voice を使い始めたばかりですか? 電話リンクは、い ### クリック発信はどのプラットフォームで使えますか? -Mac・Windows・Linux、WaveKat Voice が動作する 3 つのプラットフォームです。設定 → 一般で電話リンクをオンにすれば、どちらでも使えます。 +Mac・Windows・Linux、WaveKat Voice が動作する 3 つのプラットフォームです。設定 → 一般で電話リンクをオンにすれば、3 つとも使えます。 ### tel: の番号だけでなく sip: リンクでも使えますか? diff --git a/src/content/blog/ja/place-calls-from-the-command-line.md b/src/content/blog/ja/place-calls-from-the-command-line.md index a0ed533..2680a06 100644 --- a/src/content/blog/ja/place-calls-from-the-command-line.md +++ b/src/content/blog/ja/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [音声AI, 自動化, AIエージェント] lang: "ja" --- -WaveKat Voice にコマンドラインツールが付属するようになりました。これにより、あなたが信頼するプログラム —— Claude のような AI アシスタントを含む —— が、あなたの代わりに本物の電話をかけたり管理したりできます。アシスタントに「歯医者に電話して、誰かが出るまで待って」と頼めば、すでに開いているアプリを通して発信し、通話を追い、結果がどうだったかを伝えてくれます。今日では Mac と Linux 上のアプリに組み込まれており、あなたが手動でオンにするまでは無効のままです。 +WaveKat Voice にコマンドラインツールが付属するようになりました。これにより、あなたが信頼するプログラム —— Claude のような AI アシスタントを含む —— が、あなたの代わりに本物の電話をかけたり管理したりできます。アシスタントに「歯医者に電話して、誰かが出るまで待って」と頼めば、すでに開いているアプリを通して発信し、通話を追い、結果がどうだったかを伝えてくれます。今日では Mac・Windows・Linux 上のアプリに組み込まれており、あなたが手動でオンにするまでは無効のままです。 これは、私たちが何度も立ち返るあの目標に向けた次の一歩です。[すべての小規模ビジネスに大企業のような声を](/ja/blog/hello-world/)。大企業には電話交換機と、それを動かすソフトウェアがあります。今や、あなたのコンピューター —— そしてその上で動くアシスタント —— が、その交換機になれるのです。 diff --git a/src/content/blog/ko/click-to-call-phone-links.md b/src/content/blog/ko/click-to-call-phone-links.md index 5d7e023..c963bda 100644 --- a/src/content/blog/ko/click-to-call-phone-links.md +++ b/src/content/blog/ko/click-to-call-phone-links.md @@ -52,7 +52,7 @@ WaveKat Voice가 처음이신가요? 가장 자연스러운 순간에 전화 링 ### 어떤 플랫폼에서 클릭투콜을 지원하나요? -WaveKat Voice가 실행되는 세 플랫폼인 Mac, Windows, Linux입니다. 설정 → 일반에서 전화 링크를 켜면 두 플랫폼 모두에서 작동합니다. +WaveKat Voice가 실행되는 세 플랫폼인 Mac, Windows, Linux입니다. 설정 → 일반에서 전화 링크를 켜면 세 플랫폼 모두에서 작동합니다. ### tel: 번호뿐 아니라 sip: 링크에서도 작동하나요? diff --git a/src/content/blog/ko/place-calls-from-the-command-line.md b/src/content/blog/ko/place-calls-from-the-command-line.md index 57399cc..077c4bb 100644 --- a/src/content/blog/ko/place-calls-from-the-command-line.md +++ b/src/content/blog/ko/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [음성AI, 자동화, AI에이전트] lang: "ko" --- -WaveKat Voice는 이제 명령줄 도구를 함께 제공합니다. 그래서 당신이 신뢰하는 프로그램 — Claude 같은 AI 어시스턴트를 포함해 — 이 당신을 대신해 실제 전화를 걸고 관리할 수 있습니다. 어시스턴트에게 "치과에 전화해서 누군가 받을 때까지 기다려"라고 요청하면, 이미 열려 있는 앱을 통해 전화를 걸고, 통화를 따라가며, 결과가 어땠는지 알려줍니다. 오늘날 Mac과 Linux의 앱에 내장되어 있으며, 당신이 켜기 전까지는 꺼져 있습니다. +WaveKat Voice는 이제 명령줄 도구를 함께 제공합니다. 그래서 당신이 신뢰하는 프로그램 — Claude 같은 AI 어시스턴트를 포함해 — 이 당신을 대신해 실제 전화를 걸고 관리할 수 있습니다. 어시스턴트에게 "치과에 전화해서 누군가 받을 때까지 기다려"라고 요청하면, 이미 열려 있는 앱을 통해 전화를 걸고, 통화를 따라가며, 결과가 어땠는지 알려줍니다. 오늘날 Mac, Windows, Linux의 앱에 내장되어 있으며, 당신이 켜기 전까지는 꺼져 있습니다. 이것은 우리가 계속 되돌아오는 그 목표를 향한 다음 단계입니다: [모든 소상공인에게 대기업과 같은 목소리를 주는 것](/ko/blog/hello-world/)입니다. 대기업에는 교환대와 그것을 구동하는 소프트웨어가 있습니다. 이제 당신의 컴퓨터 — 그리고 그 위에서 실행되는 어시스턴트 — 가 바로 그 교환대가 될 수 있습니다. diff --git a/src/content/blog/place-calls-from-the-command-line.md b/src/content/blog/place-calls-from-the-command-line.md index e8d4a43..a7b3389 100644 --- a/src/content/blog/place-calls-from-the-command-line.md +++ b/src/content/blog/place-calls-from-the-command-line.md @@ -6,7 +6,7 @@ author: Eason Guo tags: [voice-ai, automation, ai-agents] --- -WaveKat Voice now ships with a command-line tool, so a program you trust — including an AI assistant like Claude — can place and manage real phone calls for you. Ask your assistant to "call the dentist and wait until someone picks up," and it dials through the app you already have open, follows the call, and tells you how it went. It's built into the app today on Mac and Linux, and it's off until you switch it on. +WaveKat Voice now ships with a command-line tool, so a program you trust — including an AI assistant like Claude — can place and manage real phone calls for you. Ask your assistant to "call the dentist and wait until someone picks up," and it dials through the app you already have open, follows the call, and tells you how it went. It's built into the app today on Mac, Windows and Linux, and it's off until you switch it on. This is the next step toward the thing we keep coming back to: [giving every small business the voice of a big one](/blog/hello-world/). A big company has a switchboard and software that drives it. Now your computer — and the assistant running on it — can be that switchboard. diff --git a/src/content/blog/zh-hant/click-to-call-phone-links.md b/src/content/blog/zh-hant/click-to-call-phone-links.md index 7220795..6bfd508 100644 --- a/src/content/blog/zh-hant/click-to-call-phone-links.md +++ b/src/content/blog/zh-hant/click-to-call-phone-links.md @@ -52,7 +52,7 @@ lang: "zh-Hant" ### 哪些平台支援點按撥號? -Mac、Windows 和 Linux,也就是 WaveKat Voice 執行的三個平台。在 設定 → 一般 中打開電話連結,兩個平台都能用。 +Mac、Windows 和 Linux,也就是 WaveKat Voice 執行的三個平台。在 設定 → 一般 中打開電話連結,三個平台都能用。 ### 它也支援 sip: 連結嗎,還是只支援 tel: 號碼? diff --git a/src/content/blog/zh-hant/place-calls-from-the-command-line.md b/src/content/blog/zh-hant/place-calls-from-the-command-line.md index abc7d41..c27b86d 100644 --- a/src/content/blog/zh-hant/place-calls-from-the-command-line.md +++ b/src/content/blog/zh-hant/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [語音AI, 自動化, AI智慧代理] lang: "zh-Hant" --- -WaveKat Voice 現在附帶了一個命令列工具,讓你信任的程式——包括像 Claude 這樣的 AI 助理——可以替你撥打和管理真實電話。讓你的助理「打給牙醫,等到有人接聽為止」,它就會透過你已經打開的應用程式撥號、跟進通話,並告訴你結果如何。今天它已內建於 Mac 和 Linux 上的應用程式中,並且在你手動開啟之前一直處於關閉狀態。 +WaveKat Voice 現在附帶了一個命令列工具,讓你信任的程式——包括像 Claude 這樣的 AI 助理——可以替你撥打和管理真實電話。讓你的助理「打給牙醫,等到有人接聽為止」,它就會透過你已經打開的應用程式撥號、跟進通話,並告訴你結果如何。今天它已內建於 Mac、Windows 和 Linux 上的應用程式中,並且在你手動開啟之前一直處於關閉狀態。 這是邁向我們始終念念不忘的目標的下一步:[讓每一家小企業都擁有大企業的聲音](/zh-hant/blog/hello-world/)。大公司有總機和驅動總機的軟體。現在,你的電腦——以及執行在它上面的助理——就可以成為那個總機。 diff --git a/src/content/blog/zh/click-to-call-phone-links.md b/src/content/blog/zh/click-to-call-phone-links.md index 3143c64..bbdc0dd 100644 --- a/src/content/blog/zh/click-to-call-phone-links.md +++ b/src/content/blog/zh/click-to-call-phone-links.md @@ -52,7 +52,7 @@ lang: "zh-Hans" ### 哪些平台支持点击拨号? -Mac、Windows 和 Linux,也就是 WaveKat Voice 运行的三个平台。在 设置 → 通用 中打开电话链接,两个平台都能用。 +Mac、Windows 和 Linux,也就是 WaveKat Voice 运行的三个平台。在 设置 → 通用 中打开电话链接,三个平台都能用。 ### 它也支持 sip: 链接吗,还是只支持 tel: 号码? diff --git a/src/content/blog/zh/place-calls-from-the-command-line.md b/src/content/blog/zh/place-calls-from-the-command-line.md index c1e4904..56a8969 100644 --- a/src/content/blog/zh/place-calls-from-the-command-line.md +++ b/src/content/blog/zh/place-calls-from-the-command-line.md @@ -7,7 +7,7 @@ tags: [语音AI, 自动化, AI智能体] lang: "zh-Hans" --- -WaveKat Voice 现在附带了一个命令行工具,让你信任的程序——包括像 Claude 这样的 AI 助手——可以替你拨打和管理真实电话。让你的助手"打给牙医,等到有人接听为止",它就会通过你已经打开的应用拨号、跟进通话,并告诉你结果如何。今天它已内置于 Mac 和 Linux 上的应用中,并且在你手动开启之前一直处于关闭状态。 +WaveKat Voice 现在附带了一个命令行工具,让你信任的程序——包括像 Claude 这样的 AI 助手——可以替你拨打和管理真实电话。让你的助手"打给牙医,等到有人接听为止",它就会通过你已经打开的应用拨号、跟进通话,并告诉你结果如何。今天它已内置于 Mac、Windows 和 Linux 上的应用中,并且在你手动开启之前一直处于关闭状态。 这是迈向我们始终念念不忘的目标的下一步:[让每一家小企业都拥有大企业的声音](/zh/blog/hello-world/)。大公司有总机和驱动总机的软件。现在,你的电脑——以及运行在它上面的助手——就可以成为那个总机。 diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index c87f65c..b886060 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -210,7 +210,7 @@ export interface UIStrings { subTalk: string; dlMac: string; dlLinux: string; - /** Opens the choice between the two Windows installers, not a download. */ + /** Downloads the x64 installer — the build every Windows PC can run. */ dlWindows: string; dlWindowsArm64: string; dlOther: string; From 62266251a027b33ce97861666307423c51686dc1 Mon Sep 17 00:00:00 2001 From: Eason WaveKat Date: Sun, 16 Aug 2026 13:36:22 +1200 Subject: [PATCH 15/15] fix(voice): the /voice/ hero row and a 404 button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three gaps the review found, all of them the same shape: a rule this branch established and then applied incompletely. `678d7b2` re-aligned every row holding because the control grows ~46px taller once the unsigned-build note appears on Windows — but it missed `VoiceOverview.astro`, which is the `/voice/` hero in all nine locales. The sibling there is a small text link, the same shape as the alternatives and provider pages, so it takes `items-baseline` for the same reason those did. The promotion script only consulted `data-dl-avail` for a non-default arch, so the rule the file's own comment states — "a row for a file the platform says is missing would 404, so the same rule runs in reverse" — held for menu rows and not for primary buttons. A release that published `windows-arm64` but not `windows-x64` left an Intel visitor a visible "Download for Windows" button resolving to a 404, and `mac` was worse still: it is the SSR default, so it rendered shown regardless. The arch is now the first published candidate of `[activeArch, 'default']`, or none — no button beats a broken one, and the menu is still there. Exercised by running the shipped script over the built markup: Mac, Linux, Windows, Windows-on-ARM, Android and iPhone are unchanged in the live all-four-published state, and each degraded combination now hides the primary instead of pointing it at a missing file. CLAUDE.md still told the next author that Voice is "Mac and Linux today; Windows when there's demand", which would reintroduce the copy this branch just removed, and `.gitignore` swallowed all of `.claude/` when only the session worktrees and settings.local.json are local state. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01P1W6SyAGqXSQUbDN4fHfUi --- .gitignore | 7 +++++-- CLAUDE.md | 10 ++++++---- src/components/VoiceDownload.astro | 25 +++++++++++++++++-------- src/components/VoiceOverview.astro | 7 ++++++- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 73e7f41..011cf44 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,8 @@ Thumbs.db *.sln *.sw? -# Claude Code local state — session worktrees are git repos of their own -.claude/ +# Claude Code local state — session worktrees are git repos of their own, and +# settings.local.json is per-machine. Scoped, not the whole `.claude/`: shared +# project config (settings.json, agents/, skills/) is meant to be committed. +.claude/worktrees/ +.claude/settings.local.json diff --git a/CLAUDE.md b/CLAUDE.md index 459aa18..834318b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -95,8 +95,9 @@ This site is optimized for classic search (SEO) **and** generative answer engine - **Q&A blocks earn their keep twice** — they render as a human FAQ *and* feed `FAQPage` schema *and* are the single most-quoted structure in AI answers. Phrase questions the way a user would type them ("Can WaveKat Voice connect to the same SIP provider as Linphone?"), and answer in 1–3 plain sentences. - **Comparison tables are extractable gold.** Keep cells short, factual, and parallel across rows; models lift table rows almost verbatim into "X vs Y" answers. - **Be specific and honest.** Concrete specifics (platforms, versions, prices, "records every call automatically") get quoted; vague superlatives get skipped. On comparison pages, name what the competitor is genuinely good at — fair framing reads as a trustworthy source to both readers and models, and avoids the "marketing fluff" discount. -- **Keep entity naming consistent.** Always "WaveKat Voice" (not "the app", "Voice", "WaveKat" interchangeably) so engines bind the facts to one entity. Same for platform claims — match the truth in `voice/index.astro` (Mac and Linux today; Windows when there's demand). -- **Don't target a single platform in copy.** Voice is Mac + Linux today; write "your computer" / "desktop" in body copy and put the platforms in a table row or a "Mac & Linux" qualifier. Titles may still include "Mac" to catch the high-volume "… for Mac" queries, but never *exclude* Linux. +- **Keep entity naming consistent.** Always "WaveKat Voice" (not "the app", "Voice", "WaveKat" interchangeably) so engines bind the facts to one entity. Same for platform claims — match the truth in `voice/index.astro` (**Mac, Windows and Linux**; Windows ships an x64 and an ARM64 installer, is younger than the other two, and isn't code-signed yet). +- **Don't target a single platform in copy.** Voice runs on all three desktops; write "your computer" / "desktop" in body copy and put the platforms in a table row or a "Mac, Windows & Linux" qualifier. Titles may still include "Mac" to catch the high-volume "… for Mac" queries, but never *exclude* the other two. +- **A platform claim is never one sentence.** Promoting a platform means the lead, the meta description, the FAQ answer, *and* the clause after it ("works on both" → "all three") — in all nine locales. Changing only the FAQ leaves the page contradicting itself, and the lead is the passage answer engines quote first. `grep` the whole post, not the section you came for. When you add a page that doesn't fit the patterns above, mirror the closest existing one (`voice/alternatives/[slug].astro` is the current best example: clear `

`, self-contained intro, comparison table, fair "what it is", Q&A, and `FAQPage` + `BreadcrumbList` schema). @@ -176,8 +177,9 @@ is the same page scrolled to the assistants section (a scene `scroll` hint, sinc it's below the 960×640 fold). - **Framed, not bare.** These use the pipeline's **Ubuntu/GNOME-framed** output - (`screenshots/framed/ubuntu/…`), so the window chrome is real, not CSS — we're - a Mac + Linux product and the author runs Ubuntu. No site-drawn frame. + (`screenshots/framed/ubuntu/…`), so the window chrome is real, not CSS — the + app is a desktop app on every platform and the author runs Ubuntu. No + site-drawn frame. - **Single theme (light), per language.** A baked-in frame can't follow the page's dark/light toggle, so we pick light and keep it consistent — but each localized surface shows the app in *its* language (`/screenshots//.webp`). diff --git a/src/components/VoiceDownload.astro b/src/components/VoiceDownload.astro index b852533..4f4daf9 100644 --- a/src/components/VoiceDownload.astro +++ b/src/components/VoiceDownload.astro @@ -391,16 +391,25 @@ const noteCls = } function resolve() { document.querySelectorAll('[data-voice-download]').forEach(function (root) { - // Fall back to the arch every machine can run if the one we'd - // rather serve isn't published in the current release. Decided - // per root and per call, so the release refresh below can - // withdraw or restore the choice by re-running this. - var arch = activeArch; - if (arch !== 'default') { + // Pick the first arch this release actually published: the one + // we'd rather serve, then the one every machine of this platform + // can run. `null` if it published neither, which shows no primary + // at all — the menu is still there, and an unpublished target + // behind a visible button is a 404, which is the one outcome + // worse than an extra click. The same rule the menu rows follow, + // so the two can't disagree about what exists. Decided per root + // and per call, so the release refresh below can withdraw or + // restore the choice by re-running this. + var order = activeArch === 'default' ? ['default'] : [activeArch, 'default']; + var arch = null; + for (var i = 0; i < order.length; i++) { var want = root.querySelector( - '[data-dl-primary="' + active + '"][data-dl-arch="' + arch + '"]', + '[data-dl-primary="' + active + '"][data-dl-arch="' + order[i] + '"]', ); - if (!want || want.dataset.dlAvail === '0') arch = 'default'; + if (want && want.dataset.dlAvail !== '0') { + arch = order[i]; + break; + } } root.querySelectorAll('[data-dl-primary]').forEach(function (el) { setShown(el, el.dataset.dlPrimary === active && el.dataset.dlArch === arch); diff --git a/src/components/VoiceOverview.astro b/src/components/VoiceOverview.astro index 89ea025..734340c 100644 --- a/src/components/VoiceOverview.astro +++ b/src/components/VoiceOverview.astro @@ -138,7 +138,12 @@ const { {intro}

-
+ {/* `items-baseline`, not `items-center`: the unsigned-build note lives inside + the download control and only appears once the promotion script picks + Windows, so the control is ~46px taller for a Windows visitor and would + drop this link by half that. The sibling is a small text link, so + baseline — not `items-start`, which would slam it to the top of the pill. */} +