@tractorscorch/clank 1.7.1 → 1.7.2
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 +14 -0
- package/README.md +19 -2
- package/dist/index.js +178 -26
- package/dist/index.js.map +1 -1
- package/dist/workspace/templates/RUNNER.md +45 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [1.7.2] — 2026-03-24
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Agent runner template (RUNNER.md)** — structured playbook for sub-agents with task decomposition, tool patterns, and report format. Automatically injected into system prompt for spawned tasks so the model doesn't have to figure out the approach from scratch
|
|
13
|
+
- **`/compact` command** — save model state, clear context, continue where you left off. Available in TUI and Telegram. Uses the LLM to summarize current task state, then clears the conversation and injects the summary as the starting point
|
|
14
|
+
- **CLI/TUI ASCII banner** — Clank logo displayed on startup in both direct chat and TUI mode
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **Telegram typing indicator leak** — typing indicator now cleared in `finally` block instead of `try` block, so it always stops even if an error occurs during streaming or message editing. Previously, errors would leave the chat permanently showing "typing..."
|
|
18
|
+
- **Install instructions** — split `npm install` and `clank setup` into separate code blocks in README so copying the block doesn't auto-run setup before install finishes
|
|
19
|
+
- **CLI chat version** — was hardcoded as `v0.1.0`, now shows correct version
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
9
23
|
## [1.7.1] — 2026-03-23
|
|
10
24
|
|
|
11
25
|
### Added
|
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.7.
|
|
12
|
+
<a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.7.2-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>
|
|
@@ -56,7 +56,17 @@ Clank is a personal AI gateway — **one daemon, many frontends**. It connects y
|
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
58
|
npm install -g @tractorscorch/clank
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then run the setup wizard (creates config, picks your model):
|
|
62
|
+
|
|
63
|
+
```bash
|
|
59
64
|
clank setup
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Start chatting:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
60
70
|
clank
|
|
61
71
|
```
|
|
62
72
|
|
|
@@ -64,7 +74,14 @@ clank
|
|
|
64
74
|
|
|
65
75
|
```bash
|
|
66
76
|
curl -fsSL https://raw.githubusercontent.com/ItsTrag1c/Clank/main/install.sh | bash
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then run setup and start:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
67
82
|
clank setup
|
|
83
|
+
```
|
|
84
|
+
```bash
|
|
68
85
|
clank
|
|
69
86
|
```
|
|
70
87
|
|
|
@@ -75,7 +92,7 @@ That's it. Setup auto-detects your local models, configures the gateway, and get
|
|
|
75
92
|
| Platform | Download |
|
|
76
93
|
|----------|----------|
|
|
77
94
|
| **npm** (all platforms) | `npm install -g @tractorscorch/clank` |
|
|
78
|
-
| **macOS** (Apple Silicon) | [Clank_1.7.
|
|
95
|
+
| **macOS** (Apple Silicon) | [Clank_1.7.2_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.7.2_macos) |
|
|
79
96
|
|
|
80
97
|
## Security Notice
|
|
81
98
|
|
package/dist/index.js
CHANGED
|
@@ -1175,6 +1175,74 @@ ${results}`
|
|
|
1175
1175
|
getContextEngine() {
|
|
1176
1176
|
return this.contextEngine;
|
|
1177
1177
|
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Compact: summarize current state, clear context, inject summary.
|
|
1180
|
+
* Returns the summary so callers can display it.
|
|
1181
|
+
*/
|
|
1182
|
+
async compactSession() {
|
|
1183
|
+
const messages = this.contextEngine.getMessages();
|
|
1184
|
+
if (messages.length < 3) {
|
|
1185
|
+
return "Nothing to compact \u2014 session is too short.";
|
|
1186
|
+
}
|
|
1187
|
+
const conversationText = messages.slice(-30).map((m) => {
|
|
1188
|
+
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
1189
|
+
const truncated = content.length > 400 ? content.slice(0, 400) + "..." : content;
|
|
1190
|
+
return `${m.role}: ${truncated}`;
|
|
1191
|
+
}).join("\n\n");
|
|
1192
|
+
const summaryPrompt = [
|
|
1193
|
+
"You are summarizing a conversation for context continuity.",
|
|
1194
|
+
"The user is compacting their session \u2014 they want to clear context but continue seamlessly.",
|
|
1195
|
+
"",
|
|
1196
|
+
"Produce a concise state summary covering:",
|
|
1197
|
+
"- What task(s) the user is working on",
|
|
1198
|
+
"- Key decisions made so far",
|
|
1199
|
+
"- Files created, modified, or discussed",
|
|
1200
|
+
"- Current progress and what comes next",
|
|
1201
|
+
"- Any important context (preferences, constraints, blockers)",
|
|
1202
|
+
"",
|
|
1203
|
+
"Format as bullet points. Be brief but complete \u2014 this is the ONLY context the model will have when resuming.",
|
|
1204
|
+
"",
|
|
1205
|
+
"Conversation:",
|
|
1206
|
+
conversationText
|
|
1207
|
+
].join("\n");
|
|
1208
|
+
let summary = "";
|
|
1209
|
+
if (this.resolvedProvider) {
|
|
1210
|
+
try {
|
|
1211
|
+
for await (const event of this.resolvedProvider.provider.stream(
|
|
1212
|
+
[{ role: "user", content: summaryPrompt }],
|
|
1213
|
+
"You are a conversation summarizer. Output only the summary.",
|
|
1214
|
+
[]
|
|
1215
|
+
)) {
|
|
1216
|
+
if (event.type === "text") {
|
|
1217
|
+
summary += event.content;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
} catch {
|
|
1221
|
+
summary = messages.slice(-6).map((m) => {
|
|
1222
|
+
const content = typeof m.content === "string" ? m.content : "";
|
|
1223
|
+
return `- [${m.role}] ${content.slice(0, 150)}`;
|
|
1224
|
+
}).join("\n");
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
if (!summary.trim()) {
|
|
1228
|
+
summary = "Session was active but summary generation failed. Ask the user for context.";
|
|
1229
|
+
}
|
|
1230
|
+
this.contextEngine.clear();
|
|
1231
|
+
this.contextEngine.ingest({
|
|
1232
|
+
role: "user",
|
|
1233
|
+
content: `[Session compacted \u2014 previous context summarized below]
|
|
1234
|
+
|
|
1235
|
+
${summary.trim()}
|
|
1236
|
+
|
|
1237
|
+
---
|
|
1238
|
+
The session was compacted by the user. Continue from where you left off. You have full context above.`,
|
|
1239
|
+
_compacted: true
|
|
1240
|
+
});
|
|
1241
|
+
if (this.currentSession) {
|
|
1242
|
+
await this.sessionStore.saveMessages(this.currentSession.id, this.contextEngine.getMessages());
|
|
1243
|
+
}
|
|
1244
|
+
return summary.trim();
|
|
1245
|
+
}
|
|
1178
1246
|
/** Destroy the engine and clean up */
|
|
1179
1247
|
destroy() {
|
|
1180
1248
|
this.cancel();
|
|
@@ -1197,12 +1265,20 @@ import { platform, hostname } from "os";
|
|
|
1197
1265
|
async function buildSystemPrompt(opts) {
|
|
1198
1266
|
const parts = [];
|
|
1199
1267
|
const compact = opts.compact ?? false;
|
|
1268
|
+
const isSubAgent = (opts.spawnDepth ?? 0) > 0;
|
|
1200
1269
|
if (!compact) {
|
|
1201
1270
|
const workspaceContent = await loadWorkspaceFiles(opts.workspaceDir);
|
|
1202
1271
|
if (workspaceContent) {
|
|
1203
1272
|
parts.push(workspaceContent);
|
|
1204
1273
|
parts.push("---");
|
|
1205
1274
|
}
|
|
1275
|
+
if (isSubAgent) {
|
|
1276
|
+
const runnerContent = await loadSingleFile(opts.workspaceDir, SUB_AGENT_FILE);
|
|
1277
|
+
if (runnerContent) {
|
|
1278
|
+
parts.push(runnerContent);
|
|
1279
|
+
parts.push("---");
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1206
1282
|
}
|
|
1207
1283
|
if (compact) {
|
|
1208
1284
|
parts.push(`Agent: ${opts.identity.name} | Model: ${opts.identity.model.primary} | Dir: ${opts.identity.workspace}`);
|
|
@@ -1269,6 +1345,18 @@ async function loadWorkspaceFiles(workspaceDir) {
|
|
|
1269
1345
|
}
|
|
1270
1346
|
return sections.length > 0 ? sections.join("\n\n---\n\n") : null;
|
|
1271
1347
|
}
|
|
1348
|
+
async function loadSingleFile(workspaceDir, filename) {
|
|
1349
|
+
const filePath = join2(workspaceDir, filename);
|
|
1350
|
+
if (existsSync2(filePath)) {
|
|
1351
|
+
try {
|
|
1352
|
+
const content = await readFile2(filePath, "utf-8");
|
|
1353
|
+
return content.trim() || null;
|
|
1354
|
+
} catch {
|
|
1355
|
+
return null;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
return null;
|
|
1359
|
+
}
|
|
1272
1360
|
async function loadProjectMemory(projectRoot) {
|
|
1273
1361
|
const candidates = [".clank.md", ".clankbuild.md", ".llamabuild.md"];
|
|
1274
1362
|
for (const filename of candidates) {
|
|
@@ -1287,7 +1375,7 @@ async function loadProjectMemory(projectRoot) {
|
|
|
1287
1375
|
async function ensureWorkspaceFiles(workspaceDir, templateDir) {
|
|
1288
1376
|
const { mkdir: mkdir7, copyFile } = await import("fs/promises");
|
|
1289
1377
|
await mkdir7(workspaceDir, { recursive: true });
|
|
1290
|
-
for (const filename of [...WORKSPACE_FILES, "BOOTSTRAP.md", "HEARTBEAT.md"]) {
|
|
1378
|
+
for (const filename of [...WORKSPACE_FILES, "BOOTSTRAP.md", "HEARTBEAT.md", "RUNNER.md"]) {
|
|
1291
1379
|
const target = join2(workspaceDir, filename);
|
|
1292
1380
|
const source = join2(templateDir, filename);
|
|
1293
1381
|
if (!existsSync2(target) && existsSync2(source)) {
|
|
@@ -1295,7 +1383,7 @@ async function ensureWorkspaceFiles(workspaceDir, templateDir) {
|
|
|
1295
1383
|
}
|
|
1296
1384
|
}
|
|
1297
1385
|
}
|
|
1298
|
-
var WORKSPACE_FILES;
|
|
1386
|
+
var WORKSPACE_FILES, SUB_AGENT_FILE;
|
|
1299
1387
|
var init_system_prompt = __esm({
|
|
1300
1388
|
"src/engine/system-prompt.ts"() {
|
|
1301
1389
|
"use strict";
|
|
@@ -1308,6 +1396,7 @@ var init_system_prompt = __esm({
|
|
|
1308
1396
|
"TOOLS.md",
|
|
1309
1397
|
"MEMORY.md"
|
|
1310
1398
|
];
|
|
1399
|
+
SUB_AGENT_FILE = "RUNNER.md";
|
|
1311
1400
|
}
|
|
1312
1401
|
});
|
|
1313
1402
|
|
|
@@ -5057,8 +5146,12 @@ async function runChat(opts) {
|
|
|
5057
5146
|
console.error(red(`Error: ${message}${recoverable ? " (recoverable)" : ""}`));
|
|
5058
5147
|
});
|
|
5059
5148
|
console.log("");
|
|
5060
|
-
console.log(
|
|
5061
|
-
console.log(
|
|
5149
|
+
console.log(cyan(" ___ _ _ "));
|
|
5150
|
+
console.log(cyan(" / __|| | __ _ _ _ | |__"));
|
|
5151
|
+
console.log(cyan(" | (__ | |/ _` || ' \\| / /"));
|
|
5152
|
+
console.log(cyan(" \\___||_|\\__,_||_||_|_\\_\\"));
|
|
5153
|
+
console.log(dim(` v1.7.2 | ${resolved.modelId} | ${identity.toolTier} tier`));
|
|
5154
|
+
console.log(dim(" Type your message. Press Ctrl+C to exit.\n"));
|
|
5062
5155
|
const rl = createInterface({
|
|
5063
5156
|
input: process.stdin,
|
|
5064
5157
|
output: process.stdout,
|
|
@@ -5123,7 +5216,7 @@ async function handleSlashCommand(input, engine, _rl) {
|
|
|
5123
5216
|
console.log(dim(`Unknown command: /${cmd}. Type /help for available commands.`));
|
|
5124
5217
|
}
|
|
5125
5218
|
}
|
|
5126
|
-
var dim,
|
|
5219
|
+
var dim, green, yellow, red, cyan;
|
|
5127
5220
|
var init_chat = __esm({
|
|
5128
5221
|
"src/cli/chat.ts"() {
|
|
5129
5222
|
"use strict";
|
|
@@ -5134,7 +5227,6 @@ var init_chat = __esm({
|
|
|
5134
5227
|
init_config2();
|
|
5135
5228
|
init_sessions();
|
|
5136
5229
|
dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
5137
|
-
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
5138
5230
|
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
5139
5231
|
yellow = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
5140
5232
|
red = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
@@ -6195,6 +6287,7 @@ var init_telegram = __esm({
|
|
|
6195
6287
|
{ command: "help", description: "Show available commands" },
|
|
6196
6288
|
{ command: "new", description: "Start a new session" },
|
|
6197
6289
|
{ command: "reset", description: "Clear current session" },
|
|
6290
|
+
{ command: "compact", description: "Save state and clear context" },
|
|
6198
6291
|
{ command: "status", description: "Agent status and info" },
|
|
6199
6292
|
{ command: "agents", description: "List available agents" },
|
|
6200
6293
|
{ command: "tasks", description: "Show background tasks" },
|
|
@@ -6245,7 +6338,7 @@ var init_telegram = __esm({
|
|
|
6245
6338
|
try {
|
|
6246
6339
|
console.log(` Telegram: processing message from ${userId} in ${chatId}`);
|
|
6247
6340
|
await ctx.api.sendChatAction(chatId, "typing");
|
|
6248
|
-
const
|
|
6341
|
+
const typingInterval2 = setInterval(() => {
|
|
6249
6342
|
bot.api.sendChatAction(chatId, "typing").catch(() => {
|
|
6250
6343
|
});
|
|
6251
6344
|
}, 4e3);
|
|
@@ -6336,13 +6429,14 @@ var init_telegram = __esm({
|
|
|
6336
6429
|
await ctx.api.sendMessage(chatId, chunk);
|
|
6337
6430
|
}
|
|
6338
6431
|
}
|
|
6339
|
-
clearInterval(typingInterval);
|
|
6340
6432
|
console.log(` Telegram: response complete (${response?.length || 0} chars)`);
|
|
6341
6433
|
} catch (err) {
|
|
6342
6434
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
6343
6435
|
console.error(` Telegram: message handler error \u2014 ${errMsg}`);
|
|
6344
6436
|
await ctx.api.sendMessage(chatId, `\u26A0\uFE0F Error: ${errMsg.slice(0, 200)}`).catch(() => {
|
|
6345
6437
|
});
|
|
6438
|
+
} finally {
|
|
6439
|
+
clearInterval(typingInterval);
|
|
6346
6440
|
}
|
|
6347
6441
|
};
|
|
6348
6442
|
const prev = chatLocks.get(chatId) || Promise.resolve();
|
|
@@ -6543,6 +6637,7 @@ You can read this file with the read_file tool.`
|
|
|
6543
6637
|
"\u{1F4AC} *Chat*",
|
|
6544
6638
|
"/new \u2014 Start a new session",
|
|
6545
6639
|
"/reset \u2014 Clear current session history",
|
|
6640
|
+
"/compact \u2014 Save state, clear context, continue",
|
|
6546
6641
|
"",
|
|
6547
6642
|
"\u{1F4CA} *Info*",
|
|
6548
6643
|
"/status \u2014 Agent, model, and session info",
|
|
@@ -6637,6 +6732,22 @@ _Switch with /agent <name>_`;
|
|
|
6637
6732
|
});
|
|
6638
6733
|
}
|
|
6639
6734
|
return command === "new" ? "\u2728 New session started. Send a message to begin." : "\u{1F5D1} Session cleared. History erased.";
|
|
6735
|
+
case "compact": {
|
|
6736
|
+
if (!this.gateway) return "Gateway not connected.";
|
|
6737
|
+
const summary = await this.gateway.compactSession({
|
|
6738
|
+
channel: "telegram",
|
|
6739
|
+
peerId: chatId,
|
|
6740
|
+
peerKind: isGroup ? "group" : "dm"
|
|
6741
|
+
});
|
|
6742
|
+
if (!summary) return "Nothing to compact \u2014 no active session.";
|
|
6743
|
+
const preview = summary.length > 300 ? summary.slice(0, 300) + "..." : summary;
|
|
6744
|
+
return `\u{1F4E6} *Session compacted*
|
|
6745
|
+
|
|
6746
|
+
Context cleared and state saved. The agent will continue where it left off.
|
|
6747
|
+
|
|
6748
|
+
_Summary:_
|
|
6749
|
+
${preview}`;
|
|
6750
|
+
}
|
|
6640
6751
|
case "model": {
|
|
6641
6752
|
const model = this.config?.agents?.defaults?.model?.primary || "unknown";
|
|
6642
6753
|
const fallbacks = this.config?.agents?.defaults?.model?.fallbacks || [];
|
|
@@ -6706,7 +6817,7 @@ _Kill with /kill <id> or /killall_`;
|
|
|
6706
6817
|
return !current ? "\u{1F4AD} Thinking display *on* \u2014 you'll see the model's reasoning above responses." : "\u{1F4AD} Thinking display *off* \u2014 only the final response will be shown.";
|
|
6707
6818
|
}
|
|
6708
6819
|
case "version": {
|
|
6709
|
-
return `\u{1F527} *Clank* v1.7.
|
|
6820
|
+
return `\u{1F527} *Clank* v1.7.2`;
|
|
6710
6821
|
}
|
|
6711
6822
|
default:
|
|
6712
6823
|
return null;
|
|
@@ -7161,6 +7272,17 @@ var init_server = __esm({
|
|
|
7161
7272
|
this.engines.delete(sessionKey);
|
|
7162
7273
|
}
|
|
7163
7274
|
}
|
|
7275
|
+
/**
|
|
7276
|
+
* Compact a session — summarize state, clear context, inject summary.
|
|
7277
|
+
* Used by channel adapters (Telegram /compact command).
|
|
7278
|
+
* Returns the summary text, or null if no active session.
|
|
7279
|
+
*/
|
|
7280
|
+
async compactSession(context) {
|
|
7281
|
+
const sessionKey = deriveSessionKey(context);
|
|
7282
|
+
const engine = this.engines.get(sessionKey);
|
|
7283
|
+
if (!engine) return null;
|
|
7284
|
+
return engine.compactSession();
|
|
7285
|
+
}
|
|
7164
7286
|
/**
|
|
7165
7287
|
* Handle an inbound message from any channel adapter.
|
|
7166
7288
|
* This is the main entry point for all non-WebSocket messages.
|
|
@@ -7285,7 +7407,7 @@ var init_server = __esm({
|
|
|
7285
7407
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
7286
7408
|
res.end(JSON.stringify({
|
|
7287
7409
|
status: "ok",
|
|
7288
|
-
version: "1.7.
|
|
7410
|
+
version: "1.7.2",
|
|
7289
7411
|
uptime: process.uptime(),
|
|
7290
7412
|
clients: this.clients.size,
|
|
7291
7413
|
agents: this.engines.size
|
|
@@ -7397,7 +7519,7 @@ var init_server = __esm({
|
|
|
7397
7519
|
const hello = {
|
|
7398
7520
|
type: "hello",
|
|
7399
7521
|
protocol: PROTOCOL_VERSION,
|
|
7400
|
-
version: "1.7.
|
|
7522
|
+
version: "1.7.2",
|
|
7401
7523
|
agents: this.config.agents.list.map((a) => ({
|
|
7402
7524
|
id: a.id,
|
|
7403
7525
|
name: a.name || a.id,
|
|
@@ -7454,6 +7576,17 @@ var init_server = __esm({
|
|
|
7454
7576
|
this.sendResponse(client, frame.id, true);
|
|
7455
7577
|
break;
|
|
7456
7578
|
}
|
|
7579
|
+
case "session.compact": {
|
|
7580
|
+
const compactKey = frame.params?.sessionKey || client.sessionKey;
|
|
7581
|
+
const compactEngine = this.engines.get(compactKey);
|
|
7582
|
+
if (compactEngine) {
|
|
7583
|
+
const summary = await compactEngine.compactSession();
|
|
7584
|
+
this.sendResponse(client, frame.id, true, { summary });
|
|
7585
|
+
} else {
|
|
7586
|
+
this.sendResponse(client, frame.id, false, "No active session to compact");
|
|
7587
|
+
}
|
|
7588
|
+
break;
|
|
7589
|
+
}
|
|
7457
7590
|
// === Agents ===
|
|
7458
7591
|
case "agent.list":
|
|
7459
7592
|
this.sendResponse(client, frame.id, true, this.config.agents.list.map((a) => ({
|
|
@@ -7687,6 +7820,7 @@ var init_server = __esm({
|
|
|
7687
7820
|
toolTier: agentConfig?.toolTier || this.config.agents.defaults.toolTier || "auto",
|
|
7688
7821
|
tools: agentConfig?.tools
|
|
7689
7822
|
};
|
|
7823
|
+
const currentDepth = sessionKey.startsWith("task:") ? (this.taskRegistry.getBySessionKey(sessionKey)?.spawnDepth ?? 0) + 1 : 0;
|
|
7690
7824
|
const compact = agentConfig?.compactPrompt ?? this.config.agents.defaults.compactPrompt ?? false;
|
|
7691
7825
|
const thinking = agentConfig?.thinking ?? this.config.agents.defaults.thinking ?? "auto";
|
|
7692
7826
|
const systemPrompt = await buildSystemPrompt({
|
|
@@ -7694,12 +7828,12 @@ var init_server = __esm({
|
|
|
7694
7828
|
workspaceDir: identity.workspace,
|
|
7695
7829
|
channel,
|
|
7696
7830
|
compact,
|
|
7697
|
-
thinking
|
|
7831
|
+
thinking,
|
|
7832
|
+
spawnDepth: currentDepth
|
|
7698
7833
|
});
|
|
7699
7834
|
const memoryBudget = resolved.isLocal ? 1500 : 4e3;
|
|
7700
7835
|
const memoryBlock = await this.memoryManager.buildMemoryBlock("", identity.workspace, memoryBudget);
|
|
7701
7836
|
const fullPrompt = memoryBlock ? systemPrompt + "\n\n---\n\n" + memoryBlock : systemPrompt;
|
|
7702
|
-
const currentDepth = sessionKey.startsWith("task:") ? (this.taskRegistry.getBySessionKey(sessionKey)?.spawnDepth ?? 0) + 1 : 0;
|
|
7703
7837
|
const maxSpawnDepth = this.config.agents.defaults.subagents?.maxSpawnDepth ?? 1;
|
|
7704
7838
|
const maxConcurrent = this.config.agents.defaults.subagents?.maxConcurrent ?? 8;
|
|
7705
7839
|
const canSpawn = currentDepth < maxSpawnDepth;
|
|
@@ -8286,7 +8420,7 @@ async function runSetup(opts) {
|
|
|
8286
8420
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
8287
8421
|
try {
|
|
8288
8422
|
console.log("");
|
|
8289
|
-
console.log(
|
|
8423
|
+
console.log(bold(" Welcome to Clank"));
|
|
8290
8424
|
console.log("");
|
|
8291
8425
|
console.log(" Clank is an AI agent that can read, write, and");
|
|
8292
8426
|
console.log(" delete files, execute commands, and access the web.");
|
|
@@ -8304,7 +8438,7 @@ async function runSetup(opts) {
|
|
|
8304
8438
|
console.log("");
|
|
8305
8439
|
console.log(" How would you like to set up Clank?");
|
|
8306
8440
|
console.log("");
|
|
8307
|
-
console.log(" 1. " +
|
|
8441
|
+
console.log(" 1. " + bold("Quick Start") + " (recommended)");
|
|
8308
8442
|
console.log(dim4(" Auto-detect local models, sensible defaults"));
|
|
8309
8443
|
console.log(" 2. Advanced");
|
|
8310
8444
|
console.log(dim4(" Full control over gateway, models, channels"));
|
|
@@ -8571,7 +8705,7 @@ async function runSetup(opts) {
|
|
|
8571
8705
|
await saveConfig(config);
|
|
8572
8706
|
console.log(green4("\n Config saved to " + getConfigDir() + "/config.json5"));
|
|
8573
8707
|
console.log("");
|
|
8574
|
-
console.log(
|
|
8708
|
+
console.log(bold(" Clank is ready!"));
|
|
8575
8709
|
console.log("");
|
|
8576
8710
|
console.log(" Start chatting:");
|
|
8577
8711
|
console.log(dim4(" clank chat \u2014 CLI chat"));
|
|
@@ -8582,7 +8716,7 @@ async function runSetup(opts) {
|
|
|
8582
8716
|
rl.close();
|
|
8583
8717
|
}
|
|
8584
8718
|
}
|
|
8585
|
-
var __dirname2, dim4,
|
|
8719
|
+
var __dirname2, dim4, bold, green4, yellow2, cyan2;
|
|
8586
8720
|
var init_setup = __esm({
|
|
8587
8721
|
"src/cli/setup.ts"() {
|
|
8588
8722
|
"use strict";
|
|
@@ -8592,7 +8726,7 @@ var init_setup = __esm({
|
|
|
8592
8726
|
init_daemon();
|
|
8593
8727
|
__dirname2 = dirname4(fileURLToPath4(import.meta.url));
|
|
8594
8728
|
dim4 = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
8595
|
-
|
|
8729
|
+
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
8596
8730
|
green4 = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
8597
8731
|
yellow2 = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
8598
8732
|
cyan2 = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
@@ -9005,13 +9139,17 @@ async function runTui(opts) {
|
|
|
9005
9139
|
return;
|
|
9006
9140
|
}
|
|
9007
9141
|
console.log("");
|
|
9008
|
-
console.log(
|
|
9142
|
+
console.log(cyan5(" ___ _ _ "));
|
|
9143
|
+
console.log(cyan5(" / __|| | __ _ _ _ | |__"));
|
|
9144
|
+
console.log(cyan5(" | (__ | |/ _` || ' \\| / /"));
|
|
9145
|
+
console.log(cyan5(" \\___||_|\\__,_||_||_|_\\_\\"));
|
|
9146
|
+
console.log(dim8(` TUI | connecting to ${wsUrl}...`));
|
|
9009
9147
|
const ws = new WebSocket2(wsUrl);
|
|
9010
9148
|
state.ws = ws;
|
|
9011
9149
|
ws.on("open", () => {
|
|
9012
9150
|
ws.send(JSON.stringify({
|
|
9013
9151
|
type: "connect",
|
|
9014
|
-
params: { auth: { token }, mode: "tui", version: "1.7.
|
|
9152
|
+
params: { auth: { token }, mode: "tui", version: "1.7.2" }
|
|
9015
9153
|
}));
|
|
9016
9154
|
});
|
|
9017
9155
|
ws.on("message", (data) => {
|
|
@@ -9184,6 +9322,11 @@ function handleFrame(state, frame) {
|
|
|
9184
9322
|
if (!res.ok && res.error) {
|
|
9185
9323
|
console.log(red5(`
|
|
9186
9324
|
Error: ${res.error}`));
|
|
9325
|
+
} else if (res.ok && res.data?.summary) {
|
|
9326
|
+
const summary = res.data.summary.slice(0, 500);
|
|
9327
|
+
console.log(green8(" Session compacted.") + dim8(" Context cleared, state saved."));
|
|
9328
|
+
console.log(dim8(` Summary:
|
|
9329
|
+
${summary}`));
|
|
9187
9330
|
}
|
|
9188
9331
|
state.streaming = false;
|
|
9189
9332
|
}
|
|
@@ -9200,6 +9343,7 @@ async function handleSlashCommand2(state, input, rl) {
|
|
|
9200
9343
|
console.log(dim8(" /model [id] \u2014 Show current model"));
|
|
9201
9344
|
console.log(dim8(" /think \u2014 Toggle thinking display"));
|
|
9202
9345
|
console.log(dim8(" /tools \u2014 Toggle tool output"));
|
|
9346
|
+
console.log(dim8(" /compact \u2014 Save state, clear context, continue"));
|
|
9203
9347
|
console.log(dim8(" /new \u2014 Start new session"));
|
|
9204
9348
|
console.log(dim8(" /reset \u2014 Reset current session"));
|
|
9205
9349
|
console.log(dim8(" /exit \u2014 Exit"));
|
|
@@ -9256,6 +9400,15 @@ async function handleSlashCommand2(state, input, rl) {
|
|
|
9256
9400
|
state.showToolOutput = !state.showToolOutput;
|
|
9257
9401
|
console.log(dim8(` Tool output: ${state.showToolOutput ? "on" : "off"}`));
|
|
9258
9402
|
break;
|
|
9403
|
+
case "compact":
|
|
9404
|
+
console.log(dim8(" Compacting session..."));
|
|
9405
|
+
state.ws?.send(JSON.stringify({
|
|
9406
|
+
type: "req",
|
|
9407
|
+
id: ++state.reqId,
|
|
9408
|
+
method: "session.compact",
|
|
9409
|
+
params: { sessionKey: state.sessionKey }
|
|
9410
|
+
}));
|
|
9411
|
+
break;
|
|
9259
9412
|
case "new":
|
|
9260
9413
|
state.sessionKey = `tui:${state.agentId}:${Date.now()}`;
|
|
9261
9414
|
console.log(green8(` New session: ${state.sessionKey}`));
|
|
@@ -9280,7 +9433,7 @@ async function handleSlashCommand2(state, input, rl) {
|
|
|
9280
9433
|
function printStatusBar(state) {
|
|
9281
9434
|
console.log(dim8(` ${state.agentName} | ${state.modelId} | ${state.sessionKey}`));
|
|
9282
9435
|
}
|
|
9283
|
-
var dim8,
|
|
9436
|
+
var dim8, green8, red5, cyan5, italic;
|
|
9284
9437
|
var init_tui = __esm({
|
|
9285
9438
|
"src/cli/tui.ts"() {
|
|
9286
9439
|
"use strict";
|
|
@@ -9288,7 +9441,6 @@ var init_tui = __esm({
|
|
|
9288
9441
|
init_config2();
|
|
9289
9442
|
init_protocol();
|
|
9290
9443
|
dim8 = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
9291
|
-
bold3 = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
9292
9444
|
green8 = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
9293
9445
|
red5 = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
9294
9446
|
cyan5 = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
@@ -9364,7 +9516,7 @@ import { existsSync as existsSync12 } from "fs";
|
|
|
9364
9516
|
async function runUninstall(opts) {
|
|
9365
9517
|
const configDir = getConfigDir();
|
|
9366
9518
|
console.log("");
|
|
9367
|
-
console.log(
|
|
9519
|
+
console.log(bold2(" Uninstall Clank"));
|
|
9368
9520
|
console.log("");
|
|
9369
9521
|
console.log(" This will permanently remove:");
|
|
9370
9522
|
console.log(red7(` ${configDir}`));
|
|
@@ -9417,7 +9569,7 @@ async function runUninstall(opts) {
|
|
|
9417
9569
|
console.log(green10(" Clank has been completely removed."));
|
|
9418
9570
|
console.log("");
|
|
9419
9571
|
}
|
|
9420
|
-
var dim10,
|
|
9572
|
+
var dim10, bold2, green10, red7, yellow4;
|
|
9421
9573
|
var init_uninstall = __esm({
|
|
9422
9574
|
"src/cli/uninstall.ts"() {
|
|
9423
9575
|
"use strict";
|
|
@@ -9425,7 +9577,7 @@ var init_uninstall = __esm({
|
|
|
9425
9577
|
init_config2();
|
|
9426
9578
|
init_gateway_cmd();
|
|
9427
9579
|
dim10 = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
9428
|
-
|
|
9580
|
+
bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
9429
9581
|
green10 = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
9430
9582
|
red7 = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
9431
9583
|
yellow4 = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
@@ -9440,7 +9592,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
|
|
|
9440
9592
|
import { dirname as dirname5, join as join20 } from "path";
|
|
9441
9593
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
9442
9594
|
var __dirname3 = dirname5(__filename3);
|
|
9443
|
-
var version = "1.7.
|
|
9595
|
+
var version = "1.7.2";
|
|
9444
9596
|
try {
|
|
9445
9597
|
const pkg = JSON.parse(readFileSync(join20(__dirname3, "..", "package.json"), "utf-8"));
|
|
9446
9598
|
version = pkg.version;
|