@meetopenbot/claude-code 0.1.12 → 0.1.14

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.
@@ -0,0 +1,4 @@
1
+ import type { Plugin } from '@meetopenbot/plugin-sdk';
2
+ declare const plugin: Plugin;
3
+ export { plugin };
4
+ export default plugin;
package/dist/index.js CHANGED
@@ -42,8 +42,9 @@ async function resolveModelConfigField() {
42
42
  // runtime.ts
43
43
  import { execSync } from "node:child_process";
44
44
  import { existsSync as existsSync2, readlinkSync as readlinkSync2, statSync as statSync2 } from "node:fs";
45
+ import { join as join2 } from "node:path";
45
46
 
46
- // node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
47
+ // ../../node_modules/.pnpm/@anthropic-ai+claude-agent-sdk@0.2.141_@cfworker+json-schema@4.1.1_zod@4.4.3/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
47
48
  import { createRequire as $S } from "node:module";
48
49
  import { execFile as E6$ } from "child_process";
49
50
  import { randomUUID as rz } from "crypto";
@@ -19370,15 +19371,15 @@ function Z_($, Q) {
19370
19371
  return null;
19371
19372
  }
19372
19373
 
19373
- // node_modules/@meetopenbot/plugin-sdk/dist/index.js
19374
+ // ../plugin-sdk/dist/index.js
19374
19375
  import { z } from "zod";
19375
19376
 
19376
- // node_modules/@meetopenbot/plugin-sdk/dist/plugin.js
19377
+ // ../plugin-sdk/dist/plugin.js
19377
19378
  function definePlugin(definition) {
19378
19379
  return definition;
19379
19380
  }
19380
19381
 
19381
- // node_modules/@meetopenbot/plugin-sdk/dist/helpers.js
19382
+ // ../plugin-sdk/dist/helpers.js
19382
19383
  function shouldHandleInvoke(event, agentId) {
19383
19384
  const routedTo = event.data?.agentId;
19384
19385
  return !(typeof routedTo === "string" && routedTo && routedTo !== agentId);
@@ -19394,6 +19395,17 @@ function agentOutput(args) {
19394
19395
  }
19395
19396
  };
19396
19397
  }
