@tractorscorch/clank 1.5.7 → 1.5.9

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,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [1.5.9] — 2026-03-23
10
+
11
+ ### Changed
12
+ - **Workspace defaults to current directory** — the agent's workspace is now the directory you run `clank` from, not a hidden `%APPDATA%/Clank/workspace` folder. This means the agent works with your actual project files out of the box
13
+ - **Full file system access** — the path guard no longer blocks reads/writes outside the workspace. Clank is a dev tool and needs to access the full system. Added security notice to README recommending dedicated hardware
14
+
15
+ ### Fixed
16
+ - **Telegram `/new` and `/reset` were no-ops** — these commands returned a "session started" message but never actually reset the session. The model kept its full conversation history. Now properly clears session store, context engine, and destroys the old engine instance
17
+ - **Security notice added to README** — recommends running Clank on dedicated hardware since it gives agents full system access
18
+
19
+ ---
20
+
21
+ ## [1.5.8] — 2026-03-23
22
+
23
+ ### Added
24
+ - **Collapsible thinking blocks** — model thinking/reasoning is now displayed in a separate clickable block above the response instead of being streamed into the message text. Click the "Thought" toggle to expand/collapse. Shows "Thinking..." while streaming, "Thought" when complete
25
+
26
+ ### Fixed
27
+ - **Thinking events were disconnected** — the full thinking pipeline (provider → agent → gateway → frontend) was broken at 3 points: provider yielded thinking as text for local models, agent only emitted a one-shot start event without content, and gateway didn't forward thinking events to clients. All 3 fixed
28
+ - **Empty responses from thinking-only models** — when a model puts all output in `reasoning_content` with empty `content` (Qwen3.5), the thinking text is now used as the response instead of showing a blank message
29
+
30
+ ---
31
+
9
32
  ## [1.5.7] — 2026-03-23
10
33
 
11
34
  ### 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.5.7-blue.svg" alt="Version" /></a>
12
+ <a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.5.9-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,13 @@ 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.5.7_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.5.7_macos) |
78
+ | **macOS** (Apple Silicon) | [Clank_1.5.9_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.5.9_macos) |
79
+
80
+ ## Security Notice
81
+
82
+ Clank is a **developer tool** that gives AI agents full access to your file system, shell, and connected services. The agent can read, write, and execute on your behalf.
83
+
84
+ **We strongly recommend running Clank on dedicated hardware** (a dev machine, VM, or container) rather than on a system with sensitive personal files, credentials, or accounts you don't want the agent to access. Treat it like giving someone SSH access to your box.
79
85
 
80
86
  ## Features
81
87
 
package/dist/index.js CHANGED
@@ -934,6 +934,7 @@ var init_agent = __esm({
934
934
  denylist: this.identity.tools?.deny
935
935
  });
936
936
  let iterationText = "";
937
+ let thinkingText = "";
937
938
  const toolCalls = [];
938
939
  let promptTokens = 0;
939
940
  let outputTokens = 0;
