@tractorscorch/clank 1.4.4 → 1.4.5

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.4.5] — 2026-03-22
10
+
11
+ ### Fixed
12
+ - **Gateway unresponsive after messages** — WebSocket frame handler was not awaited, causing unhandled promise rejections that silently killed the gateway process
13
+ - **Added `unhandledRejection` handler** — gateway now logs rejected promises instead of dying silently
14
+ - **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
15
+
16
+ ---
17
+
9
18
  ## [1.4.4] — 2026-03-22
10
19
 
11
20
  ### 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.5-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.5_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.4.5_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");
@@ -5893,6 +5897,9 @@ var init_server = __esm({
5893
5897
  }
5894
5898
  /** Start the gateway server */
5895
5899
  async start() {
5900
+ process.on("unhandledRejection", (err) => {
5901
+ console.error(` Unhandled rejection: ${err instanceof Error ? err.message : err}`);
5902
+ });
5896
5903
  if (this.config.gateway.auth.mode === "token" && !this.config.gateway.auth.token) {
5897
5904
  const { randomBytes: randomBytes2 } = await import("crypto");
5898
5905
  this.config.gateway.auth.token = randomBytes2(16).toString("hex");
@@ -6057,7 +6064,7 @@ var init_server = __esm({
6057
6064
  res.writeHead(200, { "Content-Type": "application/json" });
6058
6065
  res.end(JSON.stringify({
6059
6066
  status: "ok",
6060
- version: "1.4.4",
6067
+ version: "1.4.5",
6061
6068
  uptime: process.uptime(),
6062
6069
  clients: this.clients.size,
6063
6070
  agents: this.engines.size
@@ -6118,7 +6125,11 @@ var init_server = __esm({
6118
6125
  this.clients.set(ws, client);
6119
6126
  ws.on("message", (data) => {
6120
6127
  const frame = parseFrame(data.toString());
6121
- if (frame) this.handleFrame(client, frame);
6128
+ if (frame) {
6129
+ this.handleFrame(client, frame).catch((err) => {
6130
+ console.error(` Frame handler error: ${err instanceof Error ? err.message : err}`);
6131
+ });
6132
+ }
6122
6133
  });
6123
6134
  ws.on("close", () => {
6124
6135
  this.clients.delete(ws);
@@ -6165,7 +6176,7 @@ var init_server = __esm({
6165
6176
  const hello = {
6166
6177
  type: "hello",
6167
6178
  protocol: PROTOCOL_VERSION,
6168
- version: "1.4.4",
6179
+ version: "1.4.5",
6169
6180
  agents: this.config.agents.list.map((a) => ({
6170
6181
  id: a.id,
6171
6182
  name: a.name || a.id,
@@ -7559,7 +7570,7 @@ async function runTui(opts) {
7559
7570
  ws.on("open", () => {
7560
7571
  ws.send(JSON.stringify({
7561
7572
  type: "connect",
7562
- params: { auth: { token }, mode: "tui", version: "1.4.4" }
7573
+ params: { auth: { token }, mode: "tui", version: "1.4.5" }
7563
7574
  }));
7564
7575
  });
7565
7576
  ws.on("message", (data) => {
@@ -7988,7 +7999,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
7988
7999
  import { dirname as dirname5, join as join19 } from "path";
7989
8000
  var __filename3 = fileURLToPath5(import.meta.url);
7990
8001
  var __dirname3 = dirname5(__filename3);
7991
- var version = "1.4.4";
8002
+ var version = "1.4.5";
7992
8003
  try {
7993
8004
  const pkg = JSON.parse(readFileSync(join19(__dirname3, "..", "package.json"), "utf-8"));
7994
8005
  version = pkg.version;