@tetrixdev/ai-bridge 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import WebSocket from "ws";
11
11
 
12
12
  // src/protocol/version.ts
13
13
  var PROTOCOL_VERSION = "0.1";
14
- var BRIDGE_VERSION = "0.1.0";
14
+ var BRIDGE_VERSION = "0.1.1";
15
15
 
16
16
  // src/tools/manager.ts
17
17
  import fs from "fs";
@@ -276,26 +276,29 @@ var ToolManager = class {
276
276
 
277
277
  set -euo pipefail
278
278
 
279
- # Read arguments from stdin (the standard way AI CLIs pass tool args).
280
- STDIN_DATA=""
281
- if [ ! -t 0 ]; then
282
- STDIN_DATA=$(cat)
279
+ # Read the JSON payload from the first CLI argument when present; otherwise
280
+ # fall back to stdin (some AI CLIs pass tool args one way, some the other).
281
+ PAYLOAD_DATA=""
282
+ if [ "$#" -ge 1 ] && [ -n "\${1:-}" ]; then
283
+ PAYLOAD_DATA="$1"
284
+ elif [ ! -t 0 ]; then
285
+ PAYLOAD_DATA=$(cat)
283
286
  fi
284
287
 
285
288
  # Single Node.js invocation for input parsing, payload building, HTTP call,
286
289
  # and output extraction.
287
290
  node -e '
288
291
  const http = require("http");
289
- const stdinData = process.argv[1];
292
+ const payloadData = process.argv[1];
290
293
  const toolName = process.argv[2];
291
294
  const toolCallId = process.argv[3];
292
295
  const requestId = process.argv[4];
293
296
  const secret = process.argv[5];
294
297
 
295
- // Parse stdin as JSON, fall back to wrapping as {input: ...}
298
+ // Parse the payload as JSON, fall back to wrapping as {input: ...}
296
299
  let args = {};
297
- if (stdinData) {
298
- try { args = JSON.parse(stdinData); } catch { args = { input: stdinData }; }
300
+ if (payloadData) {
301
+ try { args = JSON.parse(payloadData); } catch { args = { input: payloadData }; }
299
302
  }
300
303
 
301
304
  const payload = JSON.stringify({
@@ -327,7 +330,7 @@ req.write(payload);
327
330
  req.end();
328
331
  // The $RANDOM-based ID here is discarded \u2014 the callback server overrides it
329
332
  // with a cryptographically strong UUID before use.
330
- ' "$STDIN_DATA" "${tool.name}" "tc_\${RANDOM}\${RANDOM}" "\${AI_BRIDGE_REQUEST_ID:-}" "${secretArg}"
333
+ ' "$PAYLOAD_DATA" "${tool.name}" "tc_\${RANDOM}\${RANDOM}" "\${AI_BRIDGE_REQUEST_ID:-}" "${secretArg}"
331
334
  `;
332
335
  }
333
336
  };
@@ -1662,14 +1665,47 @@ function createFinalizer(opts) {
1662
1665
  var ProviderAdapter = class {
1663
1666
  };
1664
1667
 
1668
+ // src/tools/prompt.ts
1669
+ function buildToolInstructions(tools, toolScriptDir) {
1670
+ if (tools.length === 0) return "";
1671
+ const cmd = (name) => toolScriptDir ? `${toolScriptDir}/${name}` : name;
1672
+ const sections = [
1673
+ "# Available Tools",
1674
+ "",
1675
+ 'You have access to the following tools. Each tool is an executable script. Call a tool by running it as a shell command with a single argument: a JSON object containing the parameters. The command prints its result to stdout. Run each tool using the exact path shown in its "Call it like" example. Use these tools whenever they help fulfill the request.'
1676
+ ];
1677
+ for (const tool of tools) {
1678
+ sections.push("", `## ${tool.name}`, "", tool.description);
1679
+ const parameters = tool.parameters ?? {};
1680
+ const properties = parameters["properties"] ?? {};
1681
+ const required = Array.isArray(parameters["required"]) ? parameters["required"].map((r) => String(r)) : [];
1682
+ const propNames = Object.keys(properties);
1683
+ if (propNames.length === 0) {
1684
+ sections.push("", "Parameters: No parameters");
1685
+ sections.push("", `Call it like: ${cmd(tool.name)} '{}'`);
1686
+ continue;
1687
+ }
1688
+ sections.push("", "Parameters:");
1689
+ for (const pname of propNames) {
1690
+ const raw = properties[pname];
1691
+ const prop = raw && typeof raw === "object" ? raw : {};
1692
+ const type = typeof prop.type === "string" ? prop.type : "any";
1693
+ const requiredLabel = required.includes(pname) ? "required" : "optional";
1694
+ const description = typeof prop.description === "string" && prop.description.length > 0 ? prop.description : "No description";
1695
+ sections.push(`- ${pname} (${type}, ${requiredLabel}): ${description}`);
1696
+ }
1697
+ const exampleParam = propNames[0];
1698
+ sections.push(
1699
+ "",
1700
+ `Call it like: ${cmd(tool.name)} '{"${exampleParam}":"<value>"}'`
1701
+ );
1702
+ }
1703
+ return sections.join("\n");
1704
+ }
1705
+
1665
1706
  // src/providers/codex.ts
1666
1707
  var log7 = createLogger("CodexAdapter");
1667
1708
  var DEFAULT_MODEL = "gpt-5.3-codex";
1668
- function buildToolPromptNote(tools) {
1669
- if (tools.length === 0) return "";
1670
- const lines = tools.map((t) => `- \`${t.name}\`: ${t.description}`);
1671
- return "\n\n---\nThe following bridge tools are available to you as shell commands. Run a tool by executing its command name in the shell (passing any arguments it documents); the command performs the action and prints the result. Use them when they help answer the request:\n" + lines.join("\n");
1672
- }
1673
1709
  var CodexAdapter = class extends ProviderAdapter {
1674
1710
  providerName = "codex";
1675
1711
  async execute(context, onEvent) {
@@ -1704,14 +1740,12 @@ var CodexAdapter = class extends ProviderAdapter {
1704
1740
  if (hasTools) {
1705
1741
  args.push(
1706
1742
  "-s",
1707
- "workspace-write",
1708
- "-c",
1709
- "sandbox_workspace_write.network_access=true",
1743
+ "danger-full-access",
1710
1744
  "-c",
1711
1745
  "approval_policy=never"
1712
1746
  );
1713
1747
  }
1714
- const toolNote = hasTools ? buildToolPromptNote(context.tools) : "";
1748
+ const toolNote = hasTools ? "\n\n" + buildToolInstructions(context.tools, context.toolScriptDir) : "";
1715
1749
  if (!cliSessionId && request.system_prompt) {
1716
1750
  args.push("--", buildCombinedPrompt(request.system_prompt, userMessage) + toolNote);
1717
1751
  } else if (toolNote) {
@@ -1963,9 +1997,13 @@ var ClaudeAdapter = class extends ProviderAdapter {
1963
1997
  args.push("--max-tokens", String(request.options.max_tokens));
1964
1998
  }
1965
1999
  if (context.tools.length > 0 && context.toolScriptDir) {
1966
- args.push("--allowedTools=bash");
2000
+ args.push("--permission-mode", "bypassPermissions");
1967
2001
  }
1968
- args.push(userMessage);
2002
+ let promptArg = userMessage;
2003
+ if (context.tools.length > 0) {
2004
+ promptArg += "\n\n" + buildToolInstructions(context.tools, context.toolScriptDir);
2005
+ }
2006
+ args.push(promptArg);
1969
2007
  if (isDebugEnabled()) {
1970
2008
  log8.debug("Spawning claude", { args: args.map((a) => a.length > 50 ? a.substring(0, 50) + "..." : a) });
1971
2009
  }
@@ -2126,13 +2164,8 @@ var ClaudeAdapter = class extends ProviderAdapter {
2126
2164
  return;
2127
2165
  }
2128
2166
  if (type === "rate_limit_event") {
2129
- log8.warn("Claude rate limit event", { type });
2130
- onEvent({
2131
- event: "error",
2132
- data: {
2133
- code: "rate_limited",
2134
- message: "Claude is currently rate-limited. The request may retry automatically, or you may need to try again in a moment."
2135
- }
2167
+ log8.debug("Claude rate limit event (informational)", {
2168
+ status: parsed["rate_limit_info"]?.["status"]
2136
2169
  });
2137
2170
  return;
2138
2171
  }
@@ -2191,6 +2224,10 @@ var GeminiAdapter = class extends ProviderAdapter {
2191
2224
  if (request.system_prompt && !cliSessionId) {
2192
2225
  prompt = buildCombinedPrompt(request.system_prompt, userMessage);
2193
2226
  }
2227
+ const hasTools = context.tools.length > 0;
2228
+ if (hasTools) {
2229
+ prompt += "\n\n" + buildToolInstructions(context.tools, context.toolScriptDir);
2230
+ }
2194
2231
  const args = [
2195
2232
  "--prompt",
2196
2233
  prompt,
@@ -2201,6 +2238,9 @@ var GeminiAdapter = class extends ProviderAdapter {
2201
2238
  "--skip-trust"
2202
2239
  // Required for headless/non-interactive mode
2203
2240
  ];
2241
+ if (hasTools) {
2242
+ args.push("--yolo");
2243
+ }
2204
2244
  if (cliSessionId) {
2205
2245
  args.push("--resume", cliSessionId);
2206
2246
  log9.debug("Resuming session", { cliSessionId });
@@ -2384,16 +2424,6 @@ var GeminiAdapter = class extends ProviderAdapter {
2384
2424
  });
2385
2425
  onEvent({ event: "done", data: {} });
2386
2426
  settled = true;
2387
- } else if (severity === "warning") {
2388
- const lowerMsg = (message ?? "").toLowerCase();
2389
- const isRateLimit = lowerMsg.includes("rate limit") || lowerMsg.includes("ratelimit") || lowerMsg.includes("quota") || lowerMsg.includes("429") || lowerMsg.includes("too many requests");
2390
- onEvent({
2391
- event: "error",
2392
- data: {
2393
- code: isRateLimit ? "rate_limited" : "provider_warning",
2394
- message: message ?? "Gemini warning"
2395
- }
2396
- });
2397
2427
  }
2398
2428
  return;
2399
2429
  }