oh-my-opencode 2.4.4 → 2.4.5

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
@@ -6061,6 +6061,10 @@ function createAnthropicAutoCompactHook(ctx, options) {
6061
6061
  event: eventHandler
6062
6062
  };
6063
6063
  }
6064
+ // src/hooks/preemptive-compaction/index.ts
6065
+ import { existsSync as existsSync15, readdirSync as readdirSync5 } from "fs";
6066
+ import { join as join19 } from "path";
6067
+
6064
6068
  // src/hooks/preemptive-compaction/constants.ts
6065
6069
  var DEFAULT_THRESHOLD = 0.85;
6066
6070
  var MIN_TOKENS_FOR_COMPACTION = 50000;
@@ -6072,6 +6076,19 @@ var CLAUDE_DEFAULT_CONTEXT_LIMIT = 200000;
6072
6076
  function isSupportedModel(modelID) {
6073
6077
  return CLAUDE_MODEL_PATTERN.test(modelID);
6074
6078
  }
6079
+ function getMessageDir4(sessionID) {
6080
+ if (!existsSync15(MESSAGE_STORAGE))
6081
+ return null;
6082
+ const directPath = join19(MESSAGE_STORAGE, sessionID);
6083
+ if (existsSync15(directPath))
6084
+ return directPath;
6085
+ for (const dir of readdirSync5(MESSAGE_STORAGE)) {
6086
+ const sessionPath = join19(MESSAGE_STORAGE, dir, sessionID);
6087
+ if (existsSync15(sessionPath))
6088
+ return sessionPath;
6089
+ }
6090
+ return null;
6091
+ }
6075
6092
  function createState() {
6076
6093
  return {
6077
6094
  lastCompactionTime: new Map,
@@ -6211,6 +6228,19 @@ function createPreemptiveCompactionHook(ctx, options) {
6211
6228
  if (assistants.length === 0)
6212
6229
  return;
6213
6230
  const lastAssistant = assistants[assistants.length - 1];
6231
+ if (!lastAssistant.providerID || !lastAssistant.modelID) {
6232
+ const messageDir = getMessageDir4(sessionID);
6233
+ const storedMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
6234
+ if (storedMessage?.model?.providerID && storedMessage?.model?.modelID) {
6235
+ lastAssistant.providerID = storedMessage.model.providerID;
6236
+ lastAssistant.modelID = storedMessage.model.modelID;
6237
+ log("[preemptive-compaction] using stored message model info", {
6238
+ sessionID,
6239
+ providerID: lastAssistant.providerID,
6240
+ modelID: lastAssistant.modelID
6241
+ });
6242
+ }
6243
+ }
6214
6244
  await checkAndTriggerCompaction(sessionID, lastAssistant);
6215
6245
  } catch {}
6216
6246
  }
@@ -6534,8 +6564,8 @@ function createThinkModeHook() {
6534
6564
  }
6535
6565
  // src/hooks/claude-code-hooks/config.ts
6536
6566
  import { homedir as homedir6 } from "os";
6537
- import { join as join19 } from "path";
6538
- import { existsSync as existsSync15 } from "fs";
6567
+ import { join as join20 } from "path";
6568
+ import { existsSync as existsSync16 } from "fs";
6539
6569
  function normalizeHookMatcher(raw) {
6540
6570
  return {
6541
6571
  matcher: raw.matcher ?? raw.pattern ?? "*",
@@ -6560,11 +6590,11 @@ function normalizeHooksConfig(raw) {
6560
6590
  function getClaudeSettingsPaths(customPath) {
6561
6591
  const home = homedir6();
6562
6592
  const paths = [
6563
- join19(home, ".claude", "settings.json"),
6564
- join19(process.cwd(), ".claude", "settings.json"),
6565
- join19(process.cwd(), ".claude", "settings.local.json")
6593
+ join20(home, ".claude", "settings.json"),
6594
+ join20(process.cwd(), ".claude", "settings.json"),
6595
+ join20(process.cwd(), ".claude", "settings.local.json")
6566
6596
  ];
6567
- if (customPath && existsSync15(customPath)) {
6597
+ if (customPath && existsSync16(customPath)) {
6568
6598
  paths.unshift(customPath);
6569
6599
  }
6570
6600
  return paths;
@@ -6588,7 +6618,7 @@ async function loadClaudeHooksConfig(customSettingsPath) {
6588
6618
  const paths = getClaudeSettingsPaths(customSettingsPath);
6589
6619
  let mergedConfig = {};
6590
6620
  for (const settingsPath of paths) {
6591
- if (existsSync15(settingsPath)) {
6621
+ if (existsSync16(settingsPath)) {
6592
6622
  try {
6593
6623
  const content = await Bun.file(settingsPath).text();
6594
6624
  const settings = JSON.parse(content);
@@ -6605,15 +6635,15 @@ async function loadClaudeHooksConfig(customSettingsPath) {
6605
6635
  }
6606
6636
 
6607
6637
  // src/hooks/claude-code-hooks/config-loader.ts
6608
- import { existsSync as existsSync16 } from "fs";
6638
+ import { existsSync as existsSync17 } from "fs";
6609
6639
  import { homedir as homedir7 } from "os";
6610
- import { join as join20 } from "path";
6611
- var USER_CONFIG_PATH = join20(homedir7(), ".config", "opencode", "opencode-cc-plugin.json");
6640
+ import { join as join21 } from "path";
6641
+ var USER_CONFIG_PATH = join21(homedir7(), ".config", "opencode", "opencode-cc-plugin.json");
6612
6642
  function getProjectConfigPath() {
6613
- return join20(process.cwd(), ".opencode", "opencode-cc-plugin.json");
6643
+ return join21(process.cwd(), ".opencode", "opencode-cc-plugin.json");
6614
6644
  }
6615
6645
  async function loadConfigFromPath(path4) {
6616
- if (!existsSync16(path4)) {
6646
+ if (!existsSync17(path4)) {
6617
6647
  return null;
6618
6648
  }
6619
6649
  try {
@@ -6792,16 +6822,16 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
6792
6822
  }
6793
6823
 
6794
6824
  // src/hooks/claude-code-hooks/transcript.ts
6795
- import { join as join21 } from "path";
6796
- import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync17, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5 } from "fs";
6825
+ import { join as join22 } from "path";
6826
+ import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync18, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5 } from "fs";
6797
6827
  import { homedir as homedir8, tmpdir as tmpdir5 } from "os";
6798
6828
  import { randomUUID } from "crypto";
6799
- var TRANSCRIPT_DIR = join21(homedir8(), ".claude", "transcripts");
6829
+ var TRANSCRIPT_DIR = join22(homedir8(), ".claude", "transcripts");
6800
6830
  function getTranscriptPath(sessionId) {
6801
- return join21(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
6831
+ return join22(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
6802
6832
  }
6803
6833
  function ensureTranscriptDir() {
6804
- if (!existsSync17(TRANSCRIPT_DIR)) {
6834
+ if (!existsSync18(TRANSCRIPT_DIR)) {
6805
6835
  mkdirSync6(TRANSCRIPT_DIR, { recursive: true });
6806
6836
  }
6807
6837
  }
@@ -6888,7 +6918,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
6888
6918
  }
6889
6919
  };
6890
6920
  entries.push(JSON.stringify(currentEntry));
6891
- const tempPath = join21(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6921
+ const tempPath = join22(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6892
6922
  writeFileSync6(tempPath, entries.join(`
6893
6923
  `) + `
6894
6924
  `);
@@ -6908,7 +6938,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
6908
6938
  ]
6909
6939
  }
6910
6940
  };
6911
- const tempPath = join21(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6941
+ const tempPath = join22(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6912
6942
  writeFileSync6(tempPath, JSON.stringify(currentEntry) + `
6913
6943
  `);
6914
6944
  return tempPath;
@@ -7120,11 +7150,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
7120
7150
  }
7121
7151
 
7122
7152
  // src/hooks/claude-code-hooks/todo.ts
7123
- import { join as join22 } from "path";
7153
+ import { join as join23 } from "path";
7124
7154
  import { homedir as homedir9 } from "os";
7125
- var TODO_DIR = join22(homedir9(), ".claude", "todos");
7155
+ var TODO_DIR = join23(homedir9(), ".claude", "todos");
7126
7156
  function getTodoPath(sessionId) {
7127
- return join22(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
7157
+ return join23(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
7128
7158
  }
7129
7159
 
7130
7160
  // src/hooks/claude-code-hooks/stop.ts
@@ -7462,17 +7492,17 @@ import { relative as relative3, resolve as resolve4 } from "path";
7462
7492
 
7463
7493
  // src/hooks/rules-injector/finder.ts
7464
7494
  import {
7465
- existsSync as existsSync18,
7466
- readdirSync as readdirSync5,
7495
+ existsSync as existsSync19,
7496
+ readdirSync as readdirSync6,
7467
7497
  realpathSync,
7468
7498
  statSync as statSync2
7469
7499
  } from "fs";
7470
- import { dirname as dirname4, join as join24, relative } from "path";
7500
+ import { dirname as dirname4, join as join25, relative } from "path";
7471
7501
 
7472
7502
  // src/hooks/rules-injector/constants.ts
7473
- import { join as join23 } from "path";
7474
- var OPENCODE_STORAGE6 = join23(xdgData2 ?? "", "opencode", "storage");
7475
- var RULES_INJECTOR_STORAGE = join23(OPENCODE_STORAGE6, "rules-injector");
7503
+ import { join as join24 } from "path";
7504
+ var OPENCODE_STORAGE6 = join24(xdgData2 ?? "", "opencode", "storage");
7505
+ var RULES_INJECTOR_STORAGE = join24(OPENCODE_STORAGE6, "rules-injector");
7476
7506
  var PROJECT_MARKERS = [
7477
7507
  ".git",
7478
7508
  "pyproject.toml",
@@ -7499,8 +7529,8 @@ function findProjectRoot(startPath) {
7499
7529
  }
7500
7530
  while (true) {
7501
7531
  for (const marker of PROJECT_MARKERS) {
7502
- const markerPath = join24(current, marker);
7503
- if (existsSync18(markerPath)) {
7532
+ const markerPath = join25(current, marker);
7533
+ if (existsSync19(markerPath)) {
7504
7534
  return current;
7505
7535
  }
7506
7536
  }
@@ -7512,12 +7542,12 @@ function findProjectRoot(startPath) {
7512
7542
  }
7513
7543
  }
7514
7544
  function findRuleFilesRecursive(dir, results) {
7515
- if (!existsSync18(dir))
7545
+ if (!existsSync19(dir))
7516
7546
  return;
7517
7547
  try {
7518
- const entries = readdirSync5(dir, { withFileTypes: true });
7548
+ const entries = readdirSync6(dir, { withFileTypes: true });
7519
7549
  for (const entry of entries) {
7520
- const fullPath = join24(dir, entry.name);
7550
+ const fullPath = join25(dir, entry.name);
7521
7551
  if (entry.isDirectory()) {
7522
7552
  findRuleFilesRecursive(fullPath, results);
7523
7553
  } else if (entry.isFile()) {
@@ -7543,7 +7573,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
7543
7573
  let distance = 0;
7544
7574
  while (true) {
7545
7575
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
7546
- const ruleDir = join24(currentDir, parent, subdir);
7576
+ const ruleDir = join25(currentDir, parent, subdir);
7547
7577
  const files = [];
7548
7578
  findRuleFilesRecursive(ruleDir, files);
7549
7579
  for (const filePath of files) {
@@ -7567,7 +7597,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
7567
7597
  currentDir = parentDir;
7568
7598
  distance++;
7569
7599
  }
7570
- const userRuleDir = join24(homeDir, USER_RULE_DIR);
7600
+ const userRuleDir = join25(homeDir, USER_RULE_DIR);
7571
7601
  const userFiles = [];
7572
7602
  findRuleFilesRecursive(userRuleDir, userFiles);
7573
7603
  for (const filePath of userFiles) {
@@ -7756,19 +7786,19 @@ function mergeGlobs(existing, newValue) {
7756
7786
 
7757
7787
  // src/hooks/rules-injector/storage.ts
7758
7788
  import {
7759
- existsSync as existsSync19,
7789
+ existsSync as existsSync20,
7760
7790
  mkdirSync as mkdirSync7,
7761
7791
  readFileSync as readFileSync9,
7762
7792
  writeFileSync as writeFileSync7,
7763
7793
  unlinkSync as unlinkSync6
7764
7794
  } from "fs";
7765
- import { join as join25 } from "path";
7795
+ import { join as join26 } from "path";
7766
7796
  function getStoragePath3(sessionID) {
7767
- return join25(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
7797
+ return join26(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
7768
7798
  }
7769
7799
  function loadInjectedRules(sessionID) {
7770
7800
  const filePath = getStoragePath3(sessionID);
7771
- if (!existsSync19(filePath))
7801
+ if (!existsSync20(filePath))
7772
7802
  return { contentHashes: new Set, realPaths: new Set };
7773
7803
  try {
7774
7804
  const content = readFileSync9(filePath, "utf-8");
@@ -7782,7 +7812,7 @@ function loadInjectedRules(sessionID) {
7782
7812
  }
7783
7813
  }
7784
7814
  function saveInjectedRules(sessionID, data) {
7785
- if (!existsSync19(RULES_INJECTOR_STORAGE)) {
7815
+ if (!existsSync20(RULES_INJECTOR_STORAGE)) {
7786
7816
  mkdirSync7(RULES_INJECTOR_STORAGE, { recursive: true });
7787
7817
  }
7788
7818
  const storageData = {
@@ -7795,7 +7825,7 @@ function saveInjectedRules(sessionID, data) {
7795
7825
  }
7796
7826
  function clearInjectedRules(sessionID) {
7797
7827
  const filePath = getStoragePath3(sessionID);
7798
- if (existsSync19(filePath)) {
7828
+ if (existsSync20(filePath)) {
7799
7829
  unlinkSync6(filePath);
7800
7830
  }
7801
7831
  }
@@ -8365,18 +8395,18 @@ async function showLocalDevToast(ctx, version, isSisyphusEnabled) {
8365
8395
  }
8366
8396
  // src/hooks/agent-usage-reminder/storage.ts
8367
8397
  import {
8368
- existsSync as existsSync22,
8398
+ existsSync as existsSync23,
8369
8399
  mkdirSync as mkdirSync8,
8370
8400
  readFileSync as readFileSync13,
8371
8401
  writeFileSync as writeFileSync10,
8372
8402
  unlinkSync as unlinkSync7
8373
8403
  } from "fs";
8374
- import { join as join30 } from "path";
8404
+ import { join as join31 } from "path";
8375
8405
 
8376
8406
  // src/hooks/agent-usage-reminder/constants.ts
8377
- import { join as join29 } from "path";
8378
- var OPENCODE_STORAGE7 = join29(xdgData2 ?? "", "opencode", "storage");
8379
- var AGENT_USAGE_REMINDER_STORAGE = join29(OPENCODE_STORAGE7, "agent-usage-reminder");
8407
+ import { join as join30 } from "path";
8408
+ var OPENCODE_STORAGE7 = join30(xdgData2 ?? "", "opencode", "storage");
8409
+ var AGENT_USAGE_REMINDER_STORAGE = join30(OPENCODE_STORAGE7, "agent-usage-reminder");
8380
8410
  var TARGET_TOOLS = new Set([
8381
8411
  "grep",
8382
8412
  "safe_grep",
@@ -8421,11 +8451,11 @@ ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
8421
8451
 
8422
8452
  // src/hooks/agent-usage-reminder/storage.ts
8423
8453
  function getStoragePath4(sessionID) {
8424
- return join30(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
8454
+ return join31(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
8425
8455
  }
8426
8456
  function loadAgentUsageState(sessionID) {
8427
8457
  const filePath = getStoragePath4(sessionID);
8428
- if (!existsSync22(filePath))
8458
+ if (!existsSync23(filePath))
8429
8459
  return null;
8430
8460
  try {
8431
8461
  const content = readFileSync13(filePath, "utf-8");
@@ -8435,7 +8465,7 @@ function loadAgentUsageState(sessionID) {
8435
8465
  }
8436
8466
  }
8437
8467
  function saveAgentUsageState(state2) {
8438
- if (!existsSync22(AGENT_USAGE_REMINDER_STORAGE)) {
8468
+ if (!existsSync23(AGENT_USAGE_REMINDER_STORAGE)) {
8439
8469
  mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
8440
8470
  }
8441
8471
  const filePath = getStoragePath4(state2.sessionID);
@@ -8443,7 +8473,7 @@ function saveAgentUsageState(state2) {
8443
8473
  }
8444
8474
  function clearAgentUsageState(sessionID) {
8445
8475
  const filePath = getStoragePath4(sessionID);
8446
- if (existsSync22(filePath)) {
8476
+ if (existsSync23(filePath)) {
8447
8477
  unlinkSync7(filePath);
8448
8478
  }
8449
8479
  }
@@ -8670,18 +8700,18 @@ function createNonInteractiveEnvHook(_ctx) {
8670
8700
  }
8671
8701
  // src/hooks/interactive-bash-session/storage.ts
8672
8702
  import {
8673
- existsSync as existsSync23,
8703
+ existsSync as existsSync24,
8674
8704
  mkdirSync as mkdirSync9,
8675
8705
  readFileSync as readFileSync14,
8676
8706
  writeFileSync as writeFileSync11,
8677
8707
  unlinkSync as unlinkSync8
8678
8708
  } from "fs";
8679
- import { join as join32 } from "path";
8709
+ import { join as join33 } from "path";
8680
8710
 
8681
8711
  // src/hooks/interactive-bash-session/constants.ts
8682
- import { join as join31 } from "path";
8683
- var OPENCODE_STORAGE8 = join31(xdgData2 ?? "", "opencode", "storage");
8684
- var INTERACTIVE_BASH_SESSION_STORAGE = join31(OPENCODE_STORAGE8, "interactive-bash-session");
8712
+ import { join as join32 } from "path";
8713
+ var OPENCODE_STORAGE8 = join32(xdgData2 ?? "", "opencode", "storage");
8714
+ var INTERACTIVE_BASH_SESSION_STORAGE = join32(OPENCODE_STORAGE8, "interactive-bash-session");
8685
8715
  var OMO_SESSION_PREFIX = "omo-";
8686
8716
  function buildSessionReminderMessage(sessions) {
8687
8717
  if (sessions.length === 0)
@@ -8693,11 +8723,11 @@ function buildSessionReminderMessage(sessions) {
8693
8723
 
8694
8724
  // src/hooks/interactive-bash-session/storage.ts
8695
8725
  function getStoragePath5(sessionID) {
8696
- return join32(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
8726
+ return join33(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
8697
8727
  }
8698
8728
  function loadInteractiveBashSessionState(sessionID) {
8699
8729
  const filePath = getStoragePath5(sessionID);
8700
- if (!existsSync23(filePath))
8730
+ if (!existsSync24(filePath))
8701
8731
  return null;
8702
8732
  try {
8703
8733
  const content = readFileSync14(filePath, "utf-8");
@@ -8712,7 +8742,7 @@ function loadInteractiveBashSessionState(sessionID) {
8712
8742
  }
8713
8743
  }
8714
8744
  function saveInteractiveBashSessionState(state2) {
8715
- if (!existsSync23(INTERACTIVE_BASH_SESSION_STORAGE)) {
8745
+ if (!existsSync24(INTERACTIVE_BASH_SESSION_STORAGE)) {
8716
8746
  mkdirSync9(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
8717
8747
  }
8718
8748
  const filePath = getStoragePath5(state2.sessionID);
@@ -8725,7 +8755,7 @@ function saveInteractiveBashSessionState(state2) {
8725
8755
  }
8726
8756
  function clearInteractiveBashSessionState(sessionID) {
8727
8757
  const filePath = getStoragePath5(sessionID);
8728
- if (existsSync23(filePath)) {
8758
+ if (existsSync24(filePath)) {
8729
8759
  unlinkSync8(filePath);
8730
8760
  }
8731
8761
  }
@@ -10669,19 +10699,19 @@ async function createGoogleAntigravityAuthPlugin({
10669
10699
  };
10670
10700
  }
10671
10701
  // src/features/claude-code-command-loader/loader.ts
10672
- import { existsSync as existsSync24, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "fs";
10702
+ import { existsSync as existsSync25, readdirSync as readdirSync7, readFileSync as readFileSync15 } from "fs";
10673
10703
  import { homedir as homedir12 } from "os";
10674
- import { join as join33, basename } from "path";
10704
+ import { join as join34, basename } from "path";
10675
10705
  function loadCommandsFromDir(commandsDir, scope) {
10676
- if (!existsSync24(commandsDir)) {
10706
+ if (!existsSync25(commandsDir)) {
10677
10707
  return [];
10678
10708
  }
10679
- const entries = readdirSync6(commandsDir, { withFileTypes: true });
10709
+ const entries = readdirSync7(commandsDir, { withFileTypes: true });
10680
10710
  const commands = [];
10681
10711
  for (const entry of entries) {
10682
10712
  if (!isMarkdownFile(entry))
10683
10713
  continue;
10684
- const commandPath = join33(commandsDir, entry.name);
10714
+ const commandPath = join34(commandsDir, entry.name);
10685
10715
  const commandName = basename(entry.name, ".md");
10686
10716
  try {
10687
10717
  const content = readFileSync15(commandPath, "utf-8");
@@ -10724,44 +10754,44 @@ function commandsToRecord(commands) {
10724
10754
  return result;
10725
10755
  }
10726
10756
  function loadUserCommands() {
10727
- const userCommandsDir = join33(homedir12(), ".claude", "commands");
10757
+ const userCommandsDir = join34(homedir12(), ".claude", "commands");
10728
10758
  const commands = loadCommandsFromDir(userCommandsDir, "user");
10729
10759
  return commandsToRecord(commands);
10730
10760
  }
10731
10761
  function loadProjectCommands() {
10732
- const projectCommandsDir = join33(process.cwd(), ".claude", "commands");
10762
+ const projectCommandsDir = join34(process.cwd(), ".claude", "commands");
10733
10763
  const commands = loadCommandsFromDir(projectCommandsDir, "project");
10734
10764
  return commandsToRecord(commands);
10735
10765
  }
10736
10766
  function loadOpencodeGlobalCommands() {
10737
- const opencodeCommandsDir = join33(homedir12(), ".config", "opencode", "command");
10767
+ const opencodeCommandsDir = join34(homedir12(), ".config", "opencode", "command");
10738
10768
  const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
10739
10769
  return commandsToRecord(commands);
10740
10770
  }
10741
10771
  function loadOpencodeProjectCommands() {
10742
- const opencodeProjectDir = join33(process.cwd(), ".opencode", "command");
10772
+ const opencodeProjectDir = join34(process.cwd(), ".opencode", "command");
10743
10773
  const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
10744
10774
  return commandsToRecord(commands);
10745
10775
  }
10746
10776
  // src/features/claude-code-skill-loader/loader.ts
10747
- import { existsSync as existsSync25, readdirSync as readdirSync7, readFileSync as readFileSync16 } from "fs";
10777
+ import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync16 } from "fs";
10748
10778
  import { homedir as homedir13 } from "os";
10749
- import { join as join34 } from "path";
10779
+ import { join as join35 } from "path";
10750
10780
  function loadSkillsFromDir(skillsDir, scope) {
10751
- if (!existsSync25(skillsDir)) {
10781
+ if (!existsSync26(skillsDir)) {
10752
10782
  return [];
10753
10783
  }
10754
- const entries = readdirSync7(skillsDir, { withFileTypes: true });
10784
+ const entries = readdirSync8(skillsDir, { withFileTypes: true });
10755
10785
  const skills = [];
10756
10786
  for (const entry of entries) {
10757
10787
  if (entry.name.startsWith("."))
10758
10788
  continue;
10759
- const skillPath = join34(skillsDir, entry.name);
10789
+ const skillPath = join35(skillsDir, entry.name);
10760
10790
  if (!entry.isDirectory() && !entry.isSymbolicLink())
10761
10791
  continue;
10762
10792
  const resolvedPath = resolveSymlink(skillPath);
10763
- const skillMdPath = join34(resolvedPath, "SKILL.md");
10764
- if (!existsSync25(skillMdPath))
10793
+ const skillMdPath = join35(resolvedPath, "SKILL.md");
10794
+ if (!existsSync26(skillMdPath))
10765
10795
  continue;
10766
10796
  try {
10767
10797
  const content = readFileSync16(skillMdPath, "utf-8");
@@ -10798,7 +10828,7 @@ $ARGUMENTS
10798
10828
  return skills;
10799
10829
  }
10800
10830
  function loadUserSkillsAsCommands() {
10801
- const userSkillsDir = join34(homedir13(), ".claude", "skills");
10831
+ const userSkillsDir = join35(homedir13(), ".claude", "skills");
10802
10832
  const skills = loadSkillsFromDir(userSkillsDir, "user");
10803
10833
  return skills.reduce((acc, skill) => {
10804
10834
  acc[skill.name] = skill.definition;
@@ -10806,7 +10836,7 @@ function loadUserSkillsAsCommands() {
10806
10836
  }, {});
10807
10837
  }
10808
10838
  function loadProjectSkillsAsCommands() {
10809
- const projectSkillsDir = join34(process.cwd(), ".claude", "skills");
10839
+ const projectSkillsDir = join35(process.cwd(), ".claude", "skills");
10810
10840
  const skills = loadSkillsFromDir(projectSkillsDir, "project");
10811
10841
  return skills.reduce((acc, skill) => {
10812
10842
  acc[skill.name] = skill.definition;
@@ -10814,9 +10844,9 @@ function loadProjectSkillsAsCommands() {
10814
10844
  }, {});
10815
10845
  }
10816
10846
  // src/features/claude-code-agent-loader/loader.ts
10817
- import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync17 } from "fs";
10847
+ import { existsSync as existsSync27, readdirSync as readdirSync9, readFileSync as readFileSync17 } from "fs";
10818
10848
  import { homedir as homedir14 } from "os";
10819
- import { join as join35, basename as basename2 } from "path";
10849
+ import { join as join36, basename as basename2 } from "path";
10820
10850
  function parseToolsConfig(toolsStr) {
10821
10851
  if (!toolsStr)
10822
10852
  return;
@@ -10830,15 +10860,15 @@ function parseToolsConfig(toolsStr) {
10830
10860
  return result;
10831
10861
  }
10832
10862
  function loadAgentsFromDir(agentsDir, scope) {
10833
- if (!existsSync26(agentsDir)) {
10863
+ if (!existsSync27(agentsDir)) {
10834
10864
  return [];
10835
10865
  }
10836
- const entries = readdirSync8(agentsDir, { withFileTypes: true });
10866
+ const entries = readdirSync9(agentsDir, { withFileTypes: true });
10837
10867
  const agents = [];
10838
10868
  for (const entry of entries) {
10839
10869
  if (!isMarkdownFile(entry))
10840
10870
  continue;
10841
- const agentPath = join35(agentsDir, entry.name);
10871
+ const agentPath = join36(agentsDir, entry.name);
10842
10872
  const agentName = basename2(entry.name, ".md");
10843
10873
  try {
10844
10874
  const content = readFileSync17(agentPath, "utf-8");
@@ -10868,7 +10898,7 @@ function loadAgentsFromDir(agentsDir, scope) {
10868
10898
  return agents;
10869
10899
  }
10870
10900
  function loadUserAgents() {
10871
- const userAgentsDir = join35(homedir14(), ".claude", "agents");
10901
+ const userAgentsDir = join36(homedir14(), ".claude", "agents");
10872
10902
  const agents = loadAgentsFromDir(userAgentsDir, "user");
10873
10903
  const result = {};
10874
10904
  for (const agent of agents) {
@@ -10877,7 +10907,7 @@ function loadUserAgents() {
10877
10907
  return result;
10878
10908
  }
10879
10909
  function loadProjectAgents() {
10880
- const projectAgentsDir = join35(process.cwd(), ".claude", "agents");
10910
+ const projectAgentsDir = join36(process.cwd(), ".claude", "agents");
10881
10911
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
10882
10912
  const result = {};
10883
10913
  for (const agent of agents) {
@@ -10886,9 +10916,9 @@ function loadProjectAgents() {
10886
10916
  return result;
10887
10917
  }
10888
10918
  // src/features/claude-code-mcp-loader/loader.ts
10889
- import { existsSync as existsSync27 } from "fs";
10919
+ import { existsSync as existsSync28 } from "fs";
10890
10920
  import { homedir as homedir15 } from "os";
10891
- import { join as join36 } from "path";
10921
+ import { join as join37 } from "path";
10892
10922
 
10893
10923
  // src/features/claude-code-mcp-loader/env-expander.ts
10894
10924
  function expandEnvVars(value) {
@@ -10957,13 +10987,13 @@ function getMcpConfigPaths() {
10957
10987
  const home = homedir15();
10958
10988
  const cwd = process.cwd();
10959
10989
  return [
10960
- { path: join36(home, ".claude", ".mcp.json"), scope: "user" },
10961
- { path: join36(cwd, ".mcp.json"), scope: "project" },
10962
- { path: join36(cwd, ".claude", ".mcp.json"), scope: "local" }
10990
+ { path: join37(home, ".claude", ".mcp.json"), scope: "user" },
10991
+ { path: join37(cwd, ".mcp.json"), scope: "project" },
10992
+ { path: join37(cwd, ".claude", ".mcp.json"), scope: "local" }
10963
10993
  ];
10964
10994
  }
10965
10995
  async function loadMcpConfigFile(filePath) {
10966
- if (!existsSync27(filePath)) {
10996
+ if (!existsSync28(filePath)) {
10967
10997
  return null;
10968
10998
  }
10969
10999
  try {
@@ -11298,11 +11328,11 @@ var EXT_TO_LANG = {
11298
11328
  ".gql": "graphql"
11299
11329
  };
11300
11330
  // src/tools/lsp/config.ts
11301
- import { existsSync as existsSync28, readFileSync as readFileSync18 } from "fs";
11302
- import { join as join37 } from "path";
11331
+ import { existsSync as existsSync29, readFileSync as readFileSync18 } from "fs";
11332
+ import { join as join38 } from "path";
11303
11333
  import { homedir as homedir16 } from "os";
11304
11334
  function loadJsonFile(path7) {
11305
- if (!existsSync28(path7))
11335
+ if (!existsSync29(path7))
11306
11336
  return null;
11307
11337
  try {
11308
11338
  return JSON.parse(readFileSync18(path7, "utf-8"));
@@ -11313,9 +11343,9 @@ function loadJsonFile(path7) {
11313
11343
  function getConfigPaths2() {
11314
11344
  const cwd = process.cwd();
11315
11345
  return {
11316
- project: join37(cwd, ".opencode", "oh-my-opencode.json"),
11317
- user: join37(homedir16(), ".config", "opencode", "oh-my-opencode.json"),
11318
- opencode: join37(homedir16(), ".config", "opencode", "opencode.json")
11346
+ project: join38(cwd, ".opencode", "oh-my-opencode.json"),
11347
+ user: join38(homedir16(), ".config", "opencode", "oh-my-opencode.json"),
11348
+ opencode: join38(homedir16(), ".config", "opencode", "opencode.json")
11319
11349
  };
11320
11350
  }
11321
11351
  function loadAllConfigs() {
@@ -11411,21 +11441,21 @@ function isServerInstalled(command) {
11411
11441
  const pathSeparator = isWindows2 ? ";" : ":";
11412
11442
  const paths = pathEnv.split(pathSeparator);
11413
11443
  for (const p of paths) {
11414
- if (existsSync28(join37(p, cmd)) || existsSync28(join37(p, cmd + ext))) {
11444
+ if (existsSync29(join38(p, cmd)) || existsSync29(join38(p, cmd + ext))) {
11415
11445
  return true;
11416
11446
  }
11417
11447
  }
11418
11448
  const cwd = process.cwd();
11419
11449
  const additionalPaths = [
11420
- join37(cwd, "node_modules", ".bin", cmd),
11421
- join37(cwd, "node_modules", ".bin", cmd + ext),
11422
- join37(homedir16(), ".config", "opencode", "bin", cmd),
11423
- join37(homedir16(), ".config", "opencode", "bin", cmd + ext),
11424
- join37(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd),
11425
- join37(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd + ext)
11450
+ join38(cwd, "node_modules", ".bin", cmd),
11451
+ join38(cwd, "node_modules", ".bin", cmd + ext),
11452
+ join38(homedir16(), ".config", "opencode", "bin", cmd),
11453
+ join38(homedir16(), ".config", "opencode", "bin", cmd + ext),
11454
+ join38(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd),
11455
+ join38(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd + ext)
11426
11456
  ];
11427
11457
  for (const p of additionalPaths) {
11428
- if (existsSync28(p)) {
11458
+ if (existsSync29(p)) {
11429
11459
  return true;
11430
11460
  }
11431
11461
  }
@@ -12020,16 +12050,16 @@ ${msg}`);
12020
12050
  }
12021
12051
  // src/tools/lsp/utils.ts
12022
12052
  import { extname as extname2, resolve as resolve6 } from "path";
12023
- import { existsSync as existsSync29, readFileSync as readFileSync20, writeFileSync as writeFileSync12 } from "fs";
12053
+ import { existsSync as existsSync30, readFileSync as readFileSync20, writeFileSync as writeFileSync12 } from "fs";
12024
12054
  function findWorkspaceRoot(filePath) {
12025
12055
  let dir = resolve6(filePath);
12026
- if (!existsSync29(dir) || !__require("fs").statSync(dir).isDirectory()) {
12056
+ if (!existsSync30(dir) || !__require("fs").statSync(dir).isDirectory()) {
12027
12057
  dir = __require("path").dirname(dir);
12028
12058
  }
12029
12059
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
12030
12060
  while (dir !== "/") {
12031
12061
  for (const marker of markers) {
12032
- if (existsSync29(__require("path").join(dir, marker))) {
12062
+ if (existsSync30(__require("path").join(dir, marker))) {
12033
12063
  return dir;
12034
12064
  }
12035
12065
  }
@@ -24954,13 +24984,13 @@ var lsp_code_action_resolve = tool({
24954
24984
  });
24955
24985
  // src/tools/ast-grep/constants.ts
24956
24986
  import { createRequire as createRequire4 } from "module";
24957
- import { dirname as dirname6, join as join39 } from "path";
24958
- import { existsSync as existsSync31, statSync as statSync4 } from "fs";
24987
+ import { dirname as dirname6, join as join40 } from "path";
24988
+ import { existsSync as existsSync32, statSync as statSync4 } from "fs";
24959
24989
 
24960
24990
  // src/tools/ast-grep/downloader.ts
24961
24991
  var {spawn: spawn5 } = globalThis.Bun;
24962
- import { existsSync as existsSync30, mkdirSync as mkdirSync10, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
24963
- import { join as join38 } from "path";
24992
+ import { existsSync as existsSync31, mkdirSync as mkdirSync10, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
24993
+ import { join as join39 } from "path";
24964
24994
  import { homedir as homedir17 } from "os";
24965
24995
  import { createRequire as createRequire3 } from "module";
24966
24996
  var REPO2 = "ast-grep/ast-grep";
@@ -24986,19 +25016,19 @@ var PLATFORM_MAP2 = {
24986
25016
  function getCacheDir3() {
24987
25017
  if (process.platform === "win32") {
24988
25018
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
24989
- const base2 = localAppData || join38(homedir17(), "AppData", "Local");
24990
- return join38(base2, "oh-my-opencode", "bin");
25019
+ const base2 = localAppData || join39(homedir17(), "AppData", "Local");
25020
+ return join39(base2, "oh-my-opencode", "bin");
24991
25021
  }
24992
25022
  const xdgCache2 = process.env.XDG_CACHE_HOME;
24993
- const base = xdgCache2 || join38(homedir17(), ".cache");
24994
- return join38(base, "oh-my-opencode", "bin");
25023
+ const base = xdgCache2 || join39(homedir17(), ".cache");
25024
+ return join39(base, "oh-my-opencode", "bin");
24995
25025
  }
24996
25026
  function getBinaryName3() {
24997
25027
  return process.platform === "win32" ? "sg.exe" : "sg";
24998
25028
  }
24999
25029
  function getCachedBinaryPath2() {
25000
- const binaryPath = join38(getCacheDir3(), getBinaryName3());
25001
- return existsSync30(binaryPath) ? binaryPath : null;
25030
+ const binaryPath = join39(getCacheDir3(), getBinaryName3());
25031
+ return existsSync31(binaryPath) ? binaryPath : null;
25002
25032
  }
25003
25033
  async function extractZip2(archivePath, destDir) {
25004
25034
  const proc = process.platform === "win32" ? spawn5([
@@ -25024,8 +25054,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
25024
25054
  }
25025
25055
  const cacheDir = getCacheDir3();
25026
25056
  const binaryName = getBinaryName3();
25027
- const binaryPath = join38(cacheDir, binaryName);
25028
- if (existsSync30(binaryPath)) {
25057
+ const binaryPath = join39(cacheDir, binaryName);
25058
+ if (existsSync31(binaryPath)) {
25029
25059
  return binaryPath;
25030
25060
  }
25031
25061
  const { arch, os: os5 } = platformInfo;
@@ -25033,21 +25063,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
25033
25063
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
25034
25064
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
25035
25065
  try {
25036
- if (!existsSync30(cacheDir)) {
25066
+ if (!existsSync31(cacheDir)) {
25037
25067
  mkdirSync10(cacheDir, { recursive: true });
25038
25068
  }
25039
25069
  const response2 = await fetch(downloadUrl, { redirect: "follow" });
25040
25070
  if (!response2.ok) {
25041
25071
  throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
25042
25072
  }
25043
- const archivePath = join38(cacheDir, assetName);
25073
+ const archivePath = join39(cacheDir, assetName);
25044
25074
  const arrayBuffer = await response2.arrayBuffer();
25045
25075
  await Bun.write(archivePath, arrayBuffer);
25046
25076
  await extractZip2(archivePath, cacheDir);
25047
- if (existsSync30(archivePath)) {
25077
+ if (existsSync31(archivePath)) {
25048
25078
  unlinkSync9(archivePath);
25049
25079
  }
25050
- if (process.platform !== "win32" && existsSync30(binaryPath)) {
25080
+ if (process.platform !== "win32" && existsSync31(binaryPath)) {
25051
25081
  chmodSync2(binaryPath, 493);
25052
25082
  }
25053
25083
  console.log(`[oh-my-opencode] ast-grep binary ready.`);
@@ -25098,8 +25128,8 @@ function findSgCliPathSync() {
25098
25128
  const require2 = createRequire4(import.meta.url);
25099
25129
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
25100
25130
  const cliDir = dirname6(cliPkgPath);
25101
- const sgPath = join39(cliDir, binaryName);
25102
- if (existsSync31(sgPath) && isValidBinary(sgPath)) {
25131
+ const sgPath = join40(cliDir, binaryName);
25132
+ if (existsSync32(sgPath) && isValidBinary(sgPath)) {
25103
25133
  return sgPath;
25104
25134
  }
25105
25135
  } catch {}
@@ -25110,8 +25140,8 @@ function findSgCliPathSync() {
25110
25140
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
25111
25141
  const pkgDir = dirname6(pkgPath);
25112
25142
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
25113
- const binaryPath = join39(pkgDir, astGrepName);
25114
- if (existsSync31(binaryPath) && isValidBinary(binaryPath)) {
25143
+ const binaryPath = join40(pkgDir, astGrepName);
25144
+ if (existsSync32(binaryPath) && isValidBinary(binaryPath)) {
25115
25145
  return binaryPath;
25116
25146
  }
25117
25147
  } catch {}
@@ -25119,7 +25149,7 @@ function findSgCliPathSync() {
25119
25149
  if (process.platform === "darwin") {
25120
25150
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
25121
25151
  for (const path7 of homebrewPaths) {
25122
- if (existsSync31(path7) && isValidBinary(path7)) {
25152
+ if (existsSync32(path7) && isValidBinary(path7)) {
25123
25153
  return path7;
25124
25154
  }
25125
25155
  }
@@ -25175,11 +25205,11 @@ var DEFAULT_MAX_MATCHES = 500;
25175
25205
 
25176
25206
  // src/tools/ast-grep/cli.ts
25177
25207
  var {spawn: spawn6 } = globalThis.Bun;
25178
- import { existsSync as existsSync32 } from "fs";
25208
+ import { existsSync as existsSync33 } from "fs";
25179
25209
  var resolvedCliPath3 = null;
25180
25210
  var initPromise2 = null;
25181
25211
  async function getAstGrepPath() {
25182
- if (resolvedCliPath3 !== null && existsSync32(resolvedCliPath3)) {
25212
+ if (resolvedCliPath3 !== null && existsSync33(resolvedCliPath3)) {
25183
25213
  return resolvedCliPath3;
25184
25214
  }
25185
25215
  if (initPromise2) {
@@ -25187,7 +25217,7 @@ async function getAstGrepPath() {
25187
25217
  }
25188
25218
  initPromise2 = (async () => {
25189
25219
  const syncPath = findSgCliPathSync();
25190
- if (syncPath && existsSync32(syncPath)) {
25220
+ if (syncPath && existsSync33(syncPath)) {
25191
25221
  resolvedCliPath3 = syncPath;
25192
25222
  setSgCliPath(syncPath);
25193
25223
  return syncPath;
@@ -25221,7 +25251,7 @@ async function runSg(options) {
25221
25251
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
25222
25252
  args.push(...paths);
25223
25253
  let cliPath = getSgCliPath();
25224
- if (!existsSync32(cliPath) && cliPath !== "sg") {
25254
+ if (!existsSync33(cliPath) && cliPath !== "sg") {
25225
25255
  const downloadedPath = await getAstGrepPath();
25226
25256
  if (downloadedPath) {
25227
25257
  cliPath = downloadedPath;
@@ -25485,24 +25515,24 @@ var ast_grep_replace = tool({
25485
25515
  var {spawn: spawn7 } = globalThis.Bun;
25486
25516
 
25487
25517
  // src/tools/grep/constants.ts
25488
- import { existsSync as existsSync34 } from "fs";
25489
- import { join as join41, dirname as dirname7 } from "path";
25518
+ import { existsSync as existsSync35 } from "fs";
25519
+ import { join as join42, dirname as dirname7 } from "path";
25490
25520
  import { spawnSync } from "child_process";
25491
25521
 
25492
25522
  // src/tools/grep/downloader.ts
25493
- import { existsSync as existsSync33, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync9 } from "fs";
25494
- import { join as join40 } from "path";
25523
+ import { existsSync as existsSync34, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync10 } from "fs";
25524
+ import { join as join41 } from "path";
25495
25525
  function getInstallDir() {
25496
25526
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
25497
- return join40(homeDir, ".cache", "oh-my-opencode", "bin");
25527
+ return join41(homeDir, ".cache", "oh-my-opencode", "bin");
25498
25528
  }
25499
25529
  function getRgPath() {
25500
25530
  const isWindows2 = process.platform === "win32";
25501
- return join40(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
25531
+ return join41(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
25502
25532
  }
25503
25533
  function getInstalledRipgrepPath() {
25504
25534
  const rgPath = getRgPath();
25505
- return existsSync33(rgPath) ? rgPath : null;
25535
+ return existsSync34(rgPath) ? rgPath : null;
25506
25536
  }
25507
25537
 
25508
25538
  // src/tools/grep/constants.ts
@@ -25525,13 +25555,13 @@ function getOpenCodeBundledRg() {
25525
25555
  const isWindows2 = process.platform === "win32";
25526
25556
  const rgName = isWindows2 ? "rg.exe" : "rg";
25527
25557
  const candidates = [
25528
- join41(execDir, rgName),
25529
- join41(execDir, "bin", rgName),
25530
- join41(execDir, "..", "bin", rgName),
25531
- join41(execDir, "..", "libexec", rgName)
25558
+ join42(execDir, rgName),
25559
+ join42(execDir, "bin", rgName),
25560
+ join42(execDir, "..", "bin", rgName),
25561
+ join42(execDir, "..", "libexec", rgName)
25532
25562
  ];
25533
25563
  for (const candidate of candidates) {
25534
- if (existsSync34(candidate)) {
25564
+ if (existsSync35(candidate)) {
25535
25565
  return candidate;
25536
25566
  }
25537
25567
  }
@@ -25934,19 +25964,19 @@ var glob = tool({
25934
25964
  }
25935
25965
  });
25936
25966
  // src/tools/slashcommand/tools.ts
25937
- import { existsSync as existsSync35, readdirSync as readdirSync10, readFileSync as readFileSync21 } from "fs";
25967
+ import { existsSync as existsSync36, readdirSync as readdirSync11, readFileSync as readFileSync21 } from "fs";
25938
25968
  import { homedir as homedir18 } from "os";
25939
- import { join as join42, basename as basename3, dirname as dirname8 } from "path";
25969
+ import { join as join43, basename as basename3, dirname as dirname8 } from "path";
25940
25970
  function discoverCommandsFromDir(commandsDir, scope) {
25941
- if (!existsSync35(commandsDir)) {
25971
+ if (!existsSync36(commandsDir)) {
25942
25972
  return [];
25943
25973
  }
25944
- const entries = readdirSync10(commandsDir, { withFileTypes: true });
25974
+ const entries = readdirSync11(commandsDir, { withFileTypes: true });
25945
25975
  const commands = [];
25946
25976
  for (const entry of entries) {
25947
25977
  if (!isMarkdownFile(entry))
25948
25978
  continue;
25949
- const commandPath = join42(commandsDir, entry.name);
25979
+ const commandPath = join43(commandsDir, entry.name);
25950
25980
  const commandName = basename3(entry.name, ".md");
25951
25981
  try {
25952
25982
  const content = readFileSync21(commandPath, "utf-8");
@@ -25974,10 +26004,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
25974
26004
  return commands;
25975
26005
  }
25976
26006
  function discoverCommandsSync() {
25977
- const userCommandsDir = join42(homedir18(), ".claude", "commands");
25978
- const projectCommandsDir = join42(process.cwd(), ".claude", "commands");
25979
- const opencodeGlobalDir = join42(homedir18(), ".config", "opencode", "command");
25980
- const opencodeProjectDir = join42(process.cwd(), ".opencode", "command");
26007
+ const userCommandsDir = join43(homedir18(), ".claude", "commands");
26008
+ const projectCommandsDir = join43(process.cwd(), ".claude", "commands");
26009
+ const opencodeGlobalDir = join43(homedir18(), ".config", "opencode", "command");
26010
+ const opencodeProjectDir = join43(process.cwd(), ".opencode", "command");
25981
26011
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
25982
26012
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
25983
26013
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -26100,246 +26130,6 @@ Provide a command name to execute.`;
26100
26130
  Try a different command name.`;
26101
26131
  }
26102
26132
  });
26103
- // src/tools/skill/types.ts
26104
- var SkillFrontmatterSchema = exports_external.object({
26105
- name: exports_external.string().regex(/^[a-z0-9-]+$/, "Name must be lowercase alphanumeric with hyphens only").min(1, "Name cannot be empty"),
26106
- description: exports_external.string().min(20, "Description must be at least 20 characters for discoverability"),
26107
- license: exports_external.string().optional(),
26108
- "allowed-tools": exports_external.array(exports_external.string()).optional(),
26109
- metadata: exports_external.record(exports_external.string(), exports_external.string()).optional()
26110
- });
26111
- // src/tools/skill/tools.ts
26112
- import { existsSync as existsSync36, readdirSync as readdirSync11, readFileSync as readFileSync22 } from "fs";
26113
- import { homedir as homedir19 } from "os";
26114
- import { join as join43, basename as basename4 } from "path";
26115
- function parseSkillFrontmatter(data) {
26116
- return {
26117
- name: typeof data.name === "string" ? data.name : "",
26118
- description: typeof data.description === "string" ? data.description : "",
26119
- license: typeof data.license === "string" ? data.license : undefined,
26120
- "allowed-tools": Array.isArray(data["allowed-tools"]) ? data["allowed-tools"] : undefined,
26121
- metadata: typeof data.metadata === "object" && data.metadata !== null ? data.metadata : undefined
26122
- };
26123
- }
26124
- function discoverSkillsFromDir(skillsDir, scope) {
26125
- if (!existsSync36(skillsDir)) {
26126
- return [];
26127
- }
26128
- const entries = readdirSync11(skillsDir, { withFileTypes: true });
26129
- const skills = [];
26130
- for (const entry of entries) {
26131
- if (entry.name.startsWith("."))
26132
- continue;
26133
- const skillPath = join43(skillsDir, entry.name);
26134
- if (entry.isDirectory() || entry.isSymbolicLink()) {
26135
- const resolvedPath = resolveSymlink(skillPath);
26136
- const skillMdPath = join43(resolvedPath, "SKILL.md");
26137
- if (!existsSync36(skillMdPath))
26138
- continue;
26139
- try {
26140
- const content = readFileSync22(skillMdPath, "utf-8");
26141
- const { data } = parseFrontmatter(content);
26142
- skills.push({
26143
- name: data.name || entry.name,
26144
- description: data.description || "",
26145
- scope
26146
- });
26147
- } catch {
26148
- continue;
26149
- }
26150
- }
26151
- }
26152
- return skills;
26153
- }
26154
- function discoverSkillsSync() {
26155
- const userSkillsDir = join43(homedir19(), ".claude", "skills");
26156
- const projectSkillsDir = join43(process.cwd(), ".claude", "skills");
26157
- const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
26158
- const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
26159
- return [...projectSkills, ...userSkills];
26160
- }
26161
- var availableSkills = discoverSkillsSync();
26162
- var skillListForDescription = availableSkills.map((s) => `- ${s.name}: ${s.description} (${s.scope})`).join(`
26163
- `);
26164
- async function parseSkillMd(skillPath) {
26165
- const resolvedPath = resolveSymlink(skillPath);
26166
- const skillMdPath = join43(resolvedPath, "SKILL.md");
26167
- if (!existsSync36(skillMdPath)) {
26168
- return null;
26169
- }
26170
- try {
26171
- let content = readFileSync22(skillMdPath, "utf-8");
26172
- content = await resolveCommandsInText(content);
26173
- const { data, body } = parseFrontmatter(content);
26174
- const frontmatter2 = parseSkillFrontmatter(data);
26175
- const metadata = {
26176
- name: frontmatter2.name || basename4(skillPath),
26177
- description: frontmatter2.description,
26178
- license: frontmatter2.license,
26179
- allowedTools: frontmatter2["allowed-tools"],
26180
- metadata: frontmatter2.metadata
26181
- };
26182
- const referencesDir = join43(resolvedPath, "references");
26183
- const scriptsDir = join43(resolvedPath, "scripts");
26184
- const assetsDir = join43(resolvedPath, "assets");
26185
- const references = existsSync36(referencesDir) ? readdirSync11(referencesDir).filter((f) => !f.startsWith(".")) : [];
26186
- const scripts = existsSync36(scriptsDir) ? readdirSync11(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
26187
- const assets = existsSync36(assetsDir) ? readdirSync11(assetsDir).filter((f) => !f.startsWith(".")) : [];
26188
- return {
26189
- name: metadata.name,
26190
- path: resolvedPath,
26191
- basePath: resolvedPath,
26192
- metadata,
26193
- content: body,
26194
- references,
26195
- scripts,
26196
- assets
26197
- };
26198
- } catch {
26199
- return null;
26200
- }
26201
- }
26202
- async function discoverSkillsFromDirAsync(skillsDir) {
26203
- if (!existsSync36(skillsDir)) {
26204
- return [];
26205
- }
26206
- const entries = readdirSync11(skillsDir, { withFileTypes: true });
26207
- const skills = [];
26208
- for (const entry of entries) {
26209
- if (entry.name.startsWith("."))
26210
- continue;
26211
- const skillPath = join43(skillsDir, entry.name);
26212
- if (entry.isDirectory() || entry.isSymbolicLink()) {
26213
- const skillInfo = await parseSkillMd(skillPath);
26214
- if (skillInfo) {
26215
- skills.push(skillInfo);
26216
- }
26217
- }
26218
- }
26219
- return skills;
26220
- }
26221
- async function discoverSkills() {
26222
- const userSkillsDir = join43(homedir19(), ".claude", "skills");
26223
- const projectSkillsDir = join43(process.cwd(), ".claude", "skills");
26224
- const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
26225
- const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
26226
- return [...projectSkills, ...userSkills];
26227
- }
26228
- function findMatchingSkills(skills, query) {
26229
- const queryLower = query.toLowerCase();
26230
- const queryTerms = queryLower.split(/\s+/).filter(Boolean);
26231
- return skills.map((skill) => {
26232
- let score = 0;
26233
- const nameLower = skill.metadata.name.toLowerCase();
26234
- const descLower = skill.metadata.description.toLowerCase();
26235
- if (nameLower === queryLower)
26236
- score += 100;
26237
- if (nameLower.includes(queryLower))
26238
- score += 50;
26239
- for (const term of queryTerms) {
26240
- if (nameLower.includes(term))
26241
- score += 20;
26242
- if (descLower.includes(term))
26243
- score += 10;
26244
- }
26245
- return { skill, score };
26246
- }).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).map(({ skill }) => skill);
26247
- }
26248
- async function loadSkillWithReferences(skill, includeRefs) {
26249
- const referencesLoaded = [];
26250
- if (includeRefs && skill.references.length > 0) {
26251
- for (const ref of skill.references) {
26252
- const refPath = join43(skill.path, "references", ref);
26253
- try {
26254
- let content = readFileSync22(refPath, "utf-8");
26255
- content = await resolveCommandsInText(content);
26256
- referencesLoaded.push({ path: ref, content });
26257
- } catch {}
26258
- }
26259
- }
26260
- return {
26261
- name: skill.name,
26262
- metadata: skill.metadata,
26263
- basePath: skill.basePath,
26264
- body: skill.content,
26265
- referencesLoaded
26266
- };
26267
- }
26268
- function formatSkillList(skills) {
26269
- if (skills.length === 0) {
26270
- return "No skills found in ~/.claude/skills/";
26271
- }
26272
- const lines = [`# Available Skills
26273
- `];
26274
- for (const skill of skills) {
26275
- lines.push(`- **${skill.metadata.name}**: ${skill.metadata.description || "(no description)"}`);
26276
- }
26277
- lines.push(`
26278
- **Total**: ${skills.length} skills`);
26279
- return lines.join(`
26280
- `);
26281
- }
26282
- function formatLoadedSkills(loadedSkills) {
26283
- if (loadedSkills.length === 0) {
26284
- return "No skills loaded.";
26285
- }
26286
- const skill = loadedSkills[0];
26287
- const sections = [];
26288
- sections.push(`Base directory for this skill: ${skill.basePath}/`);
26289
- sections.push("");
26290
- sections.push(skill.body.trim());
26291
- if (skill.referencesLoaded.length > 0) {
26292
- sections.push(`
26293
- ---
26294
- ### Loaded References
26295
- `);
26296
- for (const ref of skill.referencesLoaded) {
26297
- sections.push(`#### ${ref.path}
26298
- `);
26299
- sections.push("```");
26300
- sections.push(ref.content.trim());
26301
- sections.push("```\n");
26302
- }
26303
- }
26304
- sections.push(`
26305
- ---
26306
- **Launched skill**: ${skill.metadata.name}`);
26307
- return sections.join(`
26308
- `);
26309
- }
26310
- var skill = tool({
26311
- description: `Execute a skill within the main conversation.
26312
-
26313
- When you invoke a skill, the skill's prompt will expand and provide detailed instructions on how to complete the task.
26314
-
26315
- Available Skills:
26316
- ${skillListForDescription}`,
26317
- args: {
26318
- skill: tool.schema.string().describe("The skill name or search query to find and load. Can be exact skill name (e.g., 'python-programmer') or keywords (e.g., 'python', 'plan').")
26319
- },
26320
- async execute(args) {
26321
- const skills = await discoverSkills();
26322
- if (!args.skill) {
26323
- return formatSkillList(skills) + `
26324
-
26325
- Provide a skill name to load.`;
26326
- }
26327
- const matchingSkills = findMatchingSkills(skills, args.skill);
26328
- if (matchingSkills.length === 0) {
26329
- return `No skills found matching "${args.skill}".
26330
-
26331
- ` + formatSkillList(skills) + `
26332
-
26333
- Try a different skill name.`;
26334
- }
26335
- const loadedSkills = [];
26336
- for (const skillInfo of matchingSkills.slice(0, 3)) {
26337
- const loaded = await loadSkillWithReferences(skillInfo, true);
26338
- loadedSkills.push(loaded);
26339
- }
26340
- return formatLoadedSkills(loadedSkills);
26341
- }
26342
- });
26343
26133
  // src/tools/interactive-bash/constants.ts
26344
26134
  var DEFAULT_TIMEOUT_MS4 = 60000;
26345
26135
  var BLOCKED_TMUX_SUBCOMMANDS = [
@@ -27011,13 +26801,12 @@ var builtinTools = {
27011
26801
  ast_grep_replace,
27012
26802
  grep,
27013
26803
  glob,
27014
- slashcommand,
27015
- skill
26804
+ slashcommand
27016
26805
  };
27017
26806
  // src/features/background-agent/manager.ts
27018
26807
  import { existsSync as existsSync37, readdirSync as readdirSync12 } from "fs";
27019
26808
  import { join as join44 } from "path";
27020
- function getMessageDir4(sessionID) {
26809
+ function getMessageDir5(sessionID) {
27021
26810
  if (!existsSync37(MESSAGE_STORAGE))
27022
26811
  return null;
27023
26812
  const directPath = join44(MESSAGE_STORAGE, sessionID);
@@ -27261,7 +27050,7 @@ class BackgroundManager {
27261
27050
  log("[background-agent] Sending notification to parent session:", { parentSessionID: task.parentSessionID });
27262
27051
  setTimeout(async () => {
27263
27052
  try {
27264
- const messageDir = getMessageDir4(task.parentSessionID);
27053
+ const messageDir = getMessageDir5(task.parentSessionID);
27265
27054
  const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
27266
27055
  await this.client.session.prompt({
27267
27056
  path: { id: task.parentSessionID },
@@ -318,13 +318,4 @@ export declare const builtinTools: {
318
318
  command: string;
319
319
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
320
320
  };
321
- skill: {
322
- description: string;
323
- args: {
324
- skill: import("zod").ZodString;
325
- };
326
- execute(args: {
327
- skill: string;
328
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
329
- };
330
321
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,2 +0,0 @@
1
- export * from "./types";
2
- export { skill } from "./tools";
@@ -1,10 +0,0 @@
1
- import { z } from "zod/v4";
2
- export declare const skill: {
3
- description: string;
4
- args: {
5
- skill: z.ZodString;
6
- };
7
- execute(args: {
8
- skill: string;
9
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
10
- };
@@ -1,41 +0,0 @@
1
- import { z } from "zod/v4";
2
- export type SkillScope = "user" | "project";
3
- /**
4
- * Zod schema for skill frontmatter validation
5
- * Following Anthropic Agent Skills Specification v1.0
6
- */
7
- export declare const SkillFrontmatterSchema: z.ZodObject<{
8
- name: z.ZodString;
9
- description: z.ZodString;
10
- license: z.ZodOptional<z.ZodString>;
11
- "allowed-tools": z.ZodOptional<z.ZodArray<z.ZodString>>;
12
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
13
- }, z.core.$strip>;
14
- export type SkillFrontmatter = z.infer<typeof SkillFrontmatterSchema>;
15
- export interface SkillMetadata {
16
- name: string;
17
- description: string;
18
- license?: string;
19
- allowedTools?: string[];
20
- metadata?: Record<string, string>;
21
- }
22
- export interface SkillInfo {
23
- name: string;
24
- path: string;
25
- basePath: string;
26
- metadata: SkillMetadata;
27
- content: string;
28
- references: string[];
29
- scripts: string[];
30
- assets: string[];
31
- }
32
- export interface LoadedSkill {
33
- name: string;
34
- metadata: SkillMetadata;
35
- basePath: string;
36
- body: string;
37
- referencesLoaded: Array<{
38
- path: string;
39
- content: string;
40
- }>;
41
- }