@tractorscorch/clank 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [1.3.1] — 2026-03-23
10
+
11
+ ### Fixed
12
+ - **STT not working** — local whisper.cpp was selected by default but not installed. Added Groq as the recommended free STT provider (whisper-large-v3-turbo).
13
+ - **STT provider priority:** Groq (free, fast) → OpenAI Whisper → local whisper.cpp
14
+ - **Setup wizard:** STT now offers Groq as option 1 (recommended), OpenAI as option 2, local as option 3
15
+
16
+ ---
17
+
9
18
  ## [1.3.0] — 2026-03-23
10
19
 
11
20
  ### Added
package/dist/index.js CHANGED
@@ -3931,11 +3931,9 @@ var init_tts = __esm({
3931
3931
  constructor(config) {
3932
3932
  this.config = config;
3933
3933
  }
3934
- /** Check if TTS is available */
3935
3934
  isAvailable() {
3936
3935
  return !!(this.config.integrations.elevenlabs?.enabled && this.config.integrations.elevenlabs?.apiKey);
3937
3936
  }
3938
- /** Convert text to speech */
3939
3937
  async synthesize(text, opts) {
3940
3938
  const elevenlabs = this.config.integrations.elevenlabs;
3941
3939
  if (!elevenlabs?.enabled || !elevenlabs.apiKey) return null;
@@ -3953,29 +3951,21 @@ var init_tts = __esm({
3953
3951
  body: JSON.stringify({
3954
3952
  text,
3955
3953
  model_id: model,
3956
- voice_settings: {
3957
- stability: 0.5,
3958
- similarity_boost: 0.75
3959
- }
3954
+ voice_settings: { stability: 0.5, similarity_boost: 0.75 }
3960
3955
  })
3961
3956
  }
3962
3957
  );
3963
3958
  if (!res.ok) {
3964
- const err = await res.text().catch(() => "");
3965
- console.error(`ElevenLabs TTS error ${res.status}: ${err}`);
3959
+ console.error(`ElevenLabs TTS error ${res.status}`);
3966
3960
  return null;
3967
3961
  }
3968
3962
  const arrayBuffer = await res.arrayBuffer();
3969
- return {
3970
- audioBuffer: Buffer.from(arrayBuffer),
3971
- format: "mp3"
3972
- };
3963
+ return { audioBuffer: Buffer.from(arrayBuffer), format: "mp3" };
3973
3964
  } catch (err) {
3974
3965
  console.error(`TTS error: ${err instanceof Error ? err.message : err}`);
3975
3966
  return null;
3976
3967
  }
3977
3968
  }
3978
- /** List available voices from ElevenLabs */
3979
3969
  async listVoices() {
3980
3970
  const elevenlabs = this.config.integrations.elevenlabs;
3981
3971
  if (!elevenlabs?.enabled || !elevenlabs.apiKey) return [];
@@ -3996,41 +3986,55 @@ var init_tts = __esm({
3996
3986
  constructor(config) {
3997
3987
  this.config = config;
3998
3988
  }
3999
- /** Check if STT is available */
4000
3989
  isAvailable() {
4001
3990
  const whisper = this.config.integrations.whisper;
4002
3991
  if (whisper?.enabled) {
3992
+ if (whisper.provider === "groq" && whisper.apiKey) return true;
4003
3993
  if (whisper.provider === "openai" && whisper.apiKey) return true;
4004
3994
  if (whisper.provider === "local") return true;
4005
3995
  }
4006
3996
  if (this.config.models.providers.openai?.apiKey) return true;
3997
+ if (this.config.integrations.groq?.apiKey) return true;
4007
3998
  return false;
4008
3999
  }
4009
- /** Transcribe audio to text */
4010
4000
  async transcribe(audioBuffer, format = "ogg") {
4011
4001
  const whisper = this.config.integrations.whisper;
4012
- const apiKey = whisper?.apiKey || this.config.models.providers.openai?.apiKey;
4013
- if (apiKey && whisper?.provider !== "local") {
4014
- return this.transcribeOpenAI(audioBuffer, format, apiKey);
4002
+ const groqKey = whisper?.provider === "groq" && whisper?.apiKey ? whisper.apiKey : this.config.integrations.groq?.apiKey;
4003
+ if (groqKey) {
4004
+ const result = await this.transcribeAPI(audioBuffer, format, groqKey, "https://api.groq.com/openai/v1/audio/transcriptions", "whisper-large-v3-turbo");
4005
+ if (result) return result;
4006
+ }
4007
+ const openaiKey = whisper?.provider === "openai" && whisper?.apiKey ? whisper.apiKey : this.config.models.providers.openai?.apiKey;
4008
+ if (openaiKey) {
4009
+ const result = await this.transcribeAPI(audioBuffer, format, openaiKey, "https://api.openai.com/v1/audio/transcriptions", "whisper-1");
4010
+ if (result) return result;
4011
+ }
4012
+ if (whisper?.provider === "local") {
4013
+ return this.transcribeLocal(audioBuffer, format);
4015
4014
  }
4016
- return this.transcribeLocal(audioBuffer, format);
4015
+ return null;
4017
4016
  }
4018
- /** Transcribe via OpenAI Whisper API */
4019
- async transcribeOpenAI(audioBuffer, format, apiKey) {
4017
+ /** Transcribe via OpenAI-compatible API (works for both OpenAI and Groq) */
4018
+ async transcribeAPI(audioBuffer, format, apiKey, endpoint, model) {
4020
4019
  try {
4021
4020
  const blob = new Blob([new Uint8Array(audioBuffer)], { type: `audio/${format}` });
4022
4021
  const formData = new FormData();
4023
4022
  formData.append("file", blob, `audio.${format}`);
4024
- formData.append("model", "whisper-1");
4025
- const res = await fetch("https://api.openai.com/v1/audio/transcriptions", {
4023
+ formData.append("model", model);
4024
+ const res = await fetch(endpoint, {
4026
4025
  method: "POST",
4027
4026
  headers: { "Authorization": `Bearer ${apiKey}` },
4028
4027
  body: formData
4029
4028
  });
4030
- if (!res.ok) return null;
4029
+ if (!res.ok) {
4030
+ const errText = await res.text().catch(() => "");
4031
+ console.error(`STT API error ${res.status}: ${errText.slice(0, 200)}`);
4032
+ return null;
4033
+ }
4031
4034
  const data = await res.json();
4032
4035
  return data.text ? { text: data.text, language: data.language } : null;
4033
- } catch {
4036
+ } catch (err) {
4037
+ console.error(`STT error: ${err instanceof Error ? err.message : err}`);
4034
4038
  return null;
4035
4039
  }
4036
4040
  }
@@ -5673,7 +5677,7 @@ var init_server = __esm({
5673
5677
  res.writeHead(200, { "Content-Type": "application/json" });
5674
5678
  res.end(JSON.stringify({
5675
5679
  status: "ok",
5676
- version: "1.3.0",
5680
+ version: "1.3.1",
5677
5681
  uptime: process.uptime(),
5678
5682
  clients: this.clients.size,
5679
5683
  agents: this.engines.size
@@ -5781,7 +5785,7 @@ var init_server = __esm({
5781
5785
  const hello = {
5782
5786
  type: "hello",
5783
5787
  protocol: PROTOCOL_VERSION,
5784
- version: "1.3.0",
5788
+ version: "1.3.1",
5785
5789
  agents: this.config.agents.list.map((a) => ({
5786
5790
  id: a.id,
5787
5791
  name: a.name || a.id,
@@ -6642,27 +6646,35 @@ async function runSetup(opts) {
6642
6646
  console.log(green4(" ElevenLabs configured (TTS available)"));
6643
6647
  }
6644
6648
  }
6645
- const addWhisper = await ask(rl, cyan2(" Set up speech-to-text (Whisper)? [y/N] "));
6649
+ const addWhisper = await ask(rl, cyan2(" Set up speech-to-text (voice messages)? [y/N] "));
6646
6650
  if (addWhisper.toLowerCase() === "y") {
6647
- console.log(dim4(" 1. OpenAI Whisper API (cloud, uses OpenAI key)"));
6648
- console.log(dim4(" 2. Local whisper.cpp (requires whisper installed)"));
6651
+ console.log(dim4(" 1. Groq (recommended \u2014 free, fast)"));
6652
+ console.log(dim4(" 2. OpenAI Whisper API (paid, uses OpenAI key)"));
6653
+ console.log(dim4(" 3. Local whisper.cpp (requires manual install)"));
6649
6654
  const whisperChoice = await ask(rl, cyan2(" Choice [1]: "));
6650
- if (whisperChoice === "2") {
6655
+ if (whisperChoice === "3") {
6651
6656
  config.integrations.whisper = { enabled: true, provider: "local" };
6652
6657
  console.log(green4(" Local whisper.cpp configured"));
6653
6658
  console.log(dim4(" Make sure whisper is installed and in PATH"));
6654
- } else {
6659
+ } else if (whisperChoice === "2") {
6655
6660
  const existingKey = config.models.providers.openai?.apiKey;
6656
6661
  if (existingKey) {
6657
6662
  config.integrations.whisper = { enabled: true, provider: "openai", apiKey: existingKey };
6658
6663
  console.log(green4(" Whisper configured (using existing OpenAI key)"));
6659
6664
  } else {
6660
- const key = await ask(rl, cyan2(" OpenAI API key for Whisper: "));
6665
+ const key = await ask(rl, cyan2(" OpenAI API key: "));
6661
6666
  if (key.trim()) {
6662
6667
  config.integrations.whisper = { enabled: true, provider: "openai", apiKey: key.trim() };
6663
6668
  console.log(green4(" Whisper configured"));
6664
6669
  }
6665
6670
  }
6671
+ } else {
6672
+ console.log(dim4(" Get a free API key at: https://console.groq.com/keys"));
6673
+ const key = await ask(rl, cyan2(" Groq API key: "));
6674
+ if (key.trim()) {
6675
+ config.integrations.whisper = { enabled: true, provider: "groq", apiKey: key.trim() };
6676
+ console.log(green4(" Groq Whisper configured (free, fast)"));
6677
+ }
6666
6678
  }
6667
6679
  }
6668
6680
  if (isAdvanced) {
@@ -7138,7 +7150,7 @@ async function runTui(opts) {
7138
7150
  ws.on("open", () => {
7139
7151
  ws.send(JSON.stringify({
7140
7152
  type: "connect",
7141
- params: { auth: { token }, mode: "tui", version: "1.3.0" }
7153
+ params: { auth: { token }, mode: "tui", version: "1.3.1" }
7142
7154
  }));
7143
7155
  });
7144
7156
  ws.on("message", (data) => {
@@ -7567,7 +7579,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
7567
7579
  import { dirname as dirname5, join as join18 } from "path";
7568
7580
  var __filename3 = fileURLToPath5(import.meta.url);
7569
7581
  var __dirname3 = dirname5(__filename3);
7570
- var version = "1.3.0";
7582
+ var version = "1.3.1";
7571
7583
  try {
7572
7584
  const pkg = JSON.parse(readFileSync(join18(__dirname3, "..", "package.json"), "utf-8"));
7573
7585
  version = pkg.version;