@khalilgharbaoui/opencode-claude-code-plugin 0.31.0 → 0.31.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/README.md CHANGED
@@ -890,6 +890,8 @@ It carries the startup-diagnostics fields (plugin version, opencode version, `cl
890
890
 
891
891
  When Claude Code refused an entry in an `--mcp-config` it was handed, an **MCP config entries Claude Code skipped** section names each one with the CLI's own category and sentence. That section only appears when there is something in it. It matters because a skipped server is absent from the CLI's server list entirely rather than listed as broken, so the model silently does not have those tools; if the skipped name is `opencode_proxy` the report says so plainly, because then it is the plugin's own server and every proxied tool call in the session fails. The same thing is a warning in your terminal when it happens.
892
892
 
893
+ A **Plugins Claude Code did not load** section works the same way for Claude plugins: one the CLI demoted at load time (for example, a dependency that is not installed) is absent from its plugin list, so its skills, commands and MCP servers are silently missing. The skill bridge is such a plugin (`opencode-skills`), and a failure there is reported as the plugin's own bug rather than your config. A plugin warning only counts when its content did not load; advisory feedback about a plugin that did load stays in the log at INFO.
894
+
893
895
  ```text
894
896
  /claude-code-doctor usage
895
897
  ```
package/dist/index.js CHANGED
@@ -415,6 +415,7 @@ var DEFAULT_PROXY_TOOL_NAMES = [
415
415
  "Task"
416
416
  ];
417
417
  var PROXY_MCP_SERVER_NAME = "opencode_proxy";
418
+ var SKILL_PLUGIN_NAME = "opencode-skills";
418
419
 
419
420
  // src/cli-events.ts
420
421
  function isRecord(value) {
@@ -595,9 +596,44 @@ function parseSystemInit(msg) {
595
596
  cliVersion: str(raw.claude_code_version),
596
597
  toolCount: Array.isArray(raw.tools) ? raw.tools.length : 0,
597
598
  mcpServers: servers,
598
- mcpServerErrors: parseMcpServerErrors(msg)
599
+ mcpServerErrors: parseMcpServerErrors(msg),
600
+ pluginErrors: parsePluginDiagnostics(raw.plugin_errors),
601
+ pluginWarnings: parsePluginDiagnostics(raw.plugin_warnings),
602
+ loadedPlugins: parseLoadedPlugins(raw.plugins)
599
603
  };
600
604
  }
605
+ function parsePluginDiagnostics(raw) {
606
+ if (!Array.isArray(raw)) return [];
607
+ const diagnostics = [];
608
+ for (const entry of raw) {
609
+ if (!isRecord(entry)) continue;
610
+ diagnostics.push({
611
+ plugin: str(entry.plugin) ?? "unknown",
612
+ type: str(entry.type) ?? "unknown",
613
+ message: str(entry.message) ?? ""
614
+ });
615
+ }
616
+ return diagnostics;
617
+ }
618
+ function parseLoadedPlugins(raw) {
619
+ if (!Array.isArray(raw)) return [];
620
+ const loaded = [];
621
+ for (const entry of raw) {
622
+ if (!isRecord(entry)) continue;
623
+ for (const id of [str(entry.source), str(entry.name)]) {
624
+ if (id && !loaded.includes(id)) loaded.push(id);
625
+ }
626
+ }
627
+ return loaded;
628
+ }
629
+ function describePluginLoadFailure(diagnostic) {
630
+ const detail = diagnostic.message ? ` Claude Code said: ${diagnostic.message}` : "";
631
+ const name = diagnostic.plugin.split("@", 1)[0];
632
+ if (name === SKILL_PLUGIN_NAME) {
633
+ return `Claude Code did not load the plugin's own skill bridge "${diagnostic.plugin}" (${diagnostic.type}), so the opencode skills it bridges are missing this session. This is a plugin bug or a corrupted scratch directory rather than your config: report it with this line.${detail}`;
634
+ }
635
+ return `Claude Code did not load plugin "${diagnostic.plugin}" (${diagnostic.type}), so its skills, commands and MCP servers are missing this session.${detail}`;
636
+ }
601
637
  function apiKeySourceWarning(apiKeySource, ignoreAnthropicApiKey) {
602
638
  if (!apiKeySource || !API_KEY_SOURCES.has(apiKeySource)) return null;
603
639
  const base = `Claude Code authenticated with an API key (apiKeySource: ${apiKeySource}), so these turns bill as pay-as-you-go API usage instead of your subscription.`;
@@ -607,9 +643,32 @@ var warnedApiKeySources = /* @__PURE__ */ new Set();
607
643
  var warnedMcpFailures = /* @__PURE__ */ new Set();
608
644
  var warnedMcpSkips = /* @__PURE__ */ new Set();
609
645
  var lastMcpServerErrors = /* @__PURE__ */ new Map();
646
+ var warnedPluginDiagnostics = /* @__PURE__ */ new Set();
647
+ var lastPluginLoadFailures = /* @__PURE__ */ new Map();
610
648
  function snapshotMcpServerErrors() {
611
649
  return [...lastMcpServerErrors.values()];
612
650
  }
651
+ function snapshotPluginLoadFailures() {
652
+ return [...lastPluginLoadFailures.values()];
653
+ }
654
+ function reportPluginDiagnostics(info) {
655
+ const report = (kind, diagnostic) => {
656
+ const loaded = kind === "warning" && info.loadedPlugins.includes(diagnostic.plugin);
657
+ const message = loaded ? `Claude Code has advisory feedback for plugin "${diagnostic.plugin}" (${diagnostic.type}): ${diagnostic.message}` : describePluginLoadFailure(diagnostic);
658
+ if (!loaded) lastPluginLoadFailures.set(diagnostic.plugin, { kind, ...diagnostic });
659
+ const key = `${kind}:${diagnostic.plugin}:${diagnostic.type}`;
660
+ const data = { plugin: diagnostic.plugin, type: diagnostic.type, kind };
661
+ if (warnedPluginDiagnostics.has(key)) {
662
+ log.debug(message, data);
663
+ return;
664
+ }
665
+ warnedPluginDiagnostics.add(key);
666
+ if (loaded) log.info(message, data);
667
+ else log.warn(message, data);
668
+ };
669
+ for (const diagnostic of info.pluginErrors) report("error", diagnostic);
670
+ for (const diagnostic of info.pluginWarnings) report("warning", diagnostic);
671
+ }
613
672
  function reportSystemInit(msg, options = {}) {
614
673
  const info = parseSystemInit(msg);
615
674
  if (!info) return;
@@ -620,8 +679,11 @@ function reportSystemInit(msg, options = {}) {
620
679
  cliVersion: info.cliVersion ?? null,
621
680
  tools: info.toolCount,
622
681
  mcpServers: info.mcpServers,
623
- mcpServerErrors: info.mcpServerErrors
682
+ mcpServerErrors: info.mcpServerErrors,
683
+ pluginErrors: info.pluginErrors,
684
+ pluginWarnings: info.pluginWarnings
624
685
  });
686
+ reportPluginDiagnostics(info);
625
687
  for (const error of info.mcpServerErrors) {
626
688
  lastMcpServerErrors.set(error.name, error);
627
689
  const key2 = `${error.name}:${error.type}`;
@@ -4869,6 +4931,18 @@ function formatDoctorReport(report) {
4869
4931
  lines.push("");
4870
4932
  lines.push("A skipped server is missing from the model's tools with no other sign of it.");
4871
4933
  }
4934
+ if (report.pluginLoadFailures.length > 0) {
4935
+ lines.push("");
4936
+ lines.push("**Plugins Claude Code did not load**");
4937
+ lines.push("");
4938
+ lines.push("| plugin | kind | category | Claude Code said |");
4939
+ lines.push("|---|---|---|---|");
4940
+ for (const failure of report.pluginLoadFailures) {
4941
+ lines.push(
4942
+ `| ${failure.plugin} | ${failure.kind} | \`${failure.type}\` | ${failure.message || "no detail"} |`
4943
+ );
4944
+ }
4945
+ }
4872
4946
  lines.push("");
4873
4947
  lines.push("**Plan usage**");
4874
4948
  lines.push("");
@@ -4967,6 +5041,7 @@ async function gatherDoctorReport(options) {
4967
5041
  pendingCalls: snapshotPendingProxyCalls(),
4968
5042
  proxyServers,
4969
5043
  mcpServerErrors: snapshotMcpServerErrors(),
5044
+ pluginLoadFailures: snapshotPluginLoadFailures(),
4970
5045
  planUsage
4971
5046
  };
4972
5047
  }
@@ -4981,6 +5056,7 @@ async function buildDoctorReport(options) {
4981
5056
  pendingCalls: report.pendingCalls.length,
4982
5057
  proxyServers: report.proxyServers.map((server2) => server2.auth.status),
4983
5058
  mcpServerErrors: report.mcpServerErrors.length,
5059
+ pluginLoadFailures: report.pluginLoadFailures.length,
4984
5060
  planUsage: report.planUsage.status
4985
5061
  });
4986
5062
  return formatDoctorReport(report);
@@ -6078,7 +6154,6 @@ import * as fs5 from "fs";
6078
6154
  import * as os3 from "os";
6079
6155
  import * as path7 from "path";
6080
6156
  import { fileURLToPath as fileURLToPath2 } from "url";
6081
- var SKILL_PLUGIN_NAME = "opencode-skills";
6082
6157
  function bundledSkillsDir() {
6083
6158
  try {
6084
6159
  const here = fileURLToPath2(import.meta.url);