@rk0429/agentic-relay 0.14.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/relay.mjs +214 -40
  2. package/package.json +2 -1
package/dist/relay.mjs CHANGED
@@ -446,6 +446,7 @@ function inferFailureReason(stderr, stdout, sdkErrorMetadata) {
446
446
  const combined = `${stderr} ${stdout}`.toLowerCase();
447
447
  if (combined.includes("timed out") || combined.includes("timeout")) return "timeout";
448
448
  if (combined.includes("max turns") || combined.includes("max_turns") || combined.includes("turn limit")) return "max_turns_exhausted";
449
+ if (combined.includes("429") || combined.includes("capacity_exhausted") || combined.includes("model_capacity_exhausted") || combined.includes("ratelimitexceeded") || combined.includes("resource_exhausted")) return "rate_limit";
449
450
  return "adapter_error";
450
451
  }
451
452
  function buildContextFromEnv() {
@@ -617,7 +618,6 @@ ${input.prompt}`;
617
618
  }
618
619
  onProgress?.({ stage: "spawning", percent: 10 });
619
620
  try {
620
- let result;
621
621
  const executePromise = (async () => {
622
622
  if (input.resumeSessionId) {
623
623
  if (!adapter.continueSession) {
@@ -681,7 +681,7 @@ ${input.prompt}`;
681
681
  });
682
682
  }
683
683
  })();
684
- result = await executePromise;
684
+ const result = await executePromise;
685
685
  if (result && "_noSession" in result) {
686
686
  return {
687
687
  sessionId: session.relaySessionId,
@@ -817,7 +817,13 @@ var init_spawn_agent = __esm({
817
817
  taskInstructionPath: z2.string().optional().describe(
818
818
  "Path to a file containing task instructions. Content is prepended to the prompt. Path is resolved relative to the project root and validated against path traversal."
819
819
  ),
820
- label: z2.string().optional().describe("Human-readable label for identifying this agent in parallel results and logs.")
820
+ label: z2.string().optional().describe("Human-readable label for identifying this agent in parallel results and logs."),
821
+ maxResponseLength: z2.number().int().positive().optional().describe(
822
+ "Maximum response length in characters. When exceeded, response is truncated or summarized based on responseMode."
823
+ ),
824
+ responseMode: z2.enum(["truncate", "summarize"]).optional().describe(
825
+ "How to handle responses exceeding maxResponseLength. 'truncate' (default) cuts at limit with file save. 'summarize' uses AI to condense."
826
+ )
821
827
  });
822
828
  }
823
829
  });
