@khalilgharbaoui/opencode-claude-code-plugin 0.42.1 → 0.42.2

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/index.js CHANGED
@@ -1723,6 +1723,21 @@ function cliSupportsDontAsk(v) {
1723
1723
  if (!v) return false;
1724
1724
  return gte(v, { major: 2, minor: 1, patch: 263 });
1725
1725
  }
1726
+ var INTERACTIVE_MEASURED_CLI = "2.1.288";
1727
+ var INTERACTIVE_MEASURED = { major: 2, minor: 1, patch: 288 };
1728
+ function isUnmeasuredInteractiveCli(v) {
1729
+ if (!v) return false;
1730
+ return gte(v, INTERACTIVE_MEASURED) && !(v.major === INTERACTIVE_MEASURED.major && v.minor === INTERACTIVE_MEASURED.minor && v.patch === INTERACTIVE_MEASURED.patch);
1731
+ }
1732
+ var warnedUnmeasuredInteractive = /* @__PURE__ */ new Set();
1733
+ function reportUnmeasuredInteractiveCli(v) {
1734
+ if (!v || !isUnmeasuredInteractiveCli(v) || warnedUnmeasuredInteractive.has(v.raw)) return;
1735
+ warnedUnmeasuredInteractive.add(v.raw);
1736
+ log.warn(
1737
+ "the interactive transport has not been measured on this Claude Code version; it reads the TUI's screen and transcript, which a new release can change. If a turn hangs or a dialog is not handled, run /claude-code-doctor bundle and report it",
1738
+ { cliVersion: v.raw, measuredCli: INTERACTIVE_MEASURED_CLI }
1739
+ );
1740
+ }
1726
1741
  function cliSupportsSideQuestion(v) {
1727
1742
  if (!v) return false;
1728
1743
  return gte(v, { major: 2, minor: 1, patch: 258 });
@@ -5431,6 +5446,7 @@ function snapshotActiveProcesses(now = Date.now()) {
5431
5446
  ageMs: ap.startedAt === void 0 ? void 0 : Math.max(0, now - ap.startedAt),
5432
5447
  effort: ap.effort,
5433
5448
  attached: ap.lineEmitter.listenerCount("line") > 0,
5449
+ transport: ap.interactiveControl ? "interactive" : "headless",
5434
5450
  proxyUrl: ap.proxyServer?.url,
5435
5451
  lastStderr: typeof lastStderr === "string" ? lastStderr : void 0
5436
5452
  });
