@tractorscorch/clank 1.4.4 → 1.4.6

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,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [1.4.6] — 2026-03-22
10
+
11
+ ### Fixed
12
+ - **Telegram stutter (for real)** — when the model responds fast, the initial `sendMessage` promise hasn't resolved by the time the full response is ready, causing a duplicate message via the fallback path; now waits for the in-flight message ID before falling back
13
+
14
+ ---
15
+
16
+ ## [1.4.5] — 2026-03-22
17
+
18
+ ### Fixed
19
+ - **Gateway unresponsive after messages** — WebSocket frame handler was not awaited, causing unhandled promise rejections that silently killed the gateway process
20
+ - **Added `unhandledRejection` handler** — gateway now logs rejected promises instead of dying silently
21
+ - **Provider timeout fallback** — all providers (Ollama, Anthropic, OpenAI, Google) now have a fallback timeout (120s local, 90s cloud) if no abort signal is provided, preventing indefinite hangs when a model is unresponsive
22
+
23
+ ---
24
+
9
25
  ## [1.4.4] — 2026-03-22
10
26
 
11
27
  ### Fixed
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.4.4-blue.svg" alt="Version" /></a>
12
+ <a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.4.6-blue.svg" alt="Version" /></a>
13
13
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License" /></a>
14
14
  <a href="https://www.npmjs.com/package/@tractorscorch/clank"><img src="https://img.shields.io/npm/v/@tractorscorch/clank.svg" alt="npm" /></a>
15
15
  <a href="https://github.com/ItsTrag1c/Clank/stargazers"><img src="https://img.shields.io/github/stars/ItsTrag1c/Clank.svg" alt="Stars" /></a>
@@ -75,7 +75,7 @@ That's it. Setup auto-detects your local models, configures the gateway, and get
75
75
  | Platform | Download |
76
76
  |----------|----------|
77
77
  | **npm** (all platforms) | `npm install -g @tractorscorch/clank` |
78
- | **macOS** (Apple Silicon) | [Clank_1.4.4_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.4.4_macos) |
78
+ | **macOS** (Apple Silicon) | [Clank_1.4.6_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.4.6_macos) |
79
79
 
80
80
  ## Features
81
81
 
package/dist/index.js CHANGED
@@ -513,11 +513,12 @@ var init_ollama = __esm({
513
513
  if (this.maxResponseTokens) {
514
514
  body.max_tokens = this.maxResponseTokens;
515
515
  }
516
+ const effectiveSignal = signal || AbortSignal.timeout(12e4);
516
517
  const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
517
518
  method: "POST",
518
519
  headers: { "Content-Type": "application/json" },
519
520
  body: JSON.stringify(body),
520
- signal
521
+ signal: effectiveSignal
521
522
  });