19398
+ function toolTraceWidget(args) {
19399
+ return {
19400
+ kind: "message",
19401
+ display: "collapsed",
19402
+ widgetId: args.widgetId,
19403
+ groupId: args.groupId,
19404
+ title: args.title,
19405
+ ...args.body ? { body: args.body } : {},
19406
+ ...args.state ? { state: args.state } : {}
19407
+ };
19408
+ }
19397
19409
  function uiWidget(args) {
19398
19410
  return {
19399
19411
  type: "client:ui:widget",
@@ -19406,6 +19418,275 @@ function uiWidget(args) {
19406
19418
  };
19407
19419
  }
19408
19420
 
19421
+ // ../plugin-sdk/dist/diff.js
19422
+ import { spawnSync } from "node:child_process";
19423
+ import { readFileSync as readFileSync2 } from "node:fs";
19424
+ import { join } from "node:path";
19425
+ var MAX_DIFF_FILES = 40;
19426
+ var MAX_DIFF_PATCH_CHARS = 48e3;
19427
+ var LANG_BY_EXT = {
19428
+ ts: "typescript",
19429
+ tsx: "tsx",
19430
+ js: "javascript",
19431
+ jsx: "jsx",
19432
+ mjs: "javascript",
19433
+ cjs: "javascript",
19434
+ py: "python",
19435
+ go: "go",
19436
+ rs: "rust",
19437
+ rb: "ruby",
19438
+ java: "java",
19439
+ kt: "kotlin",
19440
+ swift: "swift",
19441
+ cs: "csharp",
19442
+ cpp: "cpp",
19443
+ cc: "cpp",
19444
+ cxx: "cpp",
19445
+ c: "c",
19446
+ h: "c",
19447
+ hpp: "cpp",
19448
+ md: "markdown",
19449
+ json: "json",
19450
+ css: "css",
19451
+ scss: "scss",
19452
+ html: "html",
19453
+ yml: "yaml",
19454
+ yaml: "yaml",
19455
+ toml: "toml",
19456
+ sh: "bash",
19457
+ bash: "bash",
19458
+ zsh: "bash",
19459
+ sql: "sql"
19460
+ };
19461
+ var WRITE_TOOLS = /^(write|write_file|notebookedit|notebook_edit)$/i;
19462
+ var EDIT_TOOLS = /^(edit|strreplace|str_replace|edit_file|replace)$/i;
19463
+ function isRecord(value) {
19464
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19465
+ }
19466
+ function asString(value) {
19467
+ return typeof value === "string" && value.length > 0 ? value : void 0;
19468
+ }
19469
+ function languageFromPath(path) {
19470
+ const base = path.split("/").pop() ?? path;
19471
+ const ext = base.includes(".") ? base.slice(base.lastIndexOf(".") + 1).toLowerCase() : "";
19472
+ return LANG_BY_EXT[ext];
19473
+ }
19474
+ function countPatchStats(patch) {
19475
+ let additions = 0;
19476
+ let deletions = 0;
19477
+ for (const line of patch.split("\n")) {
19478
+ if (line.startsWith("+") && !line.startsWith("+++"))
19479
+ additions += 1;
19480
+ else if (line.startsWith("-") && !line.startsWith("---"))
19481
+ deletions += 1;
19482
+ }
19483
+ return { additions, deletions };
19484
+ }
19485
+ function capPatch(patch) {
19486
+ if (patch.length <= MAX_DIFF_PATCH_CHARS)
19487
+ return { patch };
19488
+ return { patch: patch.slice(0, MAX_DIFF_PATCH_CHARS), truncated: true };
19489
+ }
19490
+ function summarizeDiffFiles(files) {
19491
+ const additions = files.reduce((sum, file) => sum + (file.additions ?? 0), 0);
19492
+ const deletions = files.reduce((sum, file) => sum + (file.deletions ?? 0), 0);
19493
+ const fileLabel = files.length === 1 ? "1 file" : `${files.length} files`;
19494
+ if (!additions && !deletions)
19495
+ return fileLabel;
19496
+ if (!deletions)
19497
+ return `${fileLabel} \xB7 +${additions}`;
19498
+ if (!additions)
19499
+ return `${fileLabel} \xB7 \u2212${deletions}`;
19500
+ return `${fileLabel} \xB7 +${additions} \u2212${deletions}`;
19501
+ }
19502
+ function withLanguage(path) {
19503
+ const language = languageFromPath(path);
19504
+ return language ? { language } : {};
19505
+ }
19506
+ function diffFileFromPatch(path, patch, status = "modified") {
19507
+ const stats = countPatchStats(patch);
19508
+ return {
19509
+ path,
19510
+ status,
19511
+ ...withLanguage(path),
19512
+ additions: stats.additions || void 0,
19513
+ deletions: stats.deletions || void 0,
19514
+ ...capPatch(patch)
19515
+ };
19516
+ }
19517
+ function diffFileFromWrite(path, content) {
19518
+ const capped = capPatch(content);
19519
+ return {
19520
+ path,
19521
+ status: "added",
19522
+ ...withLanguage(path),
19523
+ additions: content.split("\n").length,
19524
+ before: "",
19525
+ after: capped.patch,
19526
+ ...capped.truncated ? { truncated: true } : {}
19527
+ };
19528
+ }
19529
+ function splitUnifiedDiff(raw) {
19530
+ const text = raw.replace(/\r\n/g, "\n");
19531
+ const starts = [];
19532
+ const header = /^diff --git /gm;
19533
+ let match;
19534
+ while (match = header.exec(text))
19535
+ starts.push(match.index);
19536
+ if (starts.length === 0) {
19537
+ if (!text.trim())
19538
+ return [];
19539
+ return [diffFileFromPatch("diff", text)];
19540
+ }
19541
+ return starts.map((start, index) => {
19542
+ const chunk = text.slice(start, starts[index + 1]);
19543
+ const names = /^diff --git a\/(.+?) b\/(.+)$/m.exec(chunk);
19544
+ const oldPath = names?.[1] ?? "unknown";
19545
+ const path = names?.[2] ?? oldPath;
19546
+ let status = "modified";
19547
+ if (/^new file mode /m.test(chunk) || oldPath === "/dev/null")
19548
+ status = "added";
19549
+ else if (/^deleted file mode /m.test(chunk) || path === "/dev/null")
19550
+ status = "deleted";
19551
+ else if (/^rename from /m.test(chunk) || oldPath !== path)
19552
+ status = "renamed";
19553
+ const resolvedPath = path === "/dev/null" ? oldPath : path;
19554
+ return {
19555
+ ...diffFileFromPatch(resolvedPath, chunk, status),
19556
+ ...status === "renamed" && oldPath !== path ? { oldPath } : {}
19557
+ };
19558
+ }).slice(0, MAX_DIFF_FILES);
19559
+ }
19560
+ function pathFromArgs(input) {
19561
+ if (!isRecord(input))
19562
+ return void 0;
19563
+ return asString(input.path) ?? asString(input.file_path) ?? asString(input.target_file) ?? asString(input.notebook_path);
19564
+ }
19565
+ function writeContent(input) {
19566
+ if (!isRecord(input))
19567
+ return void 0;
19568
+ if (typeof input.content === "string")
19569
+ return input.content;
19570
+ if (typeof input.contents === "string")
19571
+ return input.contents;
19572
+ if (typeof input.new_source === "string")
19573
+ return input.new_source;
19574
+ return void 0;
19575
+ }
19576
+ function editPatchFromResult(result) {
19577
+ if (!isRecord(result))
19578
+ return void 0;
19579
+ const details = isRecord(result.details) ? result.details : void 0;
19580
+ return asString(details?.patch) ?? asString(result.patch);
19581
+ }
19582
+ function patchFromReplace(input) {
19583
+ if (!isRecord(input))
19584
+ return void 0;
19585
+ const oldText = asString(input.old_string) ?? asString(input.oldText) ?? asString(input.old_str);
19586
+ const newText = asString(input.new_string) ?? asString(input.newText) ?? asString(input.new_str);
19587
+ if (oldText == null || newText == null)
19588
+ return void 0;
19589
+ return `--- a
19590
+ +++ b
19591
+ @@
19592
+ ${oldText.split("\n").map((line) => `-${line}`).join("\n")}
19593
+ ${newText.split("\n").map((line) => `+${line}`).join("\n")}
19594
+ `;
19595
+ }
19596
+ function diffFileFromMutationTool(args) {
19597
+ const path = pathFromArgs(args.input);
19598
+ if (!path)
19599
+ return null;
19600
+ const patch = editPatchFromResult(args.result);
19601
+ if (patch)
19602
+ return diffFileFromPatch(path, patch);
19603
+ const toolName = args.toolName.replace(/[:/]/g, "_");
19604
+ if (WRITE_TOOLS.test(toolName)) {
19605
+ const content = writeContent(args.input);
19606
+ if (content === void 0)
19607
+ return null;
19608
+ return diffFileFromWrite(path, content);
19609
+ }
19610
+ if (EDIT_TOOLS.test(toolName)) {
19611
+ const replacePatch = patchFromReplace(args.input);
19612
+ if (!replacePatch)
19613
+ return null;
19614
+ return diffFileFromPatch(path, replacePatch);
19615
+ }
19616
+ return null;
19617
+ }
19618
+ function buildDiffWidget(args) {
19619
+ const files = args.files.slice(0, MAX_DIFF_FILES);
19620
+ if (files.length === 0)
19621
+ return null;
19622
+ return {
19623
+ kind: "diff",
19624
+ widgetId: args.widgetId,
19625
+ title: args.title ?? "Changes",
19626
+ description: summarizeDiffFiles(files),
19627
+ files,
19628
+ size: "full",
19629
+ display: "expanded"
19630
+ };
19631
+ }
19632
+ function git(cwd, args) {
19633
+ try {
19634
+ const result = spawnSync("git", ["-C", cwd, ...args], {
19635
+ encoding: "utf8",
19636
+ timeout: 15e3,
19637
+ maxBuffer: 8e6,
19638
+ stdio: ["ignore", "pipe", "pipe"]
19639
+ });
19640
+ if (result.status !== 0)
19641
+ return null;
19642
+ return result.stdout ?? "";
19643
+ } catch {
19644
+ return null;
19645
+ }
19646
+ }
19647
+ function snapshotWorkspace(cwd) {
19648
+ if (!cwd)
19649
+ return null;
19650
+ const inside = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
19651
+ if (inside?.trim() !== "true")
19652
+ return null;
19653
+ const stashSha = git(cwd, ["stash", "create"])?.trim() || void 0;
19654
+ const untracked = git(cwd, ["ls-files", "--others", "--exclude-standard"])?.split("\n").map((line) => line.trim()).filter(Boolean) ?? [];
19655
+ return { cwd, stashSha, untracked };
19656
+ }
19657
+ function mergeDiffFiles(existing, extra) {
19658
+ const byPath = new Map(existing.map((file) => [file.path, file]));
19659
+ for (const file of extra)
19660
+ byPath.set(file.path, file);
19661
+ return [...byPath.values()].slice(0, MAX_DIFF_FILES);
19662
+ }
19663
+ function diffFromSnapshot(snapshot) {
19664
+ if (!snapshot)
19665
+ return [];
19666
+ const { cwd, stashSha, untracked: beforeUntracked } = snapshot;
19667
+ const diffRaw = stashSha ? git(cwd, ["diff", stashSha]) : git(cwd, ["diff", "HEAD"]);
19668
+ const files = diffRaw ? splitUnifiedDiff(diffRaw) : [];
19669
+ const afterUntracked = git(cwd, ["ls-files", "--others", "--exclude-standard"])?.split("\n").map((line) => line.trim()).filter(Boolean) ?? [];
19670
+ const beforeSet = new Set(beforeUntracked);
19671
+ const extras = [];
19672
+ for (const path of afterUntracked) {
19673
+ if (beforeSet.has(path))
19674
+ continue;
19675
+ try {
19676
+ extras.push(diffFileFromWrite(path, readFileSync2(join(cwd, path), "utf8")));
19677
+ } catch {
19678
+ extras.push({ path, status: "added", ...withLanguage(path) });
19679
+ }
19680
+ }
19681
+ return mergeDiffFiles(files, extras);
19682
+ }
19683
+ function resolveRunDiffFiles(args) {
19684
+ const fromGit = diffFromSnapshot(args.snapshot ?? null);
19685
+ if (fromGit.length > 0)
19686
+ return fromGit;
19687
+ return [...args.fallback ?? []].slice(0, MAX_DIFF_FILES);
19688
+ }
19689
+
19409
19690
  // credits-auth.ts
19410
19691
  var INTEGRATIONS_TOKEN_HEADER = "x-openbot-integrations-token";
19411
19692
  var CREDITS_API_KEY_PLACEHOLDER = "openbot-credits";
@@ -19475,11 +19756,19 @@ var isIntegrationsProviderError = (message) => {
19475
19756
  var CREDITS_NOT_CONFIGURED_MESSAGE = "OpenBot Credits is not configured on this runtime. The cloud host must set OPENBOT_INTEGRATIONS_BASE_URL and OPENBOT_INTEGRATIONS_TOKEN (try redeploying the workspace).";
19476
19757
  var CREDITS_PROVIDER_UNAVAILABLE_MESSAGE = "OpenBot Credits could not reach Anthropic \u2014 the platform provider API key is not configured yet. Try again later or switch this agent to BYOK mode.";
19477
19758
  var CREDITS_AUTH_FAILED_MESSAGE = "Claude could not authenticate via OpenBot Credits. Check your workspace credit balance in settings, or switch this agent to BYOK mode.";
19759
+ var resolveClaudeConfigDir = () => {
19760
+ const baseDir = process.env.OPENBOT_BASE_DIR?.trim();
19761
+ return baseDir ? join2(baseDir, "claude") : void 0;
19762
+ };
19478
19763
  var buildSdkEnv = (authMode) => {
19479
- if (authMode !== "credits") return void 0;
19480
- const creditsEnv = buildCreditsAnthropicEnv();
19481
- if (!creditsEnv) return void 0;
19482
- return { ...process.env, ...creditsEnv };
19764
+ const creditsEnv = authMode === "credits" ? buildCreditsAnthropicEnv() : void 0;
19765
+ const claudeConfigDir = resolveClaudeConfigDir();
19766
+ if (!creditsEnv && !claudeConfigDir) return void 0;
19767
+ return {
19768
+ ...process.env,
19769
+ ...creditsEnv ?? {},
19770
+ ...claudeConfigDir ? { CLAUDE_CONFIG_DIR: claudeConfigDir } : {}
19771
+ };
19483
19772
  };
19484
19773
  var creditsErrorMessage = (message) => {
19485
19774
  if (isIntegrationsProviderError(message)) return CREDITS_PROVIDER_UNAVAILABLE_MESSAGE;
@@ -19774,6 +20063,8 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19774
20063
  const emittedToolCallIds = /* @__PURE__ */ new Set();
19775
20064
  const emittedToolResultIds = /* @__PURE__ */ new Set();
19776
20065
  const toolTitleByUseId = /* @__PURE__ */ new Map();
20066
+ const changedFiles = /* @__PURE__ */ new Map();
20067
+ const snapshot = snapshotWorkspace(workingDir);
19777
20068
  const emitAssistantText = function* (text) {
19778
20069
  if (!text) return;
19779
20070
  if (authMode === "credits") {
@@ -19837,20 +20128,12 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19837
20128
  yield uiWidget({
19838
20129
  agentId: context.state.agentId,
19839
20130
  threadId,
19840
- widget: {
19841
- kind: "message",
20131
+ widget: toolTraceWidget({
19842
20132
  widgetId: toolCallWidgetId(tool.toolUseId),
20133
+ groupId: "claude-code:tools",
19843
20134
  title: toolTitleByUseId.get(tool.toolUseId)?.title ?? "",
19844
- body: formatToolInputBody(tool.input),
19845
- display: "collapsed",
19846
- metadata: {
19847
- type: "claude_tool",
19848
- phase: "call",
19849
- toolName: tool.title,
19850
- toolUseId: tool.toolUseId,
19851
- source: "claude-code"
19852
- }
19853
- }
20135
+ body: formatToolInputBody(tool.input)
20136
+ })
19854
20137
  });
19855
20138
  }
19856
20139
  continue;
@@ -19876,24 +20159,25 @@ var claudeCodeRuntime = (options = {}) => (builder) => {
19876
20159
  yield uiWidget({
19877
20160
  agentId: context.state.agentId,
19878
20161
  threadId,
19879
- widget: {
19880
- kind: "message",
20162
+ widget: toolTraceWidget({
19881
20163
  widgetId: toolCallWidgetId(res.toolUseId),
20164
+ groupId: "claude-code:tools",
19882
20165
  title: toolTitleByUseId.get(res.toolUseId)?.title ?? "",
19883
20166
  body: formatToolResultBody(
19884
20167
  toolTitleByUseId.get(res.toolUseId)?.input,
19885
20168
  body
19886
20169
  ),
19887
- display: "collapsed",
19888
- ...state ? { state } : {},
19889
- metadata: {
19890
- type: "claude_tool",
19891
- phase: "result",
19892
- toolUseId: res.toolUseId,
19893
- source: "claude-code"
19894
- }
19895
- }
20170
+ state
20171
+ })
19896
20172
  });
20173
+ if (!res.isError) {
20174
+ const file = diffFileFromMutationTool({
20175
+ toolName: toolTitleByUseId.get(res.toolUseId)?.title ?? "",
20176
+ input: toolTitleByUseId.get(res.toolUseId)?.input,
20177
+ result: res.content
20178
+ });
20179
+ if (file) changedFiles.set(file.path, file);
20180
+ }
19897
20181
  }
19898
20182
  }
19899
20183
  }
@@ -19943,6 +20227,20 @@ ${details}` : `[claude-code] run ended with error: ${subtype}`
19943
20227
  if (lastSessionId && lastSessionId !== resumeId) {
19944
20228
  await persistSessionId(context.state, storage, lastSessionId);
19945
20229
  }
20230
+ const diff = buildDiffWidget({
20231
+ widgetId: `claude-code-diff:${threadId ?? "run"}:${Date.now()}`,
20232
+ files: resolveRunDiffFiles({
20233
+ snapshot,
20234
+ fallback: changedFiles.values()
20235
+ })
20236
+ });
20237
+ if (diff) {
20238
+ yield uiWidget({
20239
+ agentId: context.state.agentId,
20240
+ threadId,
20241
+ widget: diff
20242
+ });
20243
+ }
19946
20244
  } catch (error) {
19947
20245
  const errorMessage = formatClaudeCodeError(error, launchContext, stderrChunks);
19948
20246
  if (authMode === "credits") {
@@ -20085,7 +20383,7 @@ var claudeCodePlugin = {
20085
20383
  });
20086
20384
  }
20087
20385
  };
20088
- var claude_code_default = definePlugin(claudeCodePlugin);
20386
+ var plugin_claude_code_default = definePlugin(claudeCodePlugin);
20089
20387
  export {
20090
- claude_code_default as default
20388
+ plugin_claude_code_default as default
20091
20389
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meetopenbot/claude-code",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "type": "module",
5
5
  "description": "Claude Code plugin for OpenBot",
6
6
  "main": "./dist/index.js",
@@ -8,22 +8,28 @@
8
8
  "access": "public"
9
9
  },
10
10
  "exports": {
11
- ".": "./dist/index.js"
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
12
16
  },
13
17
  "files": [
14
18
  "dist"
15
19
  ],
16
- "scripts": {
17
- "build": "esbuild index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --external:melony --external:zod",
18
- "prepublishOnly": "npm run build"
19
- },
20
20
  "dependencies": {
21
21
  "@anthropic-ai/claude-agent-sdk": "^0.2.138",
22
- "@meetopenbot/plugin-sdk": "^0.1.4"
22
+ "@meetopenbot/plugin-sdk": "^0.2.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^20.10.1",
26
26
  "esbuild": "^0.21.0",
27
27
  "zod": "^4.3.5"
28
+ },
29
+ "types": "./dist/index.d.ts",
30
+ "scripts": {
31
+ "build": "esbuild index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --external:melony --external:zod && node ../../scripts/write-plugin-declaration.mjs",
32
+ "dev": "esbuild index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --external:melony --external:zod --watch",
33
+ "typecheck": "tsc --noEmit --allowImportingTsExtensions --module ESNext --moduleResolution Bundler --target ES2022 --skipLibCheck index.ts"
28
34
  }
29
- }
35
+ }