@@ -5845,6 +5861,7 @@ var PLUGIN_LOG_MESSAGES = /* @__PURE__ */ new Set([
5845
5861
  "skipping remote MCP server with no url",
5846
5862
  "stale scratch directory sweep failed",
5847
5863
  "task_batch resolving with child results missing",
5864
+ "the interactive transport has not been measured on this Claude Code version; it reads the TUI's screen and transcript, which a new release can change. If a turn hangs or a dialog is not handled, run /claude-code-doctor bundle and report it",
5848
5865
  "this opencode process is running an older plugin build than the one on disk",
5849
5866
  "timed out pending proxy call",
5850
5867
  "turn abort listener threw",
@@ -5994,6 +6011,7 @@ var BUNDLE_DATA_ALLOWLIST = {
5994
6011
  toolNames: "name",
5995
6012
  cliFloor: "version",
5996
6013
  cliVersion: "version",
6014
+ measuredCli: "version",
5997
6015
  // The two halves of the stale-build WARN: what this process loaded and what
5998
6016
  // is on disk now. Both are this package's own version strings.
5999
6017
  loadedVersion: "version",
@@ -6453,6 +6471,34 @@ import * as fs4 from "fs";
6453
6471
  import * as path5 from "path";
6454
6472
  import { promisify as promisify2 } from "util";
6455
6473
  import { fileURLToPath } from "url";
6474
+
6475
+ // src/transport.ts
6476
+ function requestedTransport(config, env = process.env.CLAUDE_CODE_INTERACTIVE_TRANSPORT) {
6477
+ if (config.transport !== void 0) {
6478
+ if (!["auto", "headless", "interactive"].includes(config.transport)) {
6479
+ throw new Error(`Unknown Claude transport: ${config.transport}`);
6480
+ }
6481
+ return config.transport;
6482
+ }
6483
+ const enabled = config.interactive ?? (env !== void 0 && !["", "0", "false", "no", "off"].includes(env.trim().toLowerCase()));
6484
+ return enabled ? "interactive" : "headless";
6485
+ }
6486
+ function hasInteractiveTransport() {
6487
+ const runtime = globalThis;
6488
+ return typeof runtime.Bun?.Terminal === "function";
6489
+ }
6490
+ async function selectTransport(requested, cliPath, available = hasInteractiveTransport()) {
6491
+ if (requested === "headless") return "headless";
6492
+ if (requested === "interactive") {
6493
+ if (!available) throw new Error("Interactive Claude transport requires Bun.Terminal. Run opencode under a Bun runtime with PTY support.");
6494
+ return "interactive";
6495
+ }
6496
+ if (await detectHeadlessSupport(cliPath) !== "unsupported") return "headless";
6497
+ if (!available) throw new Error("Claude no longer supports the headless flags, and Bun.Terminal is unavailable. Run opencode under a Bun runtime with PTY support.");
6498
+ return "interactive";
6499
+ }
6500
+
6501
+ // src/startup-diagnostics.ts
6456
6502
  var cachedPluginVersion;
6457
6503
  function pluginVersion() {
6458
6504
  if (cachedPluginVersion) return cachedPluginVersion;
@@ -6535,6 +6581,15 @@ function collectStartupDiagnostics(providers, opencodeVersion) {
6535
6581
  error: err instanceof Error ? err.message : String(err)
6536
6582
  });
6537
6583
  }
6584
+ let transport;
6585
+ try {
6586
+ transport = requestedTransport({
6587
+ transport: firstOption(providers, "transport"),
6588
+ interactive: firstOption(providers, "interactive")
6589
+ });
6590
+ } catch {
6591
+ transport = "invalid";
6592
+ }
6538
6593
  return {
6539
6594
  plugin: pluginVersion(),
6540
6595
  opencode: opencodeVersion ?? process.env.OPENCODE_VERSION ?? "unknown",
@@ -6547,7 +6602,8 @@ function collectStartupDiagnostics(providers, opencodeVersion) {
6547
6602
  permissionPresets: Object.entries(providers).map(
6548
6603
  ([name, entry]) => summarizePermissionPreset(name, entry?.options)
6549
6604
  ),
6550
- interactiveTransport: firstOption(providers, "interactive") === true || process.env.CLAUDE_CODE_INTERACTIVE_TRANSPORT === "1",
6605
+ transport,
6606
+ interactiveTransport: transport === "interactive",
6551
6607
  planModeQuestion: firstOption(providers, "planModeQuestion") === true,
6552
6608
  anthropicApiKeyInEnv: Boolean(
6553
6609
  process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN
@@ -6816,7 +6872,14 @@ function formatDoctorReport(report) {
6816
6872
  lines.push(`| proxyTools | ${list(report.proxyTools)} |`);
6817
6873
  lines.push(`| MCP servers (on disk) | ${list(report.mcpServers)} |`);
6818
6874
  lines.push(`| permissionPreset | ${describePermissionPresets(report.permissionPresets)} |`);
6819
- lines.push(`| transport | ${report.transport} |`);
6875
+ lines.push(
6876
+ `| transport | ${report.transport}${report.transport === "auto" ? " (headless until claude refuses `--print`)" : ""}; this conversation: ${report.transportInUse} |`
6877
+ );
6878
+ if (report.interactiveMeasured) {
6879
+ lines.push(
6880
+ `| interactive transport measured on | Claude Code ${report.interactiveMeasured.measured}${report.interactiveMeasured.unmeasured ? ` (this CLI, ${report.claudeCli.version}, is newer and unmeasured: if a turn hangs, send \`/claude-code-doctor bundle\`)` : ""} |`
6881
+ );
6882
+ }
6820
6883
  lines.push(`| planModeQuestion | ${report.planModeQuestion} |`);
6821
6884
  lines.push(`| turnStats | ${report.turnStats} |`);
6822
6885
  lines.push(`| ANTHROPIC_API_KEY in env | ${report.anthropicApiKeyInEnv ? "yes" : "no"} |`);
@@ -6837,11 +6900,11 @@ function formatDoctorReport(report) {
6837
6900
  if (report.processes.length === 0) {
6838
6901
  lines.push("None. The next message in a Claude Code session spawns one.");
6839
6902
  } else {
6840
- lines.push("| session | model | pid | in flight | age | effort |");
6841
- lines.push("|---|---|---|---|---|---|");
6903
+ lines.push("| session | model | transport | pid | in flight | age | effort |");
6904
+ lines.push("|---|---|---|---|---|---|---|");
6842
6905
  for (const proc of report.processes) {
6843
6906
  lines.push(
6844
- `| ${proc.session}${proc.compaction ? " (compaction)" : ""} | ${proc.model} | ${proc.pid ?? "unknown"} | ${proc.inFlight ? "yes" : "no"} | ${formatAge(proc.ageMs)} | ${proc.effort ?? "inherited"} |`
6907
+ `| ${proc.session}${proc.compaction ? " (compaction)" : ""} | ${proc.model} | ${proc.transport} | ${proc.pid ?? "unknown"} | ${proc.inFlight ? "yes" : "no"} | ${formatAge(proc.ageMs)} | ${proc.effort ?? "inherited"} |`
6845
6908
  );
6846
6909
  }
6847
6910
  }
@@ -7061,7 +7124,9 @@ async function gatherDoctorReport(options) {
7061
7124
  proxyTools: base.proxyTools,
7062
7125
  mcpServers: base.mcpServers,
7063
7126
  permissionPresets: base.permissionPresets,
7064
- transport: options.interactive || base.interactiveTransport ? "interactive" : "headless",
7127
+ transport: base.transport,
7128
+ transportInUse: options.interactive ? "interactive" : "headless",
7129
+ interactiveMeasured: base.transport !== "headless" || options.interactive || processes.some((proc) => proc.transport === "interactive") ? { measured: INTERACTIVE_MEASURED_CLI, unmeasured: isUnmeasuredInteractiveCli(cli) } : void 0,
7065
7130
  planModeQuestion: base.planModeQuestion,
7066
7131
  turnStats: options.turnStats,
7067
7132
  anthropicApiKeyInEnv: base.anthropicApiKeyInEnv,
@@ -10064,32 +10129,6 @@ function spawnInteractiveProcess(opts) {
10064
10129
  return ap;
10065
10130
  }
10066
10131
 
10067
- // src/transport.ts
10068
- function requestedTransport(config, env = process.env.CLAUDE_CODE_INTERACTIVE_TRANSPORT) {
10069
- if (config.transport !== void 0) {
10070
- if (!["auto", "headless", "interactive"].includes(config.transport)) {
10071
- throw new Error(`Unknown Claude transport: ${config.transport}`);
10072
- }
10073
- return config.transport;
10074
- }
10075
- const enabled = config.interactive ?? (env !== void 0 && !["", "0", "false", "no", "off"].includes(env.trim().toLowerCase()));
10076
- return enabled ? "interactive" : "headless";
10077
- }
10078
- function hasInteractiveTransport() {
10079
- const runtime = globalThis;
10080
- return typeof runtime.Bun?.Terminal === "function";
10081
- }
10082
- async function selectTransport(requested, cliPath, available = hasInteractiveTransport()) {
10083
- if (requested === "headless") return "headless";
10084
- if (requested === "interactive") {
10085
- if (!available) throw new Error("Interactive Claude transport requires Bun.Terminal. Run opencode under a Bun runtime with PTY support.");
10086
- return "interactive";
10087
- }
10088
- if (await detectHeadlessSupport(cliPath) !== "unsupported") return "headless";
10089
- if (!available) throw new Error("Claude no longer supports the headless flags, and Bun.Terminal is unavailable. Run opencode under a Bun runtime with PTY support.");
10090
- return "interactive";
10091
- }
10092
-
10093
10132
  // src/prompts.ts
10094
10133
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
10095
10134
  import { homedir as homedir8 } from "os";
@@ -13333,6 +13372,7 @@ var ClaudeCodeLanguageModel = class {
13333
13372
  return abortedBeforeWork("waiting for opencode's MCP status and the CLI version");
13334
13373
  }
13335
13374
  const [runtimeStatus, cliVersion] = prologue.value;
13375
+ if (useInteractive) reportUnmeasuredInteractiveCli(cliVersion);
13336
13376
  const ptyReadOnly = useInteractive && !compactionMode && !doctor && isReadOnlyPermissionMode(this.config.permissionMode);
13337
13377
  const ptyReadOnlySupported = cliSupportsRestricted(cliVersion) && cliSupportsDontAsk(cliVersion);
13338
13378
  if (ptyReadOnly && !ptyReadOnlySupported) {