@tractorscorch/clank 1.4.1 → 1.4.4

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/README.md CHANGED
@@ -1,172 +1,189 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/ItsTrag1c/Clank/main/docs/banner.png" alt="Clank" width="100%" />
3
- </p>
4
-
5
- <h1 align="center">Clank</h1>
6
-
7
- <p align="center">
8
- <b>Local-first AI agent gateway.</b> Open-source alternative to OpenClaw, optimized for local models.
9
- </p>
10
-
11
- <p align="center">
12
- <a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.1.0-blue.svg" alt="Version" /></a>
13
- <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License" /></a>
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
- <a href="https://github.com/ItsTrag1c/Clank/stargazers"><img src="https://img.shields.io/github/stars/ItsTrag1c/Clank.svg" alt="Stars" /></a>
16
- </p>
17
-
18
- <p align="center">
19
- <a href="https://clanksuite.dev">Website</a> ·
20
- <a href="https://github.com/ItsTrag1c/Clank/blob/main/docs/INSTALL.md">Install Guide</a> ·
21
- <a href="https://github.com/ItsTrag1c/Clank/blob/main/docs/USER_GUIDE.md">User Guide</a> ·
22
- <a href="https://github.com/ItsTrag1c/Clank/blob/main/CHANGELOG.md">Changelog</a> ·
23
- <a href="https://x.com/ClankSuite">Twitter</a> ·
24
- <a href="https://reddit.com/u/ClankSuite">Reddit</a>
25
- </p>
26
-
27
- ---
28
-
29
- ## What is Clank?
30
-
31
- Clank is a personal AI gateway — **one daemon, many frontends**. It connects your preferred interfaces (CLI, TUI, browser, Telegram, Discord) to AI agents running local or cloud models. All interfaces share sessions, memory, and agent state.
32
-
33
- **Built for people who want the OpenClaw experience without the token costs.**
34
-
35
- ```
36
- ┌─────────────────────────────┐
37
- │ Clank Gateway │
38
- │ (single daemon) │
39
- │ │
40
- │ Agent Pool + Routing │
41
- │ Sessions, Memory, Pipelines │
42
- │ Cron, Tools, Plugins │
43
- └──────────────┬───────────────┘
44
-
45
- WebSocket + HTTP (port 18790)
46
-
47
- ┌──────────┬───────────┼───────────┬──────────┐
48
- │ │ │ │ │
49
- CLI Web UI Telegram Discord TUI
50
- (direct) (browser) (bot) (bot) (terminal)
51
- ```
52
-
53
- ## Quick Start
54
-
55
- ```bash
56
- npm install -g @tractorscorch/clank
57
- clank setup
58
- clank
59
- ```
60
-
61
- That's it. Setup auto-detects your local models, configures the gateway, and gets you chatting in under 2 minutes. See the [full install guide](docs/INSTALL.md) for details.
62
-
63
- ## Features
64
-
65
- | Feature | Description |
66
- |---------|-------------|
67
- | **Local-first** | Auto-detects Ollama, LM Studio, llama.cpp, vLLM. Cloud providers optional. |
68
- | **Multi-agent** | Named agents with separate models, workspaces, tools, and routing. |
69
- | **Multi-channel** | CLI, TUI, Web UI, Telegram, Discord — all equal, all share sessions. |
70
- | **Self-configuring** | After setup, configure everything through conversation. |
71
- | **18 tools** | File ops, bash, git, web search (Brave), plus 8 self-config tools. |
72
- | **Web Control UI** | 8-panel dashboard: Chat, Agents, Sessions, Config, Pipelines, Cron, Logs, Channels. |
73
- | **Pipeline orchestration** | Chain agents together for multi-step workflows. |
74
- | **Plugin system** | Extend with custom tools, channels, and providers. 25+ hook types. |
75
- | **Cron scheduler** | Recurring and one-shot scheduled agent tasks. |
76
- | **Voice** | Cloud (ElevenLabs) or fully local (whisper.cpp + piper). |
77
- | **Memory** | TF-IDF with decay scoring. Agent learns and remembers across sessions. |
78
- | **Security** | AES-256-GCM encryption, SSRF protection, path containment, config redaction. |
79
-
80
- ## Commands
81
-
82
- ```bash
83
- # Start — gateway + TUI (Telegram/Discord stay alive in background)
84
- clank
85
-
86
- # Chat interfaces
87
- clank chat # Direct mode (no gateway needed)
88
- clank chat --web # Auto-start gateway + open Web UI
89
- clank tui # Rich TUI connected to gateway
90
- clank dashboard # Open Web UI in browser
91
-
92
- # Gateway
93
- clank gateway start # Start in background
94
- clank gateway stop # Stop
95
- clank gateway status # Show status, clients, sessions
96
- clank gateway restart # Restart
97
-
98
- # Setup & diagnostics
99
- clank setup # Onboarding wizard
100
- clank fix # Diagnostics & auto-repair
101
-
102
- # Model & agent management
103
- clank models list # Detect + list models
104
- clank models add # Add a provider (Anthropic, OpenAI, Google, Brave)
105
- clank models test # Test connectivity
106
- clank agents list # List agents
107
- clank agents add # Create an agent
108
-
109
- # Scheduled tasks
110
- clank cron list # List jobs
111
- clank cron add # Schedule a task
112
-
113
- # System
114
- clank daemon install # Auto-start at login (Windows/macOS/Linux)
115
- clank channels # Channel status
116
- clank uninstall # Remove everything
117
- ```
118
-
119
- ## Providers
120
-
121
- | Provider | Type | How |
122
- |----------|------|-----|
123
- | **Ollama** | Local | Auto-detected at `localhost:11434` |
124
- | **LM Studio** | Local | Auto-detected at `localhost:1234` |
125
- | **llama.cpp** | Local | Auto-detected at `localhost:8080` |
126
- | **vLLM** | Local | Auto-detected at `localhost:8000` |
127
- | **Anthropic** | Cloud | API key via `clank setup` or config |
128
- | **OpenAI** | Cloud | API key via `clank setup` or config |
129
- | **Google Gemini** | Cloud | API key via `clank setup` or config |
130
-
131
- Models without native tool calling automatically use prompt-based fallback tools are injected into the system prompt and parsed from text output.
132
-
133
- ## Security
134
-
135
- Clank is designed to be safe by default:
136
-
137
- - **Workspace containment** — file tools blocked outside workspace
138
- - **Bash protection** 25-pattern blocklist for destructive commands
139
- - **API key redaction** — keys never sent to LLM context
140
- - **SSRF protection** web_fetch blocks localhost, cloud metadata, internal hosts
141
- - **Gateway auth** token-based, auto-generated, localhost-only by default
142
- - **Encryption** AES-256-GCM for API keys at rest
143
-
144
- See [SECURITY.md](SECURITY.md) for the full security model.
145
-
146
- ## Documentation
147
-
148
- - **[Install Guide](docs/INSTALL.md)** Detailed installation and setup instructions
149
- - **[User Guide](docs/USER_GUIDE.md)** — How to use Clank day-to-day
150
- - **[Changelog](CHANGELOG.md)** — Version history
151
- - **[Privacy Policy](PRIVACY_POLICY.md)** — Data handling
152
- - **[Security Policy](SECURITY.md)** Security model and vulnerability reporting
153
-
154
- ## Links
155
-
156
- | | |
157
- |--|--|
158
- | **Website** | [clanksuite.dev](https://clanksuite.dev) |
159
- | **GitHub** | [ItsTrag1c/Clank](https://github.com/ItsTrag1c/Clank) |
160
- | **npm** | [npmjs.com/package/@tractorscorch/clank](https://www.npmjs.com/package/@tractorscorch/clank) |
161
- | **Twitter/X** | [@ClankSuite](https://x.com/ClankSuite) |
162
- | **Reddit** | [u/ClankSuite](https://reddit.com/u/ClankSuite) |
163
- | **Legacy** | [Clank-Legacy](https://github.com/ItsTrag1c/Clank-Legacy) (archived CLI v2.7.0 + Desktop v2.6.1) |
164
-
165
- ## Requirements
166
-
167
- - Node.js 20+
168
- - A local model server (Ollama recommended) or cloud API key
169
-
170
- ## License
171
-
172
- MIT — see [LICENSE](LICENSE)
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/ItsTrag1c/Clank/main/docs/banner.png" alt="Clank" width="100%" />
3
+ </p>
4
+
5
+ <h1 align="center">Clank</h1>
6
+
7
+ <p align="center">
8
+ <b>Local-first AI agent gateway.</b> Open-source alternative to OpenClaw, optimized for local models.
9
+ </p>
10
+
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>
13
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License" /></a>
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
+ <a href="https://github.com/ItsTrag1c/Clank/stargazers"><img src="https://img.shields.io/github/stars/ItsTrag1c/Clank.svg" alt="Stars" /></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://clanksuite.dev">Website</a> ·
20
+ <a href="https://github.com/ItsTrag1c/Clank/blob/main/docs/INSTALL.md">Install Guide</a> ·
21
+ <a href="https://github.com/ItsTrag1c/Clank/blob/main/docs/USER_GUIDE.md">User Guide</a> ·
22
+ <a href="https://github.com/ItsTrag1c/Clank/blob/main/CHANGELOG.md">Changelog</a> ·
23
+ <a href="https://x.com/ClankSuite">Twitter</a> ·
24
+ <a href="https://reddit.com/u/ClankSuite">Reddit</a>
25
+ </p>
26
+
27
+ ---
28
+
29
+ ## What is Clank?
30
+
31
+ Clank is a personal AI gateway — **one daemon, many frontends**. It connects your preferred interfaces (CLI, TUI, browser, Telegram, Discord) to AI agents running local or cloud models. All interfaces share sessions, memory, and agent state.
32
+
33
+ **Built for people who want the OpenClaw experience without the token costs.**
34
+
35
+ ```
36
+ ┌─────────────────────────────┐
37
+ │ Clank Gateway │
38
+ │ (single daemon) │
39
+ │ │
40
+ │ Agent Pool + Routing │
41
+ │ Sessions, Memory, Pipelines │
42
+ │ Cron, Tools, Plugins │
43
+ └──────────────┬───────────────┘
44
+
45
+ WebSocket + HTTP (port 18790)
46
+
47
+ ┌──────────┬───────────┼───────────┬──────────┐
48
+ │ │ │ │ │
49
+ CLI Web UI Telegram Discord TUI
50
+ (direct) (browser) (bot) (bot) (terminal)
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ ### npm (all platforms)
56
+
57
+ ```bash
58
+ npm install -g @tractorscorch/clank
59
+ clank setup
60
+ clank
61
+ ```
62
+
63
+ ### macOS (standalone binary)
64
+
65
+ ```bash
66
+ curl -fsSL https://raw.githubusercontent.com/ItsTrag1c/Clank/main/install.sh | bash
67
+ clank setup
68
+ clank
69
+ ```
70
+
71
+ That's it. Setup auto-detects your local models, configures the gateway, and gets you chatting in under 2 minutes. See the [full install guide](docs/INSTALL.md) for details.
72
+
73
+ ### Downloads
74
+
75
+ | Platform | Download |
76
+ |----------|----------|
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) |
79
+
80
+ ## Features
81
+
82
+ | Feature | Description |
83
+ |---------|-------------|
84
+ | **Local-first** | Auto-detects Ollama, LM Studio, llama.cpp, vLLM. Cloud providers optional. |
85
+ | **Multi-agent** | Named agents with separate models, workspaces, tools, and routing. |
86
+ | **Multi-channel** | CLI, TUI, Web UI, Telegram, Discord — all equal, all share sessions. |
87
+ | **Self-configuring** | After setup, configure everything through conversation. |
88
+ | **18 tools** | File ops, bash, git, web search (Brave), plus 8 self-config tools. |
89
+ | **Web Control UI** | 8-panel dashboard: Chat, Agents, Sessions, Config, Pipelines, Cron, Logs, Channels. |
90
+ | **Pipeline orchestration** | Chain agents together for multi-step workflows. |
91
+ | **Plugin system** | Extend with custom tools, channels, and providers. 25+ hook types. |
92
+ | **Cron scheduler** | Recurring and one-shot scheduled agent tasks. |
93
+ | **Voice** | Cloud (ElevenLabs) or fully local (whisper.cpp + piper). |
94
+ | **Memory** | TF-IDF with decay scoring. Agent learns and remembers across sessions. |
95
+ | **Security** | AES-256-GCM encryption, SSRF protection, path containment, config redaction. |
96
+
97
+ ## Commands
98
+
99
+ ```bash
100
+ # Start gateway + TUI (Telegram/Discord stay alive in background)
101
+ clank
102
+
103
+ # Chat interfaces
104
+ clank chat # Direct mode (no gateway needed)
105
+ clank chat --web # Auto-start gateway + open Web UI
106
+ clank tui # Rich TUI connected to gateway
107
+ clank dashboard # Open Web UI in browser
108
+
109
+ # Gateway
110
+ clank gateway start # Start in background
111
+ clank gateway stop # Stop
112
+ clank gateway status # Show status, clients, sessions
113
+ clank gateway restart # Restart
114
+
115
+ # Setup & diagnostics
116
+ clank setup # Onboarding wizard
117
+ clank fix # Diagnostics & auto-repair
118
+
119
+ # Model & agent management
120
+ clank models list # Detect + list models
121
+ clank models add # Add a provider (Anthropic, OpenAI, Google, Brave)
122
+ clank models test # Test connectivity
123
+ clank agents list # List agents
124
+ clank agents add # Create an agent
125
+
126
+ # Scheduled tasks
127
+ clank cron list # List jobs
128
+ clank cron add # Schedule a task
129
+
130
+ # System
131
+ clank daemon install # Auto-start at login (Windows/macOS/Linux)
132
+ clank channels # Channel status
133
+ clank uninstall # Remove everything
134
+ ```
135
+
136
+ ## Providers
137
+
138
+ | Provider | Type | How |
139
+ |----------|------|-----|
140
+ | **Ollama** | Local | Auto-detected at `localhost:11434` |
141
+ | **LM Studio** | Local | Auto-detected at `localhost:1234` |
142
+ | **llama.cpp** | Local | Auto-detected at `localhost:8080` |
143
+ | **vLLM** | Local | Auto-detected at `localhost:8000` |
144
+ | **Anthropic** | Cloud | API key via `clank setup` or config |
145
+ | **OpenAI** | Cloud | API key via `clank setup` or config |
146
+ | **Google Gemini** | Cloud | API key via `clank setup` or config |
147
+
148
+ Models without native tool calling automatically use prompt-based fallbacktools are injected into the system prompt and parsed from text output.
149
+
150
+ ## Security
151
+
152
+ Clank is designed to be safe by default:
153
+
154
+ - **Workspace containment** — file tools blocked outside workspace
155
+ - **Bash protection** — 25-pattern blocklist for destructive commands
156
+ - **API key redaction** — keys never sent to LLM context
157
+ - **SSRF protection** — web_fetch blocks localhost, cloud metadata, internal hosts
158
+ - **Gateway auth** token-based, auto-generated, localhost-only by default
159
+ - **Encryption** AES-256-GCM for API keys at rest
160
+
161
+ See [SECURITY.md](SECURITY.md) for the full security model.
162
+
163
+ ## Documentation
164
+
165
+ - **[Install Guide](docs/INSTALL.md)** — Detailed installation and setup instructions
166
+ - **[User Guide](docs/USER_GUIDE.md)** — How to use Clank day-to-day
167
+ - **[Changelog](CHANGELOG.md)** — Version history
168
+ - **[Privacy Policy](PRIVACY_POLICY.md)** Data handling
169
+ - **[Security Policy](SECURITY.md)** — Security model and vulnerability reporting
170
+
171
+ ## Links
172
+
173
+ | | |
174
+ |--|--|
175
+ | **Website** | [clanksuite.dev](https://clanksuite.dev) |
176
+ | **GitHub** | [ItsTrag1c/Clank](https://github.com/ItsTrag1c/Clank) |
177
+ | **npm** | [npmjs.com/package/@tractorscorch/clank](https://www.npmjs.com/package/@tractorscorch/clank) |
178
+ | **Twitter/X** | [@ClankSuite](https://x.com/ClankSuite) |
179
+ | **Reddit** | [u/ClankSuite](https://reddit.com/u/ClankSuite) |
180
+ | **Legacy** | [Clank-Legacy](https://github.com/ItsTrag1c/Clank-Legacy) (archived CLI v2.7.0 + Desktop v2.6.1) |
181
+
182
+ ## Requirements
183
+
184
+ - Node.js 20+
185
+ - A local model server (Ollama recommended) or cloud API key
186
+
187
+ ## License
188
+
189
+ MIT — see [LICENSE](LICENSE)
package/dist/index.js CHANGED
@@ -764,6 +764,7 @@ var init_agent = __esm({
764
764
  alwaysApproved = /* @__PURE__ */ new Set();
765
765
  constructor(opts) {
766
766
  super();
767
+ this.setMaxListeners(30);
767
768
  this.identity = opts.identity;
768
769
  this.toolRegistry = opts.toolRegistry;
769
770
  this.sessionStore = opts.sessionStore;
@@ -4480,14 +4481,15 @@ async function runChat(opts) {
4480
4481
  }
4481
4482
  if (!gatewayRunning) {
4482
4483
  console.log(dim("Starting gateway..."));
4483
- const { fork: fork2 } = await import("child_process");
4484
+ const { spawn } = await import("child_process");
4484
4485
  const { fileURLToPath: fileURLToPath6 } = await import("url");
4485
4486
  const { dirname: dirname6, join: join20 } = await import("path");
4486
4487
  const __filename4 = fileURLToPath6(import.meta.url);
4487
4488
  const entryPoint = join20(dirname6(__filename4), "index.js");
4488
- const child = fork2(entryPoint, ["gateway", "start", "--foreground"], {
4489
+ const child = spawn(process.execPath, [entryPoint, "gateway", "start", "--foreground"], {
4489
4490
  detached: true,
4490
- stdio: "ignore"
4491
+ stdio: "ignore",
4492
+ windowsHide: true
4491
4493
  });
4492
4494
  child.unref();
4493
4495
  for (let i = 0; i < 20; i++) {
@@ -4510,9 +4512,9 @@ async function runChat(opts) {
4510
4512
  const url = `http://127.0.0.1:${port}/#token=${token}`;
4511
4513
  console.log(dim(`Opening ${url}`));
4512
4514
  const { platform: platform5 } = await import("os");
4513
- const { exec: exec2 } = await import("child_process");
4515
+ const { exec } = await import("child_process");
4514
4516
  const openCmd = platform5() === "win32" ? `start "" "${url}"` : platform5() === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
4515
- exec2(openCmd);
4517
+ exec(openCmd);
4516
4518
  console.log(green("Web UI opened in browser."));
4517
4519
  return;
4518
4520
  }
@@ -5226,6 +5228,7 @@ var init_telegram = __esm({
5226
5228
  try {
5227
5229
  await ctx.api.sendChatAction(chatId, "typing");
5228
5230
  let streamMsgId = null;
5231
+ let sendingInitial = false;
5229
5232
  let accumulated = "";
5230
5233
  let lastEditTime = 0;
5231
5234
  const EDIT_INTERVAL = 800;
@@ -5240,7 +5243,8 @@ var init_telegram = __esm({
5240
5243
  onToken: (content) => {
5241
5244
  accumulated += content;
5242
5245
  const now = Date.now();
5243
- if (!streamMsgId && accumulated.length > 20) {
5246
+ if (!streamMsgId && !sendingInitial && accumulated.length > 20) {
5247
+ sendingInitial = true;
5244
5248
  bot.api.sendMessage(chatId, accumulated + " \u258D").then((sent) => {
5245
5249
  streamMsgId = sent.message_id;
5246
5250
  lastEditTime = now;
@@ -6053,7 +6057,7 @@ var init_server = __esm({
6053
6057
  res.writeHead(200, { "Content-Type": "application/json" });
6054
6058
  res.end(JSON.stringify({
6055
6059
  status: "ok",
6056
- version: "1.4.1",
6060
+ version: "1.4.4",
6057
6061
  uptime: process.uptime(),
6058
6062
  clients: this.clients.size,
6059
6063
  agents: this.engines.size
@@ -6161,7 +6165,7 @@ var init_server = __esm({
6161
6165
  const hello = {
6162
6166
  type: "hello",
6163
6167
  protocol: PROTOCOL_VERSION,
6164
- version: "1.4.1",
6168
+ version: "1.4.4",
6165
6169
  agents: this.config.agents.list.map((a) => ({
6166
6170
  id: a.id,
6167
6171
  name: a.name || a.id,
@@ -6360,6 +6364,13 @@ var init_server = __esm({
6360
6364
  const recent = timestamps.filter((t) => now - t < this.RATE_LIMIT_WINDOW);
6361
6365
  recent.push(now);
6362
6366
  this.rateLimiter.set(sessionKey, recent);
6367
+ if (this.rateLimiter.size > 100) {
6368
+ for (const [key, ts] of this.rateLimiter) {
6369
+ if (ts.length === 0 || now - ts[ts.length - 1] > this.RATE_LIMIT_WINDOW * 2) {
6370
+ this.rateLimiter.delete(key);
6371
+ }
6372
+ }
6373
+ }
6363
6374
  return recent.length > this.RATE_LIMIT_MAX;
6364
6375
  }
6365
6376
  /** Cancel current request for a client */
@@ -6445,7 +6456,6 @@ var init_server = __esm({
6445
6456
  }
6446
6457
  const confirmId = `confirm_${Date.now()}`;
6447
6458
  this.sendEvent(client, "confirm-needed", { id: confirmId, actions });
6448
- const timeout = setTimeout(() => resolve4(false), 3e4);
6449
6459
  const resolveHandler = (raw) => {
6450
6460
  const frame = parseFrame(raw.toString());
6451
6461
  if (frame?.type === "req" && frame.method === "confirm.resolve") {
@@ -6458,6 +6468,10 @@ var init_server = __esm({
6458
6468
  }
6459
6469
  };
6460
6470
  client.ws.on("message", resolveHandler);
6471
+ const timeout = setTimeout(() => {
6472
+ client.ws.removeListener("message", resolveHandler);
6473
+ resolve4(false);
6474
+ }, 3e4);
6461
6475
  };
6462
6476
  engine.on("confirm-needed", confirmListener);
6463
6477
  listeners.push(["confirm-needed", confirmListener]);
@@ -6508,7 +6522,6 @@ __export(gateway_cmd_exports, {
6508
6522
  gatewayStop: () => gatewayStop,
6509
6523
  isGatewayRunning: () => isGatewayRunning
6510
6524
  });
6511
- import { fork } from "child_process";
6512
6525
  import { writeFile as writeFile8, readFile as readFile12, unlink as unlink3 } from "fs/promises";
6513
6526
  import { existsSync as existsSync9 } from "fs";
6514
6527
  import { join as join15, dirname as dirname3 } from "path";
@@ -6570,15 +6583,18 @@ async function gatewayStartBackground() {
6570
6583
  }
6571
6584
  console.log(dim2(" Starting gateway in background..."));
6572
6585
  const entryPoint = join15(dirname3(__filename2), "index.js");
6573
- const logFile = join15(getConfigDir(), "logs", "gateway.log");
6574
6586
  const { mkdir: mkdir7 } = await import("fs/promises");
6587
+ const { spawn } = await import("child_process");
6588
+ const { openSync } = await import("fs");
6575
6589
  await mkdir7(join15(getConfigDir(), "logs"), { recursive: true });
6576
- const child = fork(entryPoint, ["gateway", "start", "--foreground"], {
6590
+ const logFile = join15(getConfigDir(), "logs", "gateway.log");
6591
+ const logFd = openSync(logFile, "a");
6592
+ const child = spawn(process.execPath, [entryPoint, "gateway", "start", "--foreground"], {
6577
6593
  detached: true,
6578
- stdio: ["ignore", "ignore", "ignore", "ipc"]
6594
+ stdio: ["ignore", logFd, logFd],
6595
+ windowsHide: true
6579
6596
  });
6580
6597
  child.unref();
6581
- child.disconnect();
6582
6598
  for (let i = 0; i < 20; i++) {
6583
6599
  await new Promise((r) => setTimeout(r, 500));
6584
6600
  if (await isGatewayRunning(port)) {
@@ -7543,7 +7559,7 @@ async function runTui(opts) {
7543
7559
  ws.on("open", () => {
7544
7560
  ws.send(JSON.stringify({
7545
7561
  type: "connect",
7546
- params: { auth: { token }, mode: "tui", version: "1.4.1" }
7562
+ params: { auth: { token }, mode: "tui", version: "1.4.4" }
7547
7563
  }));
7548
7564
  });
7549
7565
  ws.on("message", (data) => {
@@ -7845,14 +7861,14 @@ async function runUpdate() {
7845
7861
  }
7846
7862
  console.log(dim9(" Pulling latest version..."));
7847
7863
  try {
7848
- const output = execSync2("npm install -g @tractorscorch/clank@latest", {
7864
+ const output = execSync2("npm install -g @tractorscorch/clank@latest --force", {
7849
7865
  encoding: "utf-8",
7850
7866
  timeout: 12e4
7851
7867
  });
7852
7868
  console.log(dim9(` ${output.trim()}`));
7853
7869
  } catch (err) {
7854
7870
  console.error(red6(` Update failed: ${err instanceof Error ? err.message : err}`));
7855
- console.error(dim9(" Try manually: npm install -g @tractorscorch/clank@latest"));
7871
+ console.error(dim9(" Try manually: npm install -g @tractorscorch/clank@latest --force"));
7856
7872
  return;
7857
7873
  }
7858
7874
  try {
@@ -7972,7 +7988,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
7972
7988
  import { dirname as dirname5, join as join19 } from "path";
7973
7989
  var __filename3 = fileURLToPath5(import.meta.url);
7974
7990
  var __dirname3 = dirname5(__filename3);
7975
- var version = "1.4.1";
7991
+ var version = "1.4.4";
7976
7992
  try {
7977
7993
  const pkg = JSON.parse(readFileSync(join19(__dirname3, "..", "package.json"), "utf-8"));
7978
7994
  version = pkg.version;
@@ -8065,9 +8081,9 @@ program.command("dashboard").description("Open the Web UI in your browser").opti
8065
8081
  `);
8066
8082
  if (opts.open !== false) {
8067
8083
  const { platform: platform5 } = await import("os");
8068
- const { exec: exec2 } = await import("child_process");
8084
+ const { exec } = await import("child_process");
8069
8085
  const cmd = platform5() === "win32" ? `start ${url}` : platform5() === "darwin" ? `open ${url}` : `xdg-open ${url}`;
8070
- exec2(cmd);
8086
+ exec(cmd);
8071
8087
  }
8072
8088
  });
8073
8089
  var pipeline = program.command("pipeline").description("Manage agent pipelines");