@meetopenbot/claude-code 0.1.2 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +166 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // runtime.ts
2
+ import { existsSync as existsSync2, readlinkSync as readlinkSync2, statSync as statSync2 } from "node:fs";
3
+
1
4
  // node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
2
5
  import { createRequire as $S } from "node:module";
3
6
  import { execFile as E6$ } from "child_process";
@@ -19425,6 +19428,131 @@ var buildApiKeyWidget = (agentId, threadId, reason) => uiWidget({
19425
19428
  var toolCallWidgetId = (toolUseId) => `claude_code_tool_${toolUseId}`;
19426
19429
  var truncate = (s2, max) => s2.length > max ? `${s2.slice(0, max)}
19427
19430
  \u2026` : s2;
19431
+ var MAX_STDERR_CHARS = 4e3;
19432
+ var MAX_ERROR_CHARS = 12e3;
19433
+ var asSystemError = (value) => value && typeof value === "object" ? value : void 0;
19434
+ var spawnFailureHint = (code, executablePath) => {
19435
+ switch (code) {
19436
+ case "EACCES":
19437
+ 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.";
19438
+ case "EPERM":
19439
+ return "Operation not permitted when launching Claude Code. Common under sandboxed runtimes or restricted security policies.";
19440
+ case "ENOENT":
19441
+ return executablePath ? `No such file at "${executablePath}", or a required runtime/interpreter is missing.` : "Claude Code executable or required runtime not found.";
19442
+ case "ENOTDIR":
19443
+ case "ELOOP":
19444
+ return "Invalid executable path \u2014 a path component is not a directory or is a symlink loop.";
19445
+ default:
19446
+ return void 0;
19447
+ }
19448
+ };
19449
+ var describePathAccess = (label, path) => {
19450
+ try {
19451
+ if (!existsSync2(path)) return `${label}: missing (${path})`;
19452
+ const st = statSync2(path);
19453
+ const lines = [
19454
+ `${label}: ${path}`,
19455
+ `exists: yes`,
19456
+ `type: ${st.isDirectory() ? "directory" : st.isFile() ? "file" : "other"}`
19457
+ ];
19458
+ if (st.isFile()) {
19459
+ lines.push(`size: ${st.size} bytes`);
19460
+ lines.push(`mode: ${(st.mode & 511).toString(8)}`);
19461
+ lines.push(`executable bit: ${(st.mode & 73) !== 0 ? "yes" : "no"}`);
19462
+ }
19463
+ try {
19464
+ const target = readlinkSync2(path);
19465
+ lines.push(`symlink target: ${target}`);
19466
+ lines.push(`target exists: ${existsSync2(target) ? "yes" : "no"}`);
19467
+ } catch {
19468
+ }
19469
+ return lines.join("\n");
19470
+ } catch (inspectError) {
19471
+ return `${label}: could not inspect (${path}): ${inspectError instanceof Error ? inspectError.message : String(inspectError)}`;
19472
+ }
19473
+ };
19474
+ var launchFailureHintsFromInspection = (executableDetails, workingDirDetails, executablePath) => {
19475
+ const hints = [];
19476
+ if (workingDirDetails?.includes("missing")) {
19477
+ hints.push("Working directory does not exist. Create it or remove the cwd override from config.");
19478
+ }
19479
+ if (executableDetails?.includes("executable bit: no")) {
19480
+ const hint = spawnFailureHint("EACCES", executablePath);
19481
+ if (hint) hints.push(hint);
19482
+ }
19483
+ if (executableDetails?.includes("target exists: no")) {
19484
+ hints.push("Executable symlink target is missing. Reinstall Claude Code or point executablePath at a valid binary.");
19485
+ }
19486
+ if (executableDetails?.includes("missing")) {
19487
+ const hint = spawnFailureHint("ENOENT", executablePath);
19488
+ if (hint) hints.push(hint);
19489
+ }
19490
+ if (hints.length === 0) {
19491
+ hints.push(
19492
+ "The Claude Code process could not be started. Verify executablePath, working directory permissions, and that OpenBot can spawn child processes in this environment."
19493
+ );
19494
+ }
19495
+ return hints;
19496
+ };
19497
+ var formatClaudeCodeError = (error, context, stderrChunks) => {
19498
+ const err = error instanceof Error ? error : new Error(String(error));
19499
+ const parts = [err.message];
19500
+ const causeLines = [];
19501
+ let current = err.cause;
19502
+ while (current) {
19503
+ if (current instanceof Error) {
19504
+ causeLines.push(current.message);
19505
+ const sys2 = asSystemError(current);
19506
+ if (sys2?.code) causeLines.push(` code: ${sys2.code}`);
19507
+ if (sys2?.errno !== void 0) causeLines.push(` errno: ${sys2.errno}`);
19508
+ if (sys2?.syscall) causeLines.push(` syscall: ${sys2.syscall}`);
19509
+ if (sys2?.path) causeLines.push(` path: ${sys2.path}`);
19510
+ current = current.cause;
19511
+ } else {
19512
+ causeLines.push(String(current));
19513
+ break;
19514
+ }
19515
+ }
19516
+ if (causeLines.length > 0) parts.push(`Cause:
19517
+ ${causeLines.join("\n")}`);
19518
+ const sys = asSystemError(err.cause) ?? asSystemError(err);
19519
+ const hint = spawnFailureHint(sys?.code, context.executablePath);
19520
+ if (hint) parts.push(hint);
19521
+ 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");
19522
+ if (isLaunchFailure) {
19523
+ const executableDetails = context.executablePath ? describePathAccess("Executable", context.executablePath) : "Executable: using SDK bundled binary (no executablePath override).";
19524
+ const workingDirDetails = context.workingDir ? describePathAccess("Working directory", context.workingDir) : void 0;
19525
+ parts.push(`Launch diagnostics:
19526
+ ${executableDetails}`);
19527
+ if (workingDirDetails) parts.push(workingDirDetails);
19528
+ if (err.message.includes("failed to launch")) {
19529
+ for (const launchHint of launchFailureHintsFromInspection(
19530
+ executableDetails,
19531
+ workingDirDetails,
19532
+ context.executablePath
19533
+ )) {
19534
+ parts.push(launchHint);
19535
+ }
19536
+ }
19537
+ }
19538
+ const stderr = stderrChunks.join("").trim();
19539
+ if (stderr) parts.push(`Process stderr:
19540
+ ${truncate(stderr, MAX_STDERR_CHARS)}`);
19541
+ return truncate(parts.join("\n\n"), MAX_ERROR_CHARS);
19542
+ };
19543
+ var formatResultError = (message) => {
19544
+ if (message.type !== "result" || message.subtype === "success") return "";
19545
+ const record = asRecord(message);
19546
+ const parts = [`subtype: ${message.subtype}`];
19547
+ const result = record.result;
19548
+ if (typeof result === "string" && result) parts.push(`result: ${result}`);
19549
+ const errors = record.errors;
19550
+ if (Array.isArray(errors) && errors.length > 0) {
19551
+ parts.push(`errors:
19552
+ ${errors.map((entry) => `- ${String(entry)}`).join("\n")}`);
19553
+ }
19554
+ return parts.join("\n");
19555
+ };
19428
19556
  var formatJsonForWidget = (value, maxLen) => {
19429
19557
  try {
19430
19558
  return truncate(JSON.stringify(value, null, 2), maxLen);
@@ -19432,6 +19560,15 @@ var formatJsonForWidget = (value, maxLen) => {
19432
19560
  return truncate(String(value), maxLen);
19433
19561
  }
19434
19562
  };
19563
+ var formatToolInputBody = (input, maxLen = 8e3) => `Input:
19564
+ ${formatJsonForWidget(input, maxLen)}`;
19565
+ var formatToolResultBody = (input, output) => {
19566
+ const inputSection = formatJsonForWidget(input, 4e3);
19567
+ const parts = [`Input:
19568
+ ${inputSection}`, `Output:
19569
+ ${output}`];
19570
+ return parts.join("\n\n");
19571
+ };
19435
19572
  var formatToolResultPayload = (content, isError) => {
19436
19573
  let body;
19437
19574
  if (typeof content === "string") {
@@ -19487,6 +19624,7 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19487
19624
  system,
19488
19625
  permissionMode = "default",
19489
19626
  cwd,
19627
+ executablePath,
19490
19628
  allowedTools,
19491
19629
  storage
19492
19630
  } = options;
@@ -19499,12 +19637,21 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19499
19637
  const threadId = event.meta?.threadId || context.state.threadId;
19500
19638
  const resumeId = readPersistedSessionId(context.state);
19501
19639
  const workingDir = cwd ?? context.state.channelDetails?.cwd;
19640
+ const stderrChunks = [];
19641
+ const launchContext = {
19642
+ executablePath,
19643
+ workingDir
19644
+ };
19502
19645
  const sdkOptions = {
19503
19646
  model,
19504
19647
  permissionMode,
19648
+ stderr: (data) => {
19649
+ stderrChunks.push(data);
19650
+ },
19505
19651
  ...system ? { systemPrompt: { type: "preset", preset: "claude_code", append: system } } : {},
19506
19652
  ...resumeId ? { resume: resumeId } : {},
19507
19653
  ...workingDir ? { cwd: workingDir } : {},
19654
+ ...executablePath ? { pathToClaudeCodeExecutable: executablePath } : {},
19508
19655
  ...allowedTools ? { allowedTools } : {}
19509
19656
  };
19510
19657
  try {
@@ -19550,8 +19697,8 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19550
19697
  kind: "message",
19551
19698
  widgetId: toolCallWidgetId(tool.toolUseId),
19552
19699
  title: toolTitleByUseId.get(tool.toolUseId)?.title ?? "",
19553
- description: JSON.stringify(toolTitleByUseId.get(tool.toolUseId)?.input ?? {}),
19554
- body: formatJsonForWidget(tool.input, 8e3),
19700
+ description: "",
19701
+ body: formatToolInputBody(tool.input),
19555
19702
  display: "collapsed",
19556
19703
  metadata: {
19557
19704
  type: "claude_tool",
@@ -19597,8 +19744,11 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19597
19744
  kind: "message",
19598
19745
  widgetId: toolCallWidgetId(res.toolUseId),
19599
19746
  title: toolTitleByUseId.get(res.toolUseId)?.title ?? "",
19600
- description: JSON.stringify(toolTitleByUseId.get(res.toolUseId)?.input ?? {}),
19601
- body,
19747
+ description: "",
19748
+ body: formatToolResultBody(
19749
+ toolTitleByUseId.get(res.toolUseId)?.input,
19750
+ body
19751
+ ),
19602
19752
  display: "collapsed",
19603
19753
  ...state ? { state } : {},
19604
19754
  metadata: {
@@ -19620,10 +19770,12 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19620
19770
  yield buildApiKeyWidget(context.state.agentId, threadId, subtype);
19621
19771
  return;
19622
19772
  }
19773
+ const details = formatResultError(message);
19623
19774
  yield agentOutput({
19624
19775
  agentId: context.state.agentId,
19625
19776
  threadId,
19626
- content: `[claude-code] run ended with error: ${subtype}`
19777
+ content: details ? `[claude-code] run ended with error:
19778
+ ${details}` : `[claude-code] run ended with error: ${subtype}`
19627
19779
  });
19628
19780
  }
19629
19781
  }
@@ -19631,7 +19783,7 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19631
19783
  await persistSessionId(context.state, storage, lastSessionId);
19632
19784
  }
19633
19785
  } catch (error) {
19634
- const errorMessage = error instanceof Error ? error.message : String(error);
19786
+ const errorMessage = formatClaudeCodeError(error, launchContext, stderrChunks);
19635
19787
  if (isAuthErrorMessage(errorMessage)) {
19636
19788
  yield buildApiKeyWidget(context.state.agentId, threadId, errorMessage);
19637
19789
  return;
@@ -19639,7 +19791,8 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19639
19791
  yield agentOutput({
19640
19792
  agentId: context.state.agentId,
19641
19793
  threadId,
19642
- content: `[claude-code] error: ${errorMessage}`
19794
+ content: `[claude-code] error:
19795
+ ${errorMessage}`
19643
19796
  });
19644
19797
  }
19645
19798
  });
@@ -19710,15 +19863,21 @@ var claudeCodePlugin = {
19710
19863
  description: "How the SDK handles tool permission prompts: default | acceptEdits | bypassPermissions | plan | dontAsk | auto.",
19711
19864
  default: "default",
19712
19865
  enum: ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"]
19866
+ },
19867
+ executablePath: {
19868
+ type: "string",
19869
+ description: "Path to the Claude Code CLI executable. When unset, the SDK uses its bundled binary."
19713
19870
  }
19714
19871
  }
19715
19872
  },
19716
19873
  factory: ({ agentDetails, config, storage }) => {
19717
19874
  const model = typeof config.model === "string" && config.model ? config.model : "sonnet";
19718
19875
  const permissionMode = typeof config.permissionMode === "string" && config.permissionMode ? config.permissionMode : "default";
19876
+ const executablePath = typeof config.executablePath === "string" && config.executablePath ? config.executablePath : void 0;
19719
19877
  return claudeCodeRuntime({
19720
19878
  model,
19721
19879
  permissionMode,
19880
+ executablePath,
19722
19881
  system: agentDetails.instructions || CLAUDE_CODE_SYSTEM_PROMPT,
19723
19882
  storage
19724
19883
  });
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.3",
4
4
  "type": "module",
5
5
  "description": "Claude Code plugin for OpenBot",
6
6
  "main": "./dist/index.js",