@termhub/agent 0.5.3 → 0.6.0
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/dist/cli.js +70 -12
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -128,6 +128,8 @@ var closedReason = z2.enum(["cli_missing", "run_failed", "killed", "missing_sess
|
|
|
128
128
|
var CAPABILITY_CLAUDE = "claude";
|
|
129
129
|
var CAPABILITY_CLAUDE_SYSTEM_PROMPT = "claude.system_prompt";
|
|
130
130
|
var CAPABILITY_SIM = "sim";
|
|
131
|
+
var CAPABILITY_CLAUDE_STREAM_INPUT = "claude.stream_input";
|
|
132
|
+
var STREAM_END_INPUT_LINE = '{"type":"termhub_end_input"}';
|
|
131
133
|
var helloMessage = z2.object({
|
|
132
134
|
type: z2.literal("hello"),
|
|
133
135
|
protocol: z2.number().int().min(1),
|
|
@@ -171,9 +173,13 @@ var claudeOpenParams = z2.object({
|
|
|
171
173
|
// belongs at, so there is no separate, later place to hand it over.
|
|
172
174
|
token: z2.string(),
|
|
173
175
|
model: z2.string().nullable().optional(),
|
|
174
|
-
// Project chats
|
|
176
|
+
// Project chats and streamed runs: the server-composed text forwarded onto the CLI's argv (see
|
|
175
177
|
// `CAPABILITY_CLAUDE_SYSTEM_PROMPT`). Absent for the account-wide chat, whose argv must not change.
|
|
176
|
-
|
|
178
|
+
// 8000 because a streamed run carries the orchestrator prompt next to a project's (at most 4000
|
|
179
|
+
// each); only agents that advertise `CAPABILITY_CLAUDE_STREAM_INPUT` are ever sent more than 4000.
|
|
180
|
+
append_system_prompt: z2.string().max(8e3).nullable().optional(),
|
|
181
|
+
// See `CAPABILITY_CLAUDE_STREAM_INPUT`. Absent on every one-shot run, whose open frame must not change.
|
|
182
|
+
stream_input: z2.boolean().optional()
|
|
177
183
|
});
|
|
178
184
|
var tcpOpenParams = z2.object({ port: wdaPort }).strict();
|
|
179
185
|
var openPty = z2.object({ type: z2.literal("open"), ch: channel, kind: z2.literal("pty"), params: ptyOpenParams });
|
|
@@ -1300,6 +1306,10 @@ async function uninstall(params, home = os3.homedir()) {
|
|
|
1300
1306
|
|
|
1301
1307
|
// ../../packages/claude-cli/dist/index.js
|
|
1302
1308
|
var DISALLOWED_TOOLS = "Bash,Read,Write,Edit,WebFetch,WebSearch";
|
|
1309
|
+
var BACKGROUND_AGENT_HOOK = `input=$(cat); case "$input" in *'"agent_id"'*) exit 0;; esac; printf '%s' "$input" | grep -Eq '"run_in_background"[[:space:]]*:[[:space:]]*true' && exit 0; echo 'No chat do termhub todo subagente roda em segundo plano: repita esta chamada do Agent com run_in_background: true.' >&2; exit 2`;
|
|
1310
|
+
var CONCIERGE_SETTINGS = JSON.stringify({
|
|
1311
|
+
hooks: { PreToolUse: [{ matcher: "Agent|Task", hooks: [{ type: "command", command: BACKGROUND_AGENT_HOOK }] }] }
|
|
1312
|
+
});
|
|
1303
1313
|
function buildClaudeArgs(spec) {
|
|
1304
1314
|
return [
|
|
1305
1315
|
"-p",
|
|
@@ -1322,6 +1332,7 @@ function buildClaudeArgs(spec) {
|
|
|
1322
1332
|
"mcp__termhub__*",
|
|
1323
1333
|
"--disallowed-tools",
|
|
1324
1334
|
DISALLOWED_TOOLS,
|
|
1335
|
+
...spec.stream_input ? ["--input-format", "stream-json", "--replay-user-messages", "--settings", CONCIERGE_SETTINGS] : [],
|
|
1325
1336
|
...spec.model ? ["--model", spec.model] : [],
|
|
1326
1337
|
// Last, and only when set: the account-wide chat's argv stays exactly what it was. It is our own
|
|
1327
1338
|
// server-composed text (a project's name, key and paths), never the user's prompt, which still
|
|
@@ -1346,6 +1357,8 @@ import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
|
1346
1357
|
import { tmpdir } from "os";
|
|
1347
1358
|
import { join } from "path";
|
|
1348
1359
|
var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
|
|
1360
|
+
var STREAM_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
1361
|
+
var MAX_PENDING_INPUT_BYTES = 256 * 1024;
|
|
1349
1362
|
var KILL_GRACE_MS = 2e3;
|
|
1350
1363
|
var PROMPT_TIMEOUT_MS = 3e4;
|
|
1351
1364
|
var MAX_LINE_BYTES = MAX_FRAME - HEADER_BYTES - 1;
|
|
@@ -1378,7 +1391,8 @@ function createClaudeManager(deps) {
|
|
|
1378
1391
|
}
|
|
1379
1392
|
const runDir = dir;
|
|
1380
1393
|
socket.sendControl({ type: "opened", ch });
|
|
1381
|
-
|
|
1394
|
+
const stream = params.stream_input === true;
|
|
1395
|
+
deps.log("claude run starting", { ch, resume: params.resume, model: params.model ?? null, stream });
|
|
1382
1396
|
const env2 = { ...deps.env ?? agentEnv() };
|
|
1383
1397
|
if (params.config_dir === null) delete env2.CLAUDE_CONFIG_DIR;
|
|
1384
1398
|
else env2.CLAUDE_CONFIG_DIR = params.config_dir;
|
|
@@ -1387,7 +1401,8 @@ function createClaudeManager(deps) {
|
|
|
1387
1401
|
resume: params.resume,
|
|
1388
1402
|
mcp_config_path: mcpConfigPath,
|
|
1389
1403
|
model: params.model ?? null,
|
|
1390
|
-
append_system_prompt: params.append_system_prompt ?? null
|
|
1404
|
+
append_system_prompt: params.append_system_prompt ?? null,
|
|
1405
|
+
stream_input: stream
|
|
1391
1406
|
});
|
|
1392
1407
|
let child;
|
|
1393
1408
|
try {
|
|
@@ -1463,10 +1478,11 @@ function createClaudeManager(deps) {
|
|
|
1463
1478
|
deps.log("claude stream send failed", { ch, error: message(err) });
|
|
1464
1479
|
}
|
|
1465
1480
|
}
|
|
1481
|
+
const timeoutMs = deps.timeoutMs ?? (stream ? STREAM_TIMEOUT_MS : DEFAULT_TIMEOUT_MS2);
|
|
1466
1482
|
const timer = setTimeout(() => {
|
|
1467
|
-
deps.log("claude run timed out", { ch, timeoutMs
|
|
1483
|
+
deps.log("claude run timed out", { ch, timeoutMs });
|
|
1468
1484
|
killRun();
|
|
1469
|
-
},
|
|
1485
|
+
}, timeoutMs);
|
|
1470
1486
|
timer.unref();
|
|
1471
1487
|
const promptTimer = setTimeout(() => {
|
|
1472
1488
|
deps.log("claude run got no prompt", { ch, promptTimeoutMs: deps.promptTimeoutMs ?? PROMPT_TIMEOUT_MS });
|
|
@@ -1479,7 +1495,11 @@ function createClaudeManager(deps) {
|
|
|
1479
1495
|
promptSent: false,
|
|
1480
1496
|
kill: killRun,
|
|
1481
1497
|
promptArrived: () => clearTimeout(promptTimer),
|
|
1482
|
-
settle
|
|
1498
|
+
settle,
|
|
1499
|
+
stream,
|
|
1500
|
+
inputTail: "",
|
|
1501
|
+
inputEnded: false,
|
|
1502
|
+
discarding: false
|
|
1483
1503
|
};
|
|
1484
1504
|
runs.set(ch, run2);
|
|
1485
1505
|
child.stdin?.on("error", () => {
|
|
@@ -1525,13 +1545,51 @@ function createClaudeManager(deps) {
|
|
|
1525
1545
|
write(ch, data) {
|
|
1526
1546
|
const run2 = runs.get(ch);
|
|
1527
1547
|
if (!run2) return false;
|
|
1528
|
-
if (run2.
|
|
1529
|
-
|
|
1548
|
+
if (!run2.stream) {
|
|
1549
|
+
if (run2.promptSent) {
|
|
1550
|
+
deps.log("extra data on a claude channel ignored", { ch, bytes: data.length });
|
|
1551
|
+
return true;
|
|
1552
|
+
}
|
|
1553
|
+
run2.promptSent = true;
|
|
1554
|
+
run2.promptArrived();
|
|
1555
|
+
run2.child.stdin?.end(data);
|
|
1530
1556
|
return true;
|
|
1531
1557
|
}
|
|
1532
1558
|
run2.promptSent = true;
|
|
1533
1559
|
run2.promptArrived();
|
|
1534
|
-
run2.
|
|
1560
|
+
if (run2.inputEnded) {
|
|
1561
|
+
deps.log("claude input after its end ignored", { ch, bytes: data.length });
|
|
1562
|
+
return true;
|
|
1563
|
+
}
|
|
1564
|
+
let text = data.toString("utf8");
|
|
1565
|
+
if (run2.discarding) {
|
|
1566
|
+
const nl = text.indexOf("\n");
|
|
1567
|
+
if (nl === -1) return true;
|
|
1568
|
+
deps.log("claude input line too large, rest dropped", { ch, bytes: Buffer.byteLength(text.slice(0, nl), "utf8") });
|
|
1569
|
+
run2.discarding = false;
|
|
1570
|
+
text = text.slice(nl + 1);
|
|
1571
|
+
}
|
|
1572
|
+
run2.inputTail += text;
|
|
1573
|
+
for (; ; ) {
|
|
1574
|
+
const nl = run2.inputTail.indexOf("\n");
|
|
1575
|
+
if (nl === -1) break;
|
|
1576
|
+
const line = run2.inputTail.slice(0, nl);
|
|
1577
|
+
run2.inputTail = run2.inputTail.slice(nl + 1);
|
|
1578
|
+
if (line === STREAM_END_INPUT_LINE) {
|
|
1579
|
+
run2.inputEnded = true;
|
|
1580
|
+
if (run2.inputTail.length > 0) deps.log("claude input after its end ignored", { ch, bytes: Buffer.byteLength(run2.inputTail, "utf8") });
|
|
1581
|
+
run2.inputTail = "";
|
|
1582
|
+
run2.child.stdin?.end();
|
|
1583
|
+
return true;
|
|
1584
|
+
}
|
|
1585
|
+
if (line.trim()) run2.child.stdin?.write(`${line}
|
|
1586
|
+
`);
|
|
1587
|
+
}
|
|
1588
|
+
if (Buffer.byteLength(run2.inputTail, "utf8") > (deps.maxPendingInputBytes ?? MAX_PENDING_INPUT_BYTES)) {
|
|
1589
|
+
deps.log("claude input line too large, dropped", { ch, bytes: Buffer.byteLength(run2.inputTail, "utf8") });
|
|
1590
|
+
run2.inputTail = "";
|
|
1591
|
+
run2.discarding = true;
|
|
1592
|
+
}
|
|
1535
1593
|
return true;
|
|
1536
1594
|
},
|
|
1537
1595
|
close(ch) {
|
|
@@ -2326,7 +2384,7 @@ async function status3() {
|
|
|
2326
2384
|
}
|
|
2327
2385
|
|
|
2328
2386
|
// src/version.ts
|
|
2329
|
-
var AGENT_VERSION = "0.
|
|
2387
|
+
var AGENT_VERSION = "0.6.0";
|
|
2330
2388
|
|
|
2331
2389
|
// src/rpc/update.ts
|
|
2332
2390
|
var PACKAGE = "@termhub/agent";
|
|
@@ -2465,7 +2523,7 @@ function detectOs(platform = process.platform) {
|
|
|
2465
2523
|
if (platform === "linux") return "linux";
|
|
2466
2524
|
return null;
|
|
2467
2525
|
}
|
|
2468
|
-
var CAPABILITIES = [CAPABILITY_CLAUDE, CAPABILITY_CLAUDE_SYSTEM_PROMPT];
|
|
2526
|
+
var CAPABILITIES = [CAPABILITY_CLAUDE, CAPABILITY_CLAUDE_SYSTEM_PROMPT, CAPABILITY_CLAUDE_STREAM_INPUT];
|
|
2469
2527
|
function capabilitiesFor(osName) {
|
|
2470
2528
|
return osName === "macos" ? [...CAPABILITIES, CAPABILITY_SIM] : [...CAPABILITIES];
|
|
2471
2529
|
}
|
package/package.json
CHANGED