@annals/agent-mesh 0.17.0 → 0.17.3
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/index.js
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
} from "./chunk-KEUGYA3L.js";
|
|
34
34
|
|
|
35
35
|
// src/index.ts
|
|
36
|
-
import { createRequire } from "module";
|
|
36
|
+
import { createRequire as createRequire2 } from "module";
|
|
37
37
|
import { program } from "commander";
|
|
38
38
|
|
|
39
39
|
// src/platform/auth.ts
|
|
@@ -271,12 +271,43 @@ import { BridgeErrorCode } from "@annals/bridge-protocol";
|
|
|
271
271
|
|
|
272
272
|
// src/utils/webrtc-transfer.ts
|
|
273
273
|
import { createHash } from "crypto";
|
|
274
|
+
import { createRequire } from "module";
|
|
275
|
+
import { existsSync, copyFileSync, mkdirSync } from "fs";
|
|
276
|
+
import { join, dirname } from "path";
|
|
274
277
|
var ICE_SERVERS = ["stun:stun.l.google.com:19302"];
|
|
275
278
|
var CHUNK_SIZE = 64 * 1024;
|
|
276
279
|
var ndcModule;
|
|
280
|
+
function ensurePrebuilt() {
|
|
281
|
+
try {
|
|
282
|
+
const require3 = createRequire(import.meta.url);
|
|
283
|
+
const ndcMain = require3.resolve("node-datachannel");
|
|
284
|
+
let ndcRoot = dirname(ndcMain);
|
|
285
|
+
for (let i = 0; i < 5; i++) {
|
|
286
|
+
if (existsSync(join(ndcRoot, "package.json"))) break;
|
|
287
|
+
ndcRoot = dirname(ndcRoot);
|
|
288
|
+
}
|
|
289
|
+
const target = join(ndcRoot, "build", "Release", "node_datachannel.node");
|
|
290
|
+
if (existsSync(target)) return true;
|
|
291
|
+
const platform = process.platform;
|
|
292
|
+
const arch = process.arch;
|
|
293
|
+
const ourPkgRoot = join(dirname(import.meta.url.replace("file://", "")), "..", "..");
|
|
294
|
+
const prebuiltSrc = join(ourPkgRoot, "prebuilds", `${platform}-${arch}`, "node_datachannel.node");
|
|
295
|
+
if (!existsSync(prebuiltSrc)) {
|
|
296
|
+
log.warn(`No prebuilt binary for ${platform}-${arch}`);
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
mkdirSync(join(ndcRoot, "build", "Release"), { recursive: true });
|
|
300
|
+
copyFileSync(prebuiltSrc, target);
|
|
301
|
+
log.info(`Installed node-datachannel prebuilt for ${platform}-${arch}`);
|
|
302
|
+
return true;
|
|
303
|
+
} catch {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
277
307
|
async function loadNdc() {
|
|
278
308
|
if (ndcModule !== void 0) return ndcModule;
|
|
279
309
|
try {
|
|
310
|
+
ensurePrebuilt();
|
|
280
311
|
ndcModule = await import("node-datachannel");
|
|
281
312
|
return ndcModule;
|
|
282
313
|
} catch {
|
|
@@ -411,15 +442,15 @@ var SessionPool = class {
|
|
|
411
442
|
|
|
412
443
|
// src/utils/local-runtime-queue.ts
|
|
413
444
|
import {
|
|
414
|
-
existsSync,
|
|
415
|
-
mkdirSync,
|
|
445
|
+
existsSync as existsSync2,
|
|
446
|
+
mkdirSync as mkdirSync2,
|
|
416
447
|
readFileSync,
|
|
417
448
|
renameSync,
|
|
418
449
|
rmSync,
|
|
419
450
|
statSync,
|
|
420
451
|
writeFileSync
|
|
421
452
|
} from "fs";
|
|
422
|
-
import { join } from "path";
|
|
453
|
+
import { join as join2 } from "path";
|
|
423
454
|
import { homedir } from "os";
|
|
424
455
|
var DEFAULT_LOCK_STALE_MS = 3e4;
|
|
425
456
|
var DEFAULT_LOCK_WAIT_MS = 1e4;
|
|
@@ -476,10 +507,10 @@ var LocalRuntimeQueue = class {
|
|
|
476
507
|
leaseHeartbeatMs;
|
|
477
508
|
constructor(config, opts = {}) {
|
|
478
509
|
this.config = config;
|
|
479
|
-
const baseDir = opts.baseDir ||
|
|
480
|
-
this.runtimeRoot =
|
|
481
|
-
this.statePath =
|
|
482
|
-
this.lockPath =
|
|
510
|
+
const baseDir = opts.baseDir || join2(homedir(), ".agent-mesh");
|
|
511
|
+
this.runtimeRoot = join2(baseDir, "runtime");
|
|
512
|
+
this.statePath = join2(this.runtimeRoot, "queue-state.json");
|
|
513
|
+
this.lockPath = join2(this.runtimeRoot, "queue.lock");
|
|
483
514
|
this.lockStaleMs = opts.lockStaleMs ?? DEFAULT_LOCK_STALE_MS;
|
|
484
515
|
this.lockWaitMs = opts.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS;
|
|
485
516
|
this.lockRetryMs = opts.lockRetryMs ?? DEFAULT_LOCK_RETRY_MS;
|
|
@@ -651,8 +682,8 @@ var LocalRuntimeQueue = class {
|
|
|
651
682
|
}
|
|
652
683
|
}
|
|
653
684
|
ensureRuntimeDir() {
|
|
654
|
-
if (!
|
|
655
|
-
|
|
685
|
+
if (!existsSync2(this.runtimeRoot)) {
|
|
686
|
+
mkdirSync2(this.runtimeRoot, { recursive: true, mode: 448 });
|
|
656
687
|
}
|
|
657
688
|
}
|
|
658
689
|
defaultState() {
|
|
@@ -707,7 +738,7 @@ var LocalRuntimeQueue = class {
|
|
|
707
738
|
const acquiredAt = Date.now();
|
|
708
739
|
while (true) {
|
|
709
740
|
try {
|
|
710
|
-
|
|
741
|
+
mkdirSync2(this.lockPath, { mode: 448 });
|
|
711
742
|
break;
|
|
712
743
|
} catch (err) {
|
|
713
744
|
const e = err;
|
|
@@ -1220,6 +1251,32 @@ var BridgeManager = class {
|
|
|
1220
1251
|
}, 5 * 6e4);
|
|
1221
1252
|
timer.unref?.();
|
|
1222
1253
|
this.pendingTransfers.set(offer.transfer_id, { sender, timer });
|
|
1254
|
+
this.pushZipToWorker(offer.transfer_id, zipBuffer);
|
|
1255
|
+
}
|
|
1256
|
+
/** Push ZIP buffer to Worker DO via chunked transfer_upload messages */
|
|
1257
|
+
pushZipToWorker(transferId, zipBuffer) {
|
|
1258
|
+
const CHUNK_SIZE2 = 64 * 1024;
|
|
1259
|
+
const totalChunks = Math.ceil(zipBuffer.length / CHUNK_SIZE2);
|
|
1260
|
+
log.debug(`Pushing ZIP to Worker: transfer=${transferId.slice(0, 8)}... size=${zipBuffer.length} chunks=${totalChunks}`);
|
|
1261
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
1262
|
+
const start = i * CHUNK_SIZE2;
|
|
1263
|
+
const end = Math.min(start + CHUNK_SIZE2, zipBuffer.length);
|
|
1264
|
+
const chunk = zipBuffer.subarray(start, end);
|
|
1265
|
+
const msg = {
|
|
1266
|
+
type: "transfer_upload",
|
|
1267
|
+
transfer_id: transferId,
|
|
1268
|
+
chunk_index: i,
|
|
1269
|
+
total_chunks: totalChunks,
|
|
1270
|
+
data: chunk.toString("base64")
|
|
1271
|
+
};
|
|
1272
|
+
this.wsClient.send(msg);
|
|
1273
|
+
}
|
|
1274
|
+
const complete = {
|
|
1275
|
+
type: "transfer_upload_complete",
|
|
1276
|
+
transfer_id: transferId
|
|
1277
|
+
};
|
|
1278
|
+
this.wsClient.send(complete);
|
|
1279
|
+
log.info(`ZIP pushed to Worker: transfer=${transferId.slice(0, 8)}... (${totalChunks} chunks)`);
|
|
1223
1280
|
}
|
|
1224
1281
|
handleRtcSignalRelay(msg) {
|
|
1225
1282
|
const entry = this.pendingTransfers.get(msg.transfer_id);
|
|
@@ -1254,7 +1311,7 @@ import { spawn } from "child_process";
|
|
|
1254
1311
|
|
|
1255
1312
|
// src/utils/sandbox.ts
|
|
1256
1313
|
import { execSync } from "child_process";
|
|
1257
|
-
import { join as
|
|
1314
|
+
import { join as join3 } from "path";
|
|
1258
1315
|
var SRT_PACKAGE = "@anthropic-ai/sandbox-runtime";
|
|
1259
1316
|
var SENSITIVE_PATHS = [
|
|
1260
1317
|
// SSH & crypto keys
|
|
@@ -1313,7 +1370,7 @@ var sandboxInitialized = false;
|
|
|
1313
1370
|
async function importSandboxManager() {
|
|
1314
1371
|
try {
|
|
1315
1372
|
const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
|
|
1316
|
-
const srtPath =
|
|
1373
|
+
const srtPath = join3(globalRoot, "@anthropic-ai/sandbox-runtime/dist/index.js");
|
|
1317
1374
|
const mod = await import(srtPath);
|
|
1318
1375
|
return mod.SandboxManager;
|
|
1319
1376
|
} catch {
|
|
@@ -1519,8 +1576,8 @@ function which(command) {
|
|
|
1519
1576
|
}
|
|
1520
1577
|
|
|
1521
1578
|
// src/utils/client-workspace.ts
|
|
1522
|
-
import { mkdirSync as
|
|
1523
|
-
import { join as
|
|
1579
|
+
import { mkdirSync as mkdirSync3, readdirSync, symlinkSync, existsSync as existsSync3, lstatSync } from "fs";
|
|
1580
|
+
import { join as join4, relative } from "path";
|
|
1524
1581
|
var SYMLINK_ALLOW = /* @__PURE__ */ new Set([
|
|
1525
1582
|
"CLAUDE.md",
|
|
1526
1583
|
".claude",
|
|
@@ -1549,19 +1606,19 @@ function shouldInclude(name) {
|
|
|
1549
1606
|
return false;
|
|
1550
1607
|
}
|
|
1551
1608
|
function createClientWorkspace(projectPath, clientId) {
|
|
1552
|
-
const wsDir =
|
|
1553
|
-
const isNew = !
|
|
1554
|
-
|
|
1609
|
+
const wsDir = join4(projectPath, ".bridge-clients", clientId);
|
|
1610
|
+
const isNew = !existsSync3(wsDir);
|
|
1611
|
+
mkdirSync3(wsDir, { recursive: true });
|
|
1555
1612
|
const entries = readdirSync(projectPath, { withFileTypes: true });
|
|
1556
1613
|
for (const entry of entries) {
|
|
1557
1614
|
if (!shouldInclude(entry.name)) continue;
|
|
1558
|
-
const link =
|
|
1615
|
+
const link = join4(wsDir, entry.name);
|
|
1559
1616
|
try {
|
|
1560
1617
|
lstatSync(link);
|
|
1561
1618
|
continue;
|
|
1562
1619
|
} catch {
|
|
1563
1620
|
}
|
|
1564
|
-
const target =
|
|
1621
|
+
const target = join4(projectPath, entry.name);
|
|
1565
1622
|
const relTarget = relative(wsDir, target);
|
|
1566
1623
|
try {
|
|
1567
1624
|
symlinkSync(relTarget, link);
|
|
@@ -1577,11 +1634,11 @@ function createClientWorkspace(projectPath, clientId) {
|
|
|
1577
1634
|
|
|
1578
1635
|
// src/adapters/claude.ts
|
|
1579
1636
|
import { writeFile, mkdir, stat as stat2 } from "fs/promises";
|
|
1580
|
-
import { join as
|
|
1637
|
+
import { join as join6, relative as relative3, basename } from "path";
|
|
1581
1638
|
|
|
1582
1639
|
// src/utils/auto-upload.ts
|
|
1583
1640
|
import { readdir, readFile, stat } from "fs/promises";
|
|
1584
|
-
import { join as
|
|
1641
|
+
import { join as join5, relative as relative2 } from "path";
|
|
1585
1642
|
var MAX_AUTO_UPLOAD_FILE_SIZE = 10 * 1024 * 1024;
|
|
1586
1643
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
1587
1644
|
".git",
|
|
@@ -1606,7 +1663,7 @@ async function collectRealFiles(dir, maxFiles = Infinity) {
|
|
|
1606
1663
|
for (const entry of entries) {
|
|
1607
1664
|
if (files.length >= maxFiles) return;
|
|
1608
1665
|
if (entry.isSymbolicLink()) continue;
|
|
1609
|
-
const fullPath =
|
|
1666
|
+
const fullPath = join5(d, entry.name);
|
|
1610
1667
|
if (entry.isDirectory()) {
|
|
1611
1668
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
1612
1669
|
await walk(fullPath);
|
|
@@ -1843,7 +1900,7 @@ var ClaudeSession = class {
|
|
|
1843
1900
|
await mkdir(workspaceRoot, { recursive: true });
|
|
1844
1901
|
for (const att of attachments) {
|
|
1845
1902
|
const safeName = basename(att.name).replace(/[^a-zA-Z0-9._-]/g, "_") || "attachment";
|
|
1846
|
-
const destPath =
|
|
1903
|
+
const destPath = join6(workspaceRoot, safeName);
|
|
1847
1904
|
try {
|
|
1848
1905
|
const res = await fetch(att.url);
|
|
1849
1906
|
if (!res.ok) {
|
|
@@ -2760,7 +2817,7 @@ function registerRestartCommand(program2) {
|
|
|
2760
2817
|
|
|
2761
2818
|
// src/commands/logs.ts
|
|
2762
2819
|
import { spawn as spawn2 } from "child_process";
|
|
2763
|
-
import { existsSync as
|
|
2820
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2764
2821
|
function registerLogsCommand(program2) {
|
|
2765
2822
|
program2.command("logs <name>").description("View agent logs (follows in real-time)").option("-n, --lines <number>", "Number of lines to show", "50").action((name, opts) => {
|
|
2766
2823
|
const entry = getAgent(name);
|
|
@@ -2769,7 +2826,7 @@ function registerLogsCommand(program2) {
|
|
|
2769
2826
|
process.exit(1);
|
|
2770
2827
|
}
|
|
2771
2828
|
const logPath = getLogPath(name);
|
|
2772
|
-
if (!
|
|
2829
|
+
if (!existsSync4(logPath)) {
|
|
2773
2830
|
log.error(`No log file found for "${name}". Has this agent been started before?`);
|
|
2774
2831
|
process.exit(1);
|
|
2775
2832
|
}
|
|
@@ -2850,14 +2907,14 @@ function registerOpenCommand(program2) {
|
|
|
2850
2907
|
}
|
|
2851
2908
|
|
|
2852
2909
|
// src/commands/install.ts
|
|
2853
|
-
import { writeFileSync as writeFileSync2, existsSync as
|
|
2854
|
-
import { join as
|
|
2910
|
+
import { writeFileSync as writeFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
|
|
2911
|
+
import { join as join7 } from "path";
|
|
2855
2912
|
import { homedir as homedir4 } from "os";
|
|
2856
2913
|
import { execSync as execSync2 } from "child_process";
|
|
2857
2914
|
var LABEL = "com.agents-hot.agent-mesh";
|
|
2858
|
-
var PLIST_DIR =
|
|
2859
|
-
var PLIST_PATH =
|
|
2860
|
-
var LOG_PATH =
|
|
2915
|
+
var PLIST_DIR = join7(homedir4(), "Library", "LaunchAgents");
|
|
2916
|
+
var PLIST_PATH = join7(PLIST_DIR, `${LABEL}.plist`);
|
|
2917
|
+
var LOG_PATH = join7(homedir4(), ".agent-mesh", "logs", "launchd.log");
|
|
2861
2918
|
function detectPaths() {
|
|
2862
2919
|
return {
|
|
2863
2920
|
node: process.execPath,
|
|
@@ -2904,7 +2961,7 @@ function registerInstallCommand(program2) {
|
|
|
2904
2961
|
log.error("LaunchAgent is macOS only. On Linux, use systemd user service instead.");
|
|
2905
2962
|
process.exit(1);
|
|
2906
2963
|
}
|
|
2907
|
-
if (
|
|
2964
|
+
if (existsSync5(PLIST_PATH) && !opts.force) {
|
|
2908
2965
|
console.log(`
|
|
2909
2966
|
${YELLOW}\u2298${RESET} LaunchAgent already installed at:`);
|
|
2910
2967
|
console.log(` ${GRAY}${PLIST_PATH}${RESET}`);
|
|
@@ -2914,10 +2971,10 @@ function registerInstallCommand(program2) {
|
|
|
2914
2971
|
return;
|
|
2915
2972
|
}
|
|
2916
2973
|
const { node, script } = detectPaths();
|
|
2917
|
-
if (!
|
|
2918
|
-
|
|
2974
|
+
if (!existsSync5(PLIST_DIR)) {
|
|
2975
|
+
mkdirSync4(PLIST_DIR, { recursive: true });
|
|
2919
2976
|
}
|
|
2920
|
-
if (
|
|
2977
|
+
if (existsSync5(PLIST_PATH)) {
|
|
2921
2978
|
try {
|
|
2922
2979
|
execSync2(`launchctl bootout gui/$(id -u) "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
|
|
2923
2980
|
} catch {
|
|
@@ -2950,19 +3007,19 @@ function registerInstallCommand(program2) {
|
|
|
2950
3007
|
}
|
|
2951
3008
|
|
|
2952
3009
|
// src/commands/uninstall.ts
|
|
2953
|
-
import { existsSync as
|
|
2954
|
-
import { join as
|
|
3010
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
3011
|
+
import { join as join8 } from "path";
|
|
2955
3012
|
import { homedir as homedir5 } from "os";
|
|
2956
3013
|
import { execSync as execSync3 } from "child_process";
|
|
2957
3014
|
var LABEL2 = "com.agents-hot.agent-mesh";
|
|
2958
|
-
var PLIST_PATH2 =
|
|
3015
|
+
var PLIST_PATH2 = join8(homedir5(), "Library", "LaunchAgents", `${LABEL2}.plist`);
|
|
2959
3016
|
function registerUninstallCommand(program2) {
|
|
2960
3017
|
program2.command("uninstall").description("Remove macOS LaunchAgent (agents will no longer auto-start)").action(async () => {
|
|
2961
3018
|
if (process.platform !== "darwin") {
|
|
2962
3019
|
log.error("LaunchAgent is macOS only.");
|
|
2963
3020
|
process.exit(1);
|
|
2964
3021
|
}
|
|
2965
|
-
if (!
|
|
3022
|
+
if (!existsSync6(PLIST_PATH2)) {
|
|
2966
3023
|
console.log(`
|
|
2967
3024
|
${YELLOW}\u2298${RESET} No LaunchAgent found at ${GRAY}${PLIST_PATH2}${RESET}
|
|
2968
3025
|
`);
|
|
@@ -3648,11 +3705,11 @@ function registerChatCommand(program2) {
|
|
|
3648
3705
|
|
|
3649
3706
|
// src/commands/skills.ts
|
|
3650
3707
|
import { readFile as readFile3, writeFile as writeFile3, readdir as readdir2, mkdir as mkdir2, rm, symlink, unlink } from "fs/promises";
|
|
3651
|
-
import { join as
|
|
3708
|
+
import { join as join10, resolve, relative as relative4 } from "path";
|
|
3652
3709
|
|
|
3653
3710
|
// src/utils/skill-parser.ts
|
|
3654
3711
|
import { readFile as readFile2, writeFile as writeFile2, stat as stat3 } from "fs/promises";
|
|
3655
|
-
import { join as
|
|
3712
|
+
import { join as join9 } from "path";
|
|
3656
3713
|
function parseSkillMd(raw) {
|
|
3657
3714
|
const trimmed = raw.trimStart();
|
|
3658
3715
|
if (!trimmed.startsWith("---")) {
|
|
@@ -3734,7 +3791,7 @@ function parseSkillMd(raw) {
|
|
|
3734
3791
|
return { frontmatter, content };
|
|
3735
3792
|
}
|
|
3736
3793
|
async function loadSkillManifest(dir) {
|
|
3737
|
-
const skillMdPath =
|
|
3794
|
+
const skillMdPath = join9(dir, "SKILL.md");
|
|
3738
3795
|
try {
|
|
3739
3796
|
const raw = await readFile2(skillMdPath, "utf-8");
|
|
3740
3797
|
const { frontmatter } = parseSkillMd(raw);
|
|
@@ -3839,13 +3896,13 @@ function skillApiPath(authorLogin, slug) {
|
|
|
3839
3896
|
}
|
|
3840
3897
|
async function resolveSkillsRootAsync(pathArg) {
|
|
3841
3898
|
const projectRoot = pathArg ? resolve(pathArg) : process.cwd();
|
|
3842
|
-
const skillsDir =
|
|
3843
|
-
const claudeSkillsDir =
|
|
3899
|
+
const skillsDir = join10(projectRoot, ".agents", "skills");
|
|
3900
|
+
const claudeSkillsDir = join10(projectRoot, ".claude", "skills");
|
|
3844
3901
|
return { projectRoot, skillsDir, claudeSkillsDir };
|
|
3845
3902
|
}
|
|
3846
3903
|
async function ensureClaudeSymlink(claudeSkillsDir, slug) {
|
|
3847
3904
|
await mkdir2(claudeSkillsDir, { recursive: true });
|
|
3848
|
-
const linkPath =
|
|
3905
|
+
const linkPath = join10(claudeSkillsDir, slug);
|
|
3849
3906
|
try {
|
|
3850
3907
|
await unlink(linkPath);
|
|
3851
3908
|
} catch {
|
|
@@ -3865,7 +3922,7 @@ async function collectPackFiles(dir, manifest) {
|
|
|
3865
3922
|
}
|
|
3866
3923
|
const mainFile = manifest.main || "SKILL.md";
|
|
3867
3924
|
if (!results.includes(mainFile)) {
|
|
3868
|
-
const mainPath =
|
|
3925
|
+
const mainPath = join10(dir, mainFile);
|
|
3869
3926
|
if (await pathExists(mainPath)) {
|
|
3870
3927
|
results.unshift(mainFile);
|
|
3871
3928
|
}
|
|
@@ -3882,7 +3939,7 @@ async function walkDir(dir) {
|
|
|
3882
3939
|
}
|
|
3883
3940
|
for (const entry of entries) {
|
|
3884
3941
|
if (entry.isSymbolicLink()) continue;
|
|
3885
|
-
const fullPath =
|
|
3942
|
+
const fullPath = join10(dir, entry.name);
|
|
3886
3943
|
if (entry.isDirectory()) {
|
|
3887
3944
|
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
3888
3945
|
const sub = await walkDir(fullPath);
|
|
@@ -3900,7 +3957,7 @@ async function packSkill(dir, manifest) {
|
|
|
3900
3957
|
}
|
|
3901
3958
|
const entries = [];
|
|
3902
3959
|
for (const relPath of fileList) {
|
|
3903
|
-
const absPath =
|
|
3960
|
+
const absPath = join10(dir, relPath);
|
|
3904
3961
|
try {
|
|
3905
3962
|
const data = await readFile3(absPath);
|
|
3906
3963
|
entries.push({ path: relPath.replace(/\\/g, "/"), data });
|
|
@@ -3934,7 +3991,7 @@ function bumpVersion(current, bump) {
|
|
|
3934
3991
|
}
|
|
3935
3992
|
async function downloadAndInstallSkill(client, authorLogin, slug, skillsDir) {
|
|
3936
3993
|
const meta = await client.get(skillApiPath(authorLogin, slug));
|
|
3937
|
-
const targetDir =
|
|
3994
|
+
const targetDir = join10(skillsDir, slug);
|
|
3938
3995
|
await mkdir2(targetDir, { recursive: true });
|
|
3939
3996
|
if (meta.has_files) {
|
|
3940
3997
|
const res = await client.getRaw(`${skillApiPath(authorLogin, slug)}/download`);
|
|
@@ -3942,8 +3999,8 @@ async function downloadAndInstallSkill(client, authorLogin, slug, skillsDir) {
|
|
|
3942
3999
|
const buf = Buffer.from(arrayBuf);
|
|
3943
4000
|
const entries = extractZipBuffer(buf);
|
|
3944
4001
|
for (const entry of entries) {
|
|
3945
|
-
const filePath =
|
|
3946
|
-
const dir =
|
|
4002
|
+
const filePath = join10(targetDir, entry.path);
|
|
4003
|
+
const dir = join10(filePath, "..");
|
|
3947
4004
|
await mkdir2(dir, { recursive: true });
|
|
3948
4005
|
await writeFile3(filePath, entry.data);
|
|
3949
4006
|
}
|
|
@@ -3956,7 +4013,7 @@ async function downloadAndInstallSkill(client, authorLogin, slug, skillsDir) {
|
|
|
3956
4013
|
} else {
|
|
3957
4014
|
const res = await client.getRaw(`${skillApiPath(authorLogin, slug)}/raw`);
|
|
3958
4015
|
const content = await res.text();
|
|
3959
|
-
await writeFile3(
|
|
4016
|
+
await writeFile3(join10(targetDir, "SKILL.md"), content);
|
|
3960
4017
|
return {
|
|
3961
4018
|
slug,
|
|
3962
4019
|
name: meta.name,
|
|
@@ -3985,7 +4042,7 @@ function registerSkillsCommand(program2) {
|
|
|
3985
4042
|
try {
|
|
3986
4043
|
const dir = resolveSkillDir(pathArg);
|
|
3987
4044
|
await mkdir2(dir, { recursive: true });
|
|
3988
|
-
const skillMdPath =
|
|
4045
|
+
const skillMdPath = join10(dir, "SKILL.md");
|
|
3989
4046
|
if (await pathExists(skillMdPath)) {
|
|
3990
4047
|
const raw = await readFile3(skillMdPath, "utf-8");
|
|
3991
4048
|
const { frontmatter } = parseSkillMd(raw);
|
|
@@ -4014,7 +4071,7 @@ function registerSkillsCommand(program2) {
|
|
|
4014
4071
|
const dir = resolveSkillDir(pathArg);
|
|
4015
4072
|
const manifest = await loadSkillManifest(dir);
|
|
4016
4073
|
const result = await packSkill(dir, manifest);
|
|
4017
|
-
const outPath =
|
|
4074
|
+
const outPath = join10(dir, result.filename);
|
|
4018
4075
|
await writeFile3(outPath, result.buffer);
|
|
4019
4076
|
slog.info(`Packed ${result.files.length} files \u2192 ${result.filename} (${result.size} bytes)`);
|
|
4020
4077
|
outputJson({
|
|
@@ -4060,7 +4117,7 @@ function registerSkillsCommand(program2) {
|
|
|
4060
4117
|
if (opts.name) manifest.name = opts.name;
|
|
4061
4118
|
if (opts.version) manifest.version = opts.version;
|
|
4062
4119
|
if (opts.private !== void 0) manifest.private = opts.private;
|
|
4063
|
-
content = await readFile3(
|
|
4120
|
+
content = await readFile3(join10(dir, manifest.main || "SKILL.md"), "utf-8");
|
|
4064
4121
|
packResult = await packSkill(dir, manifest);
|
|
4065
4122
|
slog.info(`Packed ${packResult.files.length} files (${packResult.size} bytes)`);
|
|
4066
4123
|
}
|
|
@@ -4197,7 +4254,7 @@ function registerSkillsCommand(program2) {
|
|
|
4197
4254
|
skills.command("version <bump> [path]").description("Bump skill version (patch | minor | major | x.y.z)").action(async (bump, pathArg) => {
|
|
4198
4255
|
try {
|
|
4199
4256
|
const dir = resolveSkillDir(pathArg);
|
|
4200
|
-
const skillMdPath =
|
|
4257
|
+
const skillMdPath = join10(dir, "SKILL.md");
|
|
4201
4258
|
if (!await pathExists(skillMdPath)) {
|
|
4202
4259
|
outputError("not_found", "No SKILL.md found. Run `agent-mesh skills init` first.");
|
|
4203
4260
|
}
|
|
@@ -4217,7 +4274,7 @@ function registerSkillsCommand(program2) {
|
|
|
4217
4274
|
try {
|
|
4218
4275
|
const { authorLogin, slug } = parseSkillRef(ref);
|
|
4219
4276
|
const { skillsDir, claudeSkillsDir } = await resolveSkillsRootAsync(pathArg);
|
|
4220
|
-
const targetDir =
|
|
4277
|
+
const targetDir = join10(skillsDir, slug);
|
|
4221
4278
|
if (await pathExists(targetDir)) {
|
|
4222
4279
|
if (!opts.force) {
|
|
4223
4280
|
outputError("already_installed", `Skill "${slug}" is already installed at ${targetDir}. Use --force to overwrite.`);
|
|
@@ -4256,11 +4313,11 @@ function registerSkillsCommand(program2) {
|
|
|
4256
4313
|
const failed = [];
|
|
4257
4314
|
if (ref) {
|
|
4258
4315
|
const { authorLogin, slug } = parseSkillRef(ref);
|
|
4259
|
-
const targetDir =
|
|
4316
|
+
const targetDir = join10(skillsDir, slug);
|
|
4260
4317
|
if (!await pathExists(targetDir)) {
|
|
4261
4318
|
outputError("not_installed", `Skill "${slug}" is not installed. Use "skills install ${ref}" first.`);
|
|
4262
4319
|
}
|
|
4263
|
-
const skillMdPath =
|
|
4320
|
+
const skillMdPath = join10(targetDir, "SKILL.md");
|
|
4264
4321
|
let localVersion = "0.0.0";
|
|
4265
4322
|
if (await pathExists(skillMdPath)) {
|
|
4266
4323
|
const raw = await readFile3(skillMdPath, "utf-8");
|
|
@@ -4287,7 +4344,7 @@ function registerSkillsCommand(program2) {
|
|
|
4287
4344
|
for (const entry of entries) {
|
|
4288
4345
|
if (!entry.isDirectory()) continue;
|
|
4289
4346
|
const slug = entry.name;
|
|
4290
|
-
const skillMdPath =
|
|
4347
|
+
const skillMdPath = join10(skillsDir, slug, "SKILL.md");
|
|
4291
4348
|
if (!await pathExists(skillMdPath)) {
|
|
4292
4349
|
skipped.push({ slug, reason: "no_skill_md" });
|
|
4293
4350
|
continue;
|
|
@@ -4307,7 +4364,7 @@ function registerSkillsCommand(program2) {
|
|
|
4307
4364
|
skipped.push({ slug, reason: "up_to_date" });
|
|
4308
4365
|
} else {
|
|
4309
4366
|
slog.info(`Updating ${slug}: v${localVersion} \u2192 v${remoteVersion}...`);
|
|
4310
|
-
await rm(
|
|
4367
|
+
await rm(join10(skillsDir, slug), { recursive: true, force: true });
|
|
4311
4368
|
await downloadAndInstallSkill(client, authorLogin, slug, skillsDir);
|
|
4312
4369
|
updated.push({ slug, name: remote.name, old_version: localVersion, new_version: remoteVersion });
|
|
4313
4370
|
}
|
|
@@ -4328,13 +4385,13 @@ function registerSkillsCommand(program2) {
|
|
|
4328
4385
|
skills.command("remove <slug> [path]").description("Remove a locally installed skill").action(async (slug, pathArg) => {
|
|
4329
4386
|
try {
|
|
4330
4387
|
const { skillsDir, claudeSkillsDir } = await resolveSkillsRootAsync(pathArg);
|
|
4331
|
-
const targetDir =
|
|
4388
|
+
const targetDir = join10(skillsDir, slug);
|
|
4332
4389
|
if (!await pathExists(targetDir)) {
|
|
4333
4390
|
outputError("not_installed", `Skill "${slug}" is not installed at ${targetDir}`);
|
|
4334
4391
|
}
|
|
4335
4392
|
await rm(targetDir, { recursive: true, force: true });
|
|
4336
4393
|
try {
|
|
4337
|
-
await unlink(
|
|
4394
|
+
await unlink(join10(claudeSkillsDir, slug));
|
|
4338
4395
|
} catch {
|
|
4339
4396
|
}
|
|
4340
4397
|
slog.success(`Removed skill: ${slug}`);
|
|
@@ -4359,7 +4416,7 @@ function registerSkillsCommand(program2) {
|
|
|
4359
4416
|
for (const entry of entries) {
|
|
4360
4417
|
if (!entry.isDirectory()) continue;
|
|
4361
4418
|
const slug = entry.name;
|
|
4362
|
-
const skillMdPath =
|
|
4419
|
+
const skillMdPath = join10(skillsDir, slug, "SKILL.md");
|
|
4363
4420
|
if (!await pathExists(skillMdPath)) continue;
|
|
4364
4421
|
const raw = await readFile3(skillMdPath, "utf-8");
|
|
4365
4422
|
const { frontmatter } = parseSkillMd(raw);
|
|
@@ -4471,7 +4528,10 @@ function registerDiscoverCommand(program2) {
|
|
|
4471
4528
|
}
|
|
4472
4529
|
|
|
4473
4530
|
// src/commands/call.ts
|
|
4474
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
4531
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5 } from "fs";
|
|
4532
|
+
import { createHash as createHash2 } from "crypto";
|
|
4533
|
+
import { execSync as execSync4 } from "child_process";
|
|
4534
|
+
import { join as join11 } from "path";
|
|
4475
4535
|
var DEFAULT_BASE_URL4 = "https://agents.hot";
|
|
4476
4536
|
async function submitRating(baseUrl, token, agentId, callId, rating) {
|
|
4477
4537
|
const res = await fetch(`${baseUrl}/api/agents/${agentId}/rate`, {
|
|
@@ -4503,6 +4563,75 @@ function handleError2(err) {
|
|
|
4503
4563
|
}
|
|
4504
4564
|
process.exit(1);
|
|
4505
4565
|
}
|
|
4566
|
+
async function downloadTransferFiles(agentId, offer, token, outputDir, json) {
|
|
4567
|
+
const url = `${DEFAULT_BASE_URL4}/api/agents/${agentId}/transfer/${offer.transfer_id}`;
|
|
4568
|
+
if (!json) {
|
|
4569
|
+
log.info(`Downloading ${offer.file_count} file(s) (${(offer.zip_size / 1024).toFixed(1)} KB)...`);
|
|
4570
|
+
}
|
|
4571
|
+
await sleep6(1e3);
|
|
4572
|
+
let lastError = null;
|
|
4573
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
4574
|
+
try {
|
|
4575
|
+
const res = await fetch(url, {
|
|
4576
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
4577
|
+
});
|
|
4578
|
+
if (res.status === 202) {
|
|
4579
|
+
await sleep6(2e3);
|
|
4580
|
+
continue;
|
|
4581
|
+
}
|
|
4582
|
+
if (res.status === 404) {
|
|
4583
|
+
if (attempt < 4) {
|
|
4584
|
+
await sleep6(2e3);
|
|
4585
|
+
continue;
|
|
4586
|
+
}
|
|
4587
|
+
log.warn("Transfer expired or not found");
|
|
4588
|
+
return;
|
|
4589
|
+
}
|
|
4590
|
+
if (!res.ok) {
|
|
4591
|
+
log.warn(`Download failed: HTTP ${res.status}`);
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
4595
|
+
const zipBuffer = Buffer.from(arrayBuffer);
|
|
4596
|
+
const hash = createHash2("sha256").update(zipBuffer).digest("hex");
|
|
4597
|
+
if (hash !== offer.zip_sha256) {
|
|
4598
|
+
log.warn(`SHA-256 mismatch: expected ${offer.zip_sha256.slice(0, 12)}... got ${hash.slice(0, 12)}...`);
|
|
4599
|
+
return;
|
|
4600
|
+
}
|
|
4601
|
+
mkdirSync5(outputDir, { recursive: true });
|
|
4602
|
+
const zipPath = join11(outputDir, `.transfer-${offer.transfer_id.slice(0, 8)}.zip`);
|
|
4603
|
+
writeFileSync3(zipPath, zipBuffer);
|
|
4604
|
+
try {
|
|
4605
|
+
execSync4(`unzip -o -q "${zipPath}" -d "${outputDir}"`);
|
|
4606
|
+
try {
|
|
4607
|
+
execSync4(`rm "${zipPath}"`);
|
|
4608
|
+
} catch {
|
|
4609
|
+
}
|
|
4610
|
+
} catch {
|
|
4611
|
+
log.warn(`Failed to extract ZIP. Saved to: ${zipPath}`);
|
|
4612
|
+
return;
|
|
4613
|
+
}
|
|
4614
|
+
if (json) {
|
|
4615
|
+
console.log(JSON.stringify({
|
|
4616
|
+
type: "files_downloaded",
|
|
4617
|
+
file_count: offer.file_count,
|
|
4618
|
+
output_dir: outputDir,
|
|
4619
|
+
zip_size: zipBuffer.length,
|
|
4620
|
+
sha256_verified: true
|
|
4621
|
+
}));
|
|
4622
|
+
} else {
|
|
4623
|
+
log.success(`${offer.file_count} file(s) extracted to ${outputDir}`);
|
|
4624
|
+
}
|
|
4625
|
+
return;
|
|
4626
|
+
} catch (err) {
|
|
4627
|
+
lastError = err;
|
|
4628
|
+
if (attempt < 4) {
|
|
4629
|
+
await sleep6(2e3);
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
log.warn(`Download failed after retries: ${lastError?.message || "unknown error"}`);
|
|
4634
|
+
}
|
|
4506
4635
|
async function asyncCall(opts) {
|
|
4507
4636
|
const selfAgentId = process.env.AGENT_BRIDGE_AGENT_ID;
|
|
4508
4637
|
const res = await fetch(`${DEFAULT_BASE_URL4}/api/agents/${opts.id}/call`, {
|
|
@@ -4567,6 +4696,7 @@ async function asyncCall(opts) {
|
|
|
4567
4696
|
`);
|
|
4568
4697
|
}
|
|
4569
4698
|
const result = task.result || "";
|
|
4699
|
+
const offer = task.file_transfer_offer;
|
|
4570
4700
|
if (opts.json) {
|
|
4571
4701
|
console.log(JSON.stringify({
|
|
4572
4702
|
call_id,
|
|
@@ -4575,7 +4705,7 @@ async function asyncCall(opts) {
|
|
|
4575
4705
|
status: "completed",
|
|
4576
4706
|
result,
|
|
4577
4707
|
...task.attachments?.length ? { attachments: task.attachments } : {},
|
|
4578
|
-
...
|
|
4708
|
+
...offer ? { file_transfer_offer: offer } : {},
|
|
4579
4709
|
rate_hint: `POST /api/agents/${opts.id}/rate body: { call_id: "${call_id}", rating: 1-5 }`
|
|
4580
4710
|
}));
|
|
4581
4711
|
} else {
|
|
@@ -4585,10 +4715,6 @@ async function asyncCall(opts) {
|
|
|
4585
4715
|
log.info(` ${GRAY}File:${RESET} ${att.name} ${GRAY}${att.url}${RESET}`);
|
|
4586
4716
|
}
|
|
4587
4717
|
}
|
|
4588
|
-
const offer = task.file_transfer_offer;
|
|
4589
|
-
if (offer) {
|
|
4590
|
-
log.info(` ${GRAY}Files:${RESET} ${offer.file_count} file(s) available via WebRTC`);
|
|
4591
|
-
}
|
|
4592
4718
|
if (session_key) {
|
|
4593
4719
|
log.info(` ${GRAY}Session:${RESET} ${session_key}`);
|
|
4594
4720
|
}
|
|
@@ -4597,6 +4723,10 @@ async function asyncCall(opts) {
|
|
|
4597
4723
|
writeFileSync3(opts.outputFile, result);
|
|
4598
4724
|
if (!opts.json) log.info(`Saved to ${opts.outputFile}`);
|
|
4599
4725
|
}
|
|
4726
|
+
if (offer && opts.withFiles) {
|
|
4727
|
+
const outputDir = opts.outputFile ? join11(opts.outputFile, "..", "files") : join11(process.cwd(), "agent-output");
|
|
4728
|
+
await downloadTransferFiles(opts.id, offer, opts.token, outputDir, opts.json);
|
|
4729
|
+
}
|
|
4600
4730
|
if (!opts.json) {
|
|
4601
4731
|
log.info(`${GRAY}Rate this call: agent-mesh rate ${call_id} <1-5> --agent ${opts.id}${RESET}`);
|
|
4602
4732
|
}
|
|
@@ -4684,6 +4814,7 @@ async function streamCall(opts) {
|
|
|
4684
4814
|
let inThinkingBlock = false;
|
|
4685
4815
|
let callId = res.headers.get("X-Call-Id") || "";
|
|
4686
4816
|
let sessionKey = res.headers.get("X-Session-Key") || "";
|
|
4817
|
+
let fileOffer = null;
|
|
4687
4818
|
while (true) {
|
|
4688
4819
|
const { done, value } = await reader.read();
|
|
4689
4820
|
if (done) break;
|
|
@@ -4725,7 +4856,7 @@ async function streamCall(opts) {
|
|
|
4725
4856
|
}
|
|
4726
4857
|
}
|
|
4727
4858
|
if (event.file_transfer_offer) {
|
|
4728
|
-
|
|
4859
|
+
fileOffer = event.file_transfer_offer;
|
|
4729
4860
|
}
|
|
4730
4861
|
} else if (event.type === "error") {
|
|
4731
4862
|
process.stderr.write(`
|
|
@@ -4754,6 +4885,9 @@ Error: ${event.message}
|
|
|
4754
4885
|
}
|
|
4755
4886
|
}
|
|
4756
4887
|
}
|
|
4888
|
+
if (event.type === "done" && event.file_transfer_offer) {
|
|
4889
|
+
fileOffer = event.file_transfer_offer;
|
|
4890
|
+
}
|
|
4757
4891
|
} catch {
|
|
4758
4892
|
}
|
|
4759
4893
|
}
|
|
@@ -4762,6 +4896,11 @@ Error: ${event.message}
|
|
|
4762
4896
|
writeFileSync3(opts.outputFile, outputBuffer);
|
|
4763
4897
|
if (!opts.json) log.info(`Saved to ${opts.outputFile}`);
|
|
4764
4898
|
}
|
|
4899
|
+
if (fileOffer && opts.withFiles) {
|
|
4900
|
+
console.log("");
|
|
4901
|
+
const outputDir = opts.outputFile ? join11(opts.outputFile, "..", "files") : join11(process.cwd(), "agent-output");
|
|
4902
|
+
await downloadTransferFiles(opts.id, fileOffer, opts.token, outputDir, opts.json);
|
|
4903
|
+
}
|
|
4765
4904
|
if (!opts.json) {
|
|
4766
4905
|
console.log("\n");
|
|
4767
4906
|
log.success("Call completed");
|
|
@@ -5456,7 +5595,7 @@ function maybeAutoUpgradeOnStartup(opts) {
|
|
|
5456
5595
|
}
|
|
5457
5596
|
|
|
5458
5597
|
// src/index.ts
|
|
5459
|
-
var require2 =
|
|
5598
|
+
var require2 = createRequire2(import.meta.url);
|
|
5460
5599
|
var { version } = require2("../package.json");
|
|
5461
5600
|
var autoUpgrade = maybeAutoUpgradeOnStartup({ currentVersion: version });
|
|
5462
5601
|
if (autoUpgrade.relaunched) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@annals/agent-mesh",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.3",
|
|
4
4
|
"description": "CLI bridge connecting local AI agents to the Agents.Hot platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"typescript": "^5.7.0"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
|
-
"dist"
|
|
22
|
+
"dist",
|
|
23
|
+
"prebuilds"
|
|
23
24
|
],
|
|
24
25
|
"license": "MIT",
|
|
25
26
|
"repository": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|