@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 || join(homedir(), ".agent-mesh");
480
- this.runtimeRoot = join(baseDir, "runtime");
481
- this.statePath = join(this.runtimeRoot, "queue-state.json");
482
- this.lockPath = join(this.runtimeRoot, "queue.lock");
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 (!existsSync(this.runtimeRoot)) {
655
- mkdirSync(this.runtimeRoot, { recursive: true, mode: 448 });
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
- mkdirSync(this.lockPath, { mode: 448 });
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 join2 } from "path";
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 = join2(globalRoot, "@anthropic-ai/sandbox-runtime/dist/index.js");
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 mkdirSync2, readdirSync, symlinkSync, existsSync as existsSync2, lstatSync } from "fs";
1523
- import { join as join3, relative } from "path";
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 = join3(projectPath, ".bridge-clients", clientId);
1553
- const isNew = !existsSync2(wsDir);
1554
- mkdirSync2(wsDir, { recursive: true });
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 = join3(wsDir, entry.name);
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 = join3(projectPath, entry.name);
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 join5, relative as relative3, basename } from "path";
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 join4, relative as relative2 } from "path";
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 = join4(d, entry.name);
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 = join5(workspaceRoot, safeName);
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 existsSync3 } from "fs";
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 (!existsSync3(logPath)) {
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 existsSync4, mkdirSync as mkdirSync3 } from "fs";
2854
- import { join as join6 } from "path";
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 = join6(homedir4(), "Library", "LaunchAgents");
2859
- var PLIST_PATH = join6(PLIST_DIR, `${LABEL}.plist`);
2860
- var LOG_PATH = join6(homedir4(), ".agent-mesh", "logs", "launchd.log");
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 (existsSync4(PLIST_PATH) && !opts.force) {
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 (!existsSync4(PLIST_DIR)) {
2918
- mkdirSync3(PLIST_DIR, { recursive: true });
2974
+ if (!existsSync5(PLIST_DIR)) {
2975
+ mkdirSync4(PLIST_DIR, { recursive: true });
2919
2976
  }
2920
- if (existsSync4(PLIST_PATH)) {
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 existsSync5, unlinkSync as unlinkSync2 } from "fs";
2954
- import { join as join7 } from "path";
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 = join7(homedir5(), "Library", "LaunchAgents", `${LABEL2}.plist`);
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 (!existsSync5(PLIST_PATH2)) {
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 join9, resolve, relative as relative4 } from "path";
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 join8 } from "path";
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 = join8(dir, "SKILL.md");
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 = join9(projectRoot, ".agents", "skills");
3843
- const claudeSkillsDir = join9(projectRoot, ".claude", "skills");
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 = join9(claudeSkillsDir, slug);
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 = join9(dir, mainFile);
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 = join9(dir, entry.name);
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 = join9(dir, relPath);
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 = join9(skillsDir, slug);
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 = join9(targetDir, entry.path);
3946
- const dir = join9(filePath, "..");
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(join9(targetDir, "SKILL.md"), content);
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 = join9(dir, "SKILL.md");
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 = join9(dir, result.filename);
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(join9(dir, manifest.main || "SKILL.md"), "utf-8");
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 = join9(dir, "SKILL.md");
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 = join9(skillsDir, slug);
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 = join9(skillsDir, slug);
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 = join9(targetDir, "SKILL.md");
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 = join9(skillsDir, slug, "SKILL.md");
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(join9(skillsDir, slug), { recursive: true, force: true });
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 = join9(skillsDir, slug);
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(join9(claudeSkillsDir, slug));
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 = join9(skillsDir, slug, "SKILL.md");
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
- ...task.file_transfer_offer ? { file_transfer_offer: task.file_transfer_offer } : {},
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
- log.info(` ${GRAY}Files:${RESET} ${event.file_transfer_offer.file_count} file(s) available via WebRTC`);
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 = createRequire(import.meta.url);
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.0",
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": {