@@ -942,6 +943,7 @@ var init_agent = __esm({
942
943
  for (let attempt = 0; attempt < 2; attempt++) {
943
944
  if (attempt > 0) {
944
945
  iterationText = "";
946
+ thinkingText = "";
945
947
  toolCalls.length = 0;
946
948
  promptTokens = 0;
947
949
  outputTokens = 0;
@@ -960,7 +962,8 @@ var init_agent = __esm({
960
962
  this.emit("token", { content: event.content });
961
963
  break;
962
964
  case "thinking":
963
- this.emit("thinking-start");
965
+ thinkingText += event.content;
966
+ this.emit("thinking", { content: event.content });
964
967
  break;
965
968
  case "tool_call":
966
969
  toolCalls.push({
@@ -1005,6 +1008,10 @@ var init_agent = __esm({
1005
1008
  contextPercent: Math.round(this.contextEngine.utilizationPercent())
1006
1009
  });
1007
1010
  if (toolCalls.length === 0) {
1011
+ if (!iterationText && thinkingText) {
1012
+ iterationText = thinkingText;
1013
+ this.emit("token", { content: iterationText });
1014
+ }
1008
1015
  fullResponse = iterationText;
1009
1016
  this.contextEngine.ingest({ role: "assistant", content: iterationText });
1010
1017
  this.emit("response-end", { text: iterationText });
@@ -1037,6 +1044,7 @@ var init_agent = __esm({
1037
1044
  this.emit("tool-start", { id: tc.id, name: tc.name, arguments: tc.arguments });
1038
1045
  const toolCtx = {
1039
1046
  projectRoot: this.identity.workspace,
1047
+ allowExternal: true,
1040
1048
  autoApprove: this.autoApprove,
1041
1049
  agentId: this.identity.id,
1042
1050
  signal
@@ -2092,7 +2100,7 @@ function defaultConfig() {
2092
2100
  agents: {
2093
2101
  defaults: {
2094
2102
  model: { primary: "ollama/qwen3.5" },
2095
- workspace: join6(getConfigDir(), "workspace"),
2103
+ workspace: process.cwd(),
2096
2104
  toolTier: "auto",
2097
2105
  temperature: 0.7
2098
2106
  },
@@ -3112,11 +3120,7 @@ var init_openai = __esm({
3112
3120
  }
3113
3121
  if (choice?.delta?.reasoning_content) {
3114
3122
  hasContent = true;
3115
- if (this.isLocal) {
3116
- yield { type: "text", content: choice.delta.reasoning_content };
3117
- } else {
3118
- yield { type: "thinking", content: choice.delta.reasoning_content };
3119
- }
3123
+ yield { type: "thinking", content: choice.delta.reasoning_content };
3120
3124
  }
3121
3125
  if (choice?.delta?.content) {
3122
3126
  hasContent = true;
@@ -5694,9 +5698,15 @@ You can read this file with the read_file tool.`
5694
5698
  return "Use /new to start a fresh session, or /reset to clear the current one.";
5695
5699
  }
5696
5700
  case "new":
5697
- return "New session started. Send a message to begin.";
5698
5701
  case "reset":
5699
- return "Session reset. History cleared.";
5702
+ if (this.gateway) {
5703
+ await this.gateway.resetSession({
5704
+ channel: "telegram",
5705
+ peerId: chatId,
5706
+ peerKind: isGroup ? "group" : "dm"
5707
+ });
5708
+ }
5709
+ return command === "new" ? "New session started. Send a message to begin." : "Session reset. History cleared.";
5700
5710
  case "model": {
5701
5711
  const model = this.config?.agents?.defaults?.model?.primary || "unknown";
5702
5712
  return `Current model: \`${model}\``;
@@ -6131,6 +6141,20 @@ var init_server = __esm({
6131
6141
  }
6132
6142
  }
6133
6143
  }
6144
+ /**
6145
+ * Reset a session — clear its history and context.
6146
+ * Used by channel adapters (Telegram /new, /reset commands).
6147
+ */
6148
+ async resetSession(context) {
6149
+ const sessionKey = deriveSessionKey(context);
6150
+ await this.sessionStore.reset(sessionKey);
6151
+ const engine = this.engines.get(sessionKey);
6152
+ if (engine) {
6153
+ engine.getContextEngine().clear();
6154
+ engine.destroy();
6155
+ this.engines.delete(sessionKey);
6156
+ }
6157
+ }
6134
6158
  /**
6135
6159
  * Handle an inbound message from any channel adapter.
6136
6160
  * This is the main entry point for all non-WebSocket messages.
@@ -6242,7 +6266,7 @@ var init_server = __esm({
6242
6266
  res.writeHead(200, { "Content-Type": "application/json" });
6243
6267
  res.end(JSON.stringify({
6244
6268
  status: "ok",
6245
- version: "1.5.7",
6269
+ version: "1.5.9",
6246
6270
  uptime: process.uptime(),
6247
6271
  clients: this.clients.size,
6248
6272
  agents: this.engines.size
@@ -6354,7 +6378,7 @@ var init_server = __esm({
6354
6378
  const hello = {
6355
6379
  type: "hello",
6356
6380
  protocol: PROTOCOL_VERSION,
6357
- version: "1.5.7",
6381
+ version: "1.5.9",
6358
6382
  agents: this.config.agents.list.map((a) => ({
6359
6383
  id: a.id,
6360
6384
  name: a.name || a.id,
@@ -6619,6 +6643,7 @@ var init_server = __esm({
6619
6643
  wireEngineEvents(engine, client) {
6620
6644
  const eventMap = {
6621
6645
  "token": "token",
6646
+ "thinking": "thinking",
6622
6647
  "response-start": "response-start",
6623
6648
  "response-end": "response-end",
6624
6649
  "tool-start": "tool-start",
@@ -7749,7 +7774,7 @@ async function runTui(opts) {
7749
7774
  ws.on("open", () => {
7750
7775
  ws.send(JSON.stringify({
7751
7776
  type: "connect",
7752
- params: { auth: { token }, mode: "tui", version: "1.5.7" }
7777
+ params: { auth: { token }, mode: "tui", version: "1.5.9" }
7753
7778
  }));
7754
7779
  });
7755
7780
  ws.on("message", (data) => {
@@ -8178,7 +8203,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
8178
8203
  import { dirname as dirname5, join as join19 } from "path";
8179
8204
  var __filename3 = fileURLToPath5(import.meta.url);
8180
8205
  var __dirname3 = dirname5(__filename3);
8181
- var version = "1.5.7";
8206
+ var version = "1.5.9";
8182
8207
  try {
8183
8208
  const pkg = JSON.parse(readFileSync(join19(__dirname3, "..", "package.json"), "utf-8"));
8184
8209
  version = pkg.version;