522
523
  if (!res.ok) {
523
524
  const text = await res.text().catch(() => "Unknown error");
@@ -2708,6 +2709,7 @@ var init_anthropic = __esm({
2708
2709
  if (tools.length > 0) {
2709
2710
  body.tools = this.formatTools(tools);
2710
2711
  }
2712
+ const effectiveSignal = signal || AbortSignal.timeout(9e4);
2711
2713
  const res = await fetch(`${this.baseUrl}/v1/messages`, {
2712
2714
  method: "POST",
2713
2715
  headers: {
@@ -2716,7 +2718,7 @@ var init_anthropic = __esm({
2716
2718
  "anthropic-version": "2023-06-01"
2717
2719
  },
2718
2720
  body: JSON.stringify(body),
2719
- signal
2721
+ signal: effectiveSignal
2720
2722
  });
2721
2723
  if (!res.ok) {
2722
2724
  const text = await res.text().catch(() => "Unknown error");
@@ -2934,11 +2936,12 @@ var init_openai = __esm({
2934
2936
  if (this.apiKey) {
2935
2937
  headers["Authorization"] = `Bearer ${this.apiKey}`;
2936
2938
  }
2939
+ const effectiveSignal = signal || AbortSignal.timeout(9e4);
2937
2940
  const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
2938
2941
  method: "POST",
2939
2942
  headers,
2940
2943
  body: JSON.stringify(body),
2941
- signal
2944
+ signal: effectiveSignal
2942
2945
  });
2943
2946
  if (!res.ok) {
2944
2947
  const text = await res.text().catch(() => "Unknown error");
@@ -3160,11 +3163,12 @@ var init_google = __esm({
3160
3163
  body.tools = this.formatTools(tools);
3161
3164
  }
3162
3165
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:streamGenerateContent?key=${this.apiKey}&alt=sse`;
3166
+ const effectiveSignal = signal || AbortSignal.timeout(9e4);
3163
3167
  const res = await fetch(url, {
3164
3168
  method: "POST",
3165
3169
  headers: { "Content-Type": "application/json" },
3166
3170
  body: JSON.stringify(body),
3167
- signal
3171
+ signal: effectiveSignal
3168
3172
  });
3169
3173
  if (!res.ok) {
3170
3174
  const text = await res.text().catch(() => "Unknown error");
@@ -5271,6 +5275,20 @@ var init_telegram = __esm({
5271
5275
  }
5272
5276
  }
5273
5277
  );
5278
+ if (sendingInitial && !streamMsgId) {
5279
+ await new Promise((r) => {
5280
+ const check2 = setInterval(() => {
5281
+ if (streamMsgId) {
5282
+ clearInterval(check2);
5283
+ r();
5284
+ }
5285
+ }, 50);
5286
+ setTimeout(() => {
5287
+ clearInterval(check2);
5288
+ r();
5289
+ }, 3e3);
5290
+ });
5291
+ }
5274
5292
  if (streamMsgId && response) {
5275
5293
  const finalText = response.length > 4e3 ? response.slice(0, 3950) + "\n... (truncated)" : response;
5276
5294
  await bot.api.editMessageText(chatId, streamMsgId, finalText).catch(() => {
@@ -5893,6 +5911,9 @@ var init_server = __esm({
5893
5911
  }
5894
5912
  /** Start the gateway server */
5895
5913
  async start() {
5914
+ process.on("unhandledRejection", (err) => {
5915
+ console.error(` Unhandled rejection: ${err instanceof Error ? err.message : err}`);
5916
+ });
5896
5917
  if (this.config.gateway.auth.mode === "token" && !this.config.gateway.auth.token) {
5897
5918
  const { randomBytes: randomBytes2 } = await import("crypto");
5898
5919
  this.config.gateway.auth.token = randomBytes2(16).toString("hex");
@@ -6057,7 +6078,7 @@ var init_server = __esm({
6057
6078
  res.writeHead(200, { "Content-Type": "application/json" });
6058
6079
  res.end(JSON.stringify({
6059
6080
  status: "ok",
6060
- version: "1.4.4",
6081
+ version: "1.4.6",
6061
6082
  uptime: process.uptime(),
6062
6083
  clients: this.clients.size,
6063
6084
  agents: this.engines.size
@@ -6118,7 +6139,11 @@ var init_server = __esm({
6118
6139
  this.clients.set(ws, client);
6119
6140
  ws.on("message", (data) => {
6120
6141
  const frame = parseFrame(data.toString());
6121
- if (frame) this.handleFrame(client, frame);
6142
+ if (frame) {
6143
+ this.handleFrame(client, frame).catch((err) => {
6144
+ console.error(` Frame handler error: ${err instanceof Error ? err.message : err}`);
6145
+ });
6146
+ }
6122
6147
  });
6123
6148
  ws.on("close", () => {
6124
6149
  this.clients.delete(ws);
@@ -6165,7 +6190,7 @@ var init_server = __esm({
6165
6190
  const hello = {
6166
6191
  type: "hello",
6167
6192
  protocol: PROTOCOL_VERSION,
6168
- version: "1.4.4",
6193
+ version: "1.4.6",
6169
6194
  agents: this.config.agents.list.map((a) => ({
6170
6195
  id: a.id,
6171
6196
  name: a.name || a.id,
@@ -7559,7 +7584,7 @@ async function runTui(opts) {
7559
7584
  ws.on("open", () => {
7560
7585
  ws.send(JSON.stringify({
7561
7586
  type: "connect",
7562
- params: { auth: { token }, mode: "tui", version: "1.4.4" }
7587
+ params: { auth: { token }, mode: "tui", version: "1.4.6" }
7563
7588
  }));
7564
7589
  });
7565
7590
  ws.on("message", (data) => {
@@ -7861,14 +7886,14 @@ async function runUpdate() {
7861
7886
  }
7862
7887
  console.log(dim9(" Pulling latest version..."));
7863
7888
  try {
7864
- const output = execSync2("npm install -g @tractorscorch/clank@latest --force", {
7889
+ const output = execSync2("npm install -g @tractorscorch/clank@latest --force --prefer-online", {
7865
7890
  encoding: "utf-8",
7866
7891
  timeout: 12e4
7867
7892
  });
7868
7893
  console.log(dim9(` ${output.trim()}`));
7869
7894
  } catch (err) {
7870
7895
  console.error(red6(` Update failed: ${err instanceof Error ? err.message : err}`));
7871
- console.error(dim9(" Try manually: npm install -g @tractorscorch/clank@latest --force"));
7896
+ console.error(dim9(" Try manually: npm install -g @tractorscorch/clank@latest --force --prefer-online"));
7872
7897
  return;
7873
7898
  }
7874
7899
  try {
@@ -7988,7 +8013,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
7988
8013
  import { dirname as dirname5, join as join19 } from "path";
7989
8014
  var __filename3 = fileURLToPath5(import.meta.url);
7990
8015
  var __dirname3 = dirname5(__filename3);
7991
- var version = "1.4.4";
8016
+ var version = "1.4.6";
7992
8017
  try {
7993
8018
  const pkg = JSON.parse(readFileSync(join19(__dirname3, "..", "package.json"), "utf-8"));
7994
8019
  version = pkg.version;