@annals/agent-mesh 0.16.10 → 0.16.12
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
|
@@ -24,7 +24,7 @@ The ticket is one-time use and expires in 15 minutes.
|
|
|
24
24
|
|
|
25
25
|
| Agent | Status | How it connects |
|
|
26
26
|
|-------|--------|-----------------|
|
|
27
|
-
| [
|
|
27
|
+
| [Claude Code](https://github.com/nicepkg/claude) | Available | WebSocket to local gateway (Protocol v3) |
|
|
28
28
|
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | Available | stdio (stream-json format) |
|
|
29
29
|
| Codex CLI | Planned | — |
|
|
30
30
|
| Gemini CLI | Planned | — |
|
|
@@ -36,8 +36,8 @@ agent-mesh connect [type] # Connect agent to platform
|
|
|
36
36
|
--setup <url> # One-click setup from ticket URL
|
|
37
37
|
--agent-id <id> # Agent UUID
|
|
38
38
|
--project <path> # Project path (Claude adapter)
|
|
39
|
-
--gateway-url <url> #
|
|
40
|
-
--gateway-token <token> #
|
|
39
|
+
--gateway-url <url> # Claude Code gateway URL
|
|
40
|
+
--gateway-token <token> # Claude Code gateway token
|
|
41
41
|
--sandbox # Run inside sandbox (macOS, requires srt)
|
|
42
42
|
|
|
43
43
|
agent-mesh login # Authenticate
|
|
@@ -49,7 +49,7 @@ agent-mesh status # Check connection
|
|
|
49
49
|
```
|
|
50
50
|
Your machine Cloud Users
|
|
51
51
|
┌──────────────────┐ outbound ┌─────────────────────┐ ┌──────────┐
|
|
52
|
-
│
|
|
52
|
+
│ Claude Code │ WebSocket │ │ │ │
|
|
53
53
|
│ Claude Code ├──────────────► │ bridge.agents.hot │ ◄── │ Platform │
|
|
54
54
|
│ Codex (planned) │ (no inbound │ (Cloudflare Worker)│ │ IM bots │
|
|
55
55
|
│ Gemini (planned) │ ports) │ │ │ API │
|
|
@@ -83,7 +83,7 @@ For Claude Code agents, any files the agent creates or modifies are automaticall
|
|
|
83
83
|
|
|
84
84
|
## 中文说明
|
|
85
85
|
|
|
86
|
-
Agent Mesh CLI 把你本地的 AI Agent(
|
|
86
|
+
Agent Mesh CLI 把你本地的 AI Agent(Claude Code、Claude Code 等)接入 [agents.hot](https://agents.hot) 平台。用户在网页聊天,你赚钱。Agent 始终运行在你自己的机器上,无需开放端口。
|
|
87
87
|
|
|
88
88
|
每个用户自动获得独立的工作目录(workspace 隔离),Claude Code 的输出文件会自动上传回平台。
|
|
89
89
|
|
|
@@ -40,6 +40,16 @@ function updateConfig(partial) {
|
|
|
40
40
|
const existing = loadConfig();
|
|
41
41
|
saveConfig({ ...existing, ...partial });
|
|
42
42
|
}
|
|
43
|
+
function maybePrintDocsHint(docsUrl) {
|
|
44
|
+
const config = loadConfig();
|
|
45
|
+
if (config.docsHintShownAt) return;
|
|
46
|
+
process.stderr.write(`
|
|
47
|
+
[agent-mesh] Docs: ${docsUrl}
|
|
48
|
+
|
|
49
|
+
`);
|
|
50
|
+
config.docsHintShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
51
|
+
saveConfig(config);
|
|
52
|
+
}
|
|
43
53
|
function parsePositiveInt(raw) {
|
|
44
54
|
if (typeof raw !== "number" || !Number.isFinite(raw)) return void 0;
|
|
45
55
|
const n = Math.floor(raw);
|
|
@@ -944,6 +954,7 @@ export {
|
|
|
944
954
|
DEFAULT_RUNTIME_CONFIG,
|
|
945
955
|
loadConfig,
|
|
946
956
|
updateConfig,
|
|
957
|
+
maybePrintDocsHint,
|
|
947
958
|
resolveRuntimeConfig,
|
|
948
959
|
getRuntimeConfig,
|
|
949
960
|
updateRuntimeConfig,
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
isProcessAlive,
|
|
17
17
|
listAgents,
|
|
18
18
|
loadConfig,
|
|
19
|
+
maybePrintDocsHint,
|
|
19
20
|
readPid,
|
|
20
21
|
registerListCommand,
|
|
21
22
|
removeAgent,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
updateConfig,
|
|
30
31
|
updateRuntimeConfig,
|
|
31
32
|
writePid
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-KEUGYA3L.js";
|
|
33
34
|
|
|
34
35
|
// src/index.ts
|
|
35
36
|
import { createRequire } from "module";
|
|
@@ -810,7 +811,7 @@ var BridgeManager = class {
|
|
|
810
811
|
}
|
|
811
812
|
async dispatchWithLocalQueue(opts) {
|
|
812
813
|
const { msg, handle, requestKey } = opts;
|
|
813
|
-
const { session_id, request_id, content, attachments, upload_url, upload_token, client_id } = msg;
|
|
814
|
+
const { session_id, request_id, content, attachments, upload_url, upload_token, client_id, platform_task } = msg;
|
|
814
815
|
const state = this.requestDispatches.get(requestKey);
|
|
815
816
|
if (!state) return;
|
|
816
817
|
try {
|
|
@@ -831,7 +832,7 @@ var BridgeManager = class {
|
|
|
831
832
|
}
|
|
832
833
|
const uploadCredentials = upload_url && upload_token ? { uploadUrl: upload_url, uploadToken: upload_token } : void 0;
|
|
833
834
|
try {
|
|
834
|
-
handle.send(content, attachments, uploadCredentials, client_id);
|
|
835
|
+
handle.send(content, attachments, uploadCredentials, client_id, platform_task);
|
|
835
836
|
this.sessionLastSeenAt.set(session_id, Date.now());
|
|
836
837
|
} catch (err) {
|
|
837
838
|
log.error(`Failed to send to adapter: ${err}`);
|
|
@@ -889,13 +890,16 @@ var BridgeManager = class {
|
|
|
889
890
|
this.wsClient.send(chunk);
|
|
890
891
|
this.sessionLastSeenAt.set(sessionId, Date.now());
|
|
891
892
|
});
|
|
892
|
-
handle.onDone((
|
|
893
|
+
handle.onDone((payload) => {
|
|
893
894
|
void this.releaseRequestLease(sessionId, requestRef.requestId, "done");
|
|
895
|
+
const attachments = payload?.attachments;
|
|
896
|
+
const fileManifest = payload?.fileManifest;
|
|
894
897
|
const done = {
|
|
895
898
|
type: "done",
|
|
896
899
|
session_id: sessionId,
|
|
897
900
|
request_id: requestRef.requestId,
|
|
898
901
|
...attachments && attachments.length > 0 && { attachments },
|
|
902
|
+
...fileManifest && fileManifest.length > 0 && { file_manifest: fileManifest },
|
|
899
903
|
...fullResponseBuffer && { result: fullResponseBuffer }
|
|
900
904
|
};
|
|
901
905
|
this.trackRequest(sessionId, requestRef.requestId, "done");
|
|
@@ -1125,7 +1129,6 @@ var SENSITIVE_PATHS = [
|
|
|
1125
1129
|
"~/.claude/ide",
|
|
1126
1130
|
// IDE integration data
|
|
1127
1131
|
// Other AI agent configs (contain API keys / tokens)
|
|
1128
|
-
"~/.openclaw",
|
|
1129
1132
|
// ~/.agent-mesh — fine-grained: block tokens/config, allow agent workspaces
|
|
1130
1133
|
// NOT blocked: ~/.agent-mesh/agents/ (per-agent project workspaces used as cwd)
|
|
1131
1134
|
"~/.agent-mesh/config.json",
|
|
@@ -1150,11 +1153,6 @@ var SANDBOX_PRESETS = {
|
|
|
1150
1153
|
denyRead: [...SENSITIVE_PATHS],
|
|
1151
1154
|
allowWrite: [".", "/tmp"],
|
|
1152
1155
|
denyWrite: [".env", ".env.*"]
|
|
1153
|
-
},
|
|
1154
|
-
openclaw: {
|
|
1155
|
-
denyRead: [...SENSITIVE_PATHS],
|
|
1156
|
-
allowWrite: ["/tmp"],
|
|
1157
|
-
denyWrite: [".env", ".env.*"]
|
|
1158
1156
|
}
|
|
1159
1157
|
};
|
|
1160
1158
|
var sandboxManager = null;
|
|
@@ -1425,13 +1423,12 @@ function createClientWorkspace(projectPath, clientId) {
|
|
|
1425
1423
|
}
|
|
1426
1424
|
|
|
1427
1425
|
// src/adapters/claude.ts
|
|
1428
|
-
import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
|
|
1426
|
+
import { readFile as readFile2, writeFile, mkdir, stat as stat2 } from "fs/promises";
|
|
1429
1427
|
import { join as join5, relative as relative3, basename } from "path";
|
|
1430
1428
|
|
|
1431
1429
|
// src/utils/auto-upload.ts
|
|
1432
1430
|
import { readdir, readFile, stat } from "fs/promises";
|
|
1433
1431
|
import { join as join4, relative as relative2 } from "path";
|
|
1434
|
-
var MAX_AUTO_UPLOAD_FILES = 50;
|
|
1435
1432
|
var MAX_AUTO_UPLOAD_FILE_SIZE = 10 * 1024 * 1024;
|
|
1436
1433
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
1437
1434
|
".git",
|
|
@@ -1485,76 +1482,152 @@ async function collectRealFiles(dir, maxFiles = Infinity) {
|
|
|
1485
1482
|
await walk(dir);
|
|
1486
1483
|
return files;
|
|
1487
1484
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1485
|
+
|
|
1486
|
+
// src/utils/zip.ts
|
|
1487
|
+
import { deflateRawSync, inflateRawSync } from "zlib";
|
|
1488
|
+
function dosTime(date) {
|
|
1489
|
+
return {
|
|
1490
|
+
time: date.getHours() << 11 | date.getMinutes() << 5 | date.getSeconds() >> 1,
|
|
1491
|
+
date: date.getFullYear() - 1980 << 9 | date.getMonth() + 1 << 5 | date.getDate()
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
function crc32(buf) {
|
|
1495
|
+
let crc = 4294967295;
|
|
1496
|
+
for (let i = 0; i < buf.length; i++) {
|
|
1497
|
+
crc ^= buf[i];
|
|
1498
|
+
for (let j = 0; j < 8; j++) {
|
|
1499
|
+
crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
1498
1500
|
}
|
|
1499
|
-
log.debug(`Workspace snapshot: ${snapshot.size} files`);
|
|
1500
|
-
} catch (err) {
|
|
1501
|
-
log.debug(`Workspace snapshot failed: ${err}`);
|
|
1502
1501
|
}
|
|
1503
|
-
return
|
|
1502
|
+
return (crc ^ 4294967295) >>> 0;
|
|
1504
1503
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1504
|
+
function writeUint16LE(buf, val, offset) {
|
|
1505
|
+
buf[offset] = val & 255;
|
|
1506
|
+
buf[offset + 1] = val >>> 8 & 255;
|
|
1507
|
+
}
|
|
1508
|
+
function writeUint32LE(buf, val, offset) {
|
|
1509
|
+
buf[offset] = val & 255;
|
|
1510
|
+
buf[offset + 1] = val >>> 8 & 255;
|
|
1511
|
+
buf[offset + 2] = val >>> 16 & 255;
|
|
1512
|
+
buf[offset + 3] = val >>> 24 & 255;
|
|
1513
|
+
}
|
|
1514
|
+
function createZipBuffer(entries) {
|
|
1515
|
+
const now = /* @__PURE__ */ new Date();
|
|
1516
|
+
const { time, date } = dosTime(now);
|
|
1517
|
+
const records = [];
|
|
1518
|
+
const chunks = [];
|
|
1519
|
+
let offset = 0;
|
|
1520
|
+
for (const entry of entries) {
|
|
1521
|
+
const nameBytes = Buffer.from(entry.path, "utf-8");
|
|
1522
|
+
const crc = crc32(entry.data);
|
|
1523
|
+
const compressed = deflateRawSync(entry.data, { level: 6 });
|
|
1524
|
+
const compressedSize = compressed.length;
|
|
1525
|
+
const uncompressedSize = entry.data.length;
|
|
1526
|
+
const header = Buffer.alloc(30 + nameBytes.length);
|
|
1527
|
+
writeUint32LE(header, 67324752, 0);
|
|
1528
|
+
writeUint16LE(header, 20, 4);
|
|
1529
|
+
writeUint16LE(header, 0, 6);
|
|
1530
|
+
writeUint16LE(header, 8, 8);
|
|
1531
|
+
writeUint16LE(header, time, 10);
|
|
1532
|
+
writeUint16LE(header, date, 12);
|
|
1533
|
+
writeUint32LE(header, crc, 14);
|
|
1534
|
+
writeUint32LE(header, compressedSize, 18);
|
|
1535
|
+
writeUint32LE(header, uncompressedSize, 22);
|
|
1536
|
+
writeUint16LE(header, nameBytes.length, 26);
|
|
1537
|
+
writeUint16LE(header, 0, 28);
|
|
1538
|
+
nameBytes.copy(header, 30);
|
|
1539
|
+
records.push({ header, compressed, crc, compressedSize, uncompressedSize, offset });
|
|
1540
|
+
chunks.push(header, compressed);
|
|
1541
|
+
offset += header.length + compressed.length;
|
|
1542
|
+
}
|
|
1543
|
+
const centralDirStart = offset;
|
|
1544
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1545
|
+
const entry = entries[i];
|
|
1546
|
+
const rec = records[i];
|
|
1547
|
+
const nameBytes = Buffer.from(entry.path, "utf-8");
|
|
1548
|
+
const cdh = Buffer.alloc(46 + nameBytes.length);
|
|
1549
|
+
writeUint32LE(cdh, 33639248, 0);
|
|
1550
|
+
writeUint16LE(cdh, 20, 4);
|
|
1551
|
+
writeUint16LE(cdh, 20, 6);
|
|
1552
|
+
writeUint16LE(cdh, 0, 8);
|
|
1553
|
+
writeUint16LE(cdh, 8, 10);
|
|
1554
|
+
writeUint16LE(cdh, time, 12);
|
|
1555
|
+
writeUint16LE(cdh, date, 14);
|
|
1556
|
+
writeUint32LE(cdh, rec.crc, 16);
|
|
1557
|
+
writeUint32LE(cdh, rec.compressedSize, 20);
|
|
1558
|
+
writeUint32LE(cdh, rec.uncompressedSize, 24);
|
|
1559
|
+
writeUint16LE(cdh, nameBytes.length, 28);
|
|
1560
|
+
writeUint16LE(cdh, 0, 30);
|
|
1561
|
+
writeUint16LE(cdh, 0, 32);
|
|
1562
|
+
writeUint16LE(cdh, 0, 34);
|
|
1563
|
+
writeUint16LE(cdh, 0, 36);
|
|
1564
|
+
writeUint32LE(cdh, 0, 38);
|
|
1565
|
+
writeUint32LE(cdh, rec.offset, 42);
|
|
1566
|
+
nameBytes.copy(cdh, 46);
|
|
1567
|
+
chunks.push(cdh);
|
|
1568
|
+
offset += cdh.length;
|
|
1569
|
+
}
|
|
1570
|
+
const centralDirSize = offset - centralDirStart;
|
|
1571
|
+
const eocd = Buffer.alloc(22);
|
|
1572
|
+
writeUint32LE(eocd, 101010256, 0);
|
|
1573
|
+
writeUint16LE(eocd, 0, 4);
|
|
1574
|
+
writeUint16LE(eocd, 0, 6);
|
|
1575
|
+
writeUint16LE(eocd, entries.length, 8);
|
|
1576
|
+
writeUint16LE(eocd, entries.length, 10);
|
|
1577
|
+
writeUint32LE(eocd, centralDirSize, 12);
|
|
1578
|
+
writeUint32LE(eocd, centralDirStart, 16);
|
|
1579
|
+
writeUint16LE(eocd, 0, 20);
|
|
1580
|
+
chunks.push(eocd);
|
|
1581
|
+
return Buffer.concat(chunks);
|
|
1582
|
+
}
|
|
1583
|
+
function extractZipBuffer(buf) {
|
|
1584
|
+
const entries = [];
|
|
1585
|
+
let eocdOffset = -1;
|
|
1586
|
+
for (let i = buf.length - 22; i >= 0; i--) {
|
|
1587
|
+
if (buf.readUInt32LE(i) === 101010256) {
|
|
1588
|
+
eocdOffset = i;
|
|
1589
|
+
break;
|
|
1517
1590
|
}
|
|
1518
1591
|
}
|
|
1519
|
-
if (
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
const
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1592
|
+
if (eocdOffset === -1) {
|
|
1593
|
+
throw new Error("Invalid ZIP: EOCD not found");
|
|
1594
|
+
}
|
|
1595
|
+
const entryCount = buf.readUInt16LE(eocdOffset + 10);
|
|
1596
|
+
const centralDirOffset = buf.readUInt32LE(eocdOffset + 16);
|
|
1597
|
+
let offset = centralDirOffset;
|
|
1598
|
+
for (let i = 0; i < entryCount; i++) {
|
|
1599
|
+
if (buf.readUInt32LE(offset) !== 33639248) {
|
|
1600
|
+
throw new Error(`Invalid ZIP: bad central directory signature at ${offset}`);
|
|
1601
|
+
}
|
|
1602
|
+
const compressionMethod = buf.readUInt16LE(offset + 10);
|
|
1603
|
+
const compressedSize = buf.readUInt32LE(offset + 20);
|
|
1604
|
+
const uncompressedSize = buf.readUInt32LE(offset + 24);
|
|
1605
|
+
const nameLen = buf.readUInt16LE(offset + 28);
|
|
1606
|
+
const extraLen = buf.readUInt16LE(offset + 30);
|
|
1607
|
+
const commentLen = buf.readUInt16LE(offset + 32);
|
|
1608
|
+
const localHeaderOffset = buf.readUInt32LE(offset + 42);
|
|
1609
|
+
const name = buf.subarray(offset + 46, offset + 46 + nameLen).toString("utf-8");
|
|
1610
|
+
if (!name.endsWith("/")) {
|
|
1611
|
+
const localNameLen = buf.readUInt16LE(localHeaderOffset + 26);
|
|
1612
|
+
const localExtraLen = buf.readUInt16LE(localHeaderOffset + 28);
|
|
1613
|
+
const dataOffset = localHeaderOffset + 30 + localNameLen + localExtraLen;
|
|
1614
|
+
const compressedData = buf.subarray(dataOffset, dataOffset + compressedSize);
|
|
1615
|
+
let data;
|
|
1616
|
+
if (compressionMethod === 0) {
|
|
1617
|
+
data = Buffer.from(compressedData);
|
|
1618
|
+
} else if (compressionMethod === 8) {
|
|
1619
|
+
data = inflateRawSync(compressedData);
|
|
1620
|
+
} else {
|
|
1621
|
+
throw new Error(`Unsupported compression method: ${compressionMethod}`);
|
|
1543
1622
|
}
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
1547
|
-
attachments.push({
|
|
1548
|
-
name: filename,
|
|
1549
|
-
url: payload.url,
|
|
1550
|
-
type: MIME_MAP[ext] || "application/octet-stream"
|
|
1551
|
-
});
|
|
1623
|
+
if (data.length !== uncompressedSize) {
|
|
1624
|
+
throw new Error(`Size mismatch for ${name}: expected ${uncompressedSize}, got ${data.length}`);
|
|
1552
1625
|
}
|
|
1553
|
-
|
|
1554
|
-
log.warn(`Auto-upload error for ${absPath}: ${err}`);
|
|
1626
|
+
entries.push({ path: name, data });
|
|
1555
1627
|
}
|
|
1628
|
+
offset += 46 + nameLen + extraLen + commentLen;
|
|
1556
1629
|
}
|
|
1557
|
-
return
|
|
1630
|
+
return entries;
|
|
1558
1631
|
}
|
|
1559
1632
|
|
|
1560
1633
|
// src/adapters/claude.ts
|
|
@@ -1568,9 +1641,9 @@ var CLAUDE_RUNTIME_ALLOW_WRITE_PATHS = [
|
|
|
1568
1641
|
`${HOME_DIR}/.claude.json.tmp`,
|
|
1569
1642
|
`${HOME_DIR}/.local/state/claude`
|
|
1570
1643
|
];
|
|
1571
|
-
var
|
|
1572
|
-
var
|
|
1573
|
-
var
|
|
1644
|
+
var MAX_UPLOAD_FILE_SIZE = 200 * 1024 * 1024;
|
|
1645
|
+
var MAX_COLLECT_FILES = 5e3;
|
|
1646
|
+
var DEFAULT_ZIP_MAX_BYTES = 200 * 1024 * 1024;
|
|
1574
1647
|
function resolveIdleTimeoutMs() {
|
|
1575
1648
|
const raw = process.env.AGENT_BRIDGE_CLAUDE_IDLE_TIMEOUT_MS;
|
|
1576
1649
|
if (!raw) return DEFAULT_IDLE_TIMEOUT;
|
|
@@ -1606,9 +1679,7 @@ var ClaudeSession = class {
|
|
|
1606
1679
|
uploadCredentials = null;
|
|
1607
1680
|
/** Per-client workspace path (symlink-based), set on each send() */
|
|
1608
1681
|
currentWorkspace;
|
|
1609
|
-
|
|
1610
|
-
preMessageSnapshot = /* @__PURE__ */ new Map();
|
|
1611
|
-
send(message, attachments, uploadCredentials, clientId) {
|
|
1682
|
+
send(message, attachments, uploadCredentials, clientId, platformTask) {
|
|
1612
1683
|
this.resetIdleTimer();
|
|
1613
1684
|
this.doneFired = false;
|
|
1614
1685
|
this.chunksEmitted = false;
|
|
@@ -1623,13 +1694,12 @@ var ClaudeSession = class {
|
|
|
1623
1694
|
} else {
|
|
1624
1695
|
this.currentWorkspace = void 0;
|
|
1625
1696
|
}
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
void this.runCollectWorkspaceTask(collectTask);
|
|
1697
|
+
if (platformTask) {
|
|
1698
|
+
void this.runPlatformTask(platformTask);
|
|
1629
1699
|
return;
|
|
1630
1700
|
}
|
|
1631
1701
|
const args = ["-p", message, "--continue", "--output-format", "stream-json", "--verbose", "--include-partial-messages", "--dangerously-skip-permissions"];
|
|
1632
|
-
void this.downloadAttachments(attachments).then(() =>
|
|
1702
|
+
void this.downloadAttachments(attachments).then(() => {
|
|
1633
1703
|
this.launchProcess(args);
|
|
1634
1704
|
});
|
|
1635
1705
|
}
|
|
@@ -1713,80 +1783,151 @@ var ClaudeSession = class {
|
|
|
1713
1783
|
}
|
|
1714
1784
|
});
|
|
1715
1785
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
const tokenMatch = message.match(/UPLOAD_TOKEN=(\S+)/);
|
|
1725
|
-
if (!urlMatch || !tokenMatch) {
|
|
1726
|
-
return null;
|
|
1727
|
-
}
|
|
1728
|
-
return {
|
|
1729
|
-
uploadUrl: urlMatch[1].trim(),
|
|
1730
|
-
uploadToken: tokenMatch[1].trim()
|
|
1731
|
-
};
|
|
1786
|
+
getWorkspaceRoot() {
|
|
1787
|
+
return this.currentWorkspace || this.config.project || process.cwd();
|
|
1788
|
+
}
|
|
1789
|
+
normalizeRelativePath(inputPath) {
|
|
1790
|
+
const normalized = inputPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1791
|
+
if (!normalized || normalized.includes("\0")) return null;
|
|
1792
|
+
if (normalized.split("/").some((seg) => seg === "..")) return null;
|
|
1793
|
+
return normalized;
|
|
1732
1794
|
}
|
|
1733
|
-
async
|
|
1734
|
-
const workspaceRoot = this.currentWorkspace || this.config.project || process.cwd();
|
|
1795
|
+
async runPlatformTask(task) {
|
|
1735
1796
|
try {
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
this.emitChunk("NO_FILES_FOUND");
|
|
1739
|
-
this.doneFired = true;
|
|
1740
|
-
for (const cb of this.doneCallbacks) cb();
|
|
1741
|
-
return;
|
|
1797
|
+
if (!this.uploadCredentials) {
|
|
1798
|
+
throw new Error("Missing upload credentials for platform task");
|
|
1742
1799
|
}
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
const buffer = await readFile2(absPath);
|
|
1748
|
-
if (buffer.length === 0 || buffer.length > MAX_UPLOAD_FILE_SIZE) {
|
|
1749
|
-
continue;
|
|
1750
|
-
}
|
|
1751
|
-
const relPath = relative3(workspaceRoot, absPath).replace(/\\/g, "/");
|
|
1752
|
-
const filename = relPath && !relPath.startsWith("..") ? relPath : absPath.split("/").pop() || "file";
|
|
1753
|
-
const response = await fetch(task.uploadUrl, {
|
|
1754
|
-
method: "POST",
|
|
1755
|
-
headers: {
|
|
1756
|
-
"X-Upload-Token": task.uploadToken,
|
|
1757
|
-
"Content-Type": "application/json"
|
|
1758
|
-
},
|
|
1759
|
-
body: JSON.stringify({
|
|
1760
|
-
filename,
|
|
1761
|
-
content: buffer.toString("base64")
|
|
1762
|
-
})
|
|
1763
|
-
});
|
|
1764
|
-
if (!response.ok) {
|
|
1765
|
-
log.warn(`collect-files upload failed (${response.status}) for ${filename}`);
|
|
1766
|
-
continue;
|
|
1767
|
-
}
|
|
1768
|
-
const payload = await response.json();
|
|
1769
|
-
if (typeof payload.url === "string" && payload.url.length > 0) {
|
|
1770
|
-
uploadedUrls.push(payload.url);
|
|
1771
|
-
}
|
|
1772
|
-
} catch (error) {
|
|
1773
|
-
log.warn(`collect-files upload error for ${absPath}: ${error}`);
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
if (uploadedUrls.length === 0) {
|
|
1777
|
-
this.emitChunk("COLLECT_FILES_FAILED");
|
|
1800
|
+
if (task.type === "upload_file") {
|
|
1801
|
+
await this.runUploadFileTask(task.path);
|
|
1802
|
+
} else if (task.type === "upload_all_zip") {
|
|
1803
|
+
await this.runUploadAllZipTask(task.zip_name, task.max_bytes);
|
|
1778
1804
|
} else {
|
|
1779
|
-
|
|
1805
|
+
throw new Error(`Unsupported platform task: ${task.type || "unknown"}`);
|
|
1780
1806
|
}
|
|
1781
1807
|
this.doneFired = true;
|
|
1782
|
-
for (const cb of this.doneCallbacks) cb();
|
|
1783
1808
|
} catch (error) {
|
|
1784
|
-
this.emitError(new Error(`
|
|
1809
|
+
this.emitError(new Error(`Platform task failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
async runUploadFileTask(path) {
|
|
1813
|
+
const workspaceRoot = this.getWorkspaceRoot();
|
|
1814
|
+
const relPath = this.normalizeRelativePath(path);
|
|
1815
|
+
if (!relPath) {
|
|
1816
|
+
throw new Error("Invalid file path");
|
|
1817
|
+
}
|
|
1818
|
+
const absPath = join5(workspaceRoot, relPath);
|
|
1819
|
+
const info = await stat2(absPath);
|
|
1820
|
+
if (!info.isFile()) {
|
|
1821
|
+
throw new Error("Path is not a regular file");
|
|
1822
|
+
}
|
|
1823
|
+
const buffer = await readFile2(absPath);
|
|
1824
|
+
if (buffer.length === 0 || buffer.length > MAX_UPLOAD_FILE_SIZE) {
|
|
1825
|
+
throw new Error(`File size out of bounds: ${buffer.length}`);
|
|
1826
|
+
}
|
|
1827
|
+
const uploaded = await this.uploadBuffer(relPath, buffer);
|
|
1828
|
+
for (const cb of this.doneCallbacks) cb({ attachments: [uploaded] });
|
|
1829
|
+
}
|
|
1830
|
+
async runUploadAllZipTask(zipName, maxBytes) {
|
|
1831
|
+
const workspaceRoot = this.getWorkspaceRoot();
|
|
1832
|
+
const files = await this.collectWorkspaceFiles(workspaceRoot);
|
|
1833
|
+
if (files.length === 0) {
|
|
1834
|
+
throw new Error("No files found");
|
|
1785
1835
|
}
|
|
1836
|
+
const maxZipBytes = typeof maxBytes === "number" && Number.isFinite(maxBytes) && maxBytes > 0 ? Math.floor(maxBytes) : DEFAULT_ZIP_MAX_BYTES;
|
|
1837
|
+
const entries = [];
|
|
1838
|
+
let totalBytes = 0;
|
|
1839
|
+
for (const absPath of files) {
|
|
1840
|
+
this.resetIdleTimer();
|
|
1841
|
+
const relPath = relative3(workspaceRoot, absPath).replace(/\\/g, "/");
|
|
1842
|
+
if (!relPath || relPath.startsWith("..")) continue;
|
|
1843
|
+
const buffer = await readFile2(absPath);
|
|
1844
|
+
if (buffer.length === 0) continue;
|
|
1845
|
+
totalBytes += buffer.length;
|
|
1846
|
+
if (totalBytes > maxZipBytes) {
|
|
1847
|
+
throw new Error(`ZIP_TOO_LARGE:${totalBytes}`);
|
|
1848
|
+
}
|
|
1849
|
+
entries.push({ path: relPath, data: buffer });
|
|
1850
|
+
}
|
|
1851
|
+
const zipBuffer = createZipBuffer(entries);
|
|
1852
|
+
if (zipBuffer.length > maxZipBytes) {
|
|
1853
|
+
throw new Error(`ZIP_TOO_LARGE:${zipBuffer.length}`);
|
|
1854
|
+
}
|
|
1855
|
+
const safeZipName = this.normalizeRelativePath(zipName || "") || `workspace-${this.sessionId.slice(0, 8)}.zip`;
|
|
1856
|
+
const uploaded = await this.uploadBuffer(safeZipName.endsWith(".zip") ? safeZipName : `${safeZipName}.zip`, zipBuffer);
|
|
1857
|
+
for (const cb of this.doneCallbacks) cb({ attachments: [uploaded] });
|
|
1858
|
+
}
|
|
1859
|
+
async uploadBuffer(filename, buffer) {
|
|
1860
|
+
const creds = this.uploadCredentials;
|
|
1861
|
+
if (!creds) {
|
|
1862
|
+
throw new Error("Upload credentials missing");
|
|
1863
|
+
}
|
|
1864
|
+
const response = await fetch(creds.uploadUrl, {
|
|
1865
|
+
method: "POST",
|
|
1866
|
+
headers: {
|
|
1867
|
+
"X-Upload-Token": creds.uploadToken,
|
|
1868
|
+
"Content-Type": "application/json"
|
|
1869
|
+
},
|
|
1870
|
+
body: JSON.stringify({
|
|
1871
|
+
filename,
|
|
1872
|
+
content: buffer.toString("base64")
|
|
1873
|
+
})
|
|
1874
|
+
});
|
|
1875
|
+
if (!response.ok) {
|
|
1876
|
+
throw new Error(`Upload failed (${response.status}) for ${filename}`);
|
|
1877
|
+
}
|
|
1878
|
+
const payload = await response.json();
|
|
1879
|
+
if (typeof payload.url !== "string" || payload.url.length === 0) {
|
|
1880
|
+
throw new Error(`Upload response missing url for ${filename}`);
|
|
1881
|
+
}
|
|
1882
|
+
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
1883
|
+
return {
|
|
1884
|
+
name: filename,
|
|
1885
|
+
url: payload.url,
|
|
1886
|
+
type: MIME_MAP[ext] || "application/octet-stream"
|
|
1887
|
+
};
|
|
1786
1888
|
}
|
|
1787
1889
|
async collectWorkspaceFiles(workspaceRoot) {
|
|
1788
1890
|
return collectRealFiles(workspaceRoot, MAX_COLLECT_FILES);
|
|
1789
1891
|
}
|
|
1892
|
+
async collectWorkspaceManifest(workspaceRoot) {
|
|
1893
|
+
const files = await this.collectWorkspaceFiles(workspaceRoot);
|
|
1894
|
+
const manifest = [];
|
|
1895
|
+
for (const absPath of files) {
|
|
1896
|
+
const relPath = relative3(workspaceRoot, absPath).replace(/\\/g, "/");
|
|
1897
|
+
if (!relPath || relPath.startsWith("..")) continue;
|
|
1898
|
+
try {
|
|
1899
|
+
const fileStat = await stat2(absPath);
|
|
1900
|
+
if (!fileStat.isFile()) continue;
|
|
1901
|
+
const ext = relPath.split(".").pop()?.toLowerCase() || "";
|
|
1902
|
+
manifest.push({
|
|
1903
|
+
path: relPath,
|
|
1904
|
+
size: fileStat.size,
|
|
1905
|
+
mtime_ms: Math.floor(fileStat.mtimeMs),
|
|
1906
|
+
type: MIME_MAP[ext] || "application/octet-stream"
|
|
1907
|
+
});
|
|
1908
|
+
} catch {
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
manifest.sort((a, b) => a.path.localeCompare(b.path));
|
|
1912
|
+
return manifest;
|
|
1913
|
+
}
|
|
1914
|
+
async finalizeDone(attachments) {
|
|
1915
|
+
const workspaceRoot = this.getWorkspaceRoot();
|
|
1916
|
+
let fileManifest;
|
|
1917
|
+
try {
|
|
1918
|
+
fileManifest = await this.collectWorkspaceManifest(workspaceRoot);
|
|
1919
|
+
} catch (error) {
|
|
1920
|
+
log.warn(`Manifest collection failed: ${error}`);
|
|
1921
|
+
}
|
|
1922
|
+
const payload = {};
|
|
1923
|
+
if (attachments && attachments.length > 0) {
|
|
1924
|
+
payload.attachments = attachments;
|
|
1925
|
+
}
|
|
1926
|
+
if (fileManifest) {
|
|
1927
|
+
payload.fileManifest = fileManifest;
|
|
1928
|
+
}
|
|
1929
|
+
for (const cb of this.doneCallbacks) cb(payload);
|
|
1930
|
+
}
|
|
1790
1931
|
onChunk(cb) {
|
|
1791
1932
|
this.chunkCallbacks.push(cb);
|
|
1792
1933
|
}
|
|
@@ -1921,47 +2062,15 @@ var ClaudeSession = class {
|
|
|
1921
2062
|
}
|
|
1922
2063
|
}
|
|
1923
2064
|
this.doneFired = true;
|
|
1924
|
-
void this.
|
|
2065
|
+
void this.finalizeDone();
|
|
1925
2066
|
return;
|
|
1926
2067
|
}
|
|
1927
2068
|
if (event.type === "assistant" && event.subtype === "end") {
|
|
1928
2069
|
this.doneFired = true;
|
|
1929
|
-
|
|
2070
|
+
void this.finalizeDone();
|
|
1930
2071
|
return;
|
|
1931
2072
|
}
|
|
1932
2073
|
}
|
|
1933
|
-
/**
|
|
1934
|
-
* Auto-upload new/modified files from workspace, then fire done callbacks.
|
|
1935
|
-
*/
|
|
1936
|
-
async autoUploadAndDone() {
|
|
1937
|
-
let attachments;
|
|
1938
|
-
const workspaceRoot = this.currentWorkspace || this.config.project;
|
|
1939
|
-
if (this.uploadCredentials && workspaceRoot) {
|
|
1940
|
-
try {
|
|
1941
|
-
attachments = await diffAndUpload({
|
|
1942
|
-
workspace: workspaceRoot,
|
|
1943
|
-
snapshot: this.preMessageSnapshot,
|
|
1944
|
-
uploadUrl: this.uploadCredentials.uploadUrl,
|
|
1945
|
-
uploadToken: this.uploadCredentials.uploadToken
|
|
1946
|
-
});
|
|
1947
|
-
if (attachments && attachments.length > 0) {
|
|
1948
|
-
log.info(`Auto-uploaded ${attachments.length} file(s) from workspace`);
|
|
1949
|
-
}
|
|
1950
|
-
} catch (err) {
|
|
1951
|
-
log.warn(`Auto-upload failed: ${err}`);
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
for (const cb of this.doneCallbacks) cb(attachments);
|
|
1955
|
-
}
|
|
1956
|
-
/**
|
|
1957
|
-
* Snapshot all files in the workspace before Claude starts processing.
|
|
1958
|
-
*/
|
|
1959
|
-
async takeSnapshot() {
|
|
1960
|
-
this.preMessageSnapshot.clear();
|
|
1961
|
-
const workspaceRoot = this.currentWorkspace || this.config.project;
|
|
1962
|
-
if (!workspaceRoot) return;
|
|
1963
|
-
this.preMessageSnapshot = await snapshotWorkspace(workspaceRoot);
|
|
1964
|
-
}
|
|
1965
2074
|
emitChunk(text) {
|
|
1966
2075
|
this.chunksEmitted = true;
|
|
1967
2076
|
for (const cb of this.chunkCallbacks) cb(text);
|
|
@@ -2132,7 +2241,7 @@ function registerConnectCommand(program2) {
|
|
|
2132
2241
|
log.error(`Failed to start. Check logs: ${getLogPath(slug)}`);
|
|
2133
2242
|
process.exit(1);
|
|
2134
2243
|
}
|
|
2135
|
-
const { ListTUI } = await import("./list-
|
|
2244
|
+
const { ListTUI } = await import("./list-ROLJARYB.js");
|
|
2136
2245
|
const tui = new ListTUI();
|
|
2137
2246
|
await tui.run();
|
|
2138
2247
|
return;
|
|
@@ -3284,6 +3393,10 @@ async function asyncChat(opts) {
|
|
|
3284
3393
|
`);
|
|
3285
3394
|
}
|
|
3286
3395
|
}
|
|
3396
|
+
if (task.file_manifest) {
|
|
3397
|
+
process.stdout.write(`${GRAY}[manifest: ${task.file_manifest.length} files]${RESET}
|
|
3398
|
+
`);
|
|
3399
|
+
}
|
|
3287
3400
|
return;
|
|
3288
3401
|
}
|
|
3289
3402
|
if (task.status === "failed") {
|
|
@@ -3490,7 +3603,7 @@ import { readFile as readFile4, writeFile as writeFile3, readdir as readdir2, mk
|
|
|
3490
3603
|
import { join as join9, resolve, relative as relative4 } from "path";
|
|
3491
3604
|
|
|
3492
3605
|
// src/utils/skill-parser.ts
|
|
3493
|
-
import { readFile as readFile3, writeFile as writeFile2, stat as
|
|
3606
|
+
import { readFile as readFile3, writeFile as writeFile2, stat as stat3 } from "fs/promises";
|
|
3494
3607
|
import { join as join8 } from "path";
|
|
3495
3608
|
function parseSkillMd(raw) {
|
|
3496
3609
|
const trimmed = raw.trimStart();
|
|
@@ -3601,7 +3714,7 @@ async function loadSkillManifest(dir) {
|
|
|
3601
3714
|
}
|
|
3602
3715
|
async function pathExists(p) {
|
|
3603
3716
|
try {
|
|
3604
|
-
await
|
|
3717
|
+
await stat3(p);
|
|
3605
3718
|
return true;
|
|
3606
3719
|
} catch {
|
|
3607
3720
|
return false;
|
|
@@ -3632,153 +3745,6 @@ ${updated}${after}`);
|
|
|
3632
3745
|
}
|
|
3633
3746
|
}
|
|
3634
3747
|
|
|
3635
|
-
// src/utils/zip.ts
|
|
3636
|
-
import { deflateRawSync, inflateRawSync } from "zlib";
|
|
3637
|
-
function dosTime(date) {
|
|
3638
|
-
return {
|
|
3639
|
-
time: date.getHours() << 11 | date.getMinutes() << 5 | date.getSeconds() >> 1,
|
|
3640
|
-
date: date.getFullYear() - 1980 << 9 | date.getMonth() + 1 << 5 | date.getDate()
|
|
3641
|
-
};
|
|
3642
|
-
}
|
|
3643
|
-
function crc32(buf) {
|
|
3644
|
-
let crc = 4294967295;
|
|
3645
|
-
for (let i = 0; i < buf.length; i++) {
|
|
3646
|
-
crc ^= buf[i];
|
|
3647
|
-
for (let j = 0; j < 8; j++) {
|
|
3648
|
-
crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
|
-
return (crc ^ 4294967295) >>> 0;
|
|
3652
|
-
}
|
|
3653
|
-
function writeUint16LE(buf, val, offset) {
|
|
3654
|
-
buf[offset] = val & 255;
|
|
3655
|
-
buf[offset + 1] = val >>> 8 & 255;
|
|
3656
|
-
}
|
|
3657
|
-
function writeUint32LE(buf, val, offset) {
|
|
3658
|
-
buf[offset] = val & 255;
|
|
3659
|
-
buf[offset + 1] = val >>> 8 & 255;
|
|
3660
|
-
buf[offset + 2] = val >>> 16 & 255;
|
|
3661
|
-
buf[offset + 3] = val >>> 24 & 255;
|
|
3662
|
-
}
|
|
3663
|
-
function createZipBuffer(entries) {
|
|
3664
|
-
const now = /* @__PURE__ */ new Date();
|
|
3665
|
-
const { time, date } = dosTime(now);
|
|
3666
|
-
const records = [];
|
|
3667
|
-
const chunks = [];
|
|
3668
|
-
let offset = 0;
|
|
3669
|
-
for (const entry of entries) {
|
|
3670
|
-
const nameBytes = Buffer.from(entry.path, "utf-8");
|
|
3671
|
-
const crc = crc32(entry.data);
|
|
3672
|
-
const compressed = deflateRawSync(entry.data, { level: 6 });
|
|
3673
|
-
const compressedSize = compressed.length;
|
|
3674
|
-
const uncompressedSize = entry.data.length;
|
|
3675
|
-
const header = Buffer.alloc(30 + nameBytes.length);
|
|
3676
|
-
writeUint32LE(header, 67324752, 0);
|
|
3677
|
-
writeUint16LE(header, 20, 4);
|
|
3678
|
-
writeUint16LE(header, 0, 6);
|
|
3679
|
-
writeUint16LE(header, 8, 8);
|
|
3680
|
-
writeUint16LE(header, time, 10);
|
|
3681
|
-
writeUint16LE(header, date, 12);
|
|
3682
|
-
writeUint32LE(header, crc, 14);
|
|
3683
|
-
writeUint32LE(header, compressedSize, 18);
|
|
3684
|
-
writeUint32LE(header, uncompressedSize, 22);
|
|
3685
|
-
writeUint16LE(header, nameBytes.length, 26);
|
|
3686
|
-
writeUint16LE(header, 0, 28);
|
|
3687
|
-
nameBytes.copy(header, 30);
|
|
3688
|
-
records.push({ header, compressed, crc, compressedSize, uncompressedSize, offset });
|
|
3689
|
-
chunks.push(header, compressed);
|
|
3690
|
-
offset += header.length + compressed.length;
|
|
3691
|
-
}
|
|
3692
|
-
const centralDirStart = offset;
|
|
3693
|
-
for (let i = 0; i < entries.length; i++) {
|
|
3694
|
-
const entry = entries[i];
|
|
3695
|
-
const rec = records[i];
|
|
3696
|
-
const nameBytes = Buffer.from(entry.path, "utf-8");
|
|
3697
|
-
const cdh = Buffer.alloc(46 + nameBytes.length);
|
|
3698
|
-
writeUint32LE(cdh, 33639248, 0);
|
|
3699
|
-
writeUint16LE(cdh, 20, 4);
|
|
3700
|
-
writeUint16LE(cdh, 20, 6);
|
|
3701
|
-
writeUint16LE(cdh, 0, 8);
|
|
3702
|
-
writeUint16LE(cdh, 8, 10);
|
|
3703
|
-
writeUint16LE(cdh, time, 12);
|
|
3704
|
-
writeUint16LE(cdh, date, 14);
|
|
3705
|
-
writeUint32LE(cdh, rec.crc, 16);
|
|
3706
|
-
writeUint32LE(cdh, rec.compressedSize, 20);
|
|
3707
|
-
writeUint32LE(cdh, rec.uncompressedSize, 24);
|
|
3708
|
-
writeUint16LE(cdh, nameBytes.length, 28);
|
|
3709
|
-
writeUint16LE(cdh, 0, 30);
|
|
3710
|
-
writeUint16LE(cdh, 0, 32);
|
|
3711
|
-
writeUint16LE(cdh, 0, 34);
|
|
3712
|
-
writeUint16LE(cdh, 0, 36);
|
|
3713
|
-
writeUint32LE(cdh, 0, 38);
|
|
3714
|
-
writeUint32LE(cdh, rec.offset, 42);
|
|
3715
|
-
nameBytes.copy(cdh, 46);
|
|
3716
|
-
chunks.push(cdh);
|
|
3717
|
-
offset += cdh.length;
|
|
3718
|
-
}
|
|
3719
|
-
const centralDirSize = offset - centralDirStart;
|
|
3720
|
-
const eocd = Buffer.alloc(22);
|
|
3721
|
-
writeUint32LE(eocd, 101010256, 0);
|
|
3722
|
-
writeUint16LE(eocd, 0, 4);
|
|
3723
|
-
writeUint16LE(eocd, 0, 6);
|
|
3724
|
-
writeUint16LE(eocd, entries.length, 8);
|
|
3725
|
-
writeUint16LE(eocd, entries.length, 10);
|
|
3726
|
-
writeUint32LE(eocd, centralDirSize, 12);
|
|
3727
|
-
writeUint32LE(eocd, centralDirStart, 16);
|
|
3728
|
-
writeUint16LE(eocd, 0, 20);
|
|
3729
|
-
chunks.push(eocd);
|
|
3730
|
-
return Buffer.concat(chunks);
|
|
3731
|
-
}
|
|
3732
|
-
function extractZipBuffer(buf) {
|
|
3733
|
-
const entries = [];
|
|
3734
|
-
let eocdOffset = -1;
|
|
3735
|
-
for (let i = buf.length - 22; i >= 0; i--) {
|
|
3736
|
-
if (buf.readUInt32LE(i) === 101010256) {
|
|
3737
|
-
eocdOffset = i;
|
|
3738
|
-
break;
|
|
3739
|
-
}
|
|
3740
|
-
}
|
|
3741
|
-
if (eocdOffset === -1) {
|
|
3742
|
-
throw new Error("Invalid ZIP: EOCD not found");
|
|
3743
|
-
}
|
|
3744
|
-
const entryCount = buf.readUInt16LE(eocdOffset + 10);
|
|
3745
|
-
const centralDirOffset = buf.readUInt32LE(eocdOffset + 16);
|
|
3746
|
-
let offset = centralDirOffset;
|
|
3747
|
-
for (let i = 0; i < entryCount; i++) {
|
|
3748
|
-
if (buf.readUInt32LE(offset) !== 33639248) {
|
|
3749
|
-
throw new Error(`Invalid ZIP: bad central directory signature at ${offset}`);
|
|
3750
|
-
}
|
|
3751
|
-
const compressionMethod = buf.readUInt16LE(offset + 10);
|
|
3752
|
-
const compressedSize = buf.readUInt32LE(offset + 20);
|
|
3753
|
-
const uncompressedSize = buf.readUInt32LE(offset + 24);
|
|
3754
|
-
const nameLen = buf.readUInt16LE(offset + 28);
|
|
3755
|
-
const extraLen = buf.readUInt16LE(offset + 30);
|
|
3756
|
-
const commentLen = buf.readUInt16LE(offset + 32);
|
|
3757
|
-
const localHeaderOffset = buf.readUInt32LE(offset + 42);
|
|
3758
|
-
const name = buf.subarray(offset + 46, offset + 46 + nameLen).toString("utf-8");
|
|
3759
|
-
if (!name.endsWith("/")) {
|
|
3760
|
-
const localNameLen = buf.readUInt16LE(localHeaderOffset + 26);
|
|
3761
|
-
const localExtraLen = buf.readUInt16LE(localHeaderOffset + 28);
|
|
3762
|
-
const dataOffset = localHeaderOffset + 30 + localNameLen + localExtraLen;
|
|
3763
|
-
const compressedData = buf.subarray(dataOffset, dataOffset + compressedSize);
|
|
3764
|
-
let data;
|
|
3765
|
-
if (compressionMethod === 0) {
|
|
3766
|
-
data = Buffer.from(compressedData);
|
|
3767
|
-
} else if (compressionMethod === 8) {
|
|
3768
|
-
data = inflateRawSync(compressedData);
|
|
3769
|
-
} else {
|
|
3770
|
-
throw new Error(`Unsupported compression method: ${compressionMethod}`);
|
|
3771
|
-
}
|
|
3772
|
-
if (data.length !== uncompressedSize) {
|
|
3773
|
-
throw new Error(`Size mismatch for ${name}: expected ${uncompressedSize}, got ${data.length}`);
|
|
3774
|
-
}
|
|
3775
|
-
entries.push({ path: name, data });
|
|
3776
|
-
}
|
|
3777
|
-
offset += 46 + nameLen + extraLen + commentLen;
|
|
3778
|
-
}
|
|
3779
|
-
return entries;
|
|
3780
|
-
}
|
|
3781
|
-
|
|
3782
3748
|
// src/commands/skills.ts
|
|
3783
3749
|
var slog = {
|
|
3784
3750
|
info: (msg) => {
|
|
@@ -4518,7 +4484,7 @@ async function asyncCall(opts) {
|
|
|
4518
4484
|
}
|
|
4519
4485
|
process.exit(1);
|
|
4520
4486
|
}
|
|
4521
|
-
const { request_id, call_id, status, error_message, error_code } = await res.json();
|
|
4487
|
+
const { request_id, call_id, session_key, status, error_message, error_code } = await res.json();
|
|
4522
4488
|
if (status === "failed") {
|
|
4523
4489
|
log.error(`Call failed: ${error_message || error_code}`);
|
|
4524
4490
|
process.exit(1);
|
|
@@ -4553,9 +4519,11 @@ async function asyncCall(opts) {
|
|
|
4553
4519
|
console.log(JSON.stringify({
|
|
4554
4520
|
call_id,
|
|
4555
4521
|
request_id,
|
|
4522
|
+
...session_key ? { session_key } : {},
|
|
4556
4523
|
status: "completed",
|
|
4557
4524
|
result,
|
|
4558
4525
|
...task.attachments?.length ? { attachments: task.attachments } : {},
|
|
4526
|
+
...Array.isArray(task.file_manifest) ? { file_manifest: task.file_manifest } : {},
|
|
4559
4527
|
rate_hint: `POST /api/agents/${opts.id}/rate body: { call_id: "${call_id}", rating: 1-5 }`
|
|
4560
4528
|
}));
|
|
4561
4529
|
} else {
|
|
@@ -4565,6 +4533,13 @@ async function asyncCall(opts) {
|
|
|
4565
4533
|
log.info(` ${GRAY}File:${RESET} ${att.name} ${GRAY}${att.url}${RESET}`);
|
|
4566
4534
|
}
|
|
4567
4535
|
}
|
|
4536
|
+
const manifest = task.file_manifest;
|
|
4537
|
+
if (Array.isArray(manifest)) {
|
|
4538
|
+
log.info(` ${GRAY}Manifest:${RESET} ${manifest.length} file(s)`);
|
|
4539
|
+
}
|
|
4540
|
+
if (session_key) {
|
|
4541
|
+
log.info(` ${GRAY}Session:${RESET} ${session_key}`);
|
|
4542
|
+
}
|
|
4568
4543
|
}
|
|
4569
4544
|
if (opts.outputFile && result) {
|
|
4570
4545
|
writeFileSync3(opts.outputFile, result);
|
|
@@ -4573,7 +4548,7 @@ async function asyncCall(opts) {
|
|
|
4573
4548
|
if (!opts.json) {
|
|
4574
4549
|
log.info(`${GRAY}Rate this call: agent-mesh rate ${call_id} <1-5> --agent ${opts.id}${RESET}`);
|
|
4575
4550
|
}
|
|
4576
|
-
return { callId: call_id };
|
|
4551
|
+
return { callId: call_id, ...session_key ? { sessionKey: session_key } : {} };
|
|
4577
4552
|
}
|
|
4578
4553
|
if (task.status === "failed") {
|
|
4579
4554
|
if (!opts.json) {
|
|
@@ -4637,7 +4612,7 @@ async function streamCall(opts) {
|
|
|
4637
4612
|
console.log(` ${GRAY}Created${RESET} ${result.created_at}`);
|
|
4638
4613
|
console.log("");
|
|
4639
4614
|
}
|
|
4640
|
-
return;
|
|
4615
|
+
return { callId: result.call_id, ...result.session_key ? { sessionKey: result.session_key } : {} };
|
|
4641
4616
|
}
|
|
4642
4617
|
if (!res.body) {
|
|
4643
4618
|
log.error("Empty response body");
|
|
@@ -4653,6 +4628,7 @@ async function streamCall(opts) {
|
|
|
4653
4628
|
let outputBuffer = "";
|
|
4654
4629
|
let inThinkingBlock = false;
|
|
4655
4630
|
let callId = res.headers.get("X-Call-Id") || "";
|
|
4631
|
+
let sessionKey = res.headers.get("X-Session-Key") || "";
|
|
4656
4632
|
while (true) {
|
|
4657
4633
|
const { done, value } = await reader.read();
|
|
4658
4634
|
if (done) break;
|
|
@@ -4665,6 +4641,9 @@ async function streamCall(opts) {
|
|
|
4665
4641
|
const event = JSON.parse(data);
|
|
4666
4642
|
if (event.type === "start" && event.call_id) {
|
|
4667
4643
|
callId = event.call_id;
|
|
4644
|
+
if (event.session_key) {
|
|
4645
|
+
sessionKey = event.session_key;
|
|
4646
|
+
}
|
|
4668
4647
|
}
|
|
4669
4648
|
if (opts.json) {
|
|
4670
4649
|
console.log(JSON.stringify(event));
|
|
@@ -4688,6 +4667,9 @@ async function streamCall(opts) {
|
|
|
4688
4667
|
for (const att of event.attachments) {
|
|
4689
4668
|
log.info(` ${GRAY}File:${RESET} ${att.name} ${GRAY}${att.url}${RESET}`);
|
|
4690
4669
|
}
|
|
4670
|
+
if (Array.isArray(event.file_manifest)) {
|
|
4671
|
+
log.info(` ${GRAY}Manifest:${RESET} ${event.file_manifest.length} file(s)`);
|
|
4672
|
+
}
|
|
4691
4673
|
} else if (event.type === "error") {
|
|
4692
4674
|
process.stderr.write(`
|
|
4693
4675
|
Error: ${event.message}
|
|
@@ -4726,11 +4708,14 @@ Error: ${event.message}
|
|
|
4726
4708
|
if (!opts.json) {
|
|
4727
4709
|
console.log("\n");
|
|
4728
4710
|
log.success("Call completed");
|
|
4711
|
+
if (sessionKey) {
|
|
4712
|
+
log.info(`${GRAY}Session:${RESET} ${sessionKey}`);
|
|
4713
|
+
}
|
|
4729
4714
|
if (callId) {
|
|
4730
4715
|
log.info(`${GRAY}Rate this call: agent-mesh rate ${callId} <1-5> --agent ${opts.id}${RESET}`);
|
|
4731
4716
|
}
|
|
4732
4717
|
}
|
|
4733
|
-
return { callId };
|
|
4718
|
+
return { callId, ...sessionKey ? { sessionKey } : {} };
|
|
4734
4719
|
}
|
|
4735
4720
|
function registerCallCommand(program2) {
|
|
4736
4721
|
program2.command("call <agent>").description("Call an agent on the A2A network (default: async polling)").requiredOption("--task <description>", "Task description").option("--input-file <path>", "Read file and append to task description").option("--output-file <path>", "Save response text to file").option("--stream", "Use SSE streaming instead of async polling").option("--json", "Output JSONL events").option("--timeout <seconds>", "Timeout in seconds", "300").option("--rate <rating>", "Rate the agent after call (1-5)", parseInt).action(async (agentInput, opts) => {
|
|
@@ -5020,7 +5005,7 @@ function registerSubscribeCommand(program2) {
|
|
|
5020
5005
|
|
|
5021
5006
|
// src/commands/register.ts
|
|
5022
5007
|
var DEFAULT_BASE_URL5 = "https://agents.hot";
|
|
5023
|
-
var VALID_AGENT_TYPES = ["
|
|
5008
|
+
var VALID_AGENT_TYPES = ["claude", "claude-code", "cursor", "windsurf", "custom"];
|
|
5024
5009
|
function registerRegisterCommand(program2) {
|
|
5025
5010
|
program2.command("register").description("Register a new agent on the platform and get an API key").requiredOption("--name <name>", "Agent name (alphanumeric + hyphens, 3-64 chars)").option("--type <type>", "Agent type", "claude-code").option("--description <text>", "Agent description").option("--capabilities <list>", "Comma-separated capabilities").option("--base-url <url>", "Platform base URL", DEFAULT_BASE_URL5).action(async (opts) => {
|
|
5026
5011
|
if (!VALID_AGENT_TYPES.includes(opts.type)) {
|
|
@@ -5228,6 +5213,178 @@ function registerProfileCommand(program2) {
|
|
|
5228
5213
|
});
|
|
5229
5214
|
}
|
|
5230
5215
|
|
|
5216
|
+
// src/commands/files.ts
|
|
5217
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
5218
|
+
import { basename as basename2 } from "path";
|
|
5219
|
+
function formatBytes(bytes) {
|
|
5220
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
5221
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
5222
|
+
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
5223
|
+
}
|
|
5224
|
+
function defaultOutputPath(filePath) {
|
|
5225
|
+
const name = basename2(filePath || "") || "file";
|
|
5226
|
+
return name;
|
|
5227
|
+
}
|
|
5228
|
+
function defaultZipOutputPath(sessionKey) {
|
|
5229
|
+
const suffix = sessionKey.split(":").at(-1) || "session";
|
|
5230
|
+
return `session-${suffix}.zip`;
|
|
5231
|
+
}
|
|
5232
|
+
function handleError7(err) {
|
|
5233
|
+
if (err instanceof PlatformApiError) {
|
|
5234
|
+
log.error(err.message);
|
|
5235
|
+
} else {
|
|
5236
|
+
log.error(err.message);
|
|
5237
|
+
}
|
|
5238
|
+
process.exit(1);
|
|
5239
|
+
}
|
|
5240
|
+
async function resolveTargetAgent(agentInput) {
|
|
5241
|
+
const client = createClient();
|
|
5242
|
+
return resolveAgentId(agentInput, client);
|
|
5243
|
+
}
|
|
5244
|
+
async function downloadToFile(url, outputPath) {
|
|
5245
|
+
const res = await fetch(url);
|
|
5246
|
+
if (!res.ok) {
|
|
5247
|
+
throw new Error(`Download failed: HTTP ${res.status}`);
|
|
5248
|
+
}
|
|
5249
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
5250
|
+
writeFileSync4(outputPath, buf);
|
|
5251
|
+
}
|
|
5252
|
+
function registerFilesCommand(program2) {
|
|
5253
|
+
const files = program2.command("files").description("Session file manifest and on-demand upload/download commands");
|
|
5254
|
+
files.command("list").requiredOption("--agent <agent>", "Target agent ID or name").requiredOption("--session <session_key>", "Session key").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5255
|
+
try {
|
|
5256
|
+
const { id, name } = await resolveTargetAgent(opts.agent);
|
|
5257
|
+
const client = createClient();
|
|
5258
|
+
const data = await client.get(
|
|
5259
|
+
`/api/agents/${id}/files?session_key=${encodeURIComponent(opts.session)}`
|
|
5260
|
+
);
|
|
5261
|
+
if (opts.json) {
|
|
5262
|
+
console.log(JSON.stringify(data));
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
log.banner(`Session Files \u2014 ${BOLD}${name}${RESET}`);
|
|
5266
|
+
console.log(` ${GRAY}Session${RESET} ${data.session_key || opts.session}`);
|
|
5267
|
+
console.log(` ${GRAY}Count${RESET} ${data.files.length}`);
|
|
5268
|
+
if (data.updated_at) {
|
|
5269
|
+
console.log(` ${GRAY}Updated${RESET} ${data.updated_at}`);
|
|
5270
|
+
}
|
|
5271
|
+
console.log("");
|
|
5272
|
+
for (const f of data.files) {
|
|
5273
|
+
console.log(` ${f.path} ${GRAY}${formatBytes(f.size)}${RESET}`);
|
|
5274
|
+
}
|
|
5275
|
+
console.log("");
|
|
5276
|
+
} catch (err) {
|
|
5277
|
+
handleError7(err);
|
|
5278
|
+
}
|
|
5279
|
+
});
|
|
5280
|
+
files.command("upload").requiredOption("--agent <agent>", "Target agent ID or name").requiredOption("--session <session_key>", "Session key").requiredOption("--path <file_path>", "Relative file path in session workspace").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5281
|
+
try {
|
|
5282
|
+
const { id } = await resolveTargetAgent(opts.agent);
|
|
5283
|
+
const client = createClient();
|
|
5284
|
+
const data = await client.post(`/api/agents/${id}/files/upload`, {
|
|
5285
|
+
session_key: opts.session,
|
|
5286
|
+
path: opts.path
|
|
5287
|
+
});
|
|
5288
|
+
if (opts.json) {
|
|
5289
|
+
console.log(JSON.stringify(data));
|
|
5290
|
+
return;
|
|
5291
|
+
}
|
|
5292
|
+
if (!data.file?.url) {
|
|
5293
|
+
throw new Error("No file URL returned");
|
|
5294
|
+
}
|
|
5295
|
+
log.success(`Uploaded ${opts.path}`);
|
|
5296
|
+
console.log(` ${GRAY}URL${RESET} ${data.file.url}`);
|
|
5297
|
+
} catch (err) {
|
|
5298
|
+
handleError7(err);
|
|
5299
|
+
}
|
|
5300
|
+
});
|
|
5301
|
+
files.command("upload-all").requiredOption("--agent <agent>", "Target agent ID or name").requiredOption("--session <session_key>", "Session key").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5302
|
+
try {
|
|
5303
|
+
const { id } = await resolveTargetAgent(opts.agent);
|
|
5304
|
+
const client = createClient();
|
|
5305
|
+
const data = await client.post(`/api/agents/${id}/files/upload-all`, {
|
|
5306
|
+
session_key: opts.session
|
|
5307
|
+
});
|
|
5308
|
+
if (opts.json) {
|
|
5309
|
+
console.log(JSON.stringify(data));
|
|
5310
|
+
return;
|
|
5311
|
+
}
|
|
5312
|
+
if (!data.file?.url) {
|
|
5313
|
+
throw new Error("No ZIP URL returned");
|
|
5314
|
+
}
|
|
5315
|
+
log.success("Uploaded session ZIP");
|
|
5316
|
+
console.log(` ${GRAY}URL${RESET} ${data.file.url}`);
|
|
5317
|
+
} catch (err) {
|
|
5318
|
+
handleError7(err);
|
|
5319
|
+
}
|
|
5320
|
+
});
|
|
5321
|
+
files.command("download").requiredOption("--agent <agent>", "Target agent ID or name").requiredOption("--session <session_key>", "Session key").requiredOption("--path <file_path>", "Relative file path in session workspace").option("--output <path>", "Local output path").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5322
|
+
try {
|
|
5323
|
+
const { id } = await resolveTargetAgent(opts.agent);
|
|
5324
|
+
const client = createClient();
|
|
5325
|
+
const data = await client.post(`/api/agents/${id}/files/upload`, {
|
|
5326
|
+
session_key: opts.session,
|
|
5327
|
+
path: opts.path
|
|
5328
|
+
});
|
|
5329
|
+
const url = data.file?.url;
|
|
5330
|
+
if (!url) throw new Error("No file URL returned");
|
|
5331
|
+
const output = opts.output || defaultOutputPath(opts.path);
|
|
5332
|
+
await downloadToFile(url, output);
|
|
5333
|
+
if (opts.json) {
|
|
5334
|
+
console.log(JSON.stringify({ success: true, output, url }));
|
|
5335
|
+
return;
|
|
5336
|
+
}
|
|
5337
|
+
log.success(`Downloaded ${opts.path}`);
|
|
5338
|
+
console.log(` ${GRAY}Saved${RESET} ${output}`);
|
|
5339
|
+
} catch (err) {
|
|
5340
|
+
handleError7(err);
|
|
5341
|
+
}
|
|
5342
|
+
});
|
|
5343
|
+
files.command("download-all").requiredOption("--agent <agent>", "Target agent ID or name").requiredOption("--session <session_key>", "Session key").option("--output <path>", "Local output path").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5344
|
+
try {
|
|
5345
|
+
const { id } = await resolveTargetAgent(opts.agent);
|
|
5346
|
+
const client = createClient();
|
|
5347
|
+
const data = await client.post(`/api/agents/${id}/files/upload-all`, {
|
|
5348
|
+
session_key: opts.session
|
|
5349
|
+
});
|
|
5350
|
+
const url = data.file?.url;
|
|
5351
|
+
if (!url) throw new Error("No ZIP URL returned");
|
|
5352
|
+
const output = opts.output || defaultZipOutputPath(opts.session);
|
|
5353
|
+
await downloadToFile(url, output);
|
|
5354
|
+
if (opts.json) {
|
|
5355
|
+
console.log(JSON.stringify({ success: true, output, url }));
|
|
5356
|
+
return;
|
|
5357
|
+
}
|
|
5358
|
+
log.success("Downloaded session ZIP");
|
|
5359
|
+
console.log(` ${GRAY}Saved${RESET} ${output}`);
|
|
5360
|
+
} catch (err) {
|
|
5361
|
+
handleError7(err);
|
|
5362
|
+
}
|
|
5363
|
+
});
|
|
5364
|
+
files.command("help").description("Show machine-readable files command reference").option("--json", "Output JSON format").action((opts) => {
|
|
5365
|
+
const reference = {
|
|
5366
|
+
command: "agent-mesh files",
|
|
5367
|
+
docs: "https://agents.hot/docs/cli/files",
|
|
5368
|
+
commands: [
|
|
5369
|
+
{ name: "list", required: ["--agent", "--session"], optional: ["--json"] },
|
|
5370
|
+
{ name: "upload", required: ["--agent", "--session", "--path"], optional: ["--json"] },
|
|
5371
|
+
{ name: "upload-all", required: ["--agent", "--session"], optional: ["--json"] },
|
|
5372
|
+
{ name: "download", required: ["--agent", "--session", "--path"], optional: ["--output", "--json"] },
|
|
5373
|
+
{ name: "download-all", required: ["--agent", "--session"], optional: ["--output", "--json"] }
|
|
5374
|
+
]
|
|
5375
|
+
};
|
|
5376
|
+
if (opts.json) {
|
|
5377
|
+
console.log(JSON.stringify(reference));
|
|
5378
|
+
return;
|
|
5379
|
+
}
|
|
5380
|
+
log.banner("Files Command Reference");
|
|
5381
|
+
console.log(` ${GRAY}Docs${RESET} ${reference.docs}`);
|
|
5382
|
+
for (const item of reference.commands) {
|
|
5383
|
+
console.log(` ${item.name}`);
|
|
5384
|
+
}
|
|
5385
|
+
});
|
|
5386
|
+
}
|
|
5387
|
+
|
|
5231
5388
|
// src/utils/auto-updater.ts
|
|
5232
5389
|
import { spawnSync } from "child_process";
|
|
5233
5390
|
var AUTO_UPGRADE_ENV = "AGENT_MESH_AUTO_UPGRADE";
|
|
@@ -5304,8 +5461,8 @@ function fetchLatestVersion(pkg) {
|
|
|
5304
5461
|
if (result.error || result.status !== 0) return null;
|
|
5305
5462
|
return parseLatestVersion(result.stdout ?? "");
|
|
5306
5463
|
}
|
|
5307
|
-
function
|
|
5308
|
-
const result = spawnSync("npm", ["install", "-g", `${pkg}
|
|
5464
|
+
function installResolvedVersion(pkg, version2) {
|
|
5465
|
+
const result = spawnSync("npm", ["install", "-g", `${pkg}@${version2}`], {
|
|
5309
5466
|
stdio: "inherit",
|
|
5310
5467
|
timeout: INSTALL_TIMEOUT_MS
|
|
5311
5468
|
});
|
|
@@ -5334,7 +5491,7 @@ function maybeAutoUpgradeOnStartup(opts) {
|
|
|
5334
5491
|
if (!latest) return { relaunched: false };
|
|
5335
5492
|
if (compareSemver(latest, current) <= 0) return { relaunched: false };
|
|
5336
5493
|
log.info(`New ${packageName} version found: v${current} -> v${latest}. Upgrading...`);
|
|
5337
|
-
if (!
|
|
5494
|
+
if (!installResolvedVersion(packageName, latest)) {
|
|
5338
5495
|
log.warn("Auto-upgrade failed. Continuing with current version.");
|
|
5339
5496
|
return { relaunched: false };
|
|
5340
5497
|
}
|
|
@@ -5353,6 +5510,14 @@ program.name("agent-mesh").description("Connect local AI agents to the Agents.Ho
|
|
|
5353
5510
|
console.log(version);
|
|
5354
5511
|
process.exit(0);
|
|
5355
5512
|
});
|
|
5513
|
+
program.configureOutput({
|
|
5514
|
+
outputError: (str, write) => {
|
|
5515
|
+
write(str);
|
|
5516
|
+
if (str.trim().length > 0) {
|
|
5517
|
+
write("\nDocs: https://agents.hot/docs/cli\n");
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
});
|
|
5356
5521
|
registerConnectCommand(program);
|
|
5357
5522
|
registerLoginCommand(program);
|
|
5358
5523
|
registerStatusCommand(program);
|
|
@@ -5377,4 +5542,21 @@ registerRegisterCommand(program);
|
|
|
5377
5542
|
registerRateCommand(program);
|
|
5378
5543
|
registerRuntimeCommand(program);
|
|
5379
5544
|
registerProfileCommand(program);
|
|
5545
|
+
registerFilesCommand(program);
|
|
5546
|
+
program.command("help").description("Show CLI help").option("--json", "Output machine-readable command reference").action((opts) => {
|
|
5547
|
+
if (opts.json) {
|
|
5548
|
+
const commands = program.commands.map((cmd) => cmd.name()).filter((name) => name !== "help");
|
|
5549
|
+
console.log(JSON.stringify({
|
|
5550
|
+
name: "agent-mesh",
|
|
5551
|
+
docs: "https://agents.hot/docs/cli",
|
|
5552
|
+
commands
|
|
5553
|
+
}));
|
|
5554
|
+
return;
|
|
5555
|
+
}
|
|
5556
|
+
program.outputHelp();
|
|
5557
|
+
});
|
|
5558
|
+
var wantsJsonOutput = process.argv.includes("--json");
|
|
5559
|
+
if (!wantsJsonOutput && !process.argv.includes("--version") && !process.argv.includes("-v")) {
|
|
5560
|
+
maybePrintDocsHint("https://agents.hot/docs/cli");
|
|
5561
|
+
}
|
|
5380
5562
|
program.parse();
|