@@ -858,11 +864,11 @@ function extractMentionedPaths(stdout) {
858
864
  for (const pattern of patterns) {
859
865
  let match;
860
866
  while ((match = pattern.exec(stdout)) !== null) {
861
- let path = match[1];
862
- if (path.startsWith("./")) {
863
- path = path.slice(2);
867
+ let path2 = match[1];
868
+ if (path2.startsWith("./")) {
869
+ path2 = path2.slice(2);
864
870
  }
865
- paths.add(path);
871
+ paths.add(path2);
866
872
  }
867
873
  }
868
874
  return paths;
@@ -897,7 +903,7 @@ async function detectConflicts(before, after, agentResults) {
897
903
  }
898
904
  }
899
905
  const conflicts = Array.from(fileToAgents.entries()).map(
900
- ([path, agents]) => ({ path, agents })
906
+ ([path2, agents]) => ({ path: path2, agents })
901
907
  );
902
908
  return {
903
909
  conflicts,
@@ -1207,8 +1213,128 @@ var init_types = __esm({
1207
1213
  }
1208
1214
  });
1209
1215
 
1216
+ // src/mcp-server/response-summarizer.ts
1217
+ import Anthropic from "@anthropic-ai/sdk";
1218
+ async function summarizeResponse(text, targetLength) {
1219
+ const client = new Anthropic();
1220
+ const message = await client.messages.create({
1221
+ model: "claude-haiku-4-5-20251001",
1222
+ max_tokens: Math.max(1024, Math.ceil(targetLength / 3)),
1223
+ messages: [
1224
+ {
1225
+ role: "user",
1226
+ content: `Summarize the following text in ${targetLength} characters or less. Prioritize:
1227
+ 1. Key deliverables, artifacts, and file changes
1228
+ 2. Important decisions and conclusions
1229
+ 3. Action items and next steps
1230
+
1231
+ Preserve technical details (file paths, function names, error messages) when possible.
1232
+
1233
+ <text>
1234
+ ${text}
1235
+ </text>`
1236
+ }
1237
+ ]
1238
+ });
1239
+ const content = message.content[0];
1240
+ if (content?.type !== "text") {
1241
+ throw new Error("Unexpected response format from summarization API");
1242
+ }
1243
+ return content.text;
1244
+ }
1245
+ var init_response_summarizer = __esm({
1246
+ "src/mcp-server/response-summarizer.ts"() {
1247
+ "use strict";
1248
+ }
1249
+ });
1250
+
1210
1251
  // src/mcp-server/response-formatter.ts
1211
- function formatSpawnAgentResponse(result) {
1252
+ import * as fs from "fs";
1253
+ import * as path from "path";
1254
+ import * as os from "os";
1255
+ function saveFullResponse(content, sessionId) {
1256
+ try {
1257
+ const dir = sessionId ? path.join(RESPONSE_DIR, sessionId) : path.join(RESPONSE_DIR, `anonymous-${Date.now()}`);
1258
+ fs.mkdirSync(dir, { recursive: true });
1259
+ const filePath = path.join(dir, "response.txt");
1260
+ fs.writeFileSync(filePath, content, "utf-8");
1261
+ try {
1262
+ const entries = fs.readdirSync(RESPONSE_DIR).map((name) => {
1263
+ const fullPath = path.join(RESPONSE_DIR, name);
1264
+ try {
1265
+ const stat = fs.statSync(fullPath);
1266
+ return { name, fullPath, mtimeMs: stat.mtimeMs };
1267
+ } catch {
1268
+ return null;
1269
+ }
1270
+ }).filter((e) => e !== null).sort((a, b) => a.mtimeMs - b.mtimeMs);
1271
+ if (entries.length > MAX_SAVED_RESPONSES) {
1272
+ const toRemove = entries.slice(0, entries.length - MAX_SAVED_RESPONSES);
1273
+ for (const entry of toRemove) {
1274
+ fs.rmSync(entry.fullPath, { recursive: true, force: true });
1275
+ }
1276
+ }
1277
+ } catch {
1278
+ }
1279
+ return filePath;
1280
+ } catch {
1281
+ return void 0;
1282
+ }
1283
+ }
1284
+ async function processStdout(stdout, options) {
1285
+ const maxLength = options?.maxLength ?? STDOUT_DEFAULT_MAX_LENGTH;
1286
+ const mode = options?.mode ?? "truncate";
1287
+ if (stdout.length <= maxLength) {
1288
+ return { text: stdout, truncated: false };
1289
+ }
1290
+ const savedFilePath = saveFullResponse(stdout, options?.sessionId);
1291
+ const savedInfo = savedFilePath ? ` Full response saved to: ${savedFilePath}` : "";
1292
+ if (mode === "summarize") {
1293
+ try {
1294
+ const summary = await summarizeResponse(stdout, maxLength);
1295
+ const footer2 = `
1296
+
1297
+ [RESPONSE SUMMARIZED: original ${stdout.length} chars exceeded limit ${maxLength} chars.${savedInfo}]`;
1298
+ return { text: summary + footer2, truncated: true, savedFilePath };
1299
+ } catch {
1300
+ }
1301
+ }
1302
+ const truncated = stdout.slice(0, maxLength);
1303
+ const footer = `
1304
+
1305
+ [RESPONSE TRUNCATED: original ${stdout.length} chars exceeded limit ${maxLength} chars.${savedInfo}]`;
1306
+ return { text: truncated + footer, truncated: true, savedFilePath };
1307
+ }
1308
+ function truncateStderr(stderr) {
1309
+ if (!stderr) return stderr;
1310
+ const blocks = stderr.split("\n\n");
1311
+ if (blocks.length > 1) {
1312
+ const seen = /* @__PURE__ */ new Set();
1313
+ const unique = [];
1314
+ let duplicateCount = 0;
1315
+ for (const block of blocks) {
1316
+ const trimmed = block.trim();
1317
+ if (!trimmed) continue;
1318
+ if (seen.has(trimmed)) {
1319
+ duplicateCount++;
1320
+ } else {
1321
+ seen.add(trimmed);
1322
+ unique.push(block);
1323
+ }
1324
+ }
1325
+ if (duplicateCount > 0) {
1326
+ stderr = unique.join("\n\n") + `
1327
+ [${duplicateCount} duplicate block(s) removed]`;
1328
+ }
1329
+ }
1330
+ if (stderr.length > STDERR_MAX_LENGTH) {
1331
+ const totalLength = stderr.length;
1332
+ stderr = stderr.slice(0, STDERR_MAX_LENGTH) + `
1333
+ [truncated, ${totalLength} total chars]`;
1334
+ }
1335
+ return stderr;
1336
+ }
1337
+ async function formatSpawnAgentResponse(result, options) {
1212
1338
  const isError = result.exitCode !== 0;
1213
1339
  let text;
1214
1340
  if (isError) {
@@ -1216,12 +1342,13 @@ function formatSpawnAgentResponse(result) {
1216
1342
  text = `FAILED (exit ${result.exitCode}${reasonPart})`;
1217
1343
  if (result.stderr) {
1218
1344
  text += `
1219
- ${result.stderr}`;
1345
+ ${truncateStderr(result.stderr)}`;
1220
1346
  }
1221
1347
  } else {
1348
+ const processed = await processStdout(result.stdout, options);
1222
1349
  text = `Session: ${result.sessionId}
1223
1350
 
1224
- ${result.stdout}`;
1351
+ ${processed.text}`;
1225
1352
  }
1226
1353
  if (result.metadata) {
1227
1354
  text += `
@@ -1232,7 +1359,7 @@ ${JSON.stringify(result.metadata, null, 2)}
1232
1359
  }
1233
1360
  return { text, isError };
1234
1361
  }
1235
- function formatParallelResponse(result) {
1362
+ async function formatParallelResponse(result, options, perAgentOptions) {
1236
1363
  const isError = result.failureCount === result.totalCount;
1237
1364
  const parts = [];
1238
1365
  if (result.hasConflicts && result.conflicts) {
@@ -1252,11 +1379,13 @@ function formatParallelResponse(result) {
1252
1379
  const duration = r.metadata?.durationMs !== void 0 ? `${(r.metadata.durationMs / 1e3).toFixed(1)}s` : "?s";
1253
1380
  if (r.exitCode === 0) {
1254
1381
  parts.push(`--- Agent ${r.index}${labelPart} (${backend}, ${duration}) SUCCESS ---`);
1255
- parts.push(r.stdout || "(no output)");
1382
+ const agentOptions = perAgentOptions?.get(r.index) ?? options;
1383
+ const processed = await processStdout(r.stdout || "", agentOptions);
1384
+ parts.push(processed.text || "(no output)");
1256
1385
  } else {
1257
1386
  const reasonPart = r.failureReason ? `, reason: ${r.failureReason}` : "";
1258
1387
  parts.push(`--- Agent ${r.index}${labelPart} FAILED (${backend}, ${duration}${reasonPart}) ---`);
1259
- parts.push(r.stderr || r.error || "(no output)");
1388
+ parts.push(truncateStderr(r.stderr || r.error || "") || "(no output)");
1260
1389
  }
1261
1390
  parts.push("");
1262
1391
  }
@@ -1265,9 +1394,15 @@ ${JSON.stringify(result, null, 2)}
1265
1394
  </metadata>`);
1266
1395
  return { text: parts.join("\n"), isError };
1267
1396
  }
1397
+ var STDERR_MAX_LENGTH, STDOUT_DEFAULT_MAX_LENGTH, MAX_SAVED_RESPONSES, RESPONSE_DIR;
1268
1398
  var init_response_formatter = __esm({
1269
1399
  "src/mcp-server/response-formatter.ts"() {
1270
1400
  "use strict";
1401
+ init_response_summarizer();
1402
+ STDERR_MAX_LENGTH = 2e3;
1403
+ STDOUT_DEFAULT_MAX_LENGTH = 2e4;
1404
+ MAX_SAVED_RESPONSES = 100;
1405
+ RESPONSE_DIR = path.join(os.tmpdir(), "agentic-relay-responses");
1271
1406
  }
1272
1407
  });
1273
1408
 
@@ -1314,15 +1449,16 @@ var init_server = __esm({
1314
1449
  };
1315
1450
  MAX_CHILD_HTTP_SESSIONS = 100;
1316
1451
  RelayMCPServer = class {
1317
- constructor(registry2, sessionManager2, guardConfig, hooksEngine2, contextMonitor2) {
1452
+ constructor(registry2, sessionManager2, guardConfig, hooksEngine2, contextMonitor2, defaultMaxResponseLength) {
1318
1453
  this.registry = registry2;
1319
1454
  this.sessionManager = sessionManager2;
1320
1455
  this.hooksEngine = hooksEngine2;
1321
1456
  this.contextMonitor = contextMonitor2;
1457
+ this.defaultMaxResponseLength = defaultMaxResponseLength;
1322
1458
  this.guard = new RecursionGuard(guardConfig);
1323
1459
  this.backendSelector = new BackendSelector();
1324
1460
  this.server = new McpServer(
1325
- { name: "agentic-relay", version: "0.14.1" },
1461
+ { name: "agentic-relay", version: "0.16.0" },
1326
1462
  createMcpServerOptions()
1327
1463
  );
1328
1464
  this.registerTools(this.server);
@@ -1357,7 +1493,12 @@ var init_server = __esm({
1357
1493
  this.backendSelector,
1358
1494
  this._childHttpUrl
1359
1495
  );
1360
- const { text, isError } = formatSpawnAgentResponse(result);
1496
+ const controlOptions = {
1497
+ maxLength: params.maxResponseLength ?? this.defaultMaxResponseLength ?? STDOUT_DEFAULT_MAX_LENGTH,
1498
+ mode: params.responseMode ?? "truncate",
1499
+ sessionId: result.sessionId
1500
+ };
1501
+ const { text, isError } = await formatSpawnAgentResponse(result, controlOptions);
1361
1502
  const callToolResult = {
1362
1503
  content: [{ type: "text", text }],
1363
1504
  isError
@@ -1404,7 +1545,11 @@ var init_server = __esm({
1404
1545
  this.backendSelector,
1405
1546
  this._childHttpUrl
1406
1547
  );
1407
- const { text, isError } = formatParallelResponse(result);
1548
+ const controlOptions = {
1549
+ maxLength: this.defaultMaxResponseLength ?? STDOUT_DEFAULT_MAX_LENGTH,
1550
+ mode: "truncate"
1551
+ };
1552
+ const { text, isError } = await formatParallelResponse(result, controlOptions);
1408
1553
  const callToolResult = {
1409
1554
  content: [{ type: "text", text }],
1410
1555
  isError
@@ -1520,7 +1665,11 @@ var init_server = __esm({
1520
1665
  this.backendSelector,
1521
1666
  this._childHttpUrl
1522
1667
  );
1523
- const { text, isError } = formatParallelResponse(result);
1668
+ const controlOptions = {
1669
+ maxLength: this.defaultMaxResponseLength ?? STDOUT_DEFAULT_MAX_LENGTH,
1670
+ mode: "truncate"
1671
+ };
1672
+ const { text, isError } = await formatParallelResponse(result, controlOptions);
1524
1673
  return {
1525
1674
  content: [{ type: "text", text }],
1526
1675
  isError
@@ -1684,7 +1833,7 @@ var init_server = __esm({
1684
1833
  sessionIdGenerator: () => randomUUID()
1685
1834
  });
1686
1835
  const server = new McpServer(
1687
- { name: "agentic-relay", version: "0.14.1" },
1836
+ { name: "agentic-relay", version: "0.16.0" },
1688
1837
  createMcpServerOptions()
1689
1838
  );
1690
1839
  this.registerTools(server);
@@ -1740,7 +1889,7 @@ var init_server = __esm({
1740
1889
 
1741
1890
  // src/bin/relay.ts
1742
1891
  import { defineCommand as defineCommand10, runMain } from "citty";
1743
- import { join as join9 } from "path";
1892
+ import { join as join10 } from "path";
1744
1893
  import { homedir as homedir6 } from "os";
1745
1894
 
1746
1895
  // src/infrastructure/process-manager.ts
@@ -2856,6 +3005,12 @@ init_logger();
2856
3005
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
2857
3006
  import { homedir as homedir3 } from "os";
2858
3007
  import { join as join3, dirname as dirname3 } from "path";
3008
+ var GEMINI_FALLBACK_CHAIN = [
3009
+ "gemini-3.1-pro-preview",
3010
+ "gemini-2.5-pro",
3011
+ "gemini-2.5-flash"
3012
+ ];
3013
+ var RATE_LIMIT_PATTERN = /429|MODEL_CAPACITY_EXHAUSTED|rateLimitExceeded|RESOURCE_EXHAUSTED/i;
2859
3014
  var GeminiAdapter = class extends BaseAdapter {
2860
3015
  id = "gemini";
2861
3016
  command = "gemini";
@@ -2935,6 +3090,21 @@ ${prompt}`;
2935
3090
  if (!flags.prompt) {
2936
3091
  throw new Error("execute requires a prompt (-p flag)");
2937
3092
  }
3093
+ if (flags.model) {
3094
+ return this.executeOnce(flags);
3095
+ }
3096
+ let lastResult;
3097
+ for (const model of GEMINI_FALLBACK_CHAIN) {
3098
+ const result = await this.executeOnce({ ...flags, model });
3099
+ if (result.exitCode === 0 || !RATE_LIMIT_PATTERN.test(result.stderr)) {
3100
+ return result;
3101
+ }
3102
+ logger.warn(`Gemini model ${model} rate limited, trying next fallback...`);
3103
+ lastResult = result;
3104
+ }
3105
+ return lastResult;
3106
+ }
3107
+ async executeOnce(flags) {
2938
3108
  const effectivePrompt = this.buildEffectivePrompt(flags);
2939
3109
  const args = [];
2940
3110
  if (flags.model) {
@@ -3263,7 +3433,8 @@ var relayConfigSchema = z.object({
3263
3433
  mcpServerMode: z.object({
3264
3434
  maxDepth: z.number().int().positive(),
3265
3435
  maxCallsPerSession: z.number().int().positive(),
3266
- timeoutSec: z.number().positive()
3436
+ timeoutSec: z.number().positive(),
3437
+ maxResponseLength: z.number().int().positive().optional()
3267
3438
  }).optional(),
3268
3439
  telemetry: z.object({
3269
3440
  enabled: z.boolean()
@@ -3292,8 +3463,8 @@ function deepMerge(target, source) {
3292
3463
  function isPlainObject(value) {
3293
3464
  return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
3294
3465
  }
3295
- function getByPath(obj, path) {
3296
- const parts = path.split(".");
3466
+ function getByPath(obj, path2) {
3467
+ const parts = path2.split(".");
3297
3468
  let current = obj;
3298
3469
  for (const part of parts) {
3299
3470
  if (!isPlainObject(current)) return void 0;
@@ -3301,8 +3472,8 @@ function getByPath(obj, path) {
3301
3472
  }
3302
3473
  return current;
3303
3474
  }
3304
- function setByPath(obj, path, value) {
3305
- const parts = path.split(".");
3475
+ function setByPath(obj, path2, value) {
3476
+ const parts = path2.split(".");
3306
3477
  let current = obj;
3307
3478
  for (let i = 0; i < parts.length - 1; i++) {
3308
3479
  const part = parts[i];
@@ -4494,6 +4665,7 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
4494
4665
  return;
4495
4666
  }
4496
4667
  let guardConfig;
4668
+ let defaultMaxResponseLength;
4497
4669
  try {
4498
4670
  const config = await configManager2.getConfig();
4499
4671
  if (config.mcpServerMode) {
@@ -4502,6 +4674,7 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
4502
4674
  maxCallsPerSession: config.mcpServerMode.maxCallsPerSession ?? 20,
4503
4675
  timeoutSec: config.mcpServerMode.timeoutSec ?? 86400
4504
4676
  };
4677
+ defaultMaxResponseLength = config.mcpServerMode.maxResponseLength;
4505
4678
  }
4506
4679
  } catch {
4507
4680
  }
@@ -4512,7 +4685,8 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
4512
4685
  sessionManager2,
4513
4686
  guardConfig,
4514
4687
  hooksEngine2,
4515
- contextMonitor2
4688
+ contextMonitor2,
4689
+ defaultMaxResponseLength
4516
4690
  );
4517
4691
  await server.start({ transport, port });
4518
4692
  }
@@ -4674,7 +4848,7 @@ function createVersionCommand(registry2) {
4674
4848
  description: "Show relay and backend versions"
4675
4849
  },
4676
4850
  async run() {
4677
- const relayVersion = "0.14.1";
4851
+ const relayVersion = "0.16.0";
4678
4852
  console.log(`agentic-relay v${relayVersion}`);
4679
4853
  console.log("");
4680
4854
  console.log("Backends:");
@@ -4699,7 +4873,7 @@ function createVersionCommand(registry2) {
4699
4873
  // src/commands/doctor.ts
4700
4874
  import { defineCommand as defineCommand8 } from "citty";
4701
4875
  import { access, constants, readdir as readdir2 } from "fs/promises";
4702
- import { join as join7 } from "path";
4876
+ import { join as join8 } from "path";
4703
4877
  import { homedir as homedir5 } from "os";
4704
4878
  import { execFile as execFile2 } from "child_process";
4705
4879
  import { promisify as promisify2 } from "util";
@@ -4760,8 +4934,8 @@ async function checkConfig(configManager2) {
4760
4934
  }
4761
4935
  }
4762
4936
  async function checkSessionsDir() {
4763
- const relayHome2 = process.env["RELAY_HOME"] ?? join7(homedir5(), ".relay");
4764
- const sessionsDir = join7(relayHome2, "sessions");
4937
+ const relayHome2 = process.env["RELAY_HOME"] ?? join8(homedir5(), ".relay");
4938
+ const sessionsDir = join8(relayHome2, "sessions");
4765
4939
  try {
4766
4940
  await access(sessionsDir, constants.W_OK);
4767
4941
  return {
@@ -4874,8 +5048,8 @@ async function checkBackendAuthEnv() {
4874
5048
  return results;
4875
5049
  }
4876
5050
  async function checkSessionsDiskUsage() {
4877
- const relayHome2 = process.env["RELAY_HOME"] ?? join7(homedir5(), ".relay");
4878
- const sessionsDir = join7(relayHome2, "sessions");
5051
+ const relayHome2 = process.env["RELAY_HOME"] ?? join8(homedir5(), ".relay");
5052
+ const sessionsDir = join8(relayHome2, "sessions");
4879
5053
  try {
4880
5054
  const entries = await readdir2(sessionsDir);
4881
5055
  const fileCount = entries.length;
@@ -4949,7 +5123,7 @@ function createDoctorCommand(registry2, configManager2) {
4949
5123
  init_logger();
4950
5124
  import { defineCommand as defineCommand9 } from "citty";
4951
5125
  import { mkdir as mkdir6, writeFile as writeFile6, access as access2, readFile as readFile6 } from "fs/promises";
4952
- import { join as join8 } from "path";
5126
+ import { join as join9 } from "path";
4953
5127
  var DEFAULT_CONFIG2 = {
4954
5128
  defaultBackend: "claude",
4955
5129
  backends: {},
@@ -4963,8 +5137,8 @@ function createInitCommand() {
4963
5137
  },
4964
5138
  async run() {
4965
5139
  const projectDir = process.cwd();
4966
- const relayDir = join8(projectDir, ".relay");
4967
- const configPath = join8(relayDir, "config.json");
5140
+ const relayDir = join9(projectDir, ".relay");
5141
+ const configPath = join9(relayDir, "config.json");
4968
5142
  try {
4969
5143
  await access2(relayDir);
4970
5144
  logger.info(
@@ -4980,7 +5154,7 @@ function createInitCommand() {
4980
5154
  "utf-8"
4981
5155
  );
4982
5156
  logger.success(`Created ${configPath}`);
4983
- const gitignorePath = join8(projectDir, ".gitignore");
5157
+ const gitignorePath = join9(projectDir, ".gitignore");
4984
5158
  try {
4985
5159
  const gitignoreContent = await readFile6(gitignorePath, "utf-8");
4986
5160
  if (!gitignoreContent.includes(".relay/config.local.json")) {
@@ -5006,8 +5180,8 @@ registry.registerLazy("claude", () => new ClaudeAdapter(processManager));
5006
5180
  registry.registerLazy("codex", () => new CodexAdapter(processManager));
5007
5181
  registry.registerLazy("gemini", () => new GeminiAdapter(processManager));
5008
5182
  var sessionManager = new SessionManager();
5009
- var relayHome = process.env["RELAY_HOME"] ?? join9(homedir6(), ".relay");
5010
- var projectRelayDir = join9(process.cwd(), ".relay");
5183
+ var relayHome = process.env["RELAY_HOME"] ?? join10(homedir6(), ".relay");
5184
+ var projectRelayDir = join10(process.cwd(), ".relay");
5011
5185
  var configManager = new ConfigManager(relayHome, projectRelayDir);
5012
5186
  var authManager = new AuthManager(registry);
5013
5187
  var eventBus = new EventBus();
@@ -5024,7 +5198,7 @@ void configManager.getConfig().then((config) => {
5024
5198
  var main = defineCommand10({
5025
5199
  meta: {
5026
5200
  name: "relay",
5027
- version: "0.14.1",
5201
+ version: "0.16.0",
5028
5202
  description: "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI"
5029
5203
  },
5030
5204
  subCommands: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rk0429/agentic-relay",
3
- "version": "0.14.1",
3
+ "version": "0.16.0",
4
4
  "description": "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI with MCP-based multi-layer sub-agent orchestration",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -50,6 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@anthropic-ai/claude-agent-sdk": "^0.2.59",
53
+ "@anthropic-ai/sdk": "^0.78.0",
53
54
  "@modelcontextprotocol/sdk": "^1.27.1",
54
55
  "@openai/codex-sdk": "^0.105.0",
55
56
  "citty": "^0.1.6",