@meetopenbot/claude-code 0.1.2 → 0.1.4

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/index.js +181 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ // runtime.ts
2
+ import { execSync } from "node:child_process";
3
+ import { existsSync as existsSync2, readlinkSync as readlinkSync2, statSync as statSync2 } from "node:fs";
4
+
1
5
  // node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
2
6
  import { createRequire as $S } from "node:module";
3
7
  import { execFile as E6$ } from "child_process";
@@ -19425,6 +19429,131 @@ var buildApiKeyWidget = (agentId, threadId, reason) => uiWidget({
19425
19429
  var toolCallWidgetId = (toolUseId) => `claude_code_tool_${toolUseId}`;
19426
19430
  var truncate = (s2, max) => s2.length > max ? `${s2.slice(0, max)}
19427
19431
  \u2026` : s2;
19432
+ var MAX_STDERR_CHARS = 4e3;
19433
+ var MAX_ERROR_CHARS = 12e3;
19434
+ var asSystemError = (value) => value && typeof value === "object" ? value : void 0;
19435
+ var spawnFailureHint = (code, executablePath) => {
19436
+ switch (code) {
19437
+ case "EACCES":
19438
+ return executablePath ? `Permission denied executing "${executablePath}". Check chmod +x and macOS quarantine (xattr -d com.apple.quarantine "${executablePath}").` : "Permission denied executing the Claude Code binary.";
19439
+ case "EPERM":
19440
+ return "Operation not permitted when launching Claude Code. Common under sandboxed runtimes or restricted security policies.";
19441
+ case "ENOENT":
19442
+ return executablePath ? `No such file at "${executablePath}", or a required runtime/interpreter is missing.` : "Claude Code executable or required runtime not found.";
19443
+ case "ENOTDIR":
19444
+ case "ELOOP":
19445
+ return "Invalid executable path \u2014 a path component is not a directory or is a symlink loop.";
19446
+ default:
19447
+ return void 0;
19448
+ }
19449
+ };
19450
+ var describePathAccess = (label, path) => {
19451
+ try {
19452
+ if (!existsSync2(path)) return `${label}: missing (${path})`;
19453
+ const st = statSync2(path);
19454
+ const lines = [
19455
+ `${label}: ${path}`,
19456
+ `exists: yes`,
19457
+ `type: ${st.isDirectory() ? "directory" : st.isFile() ? "file" : "other"}`
19458
+ ];
19459
+ if (st.isFile()) {
19460
+ lines.push(`size: ${st.size} bytes`);
19461
+ lines.push(`mode: ${(st.mode & 511).toString(8)}`);
19462
+ lines.push(`executable bit: ${(st.mode & 73) !== 0 ? "yes" : "no"}`);
19463
+ }
19464
+ try {
19465
+ const target = readlinkSync2(path);
19466
+ lines.push(`symlink target: ${target}`);
19467
+ lines.push(`target exists: ${existsSync2(target) ? "yes" : "no"}`);
19468
+ } catch {
19469
+ }
19470
+ return lines.join("\n");
19471
+ } catch (inspectError) {
19472
+ return `${label}: could not inspect (${path}): ${inspectError instanceof Error ? inspectError.message : String(inspectError)}`;
19473
+ }
19474
+ };
19475
+ var launchFailureHintsFromInspection = (executableDetails, workingDirDetails, executablePath) => {
19476
+ const hints = [];
19477
+ if (workingDirDetails?.includes("missing")) {
19478
+ hints.push("Working directory does not exist. Create it or remove the cwd override from config.");
19479
+ }
19480
+ if (executableDetails?.includes("executable bit: no")) {
19481
+ const hint = spawnFailureHint("EACCES", executablePath);
19482
+ if (hint) hints.push(hint);
19483
+ }
19484
+ if (executableDetails?.includes("target exists: no")) {
19485
+ hints.push("Executable symlink target is missing. Reinstall Claude Code or point executablePath at a valid binary.");
19486
+ }
19487
+ if (executableDetails?.includes("missing")) {
19488
+ const hint = spawnFailureHint("ENOENT", executablePath);
19489
+ if (hint) hints.push(hint);
19490
+ }
19491
+ if (hints.length === 0) {
19492
+ hints.push(
19493
+ "The Claude Code process could not be started. Verify executablePath, working directory permissions, and that OpenBot can spawn child processes in this environment."
19494
+ );
19495
+ }
19496
+ return hints;
19497
+ };
19498
+ var formatClaudeCodeError = (error, context, stderrChunks) => {
19499
+ const err = error instanceof Error ? error : new Error(String(error));
19500
+ const parts = [err.message];
19501
+ const causeLines = [];
19502
+ let current = err.cause;
19503
+ while (current) {
19504
+ if (current instanceof Error) {
19505
+ causeLines.push(current.message);
19506
+ const sys2 = asSystemError(current);
19507
+ if (sys2?.code) causeLines.push(` code: ${sys2.code}`);
19508
+ if (sys2?.errno !== void 0) causeLines.push(` errno: ${sys2.errno}`);
19509
+ if (sys2?.syscall) causeLines.push(` syscall: ${sys2.syscall}`);
19510
+ if (sys2?.path) causeLines.push(` path: ${sys2.path}`);
19511
+ current = current.cause;
19512
+ } else {
19513
+ causeLines.push(String(current));
19514
+ break;
19515
+ }
19516
+ }
19517
+ if (causeLines.length > 0) parts.push(`Cause:
19518
+ ${causeLines.join("\n")}`);
19519
+ const sys = asSystemError(err.cause) ?? asSystemError(err);
19520
+ const hint = spawnFailureHint(sys?.code, context.executablePath);
19521
+ if (hint) parts.push(hint);
19522
+ const isLaunchFailure = err.message.includes("failed to launch") || err.message.includes("not found") || err.message.includes("Failed to spawn") || err.message.includes("exited with code") || err.message.includes("terminated by signal");
19523
+ if (isLaunchFailure) {
19524
+ const executableDetails = context.executablePath ? describePathAccess("Executable", context.executablePath) : "Executable: using SDK bundled binary (no executablePath override).";
19525
+ const workingDirDetails = context.workingDir ? describePathAccess("Working directory", context.workingDir) : void 0;
19526
+ parts.push(`Launch diagnostics:
19527
+ ${executableDetails}`);
19528
+ if (workingDirDetails) parts.push(workingDirDetails);
19529
+ if (err.message.includes("failed to launch")) {
19530
+ for (const launchHint of launchFailureHintsFromInspection(
19531
+ executableDetails,
19532
+ workingDirDetails,
19533
+ context.executablePath
19534
+ )) {
19535
+ parts.push(launchHint);
19536
+ }
19537
+ }
19538
+ }
19539
+ const stderr = stderrChunks.join("").trim();
19540
+ if (stderr) parts.push(`Process stderr:
19541
+ ${truncate(stderr, MAX_STDERR_CHARS)}`);
19542
+ return truncate(parts.join("\n\n"), MAX_ERROR_CHARS);
19543
+ };
19544
+ var formatResultError = (message) => {
19545
+ if (message.type !== "result" || message.subtype === "success") return "";
19546
+ const record = asRecord(message);
19547
+ const parts = [`subtype: ${message.subtype}`];
19548
+ const result = record.result;
19549
+ if (typeof result === "string" && result) parts.push(`result: ${result}`);
19550
+ const errors = record.errors;
19551
+ if (Array.isArray(errors) && errors.length > 0) {
19552
+ parts.push(`errors:
19553
+ ${errors.map((entry) => `- ${String(entry)}`).join("\n")}`);
19554
+ }
19555
+ return parts.join("\n");
19556
+ };
19428
19557
  var formatJsonForWidget = (value, maxLen) => {
19429
19558
  try {
19430
19559
  return truncate(JSON.stringify(value, null, 2), maxLen);
@@ -19432,6 +19561,15 @@ var formatJsonForWidget = (value, maxLen) => {
19432
19561
  return truncate(String(value), maxLen);
19433
19562
  }
19434
19563
  };
19564
+ var formatToolInputBody = (input, maxLen = 8e3) => `Input:
19565
+ ${formatJsonForWidget(input, maxLen)}`;
19566
+ var formatToolResultBody = (input, output) => {
19567
+ const inputSection = formatJsonForWidget(input, 4e3);
19568
+ const parts = [`Input:
19569
+ ${inputSection}`, `Output:
19570
+ ${output}`];
19571
+ return parts.join("\n\n");
19572
+ };
19435
19573
  var formatToolResultPayload = (content, isError) => {
19436
19574
  let body;
19437
19575
  if (typeof content === "string") {
@@ -19481,15 +19619,28 @@ var parseToolResultBlock = (block) => {
19481
19619
  }
19482
19620
  return null;
19483
19621
  };
19622
+ var findClaudeExecutable = () => {
19623
+ try {
19624
+ const command = process.platform === "win32" ? "where claude" : "which claude";
19625
+ const path = execSync(command, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
19626
+ if (path && existsSync2(path)) {
19627
+ return path;
19628
+ }
19629
+ } catch {
19630
+ }
19631
+ return void 0;
19632
+ };
19484
19633
  var claudeCodeRuntime = (options = {}) => (builder) => {
19485
19634
  const {
19486
19635
  model = "sonnet",
19487
19636
  system,
19488
19637
  permissionMode = "default",
19489
19638
  cwd,
19639
+ executablePath: executablePathOverride,
19490
19640
  allowedTools,
19491
19641
  storage
19492
19642
  } = options;
19643
+ const executablePath = executablePathOverride || findClaudeExecutable();
19493
19644
  builder.on("agent:invoke", async function* (event, context) {
19494
19645
  if (!shouldHandleInvoke(event, context.state.agentId)) {
19495
19646
  return;
@@ -19499,12 +19650,21 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19499
19650
  const threadId = event.meta?.threadId || context.state.threadId;
19500
19651
  const resumeId = readPersistedSessionId(context.state);
19501
19652
  const workingDir = cwd ?? context.state.channelDetails?.cwd;
19653
+ const stderrChunks = [];
19654
+ const launchContext = {
19655
+ executablePath,
19656
+ workingDir
19657
+ };
19502
19658
  const sdkOptions = {
19503
19659
  model,
19504
19660
  permissionMode,
19661
+ stderr: (data) => {
19662
+ stderrChunks.push(data);
19663
+ },
19505
19664
  ...system ? { systemPrompt: { type: "preset", preset: "claude_code", append: system } } : {},
19506
19665
  ...resumeId ? { resume: resumeId } : {},
19507
19666
  ...workingDir ? { cwd: workingDir } : {},
19667
+ ...executablePath ? { pathToClaudeCodeExecutable: executablePath } : {},
19508
19668
  ...allowedTools ? { allowedTools } : {}
19509
19669
  };
19510
19670
  try {
@@ -19550,8 +19710,8 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19550
19710
  kind: "message",
19551
19711
  widgetId: toolCallWidgetId(tool.toolUseId),
19552
19712
  title: toolTitleByUseId.get(tool.toolUseId)?.title ?? "",
19553
- description: JSON.stringify(toolTitleByUseId.get(tool.toolUseId)?.input ?? {}),
19554
- body: formatJsonForWidget(tool.input, 8e3),
19713
+ description: "",
19714
+ body: formatToolInputBody(tool.input),
19555
19715
  display: "collapsed",
19556
19716
  metadata: {
19557
19717
  type: "claude_tool",
@@ -19597,8 +19757,11 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19597
19757
  kind: "message",
19598
19758
  widgetId: toolCallWidgetId(res.toolUseId),
19599
19759
  title: toolTitleByUseId.get(res.toolUseId)?.title ?? "",
19600
- description: JSON.stringify(toolTitleByUseId.get(res.toolUseId)?.input ?? {}),
19601
- body,
19760
+ description: "",
19761
+ body: formatToolResultBody(
19762
+ toolTitleByUseId.get(res.toolUseId)?.input,
19763
+ body
19764
+ ),
19602
19765
  display: "collapsed",
19603
19766
  ...state ? { state } : {},
19604
19767
  metadata: {
@@ -19620,10 +19783,12 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19620
19783
  yield buildApiKeyWidget(context.state.agentId, threadId, subtype);
19621
19784
  return;
19622
19785
  }
19786
+ const details = formatResultError(message);
19623
19787
  yield agentOutput({
19624
19788
  agentId: context.state.agentId,
19625
19789
  threadId,
19626
- content: `[claude-code] run ended with error: ${subtype}`
19790
+ content: details ? `[claude-code] run ended with error:
19791
+ ${details}` : `[claude-code] run ended with error: ${subtype}`
19627
19792
  });
19628
19793
  }
19629
19794
  }
@@ -19631,7 +19796,7 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19631
19796
  await persistSessionId(context.state, storage, lastSessionId);
19632
19797
  }
19633
19798
  } catch (error) {
19634
- const errorMessage = error instanceof Error ? error.message : String(error);
19799
+ const errorMessage = formatClaudeCodeError(error, launchContext, stderrChunks);
19635
19800
  if (isAuthErrorMessage(errorMessage)) {
19636
19801
  yield buildApiKeyWidget(context.state.agentId, threadId, errorMessage);
19637
19802
  return;
@@ -19639,7 +19804,8 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19639
19804
  yield agentOutput({
19640
19805
  agentId: context.state.agentId,
19641
19806
  threadId,
19642
- content: `[claude-code] error: ${errorMessage}`
19807
+ content: `[claude-code] error:
19808
+ ${errorMessage}`
19643
19809
  });
19644
19810
  }
19645
19811
  });
@@ -19708,17 +19874,23 @@ var claudeCodePlugin = {
19708
19874
  permissionMode: {
19709
19875
  type: "string",
19710
19876
  description: "How the SDK handles tool permission prompts: default | acceptEdits | bypassPermissions | plan | dontAsk | auto.",
19711
- default: "default",
19877
+ default: "bypassPermissions",
19712
19878
  enum: ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"]
19879
+ },
19880
+ executablePath: {
19881
+ type: "string",
19882
+ description: "Path to the Claude Code CLI executable. When unset, the plugin attempts to find it in your PATH, falling back to the SDK bundled binary."
19713
19883
  }
19714
19884
  }
19715
19885
  },
19716
19886
  factory: ({ agentDetails, config, storage }) => {
19717
19887
  const model = typeof config.model === "string" && config.model ? config.model : "sonnet";
19718
- const permissionMode = typeof config.permissionMode === "string" && config.permissionMode ? config.permissionMode : "default";
19888
+ const permissionMode = typeof config.permissionMode === "string" && config.permissionMode ? config.permissionMode : "bypassPermissions";
19889
+ const executablePath = typeof config.executablePath === "string" && config.executablePath ? config.executablePath : void 0;
19719
19890
  return claudeCodeRuntime({
19720
19891
  model,
19721
19892
  permissionMode,
19893
+ executablePath,
19722
19894
  system: agentDetails.instructions || CLAUDE_CODE_SYSTEM_PROMPT,
19723
19895
  storage
19724
19896
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meetopenbot/claude-code",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Claude Code plugin for OpenBot",
6
6
  "main": "./dist/index.js",