@khalilgharbaoui/opencode-claude-code-plugin 0.36.4 → 0.37.0

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
@@ -808,6 +808,13 @@ function formatSilentTurnNote(hadReasoning) {
808
808
  const what = hadReasoning ? "Claude Code finished the turn after thinking but never wrote an answer" : "Claude Code finished the turn without writing anything or calling a tool";
809
809
  return `
810
810
  ${SILENT_TURN_MARKER} ${what}, so there is no reply above. Nothing failed and nothing is pending: send the message again, or rephrase it.
811
+ `;
812
+ }
813
+ var UNATTENDED_REPLAY_MARKER = "\u258C **between turns:**";
814
+ function formatUnattendedReplayNote(dropped) {
815
+ const lost = dropped > 0 ? ` ${dropped} earlier line${dropped === 1 ? "" : "s"} were dropped.` : "";
816
+ return `${UNATTENDED_REPLAY_MARKER} The Claude Code CLI wrote this after the previous turn had already finished, so it is not an answer to the message above.${lost}
817
+
811
818
  `;
812
819
  }
813
820
  var UNRECOGNIZED_MODEL_STDERR_MARKER = "[claude-code:unrecognized_model]";
@@ -5464,6 +5471,7 @@ var PLUGIN_LOG_MESSAGES = /* @__PURE__ */ new Set([
5464
5471
  "skipping remote MCP server with no url",
5465
5472
  "stale scratch directory sweep failed",
5466
5473
  "task_batch resolving with child results missing",
5474
+ "this opencode process is running an older plugin build than the one on disk",
5467
5475
  "timed out pending proxy call",
5468
5476
  "turn abort listener threw",
5469
5477
  "two different skills share a name; bridging the one the nearest root claimed",
@@ -5612,6 +5620,10 @@ var BUNDLE_DATA_ALLOWLIST = {
5612
5620
  toolNames: "name",
5613
5621
  cliFloor: "version",
5614
5622
  cliVersion: "version",
5623
+ // The two halves of the stale-build WARN: what this process loaded and what
5624
+ // is on disk now. Both are this package's own version strings.
5625
+ loadedVersion: "version",
5626
+ onDiskVersion: "version",
5615
5627
  opencode: "version",
5616
5628
  plugin: "version",
5617
5629
  version: "version",
@@ -5861,8 +5873,8 @@ function redactLogLine(raw, context) {
5861
5873
  if (!parsed.data || Object.keys(parsed.data).length === 0) return head;
5862
5874
  return `${head} ${JSON.stringify(sanitizeLogData(parsed.data, context))}`;
5863
5875
  }
5864
- function readLogTail(path10, maxBytes = BUNDLE_TAIL_BYTES) {
5865
- const fd = openSync(path10, "r");
5876
+ function readLogTail(path11, maxBytes = BUNDLE_TAIL_BYTES) {
5877
+ const fd = openSync(path11, "r");
5866
5878
  try {
5867
5879
  const size = fstatSync(fd).size;
5868
5880
  const length = Math.min(size, maxBytes);
@@ -6052,6 +6064,11 @@ async function fetchPlanUsage(cliPath, options = {}) {
6052
6064
  }
6053
6065
  }
6054
6066
 
6067
+ // src/stale-build.ts
6068
+ import * as fs5 from "fs";
6069
+ import * as path6 from "path";
6070
+ import { fileURLToPath as fileURLToPath2 } from "url";
6071
+
6055
6072
  // src/startup-diagnostics.ts
6056
6073
  import { execFile as execFile3 } from "child_process";
6057
6074
  import * as fs4 from "fs";
@@ -6191,6 +6208,161 @@ function logStartupDiagnostics(providers, opencodeVersion) {
6191
6208
  })();
6192
6209
  }
6193
6210
 
6211
+ // src/stale-build.ts
6212
+ var STALE_BUILD_MARKER = "\u258C **restart opencode:**";
6213
+ var STALE_BUILD_THROTTLE_MS = 6e4;
6214
+ var STALE_BUILD_SESSION_CAP = 64;
6215
+ function compareBuilds(loaded, onDisk) {
6216
+ if (!onDisk) return null;
6217
+ if (onDisk.version !== loaded.version) {
6218
+ return {
6219
+ kind: "version",
6220
+ loadedVersion: loaded.version,
6221
+ onDiskVersion: onDisk.version,
6222
+ loadedAt: loaded.loadedAt
6223
+ };
6224
+ }
6225
+ if (loaded.mtimeMs === void 0 || loaded.size === void 0) return null;
6226
+ if (onDisk.mtimeMs === loaded.mtimeMs && onDisk.size === loaded.size) return null;
6227
+ return {
6228
+ kind: "rebuilt",
6229
+ loadedVersion: loaded.version,
6230
+ onDiskVersion: onDisk.version,
6231
+ loadedAt: loaded.loadedAt,
6232
+ rebuiltAt: onDisk.mtimeMs
6233
+ };
6234
+ }
6235
+ function formatLocalMinute(ms) {
6236
+ const when = new Date(ms);
6237
+ const pad = (value) => String(value).padStart(2, "0");
6238
+ return `${when.getFullYear()}-${pad(when.getMonth() + 1)}-${pad(when.getDate())} ${pad(when.getHours())}:${pad(when.getMinutes())}`;
6239
+ }
6240
+ function formatStaleBuildNote(stale) {
6241
+ const loadedAt = formatLocalMinute(stale.loadedAt);
6242
+ if (stale.kind === "version") {
6243
+ return `${STALE_BUILD_MARKER} plugin ${stale.onDiskVersion} is on disk, but this opencode process still runs ${stale.loadedVersion}, loaded ${loadedAt}. opencode reads a plugin once at startup, so fixes since then are not active here: quit every opencode window and relaunch.`;
6244
+ }
6245
+ const rebuiltAt = stale.rebuiltAt === void 0 ? "since" : `at ${formatLocalMinute(stale.rebuiltAt)}`;
6246
+ return `${STALE_BUILD_MARKER} this opencode process loaded plugin ${stale.loadedVersion} at ${loadedAt}, and that build was rebuilt on disk ${rebuiltAt}. opencode reads a plugin once at startup, so what you just built is not running here: quit every opencode window and relaunch.`;
6247
+ }
6248
+ function describeBuildStatus(status) {
6249
+ const loadedAt = formatLocalMinute(status.loaded.loadedAt);
6250
+ switch (status.verdict) {
6251
+ case "current":
6252
+ return `${status.loaded.version}, loaded ${loadedAt}, current`;
6253
+ case "version":
6254
+ return `${status.loaded.version}, loaded ${loadedAt}; on disk ${status.onDisk?.version ?? "unknown"}. Restart opencode to run it`;
6255
+ case "rebuilt":
6256
+ return `${status.loaded.version}, loaded ${loadedAt}; the same version was rebuilt on disk ${status.onDisk ? `at ${formatLocalMinute(status.onDisk.mtimeMs)}` : "since"}. Restart opencode to run it`;
6257
+ case "unreadable":
6258
+ return `${status.loaded.version}, loaded ${loadedAt}; the build on disk could not be read`;
6259
+ }
6260
+ }
6261
+ function createStaleBuildWatch(io) {
6262
+ const throttleMs = io.throttleMs ?? STALE_BUILD_THROTTLE_MS;
6263
+ const warn = io.warn ?? ((data) => {
6264
+ log.warn(
6265
+ "this opencode process is running an older plugin build than the one on disk",
6266
+ data
6267
+ );
6268
+ });
6269
+ const claimed = /* @__PURE__ */ new Set();
6270
+ const warned = /* @__PURE__ */ new Set();
6271
+ let checkedAt;
6272
+ let cached = null;
6273
+ const read = () => {
6274
+ let onDisk;
6275
+ try {
6276
+ onDisk = io.readOnDisk();
6277
+ } catch {
6278
+ onDisk = void 0;
6279
+ }
6280
+ const stale = compareBuilds(io.loaded, onDisk);
6281
+ const verdict = !onDisk ? "unreadable" : stale ? stale.kind : "current";
6282
+ return { loaded: io.loaded, onDisk, stale, verdict };
6283
+ };
6284
+ return {
6285
+ get loaded() {
6286
+ return io.loaded;
6287
+ },
6288
+ check() {
6289
+ const now = io.now();
6290
+ if (checkedAt !== void 0 && now - checkedAt < throttleMs) return cached;
6291
+ checkedAt = now;
6292
+ const status = read();
6293
+ cached = status.stale;
6294
+ if (status.stale && status.onDisk) {
6295
+ const identity = `${status.stale.kind}:${status.onDisk.version}:${status.onDisk.mtimeMs}:${status.onDisk.size}`;
6296
+ if (!warned.has(identity)) {
6297
+ warned.add(identity);
6298
+ warn({
6299
+ kind: status.stale.kind,
6300
+ loadedVersion: status.stale.loadedVersion,
6301
+ onDiskVersion: status.stale.onDiskVersion,
6302
+ path: io.loaded.entryPath
6303
+ });
6304
+ }
6305
+ }
6306
+ return cached;
6307
+ },
6308
+ describe() {
6309
+ return read();
6310
+ },
6311
+ claimSession(sessionId) {
6312
+ if (claimed.has(sessionId)) return false;
6313
+ claimed.add(sessionId);
6314
+ while (claimed.size > STALE_BUILD_SESSION_CAP) {
6315
+ const oldest = claimed.values().next();
6316
+ if (oldest.done) break;
6317
+ claimed.delete(oldest.value);
6318
+ }
6319
+ return true;
6320
+ },
6321
+ claimedSessions() {
6322
+ return [...claimed];
6323
+ }
6324
+ };
6325
+ }
6326
+ function defaultEntryPath() {
6327
+ return fileURLToPath2(import.meta.url);
6328
+ }
6329
+ function readOnDiskBuild(entryPath) {
6330
+ try {
6331
+ const raw = fs5.readFileSync(path6.join(path6.dirname(entryPath), "..", "package.json"), "utf8");
6332
+ const version = JSON.parse(raw).version;
6333
+ if (typeof version !== "string" || version.length === 0) return void 0;
6334
+ const stat = fs5.statSync(entryPath);
6335
+ return { version, mtimeMs: stat.mtimeMs, size: stat.size };
6336
+ } catch {
6337
+ return void 0;
6338
+ }
6339
+ }
6340
+ function recordLoadedBuild() {
6341
+ const entryPath = defaultEntryPath();
6342
+ let mtimeMs;
6343
+ let size;
6344
+ try {
6345
+ const stat = fs5.statSync(entryPath);
6346
+ mtimeMs = stat.mtimeMs;
6347
+ size = stat.size;
6348
+ } catch {
6349
+ }
6350
+ return { version: pluginVersion(), entryPath, mtimeMs, size, loadedAt: Date.now() };
6351
+ }
6352
+ var loadedAtImport = recordLoadedBuild();
6353
+ var watch;
6354
+ function staleBuildWatch() {
6355
+ if (!watch) {
6356
+ const loaded = loadedAtImport;
6357
+ watch = createStaleBuildWatch({
6358
+ loaded,
6359
+ readOnDisk: () => readOnDiskBuild(loaded.entryPath),
6360
+ now: () => Date.now()
6361
+ });
6362
+ }
6363
+ return watch;
6364
+ }
6365
+
6194
6366
  // src/doctor.ts
6195
6367
  var DOCTOR_COMMAND = "claude-code-doctor";
6196
6368
  var DOCTOR_COMMAND_DESCRIPTION = "Report what the Claude Code plugin sees: versions, cwd, live processes, pending proxy calls. Add `usage` for plan windows, or `bundle` for a redacted log you can paste into an issue";
@@ -6262,6 +6434,7 @@ function formatDoctorReport(report) {
6262
6434
  lines.push("| Field | Value |");
6263
6435
  lines.push("|---|---|");
6264
6436
  lines.push(`| plugin | ${report.plugin} |`);
6437
+ lines.push(`| plugin build | ${describeBuildStatus(report.build)} |`);
6265
6438
  lines.push(`| opencode | ${report.opencode} |`);
6266
6439
  lines.push(`| claude CLI | \`${report.claudeCli.path}\` (${report.claudeCli.version}) |`);
6267
6440
  lines.push(`| cwd | \`${report.cwd.resolved}\` (${report.cwd.source}) |`);
@@ -6505,6 +6678,8 @@ async function gatherDoctorReport(options) {
6505
6678
  }) : { status: "not-requested" };
6506
6679
  return {
6507
6680
  plugin: base.plugin,
6681
+ // `describe`, not `check`: unthrottled, silent, and it claims no session.
6682
+ build: staleBuildWatch().describe(),
6508
6683
  opencode: base.opencode,
6509
6684
  claudeCli: { path: cliPath, version: cli?.raw ?? "not detected" },
6510
6685
  cwd: base.cwd,
@@ -6571,6 +6746,7 @@ async function buildDoctorReport(options) {
6571
6746
  const report = await gatherDoctorReport(options);
6572
6747
  log.info("claude-code doctor report", {
6573
6748
  plugin: report.plugin,
6749
+ verdict: report.build.verdict,
6574
6750
  opencode: report.opencode,
6575
6751
  cwd: report.cwd,
6576
6752
  processes: report.processes.length,
@@ -6594,7 +6770,7 @@ Could not build the report: ${message}`;
6594
6770
 
6595
6771
  // src/agent-models.ts
6596
6772
  import { readFile, readdir } from "fs/promises";
6597
- import path6 from "path";
6773
+ import path7 from "path";
6598
6774
 
6599
6775
  // src/models.ts
6600
6776
  var PROVIDER_ID = "claude-code";
@@ -7097,11 +7273,11 @@ async function readAgentMarkdownRecords(directories) {
7097
7273
  const name = entry.slice(0, -3);
7098
7274
  if (records[name]) continue;
7099
7275
  try {
7100
- const text = await readFile(path6.join(directory, entry), "utf8");
7276
+ const text = await readFile(path7.join(directory, entry), "utf8");
7101
7277
  records[name] = parseAgentFrontmatter(text);
7102
7278
  } catch (err) {
7103
7279
  log.debug("failed to read agent markdown", {
7104
- file: path6.join(directory, entry),
7280
+ file: path7.join(directory, entry),
7105
7281
  error: String(err)
7106
7282
  });
7107
7283
  }
@@ -7113,12 +7289,12 @@ function agentDirectories(home, projectDirectory) {
7113
7289
  const directories = [];
7114
7290
  if (projectDirectory) {
7115
7291
  for (const name of AGENT_DIR_NAMES) {
7116
- directories.push(path6.join(projectDirectory, ".opencode", name));
7292
+ directories.push(path7.join(projectDirectory, ".opencode", name));
7117
7293
  }
7118
7294
  }
7119
7295
  if (home) {
7120
7296
  for (const name of AGENT_DIR_NAMES) {
7121
- directories.push(path6.join(home, ".config", "opencode", name));
7297
+ directories.push(path7.join(home, ".config", "opencode", name));
7122
7298
  }
7123
7299
  }
7124
7300
  return directories;
@@ -7286,7 +7462,9 @@ var PLUGIN_NOTE_MARKERS = [
7286
7462
  SILENT_TURN_MARKER,
7287
7463
  FAILOVER_MARKER,
7288
7464
  ACCOUNT_BLOCK_MARKER,
7289
- MODEL_FALLBACK_MARKER
7465
+ MODEL_FALLBACK_MARKER,
7466
+ UNATTENDED_REPLAY_MARKER,
7467
+ STALE_BUILD_MARKER
7290
7468
  ];
7291
7469
  function isPluginNote(part) {
7292
7470
  if (!part || part.type !== "text" || typeof part.text !== "string") return false;
@@ -7673,14 +7851,14 @@ Now continuing with the current message:
7673
7851
 
7674
7852
  // src/skill-bridge.ts
7675
7853
  import * as crypto3 from "crypto";
7676
- import * as fs5 from "fs";
7854
+ import * as fs6 from "fs";
7677
7855
  import * as os3 from "os";
7678
- import * as path7 from "path";
7679
- import { fileURLToPath as fileURLToPath2 } from "url";
7856
+ import * as path8 from "path";
7857
+ import { fileURLToPath as fileURLToPath3 } from "url";
7680
7858
  function bundledSkillsDir() {
7681
7859
  try {
7682
- const here = fileURLToPath2(import.meta.url);
7683
- const dir = path7.resolve(path7.dirname(here), "..", "skills");
7860
+ const here = fileURLToPath3(import.meta.url);
7861
+ const dir = path8.resolve(path8.dirname(here), "..", "skills");
7684
7862
  return dirExists2(dir) ? dir : null;
7685
7863
  } catch {
7686
7864
  return null;
@@ -7688,16 +7866,16 @@ function bundledSkillsDir() {
7688
7866
  }
7689
7867
  function dirExists2(p) {
7690
7868
  try {
7691
- return fs5.statSync(p).isDirectory();
7869
+ return fs6.statSync(p).isDirectory();
7692
7870
  } catch {
7693
7871
  return false;
7694
7872
  }
7695
7873
  }
7696
7874
  function realPath(p) {
7697
7875
  try {
7698
- return fs5.realpathSync(p);
7876
+ return fs6.realpathSync(p);
7699
7877
  } catch {
7700
- return path7.resolve(p);
7878
+ return path8.resolve(p);
7701
7879
  }
7702
7880
  }
7703
7881
  function envEnabled(name) {
@@ -7718,10 +7896,10 @@ function declaredSkillName(source) {
7718
7896
  return SAFE_SKILL_NAME.test(name) ? name : null;
7719
7897
  }
7720
7898
  function readSkill(root, entry) {
7721
- const dir = path7.join(root, entry);
7899
+ const dir = path8.join(root, entry);
7722
7900
  let source;
7723
7901
  try {
7724
- source = fs5.readFileSync(path7.join(dir, "SKILL.md"), "utf8");
7902
+ source = fs6.readFileSync(path8.join(dir, "SKILL.md"), "utf8");
7725
7903
  } catch {
7726
7904
  return null;
7727
7905
  }
@@ -7739,47 +7917,47 @@ function skillRoots(cwd) {
7739
7917
  const roots = [];
7740
7918
  const seen = /* @__PURE__ */ new Set();
7741
7919
  const push = (p) => {
7742
- const abs = path7.resolve(p);
7920
+ const abs = path8.resolve(p);
7743
7921
  if (seen.has(abs)) return;
7744
7922
  seen.add(abs);
7745
7923
  if (dirExists2(abs)) roots.push(abs);
7746
7924
  };
7747
7925
  const home = os3.homedir();
7748
- const homeDir = home ? path7.resolve(home) : null;
7749
- let current = path7.resolve(cwd);
7926
+ const homeDir = home ? path8.resolve(home) : null;
7927
+ let current = path8.resolve(cwd);
7750
7928
  while (true) {
7751
- push(path7.join(current, ".opencode", "skills"));
7929
+ push(path8.join(current, ".opencode", "skills"));
7752
7930
  if (current !== homeDir) {
7753
- push(path7.join(current, ".claude", "skills"));
7754
- push(path7.join(current, ".agents", "skills"));
7931
+ push(path8.join(current, ".claude", "skills"));
7932
+ push(path8.join(current, ".agents", "skills"));
7755
7933
  }
7756
- const parent = path7.dirname(current);
7934
+ const parent = path8.dirname(current);
7757
7935
  if (parent === current) break;
7758
7936
  current = parent;
7759
7937
  }
7760
- if (homeDir) push(path7.join(homeDir, ".opencode", "skills"));
7938
+ if (homeDir) push(path8.join(homeDir, ".opencode", "skills"));
7761
7939
  const envDir = process.env.OPENCODE_CONFIG_DIR;
7762
7940
  if (envDir) {
7763
- push(path7.join(envDir, "skills"));
7764
- push(path7.join(envDir, "skill"));
7941
+ push(path8.join(envDir, "skills"));
7942
+ push(path8.join(envDir, "skill"));
7765
7943
  }
7766
- const xdg = process.env.XDG_CONFIG_HOME ?? (homeDir ? path7.join(homeDir, ".config") : null);
7944
+ const xdg = process.env.XDG_CONFIG_HOME ?? (homeDir ? path8.join(homeDir, ".config") : null);
7767
7945
  if (xdg) {
7768
- push(path7.join(xdg, "opencode", "skills"));
7769
- push(path7.join(xdg, "opencode", "skill"));
7946
+ push(path8.join(xdg, "opencode", "skills"));
7947
+ push(path8.join(xdg, "opencode", "skill"));
7770
7948
  }
7771
7949
  if (homeDir && !envEnabled("OPENCODE_DISABLE_EXTERNAL_SKILLS")) {
7772
7950
  if (!envEnabled("OPENCODE_DISABLE_CLAUDE_CODE_SKILLS")) {
7773
- push(path7.join(homeDir, ".claude", "skills"));
7951
+ push(path8.join(homeDir, ".claude", "skills"));
7774
7952
  }
7775
- push(path7.join(homeDir, ".agents", "skills"));
7953
+ push(path8.join(homeDir, ".agents", "skills"));
7776
7954
  }
7777
7955
  return roots;
7778
7956
  }
7779
7957
  function collectSkills(root, claimed, found) {
7780
7958
  let entries;
7781
7959
  try {
7782
- entries = fs5.readdirSync(root, { withFileTypes: true });
7960
+ entries = fs6.readdirSync(root, { withFileTypes: true });
7783
7961
  } catch {
7784
7962
  return;
7785
7963
  }
@@ -7819,23 +7997,23 @@ function discoverBundledSkills() {
7819
7997
  }
7820
7998
  function claudeConfigDir(configDir) {
7821
7999
  const explicit = configDir ?? process.env.CLAUDE_CONFIG_DIR;
7822
- if (explicit) return path7.resolve(expandHome(explicit));
8000
+ if (explicit) return path8.resolve(expandHome(explicit));
7823
8001
  const home = os3.homedir();
7824
- return home ? path7.resolve(home, ".claude") : null;
8002
+ return home ? path8.resolve(home, ".claude") : null;
7825
8003
  }
7826
8004
  function installedPluginSkillRoots(configDir, cwd) {
7827
8005
  if (!configDir) return [];
7828
8006
  let parsed;
7829
8007
  try {
7830
8008
  parsed = JSON.parse(
7831
- fs5.readFileSync(path7.join(configDir, "plugins", "installed_plugins.json"), "utf8")
8009
+ fs6.readFileSync(path8.join(configDir, "plugins", "installed_plugins.json"), "utf8")
7832
8010
  );
7833
8011
  } catch {
7834
8012
  return [];
7835
8013
  }
7836
8014
  const plugins = parsed?.plugins;
7837
8015
  if (!plugins || typeof plugins !== "object") return [];
7838
- const workspace = path7.resolve(cwd);
8016
+ const workspace = path8.resolve(cwd);
7839
8017
  const roots = [];
7840
8018
  for (const installs of Object.values(plugins)) {
7841
8019
  if (!Array.isArray(installs)) continue;
@@ -7843,28 +8021,28 @@ function installedPluginSkillRoots(configDir, cwd) {
7843
8021
  const entry = install;
7844
8022
  if (typeof entry?.installPath !== "string" || !entry.installPath) continue;
7845
8023
  if (entry.scope !== "user" && !coversWorkspace(entry.projectPath, workspace)) continue;
7846
- roots.push(path7.join(entry.installPath, "skills"));
8024
+ roots.push(path8.join(entry.installPath, "skills"));
7847
8025
  }
7848
8026
  }
7849
8027
  return roots;
7850
8028
  }
7851
8029
  function coversWorkspace(projectPath, workspace) {
7852
8030
  if (typeof projectPath !== "string" || !projectPath) return false;
7853
- const root = path7.resolve(projectPath);
8031
+ const root = path8.resolve(projectPath);
7854
8032
  if (root === workspace) return true;
7855
- const rel = path7.relative(root, workspace);
7856
- return rel !== "" && !rel.startsWith("..") && !path7.isAbsolute(rel);
8033
+ const rel = path8.relative(root, workspace);
8034
+ return rel !== "" && !rel.startsWith("..") && !path8.isAbsolute(rel);
7857
8035
  }
7858
8036
  function discoverNativeClaudeSkills(opts) {
7859
8037
  const found = [];
7860
8038
  const scanned = /* @__PURE__ */ new Set();
7861
8039
  const scan = (root, scope) => {
7862
- const abs = path7.resolve(root);
8040
+ const abs = path8.resolve(root);
7863
8041
  if (scanned.has(abs)) return;
7864
8042
  scanned.add(abs);
7865
8043
  let entries;
7866
8044
  try {
7867
- entries = fs5.readdirSync(abs, { withFileTypes: true });
8045
+ entries = fs6.readdirSync(abs, { withFileTypes: true });
7868
8046
  } catch {
7869
8047
  return;
7870
8048
  }
@@ -7876,13 +8054,13 @@ function discoverNativeClaudeSkills(opts) {
7876
8054
  }
7877
8055
  };
7878
8056
  const configDir = claudeConfigDir(opts.configDir);
7879
- if (configDir) scan(path7.join(configDir, "skills"), "user");
8057
+ if (configDir) scan(path8.join(configDir, "skills"), "user");
7880
8058
  const home = os3.homedir();
7881
- const homeDir = home ? path7.resolve(home) : null;
7882
- let current = path7.resolve(opts.cwd);
8059
+ const homeDir = home ? path8.resolve(home) : null;
8060
+ let current = path8.resolve(opts.cwd);
7883
8061
  while (true) {
7884
- if (current !== homeDir) scan(path7.join(current, ".claude", "skills"), "project");
7885
- const parent = path7.dirname(current);
8062
+ if (current !== homeDir) scan(path8.join(current, ".claude", "skills"), "project");
8063
+ const parent = path8.dirname(current);
7886
8064
  if (parent === current) break;
7887
8065
  current = parent;
7888
8066
  }
@@ -7916,10 +8094,10 @@ function dropNativelyLoadedSkills(skills, native) {
7916
8094
  }
7917
8095
  function readBundledSkillInfos() {
7918
8096
  return discoverBundledSkills().flatMap((skill) => {
7919
- const file = path7.join(skill.dir, "SKILL.md");
8097
+ const file = path8.join(skill.dir, "SKILL.md");
7920
8098
  let text;
7921
8099
  try {
7922
- text = fs5.readFileSync(file, "utf8");
8100
+ text = fs6.readFileSync(file, "utf8");
7923
8101
  } catch {
7924
8102
  return [];
7925
8103
  }
@@ -7943,15 +8121,15 @@ function readBundledSkillInfos() {
7943
8121
  }
7944
8122
  function linkSkill(source, target) {
7945
8123
  try {
7946
- fs5.symlinkSync(source, target, process.platform === "win32" ? "junction" : "dir");
8124
+ fs6.symlinkSync(source, target, process.platform === "win32" ? "junction" : "dir");
7947
8125
  return;
7948
8126
  } catch {
7949
- fs5.cpSync(source, target, { recursive: true, dereference: true });
8127
+ fs6.cpSync(source, target, { recursive: true, dereference: true });
7950
8128
  }
7951
8129
  }
7952
8130
  function fileExists2(p) {
7953
8131
  try {
7954
- return fs5.statSync(p).isFile();
8132
+ return fs6.statSync(p).isFile();
7955
8133
  } catch {
7956
8134
  return false;
7957
8135
  }
@@ -7960,14 +8138,14 @@ function buildSkillPluginDir(skills) {
7960
8138
  if (skills.length === 0) return null;
7961
8139
  const fingerprint = skills.map((s) => `${s.name}\0${s.dir}`).join("\n");
7962
8140
  const hash = crypto3.createHash("sha256").update(fingerprint).digest("hex").slice(0, 12);
7963
- const root = path7.join(pluginTmpDir(), `skills-${hash}`);
7964
- const manifest = path7.join(root, ".claude-plugin", "plugin.json");
8141
+ const root = path8.join(pluginTmpDir(), `skills-${hash}`);
8142
+ const manifest = path8.join(root, ".claude-plugin", "plugin.json");
7965
8143
  if (fileExists2(manifest)) return root;
7966
8144
  try {
7967
- fs5.rmSync(root, { recursive: true, force: true });
7968
- fs5.mkdirSync(path7.join(root, ".claude-plugin"), { recursive: true });
7969
- fs5.mkdirSync(path7.join(root, "skills"), { recursive: true });
7970
- fs5.writeFileSync(
8145
+ fs6.rmSync(root, { recursive: true, force: true });
8146
+ fs6.mkdirSync(path8.join(root, ".claude-plugin"), { recursive: true });
8147
+ fs6.mkdirSync(path8.join(root, "skills"), { recursive: true });
8148
+ fs6.writeFileSync(
7971
8149
  manifest,
7972
8150
  JSON.stringify(
7973
8151
  {
@@ -7980,7 +8158,7 @@ function buildSkillPluginDir(skills) {
7980
8158
  { encoding: "utf8", mode: 384 }
7981
8159
  );
7982
8160
  for (const skill of skills) {
7983
- linkSkill(skill.dir, path7.join(root, "skills", skill.name));
8161
+ linkSkill(skill.dir, path8.join(root, "skills", skill.name));
7984
8162
  }
7985
8163
  } catch (err) {
7986
8164
  log.warn("failed to stage opencode skill plugin dir", {
@@ -7996,7 +8174,7 @@ function registerBundledSkillPath(config) {
7996
8174
  if (!dir) return false;
7997
8175
  config.skills ??= {};
7998
8176
  const paths = config.skills.paths ??= [];
7999
- if (paths.some((p) => path7.resolve(p) === dir)) return false;
8177
+ if (paths.some((p) => path8.resolve(p) === dir)) return false;
8000
8178
  paths.push(dir);
8001
8179
  return true;
8002
8180
  }
@@ -8047,12 +8225,12 @@ import { unlink as unlink2 } from "fs/promises";
8047
8225
 
8048
8226
  // src/claude-session-bun.ts
8049
8227
  import * as os4 from "os";
8050
- import * as fs6 from "fs";
8051
- import * as path8 from "path";
8228
+ import * as fs7 from "fs";
8229
+ import * as path9 from "path";
8052
8230
  import { execFileSync } from "child_process";
8053
8231
  import { randomUUID as randomUUID4 } from "crypto";
8054
8232
  function resolveClaude(cmd = "claude") {
8055
- if (path8.isAbsolute(cmd) && fs6.existsSync(cmd)) return cmd;
8233
+ if (path9.isAbsolute(cmd) && fs7.existsSync(cmd)) return cmd;
8056
8234
  const viaBun = Bun.which(cmd);
8057
8235
  if (viaBun) return viaBun;
8058
8236
  const isWin = os4.platform() === "win32";
@@ -8061,17 +8239,17 @@ function resolveClaude(cmd = "claude") {
8061
8239
  encoding: "utf8",
8062
8240
  stdio: ["ignore", "pipe", "ignore"]
8063
8241
  });
8064
- const first = out.split(/\r?\n/).map((l) => l.trim()).filter(Boolean).find((p) => fs6.existsSync(p));
8242
+ const first = out.split(/\r?\n/).map((l) => l.trim()).filter(Boolean).find((p) => fs7.existsSync(p));
8065
8243
  if (first) return first;
8066
8244
  } catch {
8067
8245
  }
8068
8246
  throw new Error(`Could not resolve command on PATH: ${cmd}`);
8069
8247
  }
8070
8248
  function encodeCwd(cwd) {
8071
- const resolved = path8.resolve(cwd);
8249
+ const resolved = path9.resolve(cwd);
8072
8250
  let real = resolved;
8073
8251
  try {
8074
- real = fs6.realpathSync.native(resolved);
8252
+ real = fs7.realpathSync.native(resolved);
8075
8253
  } catch {
8076
8254
  }
8077
8255
  return real.replace(/[^a-zA-Z0-9]/g, "-");
@@ -8156,12 +8334,12 @@ var TERMINAL_STOP = /* @__PURE__ */ new Set(["end_turn", "stop_sequence", "max_t
8156
8334
  var delay = (ms) => new Promise((r) => setTimeout(r, ms));
8157
8335
  function resolveConfigDir(configDir) {
8158
8336
  const value = configDir ?? process.env.CLAUDE_CONFIG_DIR;
8159
- if (!value) return path8.join(os4.homedir(), ".claude");
8337
+ if (!value) return path9.join(os4.homedir(), ".claude");
8160
8338
  if (value === "~") return os4.homedir();
8161
8339
  if (value.startsWith("~/") || value.startsWith("~\\")) {
8162
- return path8.join(os4.homedir(), value.slice(2));
8340
+ return path9.join(os4.homedir(), value.slice(2));
8163
8341
  }
8164
- return path8.resolve(value);
8342
+ return path9.resolve(value);
8165
8343
  }
8166
8344
  var ClaudeSession = class {
8167
8345
  sessionId;
@@ -8179,11 +8357,11 @@ var ClaudeSession = class {
8179
8357
  signal;
8180
8358
  o;
8181
8359
  constructor(opts = {}) {
8182
- this.cwd = path8.resolve(opts.cwd ?? process.cwd());
8360
+ this.cwd = path9.resolve(opts.cwd ?? process.cwd());
8183
8361
  this.configDir = resolveConfigDir(opts.configDir);
8184
8362
  this.signal = opts.signal;
8185
8363
  this.sessionId = randomUUID4();
8186
- this.jsonlPath = path8.join(
8364
+ this.jsonlPath = path9.join(
8187
8365
  this.configDir,
8188
8366
  "projects",
8189
8367
  encodeCwd(this.cwd),
@@ -8306,7 +8484,7 @@ var ClaudeSession = class {
8306
8484
  }
8307
8485
  readRawLines() {
8308
8486
  try {
8309
- return fs6.readFileSync(this.jsonlPath, "utf8").split("\n");
8487
+ return fs7.readFileSync(this.jsonlPath, "utf8").split("\n");
8310
8488
  } catch {
8311
8489
  return [];
8312
8490
  }
@@ -8703,13 +8881,13 @@ function spawnInteractiveProcess(opts) {
8703
8881
  }
8704
8882
 
8705
8883
  // src/prompts.ts
8706
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
8884
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
8707
8885
  import { homedir as homedir7 } from "os";
8708
8886
  import { randomUUID as randomUUID5 } from "crypto";
8709
- import { dirname as dirname5, join as join8 } from "path";
8710
- function readPromptFileIfPresent(path10) {
8887
+ import { dirname as dirname6, join as join9 } from "path";
8888
+ function readPromptFileIfPresent(path11) {
8711
8889
  try {
8712
- const content = readFileSync5(path10, "utf8").trim();
8890
+ const content = readFileSync6(path11, "utf8").trim();
8713
8891
  return content || void 0;
8714
8892
  } catch {
8715
8893
  return void 0;
@@ -8718,9 +8896,9 @@ function readPromptFileIfPresent(path10) {
8718
8896
  function nearestWorkspaceAgentsPrompt(cwd) {
8719
8897
  let dir = cwd;
8720
8898
  while (true) {
8721
- const content = readPromptFileIfPresent(join8(dir, "AGENTS.md"));
8899
+ const content = readPromptFileIfPresent(join9(dir, "AGENTS.md"));
8722
8900
  if (content) return content;
8723
- const parent = dirname5(dir);
8901
+ const parent = dirname6(dir);
8724
8902
  if (parent === dir) return void 0;
8725
8903
  dir = parent;
8726
8904
  }
@@ -8827,8 +9005,8 @@ ${options.compressionSummary.trim()}`
8827
9005
  for (const s of extraSystemContent) {
8828
9006
  if (s.trim()) parts.push(s.trim());
8829
9007
  }
8830
- const configRoot = process.env.XDG_CONFIG_HOME ?? join8(homedir7(), ".config");
8831
- const globalAgents = readPromptFileIfPresent(join8(configRoot, "opencode", "AGENTS.md"));
9008
+ const configRoot = process.env.XDG_CONFIG_HOME ?? join9(homedir7(), ".config");
9009
+ const globalAgents = readPromptFileIfPresent(join9(configRoot, "opencode", "AGENTS.md"));
8832
9010
  const workspaceAgents = nearestWorkspaceAgentsPrompt(cwd);
8833
9011
  const forwarded = extraSystemContent.join("\n\n");
8834
9012
  const pushGlobal = !!globalAgents && !forwarded.includes(globalAgents);
@@ -8839,10 +9017,10 @@ ${options.compressionSummary.trim()}`
8839
9017
  if (includeMultiStepHint) parts.push(MULTI_STEP_TASK_HINT);
8840
9018
  const content = parts.join("\n\n");
8841
9019
  if (!content) return void 0;
8842
- const path10 = join8(pluginTmpDir(), `opencode-cc-sys-${randomUUID5()}.md`);
9020
+ const path11 = join9(pluginTmpDir(), `opencode-cc-sys-${randomUUID5()}.md`);
8843
9021
  try {
8844
- writeFileSync4(path10, content, { encoding: "utf8", mode: 384 });
8845
- return path10;
9022
+ writeFileSync4(path11, content, { encoding: "utf8", mode: 384 });
9023
+ return path11;
8846
9024
  } catch (err) {
8847
9025
  log.warn("failed to write system prompt file", { error: String(err) });
8848
9026
  return void 0;
@@ -9688,6 +9866,8 @@ function createTurnState(init) {
9688
9866
  toolCallMap: /* @__PURE__ */ new Map(),
9689
9867
  skipResultForIds: /* @__PURE__ */ new Set(),
9690
9868
  toolCallsById: /* @__PURE__ */ new Map(),
9869
+ toolCallEmittedIds: /* @__PURE__ */ new Set(),
9870
+ toolCallAnsweredIds: /* @__PURE__ */ new Set(),
9691
9871
  resultMeta: {},
9692
9872
  lastCallUsage: void 0,
9693
9873
  resultFailure: void 0,
@@ -9704,6 +9884,23 @@ function createTurnState(init) {
9704
9884
  };
9705
9885
  return state;
9706
9886
  }
9887
+ function cliToolCallInputJson(state, id) {
9888
+ for (const entry of state.toolCallMap.values()) {
9889
+ if (entry.id === id) return entry.inputJson || "{}";
9890
+ }
9891
+ return "{}";
9892
+ }
9893
+ function emitCliToolCall(state, id, name, inputJson, executed) {
9894
+ if (state.toolCallEmittedIds.has(id)) return;
9895
+ state.toolCallEmittedIds.add(id);
9896
+ state.controller.enqueue({
9897
+ type: "tool-call",
9898
+ toolCallId: id,
9899
+ toolName: name,
9900
+ input: inputJson,
9901
+ providerExecuted: executed
9902
+ });
9903
+ }
9707
9904
 
9708
9905
  // src/turn-abort.ts
9709
9906
  function watchTurnAbort(signal) {
@@ -10113,9 +10310,46 @@ function deliverPendingCompletions(state, force = false) {
10113
10310
  armStartWatchdog(state);
10114
10311
  return true;
10115
10312
  }
10313
+ var CLI_RESULT_DEFERRED_OUTPUT = "Claude Code ran this tool itself and kept its output in its own context. This step ended on a tool call opencode has to run, so the output was not available to show here.";
10314
+ function closeDeferredCliToolResults(state) {
10315
+ const answer = (id, name, stage) => {
10316
+ emitCliToolCall(state, id, name, cliToolCallInputJson(state, id), true);
10317
+ state.controller.enqueue({
10318
+ type: "tool-result",
10319
+ toolCallId: id,
10320
+ toolName: name,
10321
+ result: {
10322
+ output: CLI_RESULT_DEFERRED_OUTPUT,
10323
+ title: name,
10324
+ metadata: {}
10325
+ },
10326
+ providerExecuted: true
10327
+ });
10328
+ state.toolCallsById.delete(id);
10329
+ state.toolCallAnsweredIds.add(id);
10330
+ log.info("closing a CLI-executed tool call whose result this step cannot wait for", {
10331
+ sessionKey: state.sessionKey,
10332
+ toolUseId: id,
10333
+ name,
10334
+ stage
10335
+ });
10336
+ };
10337
+ for (const [id, toolCall] of [...state.toolCallsById]) {
10338
+ if (state.skipResultForIds.has(id)) continue;
10339
+ answer(id, toolCall.name, "registered");
10340
+ }
10341
+ for (const entry of state.toolCallMap.values()) {
10342
+ if (!entry.started || !entry.mappedName) continue;
10343
+ if (state.skipResultForIds.has(entry.id)) continue;
10344
+ if (state.toolCallAnsweredIds.has(entry.id)) continue;
10345
+ if (state.toolCallEmittedIds.has(entry.id)) continue;
10346
+ answer(entry.id, entry.mappedName, "open-block");
10347
+ }
10348
+ }
10116
10349
  function finishWithToolCalls(state, calls) {
10117
10350
  if (state.controllerClosed) return;
10118
10351
  if (calls.length === 0) return;
10352
+ closeDeferredCliToolResults(state);
10119
10353
  const enqueueToolCall = (toolCallId, toolName, input) => {
10120
10354
  state.controller.enqueue({
10121
10355
  type: "tool-input-start",
@@ -10321,6 +10555,26 @@ var KNOWN_DELTA_TYPES = /* @__PURE__ */ new Set([
10321
10555
  "signature_delta"
10322
10556
  ]);
10323
10557
  var PROXY_RESULT_BOUNDARY_GRACE_MS = 250;
10558
+ function adoptOpenCliToolCall(state, ctx, id) {
10559
+ for (const entry of state.toolCallMap.values()) {
10560
+ if (entry.id !== id || !entry.started || !entry.mappedName) continue;
10561
+ let parsedInput = {};
10562
+ try {
10563
+ parsedInput = JSON.parse(entry.inputJson || "{}");
10564
+ } catch {
10565
+ }
10566
+ const { input: mappedInput, executed } = mapTool(entry.name, parsedInput, {
10567
+ webSearch: ctx.config.webSearch,
10568
+ sessionId: getClaudeSessionId(state.sessionKey),
10569
+ toolUseId: entry.id
10570
+ });
10571
+ const registration = { id: entry.id, name: entry.mappedName, input: parsedInput };
10572
+ state.toolCallsById.set(entry.id, registration);
10573
+ emitCliToolCall(state, entry.id, entry.mappedName, JSON.stringify(mappedInput), executed);
10574
+ return registration;
10575
+ }
10576
+ return void 0;
10577
+ }
10324
10578
  function createLineHandler(state, ctx) {
10325
10579
  return (line) => {
10326
10580
  if (!line.trim()) return;
@@ -10449,6 +10703,7 @@ function createLineHandler(state, ctx) {
10449
10703
  );
10450
10704
  if (!skip) {
10451
10705
  entry.started = true;
10706
+ entry.mappedName = mappedName;
10452
10707
  state.controller.enqueue({
10453
10708
  type: "tool-input-start",
10454
10709
  id: block2.id,
@@ -10606,20 +10861,14 @@ ${plan}
10606
10861
  sessionId: getClaudeSessionId(state.sessionKey),
10607
10862
  toolUseId: tc.id
10608
10863
  });
10609
- if (!skip) {
10864
+ if (!skip && !state.toolCallAnsweredIds.has(tc.id)) {
10610
10865
  state.toolCallsById.set(tc.id, {
10611
10866
  id: tc.id,
10612
10867
  name: mappedName,
10613
10868
  input: parsedInput
10614
10869
  });
10615
10870
  if (!executed) state.skipResultForIds.add(tc.id);
10616
- state.controller.enqueue({
10617
- type: "tool-call",
10618
- toolCallId: tc.id,
10619
- toolName: mappedName,
10620
- input: JSON.stringify(mappedInput),
10621
- providerExecuted: executed
10622
- });
10871
+ emitCliToolCall(state, tc.id, mappedName, JSON.stringify(mappedInput), executed);
10623
10872
  }
10624
10873
  log.info("tool call complete", {
10625
10874
  name: tc.name,
@@ -10805,13 +11054,7 @@ ${plan}
10805
11054
  toolName: mappedName,
10806
11055
  providerExecuted: executed
10807
11056
  });
10808
- state.controller.enqueue({
10809
- type: "tool-call",
10810
- toolCallId: block2.id,
10811
- toolName: mappedName,
10812
- input: JSON.stringify(mappedInput),
10813
- providerExecuted: executed
10814
- });
11057
+ emitCliToolCall(state, block2.id, mappedName, JSON.stringify(mappedInput), executed);
10815
11058
  }
10816
11059
  log.info("tool_use from assistant message", {
10817
11060
  name: block2.name,
@@ -10877,7 +11120,7 @@ ${plan}
10877
11120
  noteToolActivity(state);
10878
11121
  }
10879
11122
  }
10880
- const toolCall = state.toolCallsById.get(block2.tool_use_id);
11123
+ const toolCall = state.toolCallsById.get(block2.tool_use_id) ?? adoptOpenCliToolCall(state, ctx, block2.tool_use_id);
10881
11124
  if (toolCall) {
10882
11125
  const isError = block2.is_error === true;
10883
11126
  state.controller.enqueue({
@@ -10899,6 +11142,7 @@ ${plan}
10899
11142
  isError
10900
11143
  });
10901
11144
  state.toolCallsById.delete(block2.tool_use_id);
11145
+ state.toolCallAnsweredIds.add(block2.tool_use_id);
10902
11146
  }
10903
11147
  }
10904
11148
  }
@@ -11829,6 +12073,11 @@ var ClaudeCodeLanguageModel = class {
11829
12073
  // the operator is usually not even looking at.
11830
12074
  childSession: !!await fetchSessionParentId(affinity)
11831
12075
  });
12076
+ let staleBuild = null;
12077
+ if (!compactionMode && mode !== "generate" && affinity !== "default") {
12078
+ staleBuild = staleBuildWatch().check();
12079
+ if (staleBuild && await fetchSessionParentId(affinity)) staleBuild = null;
12080
+ }
11832
12081
  log.info("doStream starting", {
11833
12082
  cwd,
11834
12083
  model: effectiveModelId,
@@ -12289,6 +12538,14 @@ var ClaudeCodeLanguageModel = class {
12289
12538
  if (stoppedBeforeWork()) return;
12290
12539
  state.streamStarted = true;
12291
12540
  controller.enqueue({ type: "stream-start", warnings });
12541
+ if (staleBuild && staleBuildWatch().claimSession(affinity)) {
12542
+ controller.enqueue({
12543
+ type: "text-delta",
12544
+ id: state.startTextBlock(),
12545
+ delta: formatStaleBuildNote(staleBuild)
12546
+ });
12547
+ state.endTextBlock();
12548
+ }
12292
12549
  if (failoverNote) {
12293
12550
  controller.enqueue({
12294
12551
  type: "text-delta",
@@ -12561,16 +12818,12 @@ var ClaudeCodeLanguageModel = class {
12561
12818
  });
12562
12819
  let partialText = false;
12563
12820
  {
12564
- if (unattended.dropped > 0) {
12565
- const id = state.startTextBlock();
12566
- controller.enqueue({
12567
- type: "text-delta",
12568
- id,
12569
- delta: `> _${unattended.dropped} lines of output emitted between turns were dropped._
12570
-
12571
- `
12572
- });
12573
- }
12821
+ const replayId = state.startTextBlock();
12822
+ controller.enqueue({
12823
+ type: "text-delta",
12824
+ id: replayId,
12825
+ delta: formatUnattendedReplayNote(unattended.dropped)
12826
+ });
12574
12827
  for (const line of unattended.lines) {
12575
12828
  try {
12576
12829
  const outer = JSON.parse(line);
@@ -12740,34 +12993,34 @@ var ClaudeCodeLanguageModel = class {
12740
12993
  import {
12741
12994
  existsSync as existsSync3,
12742
12995
  mkdirSync as mkdirSync4,
12743
- readFileSync as readFileSync6,
12996
+ readFileSync as readFileSync7,
12744
12997
  realpathSync as realpathSync4,
12745
12998
  rmSync as rmSync3,
12746
12999
  writeFileSync as writeFileSync5
12747
13000
  } from "fs";
12748
13001
  import { homedir as homedir8 } from "os";
12749
- import { dirname as dirname6, join as join9, resolve as resolve5 } from "path";
12750
- import { fileURLToPath as fileURLToPath3 } from "url";
13002
+ import { dirname as dirname7, join as join10, resolve as resolve5 } from "path";
13003
+ import { fileURLToPath as fileURLToPath4 } from "url";
12751
13004
  var STALE_PACKAGE_NAME = "opencode-claude-code-plugin";
12752
13005
  var SUSPECT_DESCRIPTION_TOKEN = "Claude Code";
12753
13006
  var alreadyRan = false;
12754
13007
  function candidateCacheRoots() {
12755
13008
  const xdg = process.env.XDG_CACHE_HOME;
12756
13009
  return [
12757
- xdg ? join9(xdg, "opencode") : null,
12758
- join9(homedir8(), ".cache", "opencode"),
12759
- join9(homedir8(), "Library", "Caches", "opencode")
13010
+ xdg ? join10(xdg, "opencode") : null,
13011
+ join10(homedir8(), ".cache", "opencode"),
13012
+ join10(homedir8(), "Library", "Caches", "opencode")
12760
13013
  ].filter((p) => Boolean(p));
12761
13014
  }
12762
13015
  function userOpencodeJsonPath() {
12763
- const xdgConfig = process.env.XDG_CONFIG_HOME ?? join9(homedir8(), ".config");
12764
- return join9(xdgConfig, "opencode", "opencode.json");
13016
+ const xdgConfig = process.env.XDG_CONFIG_HOME ?? join10(homedir8(), ".config");
13017
+ return join10(xdgConfig, "opencode", "opencode.json");
12765
13018
  }
12766
13019
  function userIntendsToUseUnscoped() {
12767
13020
  const cfg = userOpencodeJsonPath();
12768
13021
  if (!existsSync3(cfg)) return false;
12769
13022
  try {
12770
- const json = JSON.parse(readFileSync6(cfg, "utf8"));
13023
+ const json = JSON.parse(readFileSync7(cfg, "utf8"));
12771
13024
  const plugins = json.plugin;
12772
13025
  if (!Array.isArray(plugins)) return false;
12773
13026
  return plugins.some(
@@ -12779,7 +13032,7 @@ function userIntendsToUseUnscoped() {
12779
13032
  }
12780
13033
  function ourLoadedDir() {
12781
13034
  try {
12782
- const filePath = fileURLToPath3(import.meta.url);
13035
+ const filePath = fileURLToPath4(import.meta.url);
12783
13036
  return realpathSync4(resolve5(filePath, "..", ".."));
12784
13037
  } catch {
12785
13038
  return null;
@@ -12788,19 +13041,19 @@ function ourLoadedDir() {
12788
13041
  function ourVersion(dir) {
12789
13042
  if (!dir) return null;
12790
13043
  try {
12791
- const pkg = JSON.parse(readFileSync6(join9(dir, "package.json"), "utf8"));
13044
+ const pkg = JSON.parse(readFileSync7(join10(dir, "package.json"), "utf8"));
12792
13045
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
12793
13046
  } catch {
12794
13047
  return null;
12795
13048
  }
12796
13049
  }
12797
13050
  function markerPath() {
12798
- const stateRoot = process.env.XDG_STATE_HOME ?? join9(homedir8(), ".local", "state");
12799
- return join9(stateRoot, "opencode-claude-code-plugin", "cleanup-stale.json");
13051
+ const stateRoot = process.env.XDG_STATE_HOME ?? join10(homedir8(), ".local", "state");
13052
+ return join10(stateRoot, "opencode-claude-code-plugin", "cleanup-stale.json");
12800
13053
  }
12801
13054
  function markerVersion() {
12802
13055
  try {
12803
- const marker = JSON.parse(readFileSync6(markerPath(), "utf8"));
13056
+ const marker = JSON.parse(readFileSync7(markerPath(), "utf8"));
12804
13057
  return typeof marker.version === "string" ? marker.version : null;
12805
13058
  } catch {
12806
13059
  return null;
@@ -12809,7 +13062,7 @@ function markerVersion() {
12809
13062
  function writeMarker(version) {
12810
13063
  const file = markerPath();
12811
13064
  try {
12812
- mkdirSync4(dirname6(file), { recursive: true });
13065
+ mkdirSync4(dirname7(file), { recursive: true });
12813
13066
  writeFileSync5(
12814
13067
  file,
12815
13068
  JSON.stringify({ version, at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n",
@@ -12845,7 +13098,7 @@ function cleanupStaleUnscopedInstall() {
12845
13098
  }
12846
13099
  function cleanupOne(cacheRoot, ourDir) {
12847
13100
  if (!existsSync3(cacheRoot)) return;
12848
- const stalePath = join9(cacheRoot, "node_modules", STALE_PACKAGE_NAME);
13101
+ const stalePath = join10(cacheRoot, "node_modules", STALE_PACKAGE_NAME);
12849
13102
  if (!existsSync3(stalePath)) return;
12850
13103
  let realStalePath = stalePath;
12851
13104
  try {
@@ -12853,11 +13106,11 @@ function cleanupOne(cacheRoot, ourDir) {
12853
13106
  } catch {
12854
13107
  }
12855
13108
  if (ourDir && realStalePath === ourDir) return;
12856
- const pkgJsonPath = join9(stalePath, "package.json");
13109
+ const pkgJsonPath = join10(stalePath, "package.json");
12857
13110
  if (!existsSync3(pkgJsonPath)) return;
12858
13111
  let pkg = {};
12859
13112
  try {
12860
- pkg = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
13113
+ pkg = JSON.parse(readFileSync7(pkgJsonPath, "utf8"));
12861
13114
  } catch {
12862
13115
  return;
12863
13116
  }
@@ -12873,10 +13126,10 @@ function cleanupOne(cacheRoot, ourDir) {
12873
13126
  });
12874
13127
  return;
12875
13128
  }
12876
- const cachePkgJson = join9(cacheRoot, "package.json");
13129
+ const cachePkgJson = join10(cacheRoot, "package.json");
12877
13130
  if (!existsSync3(cachePkgJson)) return;
12878
13131
  try {
12879
- const cfg = JSON.parse(readFileSync6(cachePkgJson, "utf8"));
13132
+ const cfg = JSON.parse(readFileSync7(cachePkgJson, "utf8"));
12880
13133
  if (cfg?.dependencies?.[STALE_PACKAGE_NAME]) {
12881
13134
  delete cfg.dependencies[STALE_PACKAGE_NAME];
12882
13135
  writeFileSync5(cachePkgJson, JSON.stringify(cfg, null, 2) + "\n");
@@ -12890,7 +13143,7 @@ function cleanupOne(cacheRoot, ourDir) {
12890
13143
  }
12891
13144
 
12892
13145
  // src/v2-client.ts
12893
- import path9 from "path";
13146
+ import path10 from "path";
12894
13147
  function formatAgentTypeList(agents) {
12895
13148
  const lines = agents.flatMap((agent) => {
12896
13149
  if (agent.hidden === true || agent.mode === "primary") return [];
@@ -12919,7 +13172,7 @@ function toV1Session(info) {
12919
13172
  if (!info || typeof info !== "object") return void 0;
12920
13173
  const session = info;
12921
13174
  const root = session.location?.directory;
12922
- const directory = typeof root === "string" ? typeof session.subpath === "string" && session.subpath.length > 0 ? path9.resolve(root, session.subpath) : root : void 0;
13175
+ const directory = typeof root === "string" ? typeof session.subpath === "string" && session.subpath.length > 0 ? path10.resolve(root, session.subpath) : root : void 0;
12923
13176
  return { ...info, directory, parentID: session.parentID };
12924
13177
  }
12925
13178
  function toV1Messages(messages) {