oh-my-opencode 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1831,6 +1831,147 @@ ${content}`;
1831
1831
  event: eventHandler
1832
1832
  };
1833
1833
  }
1834
+ // src/hooks/directory-readme-injector/index.ts
1835
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
1836
+ import { dirname as dirname3, join as join10, resolve as resolve2 } from "path";
1837
+
1838
+ // src/hooks/directory-readme-injector/storage.ts
1839
+ import {
1840
+ existsSync as existsSync7,
1841
+ mkdirSync as mkdirSync4,
1842
+ readFileSync as readFileSync4,
1843
+ writeFileSync as writeFileSync3,
1844
+ unlinkSync as unlinkSync4
1845
+ } from "fs";
1846
+ import { join as join9 } from "path";
1847
+
1848
+ // src/hooks/directory-readme-injector/constants.ts
1849
+ import { join as join8 } from "path";
1850
+ var OPENCODE_STORAGE3 = join8(xdgData ?? "", "opencode", "storage");
1851
+ var README_INJECTOR_STORAGE = join8(OPENCODE_STORAGE3, "directory-readme");
1852
+ var README_FILENAME = "README.md";
1853
+
1854
+ // src/hooks/directory-readme-injector/storage.ts
1855
+ function getStoragePath2(sessionID) {
1856
+ return join9(README_INJECTOR_STORAGE, `${sessionID}.json`);
1857
+ }
1858
+ function loadInjectedPaths2(sessionID) {
1859
+ const filePath = getStoragePath2(sessionID);
1860
+ if (!existsSync7(filePath))
1861
+ return new Set;
1862
+ try {
1863
+ const content = readFileSync4(filePath, "utf-8");
1864
+ const data = JSON.parse(content);
1865
+ return new Set(data.injectedPaths);
1866
+ } catch {
1867
+ return new Set;
1868
+ }
1869
+ }
1870
+ function saveInjectedPaths2(sessionID, paths) {
1871
+ if (!existsSync7(README_INJECTOR_STORAGE)) {
1872
+ mkdirSync4(README_INJECTOR_STORAGE, { recursive: true });
1873
+ }
1874
+ const data = {
1875
+ sessionID,
1876
+ injectedPaths: [...paths],
1877
+ updatedAt: Date.now()
1878
+ };
1879
+ writeFileSync3(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
1880
+ }
1881
+ function clearInjectedPaths2(sessionID) {
1882
+ const filePath = getStoragePath2(sessionID);
1883
+ if (existsSync7(filePath)) {
1884
+ unlinkSync4(filePath);
1885
+ }
1886
+ }
1887
+
1888
+ // src/hooks/directory-readme-injector/index.ts
1889
+ function createDirectoryReadmeInjectorHook(ctx) {
1890
+ const sessionCaches = new Map;
1891
+ function getSessionCache(sessionID) {
1892
+ if (!sessionCaches.has(sessionID)) {
1893
+ sessionCaches.set(sessionID, loadInjectedPaths2(sessionID));
1894
+ }
1895
+ return sessionCaches.get(sessionID);
1896
+ }
1897
+ function resolveFilePath(title) {
1898
+ if (!title)
1899
+ return null;
1900
+ if (title.startsWith("/"))
1901
+ return title;
1902
+ return resolve2(ctx.directory, title);
1903
+ }
1904
+ function findReadmeMdUp(startDir) {
1905
+ const found = [];
1906
+ let current = startDir;
1907
+ while (true) {
1908
+ const readmePath = join10(current, README_FILENAME);
1909
+ if (existsSync8(readmePath)) {
1910
+ found.push(readmePath);
1911
+ }
1912
+ if (current === ctx.directory)
1913
+ break;
1914
+ const parent = dirname3(current);
1915
+ if (parent === current)
1916
+ break;
1917
+ if (!parent.startsWith(ctx.directory))
1918
+ break;
1919
+ current = parent;
1920
+ }
1921
+ return found.reverse();
1922
+ }
1923
+ const toolExecuteAfter = async (input, output) => {
1924
+ if (input.tool.toLowerCase() !== "read")
1925
+ return;
1926
+ const filePath = resolveFilePath(output.title);
1927
+ if (!filePath)
1928
+ return;
1929
+ const dir = dirname3(filePath);
1930
+ const cache = getSessionCache(input.sessionID);
1931
+ const readmePaths = findReadmeMdUp(dir);
1932
+ const toInject = [];
1933
+ for (const readmePath of readmePaths) {
1934
+ const readmeDir = dirname3(readmePath);
1935
+ if (cache.has(readmeDir))
1936
+ continue;
1937
+ try {
1938
+ const content = readFileSync5(readmePath, "utf-8");
1939
+ toInject.push({ path: readmePath, content });
1940
+ cache.add(readmeDir);
1941
+ } catch {}
1942
+ }
1943
+ if (toInject.length === 0)
1944
+ return;
1945
+ for (const { path: path2, content } of toInject) {
1946
+ output.output += `
1947
+
1948
+ [Project README: ${path2}]
1949
+ ${content}`;
1950
+ }
1951
+ saveInjectedPaths2(input.sessionID, cache);
1952
+ };
1953
+ const eventHandler = async ({ event }) => {
1954
+ const props = event.properties;
1955
+ if (event.type === "session.deleted") {
1956
+ const sessionInfo = props?.info;
1957
+ if (sessionInfo?.id) {
1958
+ sessionCaches.delete(sessionInfo.id);
1959
+ clearInjectedPaths2(sessionInfo.id);
1960
+ }
1961
+ }
1962
+ if (event.type === "session.compacted") {
1963
+ const sessionID = props?.sessionID ?? props?.info?.id;
1964
+ if (sessionID) {
1965
+ sessionCaches.delete(sessionID);
1966
+ clearInjectedPaths2(sessionID);
1967
+ }
1968
+ }
1969
+ };
1970
+ return {
1971
+ "tool.execute.after": toolExecuteAfter,
1972
+ event: eventHandler
1973
+ };
1974
+ }
1834
1975
  // src/hooks/empty-task-response-detector.ts
1835
1976
  var EMPTY_RESPONSE_WARNING = `[Task Empty Response Warning]
1836
1977
 
@@ -2306,8 +2447,8 @@ function createThinkModeHook() {
2306
2447
  }
2307
2448
  // src/hooks/claude-code-hooks/config.ts
2308
2449
  import { homedir as homedir2 } from "os";
2309
- import { join as join8 } from "path";
2310
- import { existsSync as existsSync7 } from "fs";
2450
+ import { join as join11 } from "path";
2451
+ import { existsSync as existsSync9 } from "fs";
2311
2452
  function normalizeHookMatcher(raw) {
2312
2453
  return {
2313
2454
  matcher: raw.matcher ?? raw.pattern ?? "*",
@@ -2332,11 +2473,11 @@ function normalizeHooksConfig(raw) {
2332
2473
  function getClaudeSettingsPaths(customPath) {
2333
2474
  const home = homedir2();
2334
2475
  const paths = [
2335
- join8(home, ".claude", "settings.json"),
2336
- join8(process.cwd(), ".claude", "settings.json"),
2337
- join8(process.cwd(), ".claude", "settings.local.json")
2476
+ join11(home, ".claude", "settings.json"),
2477
+ join11(process.cwd(), ".claude", "settings.json"),
2478
+ join11(process.cwd(), ".claude", "settings.local.json")
2338
2479
  ];
2339
- if (customPath && existsSync7(customPath)) {
2480
+ if (customPath && existsSync9(customPath)) {
2340
2481
  paths.unshift(customPath);
2341
2482
  }
2342
2483
  return paths;
@@ -2360,7 +2501,7 @@ async function loadClaudeHooksConfig(customSettingsPath) {
2360
2501
  const paths = getClaudeSettingsPaths(customSettingsPath);
2361
2502
  let mergedConfig = {};
2362
2503
  for (const settingsPath of paths) {
2363
- if (existsSync7(settingsPath)) {
2504
+ if (existsSync9(settingsPath)) {
2364
2505
  try {
2365
2506
  const content = await Bun.file(settingsPath).text();
2366
2507
  const settings = JSON.parse(content);
@@ -2377,9 +2518,9 @@ async function loadClaudeHooksConfig(customSettingsPath) {
2377
2518
  }
2378
2519
 
2379
2520
  // src/hooks/claude-code-hooks/config-loader.ts
2380
- import { existsSync as existsSync8 } from "fs";
2521
+ import { existsSync as existsSync10 } from "fs";
2381
2522
  import { homedir as homedir3 } from "os";
2382
- import { join as join10 } from "path";
2523
+ import { join as join13 } from "path";
2383
2524
 
2384
2525
  // src/shared/logger.ts
2385
2526
  import * as fs3 from "fs";
@@ -2396,12 +2537,12 @@ function log(message, data) {
2396
2537
  }
2397
2538
 
2398
2539
  // src/hooks/claude-code-hooks/config-loader.ts
2399
- var USER_CONFIG_PATH = join10(homedir3(), ".config", "opencode", "opencode-cc-plugin.json");
2540
+ var USER_CONFIG_PATH = join13(homedir3(), ".config", "opencode", "opencode-cc-plugin.json");
2400
2541
  function getProjectConfigPath() {
2401
- return join10(process.cwd(), ".opencode", "opencode-cc-plugin.json");
2542
+ return join13(process.cwd(), ".opencode", "opencode-cc-plugin.json");
2402
2543
  }
2403
2544
  async function loadConfigFromPath(path3) {
2404
- if (!existsSync8(path3)) {
2545
+ if (!existsSync10(path3)) {
2405
2546
  return null;
2406
2547
  }
2407
2548
  try {
@@ -2494,14 +2635,14 @@ function parseFrontmatter(content) {
2494
2635
  import { spawn as spawn3 } from "child_process";
2495
2636
  import { exec } from "child_process";
2496
2637
  import { promisify } from "util";
2497
- import { existsSync as existsSync9 } from "fs";
2638
+ import { existsSync as existsSync11 } from "fs";
2498
2639
  var DEFAULT_ZSH_PATHS = ["/bin/zsh", "/usr/bin/zsh", "/usr/local/bin/zsh"];
2499
2640
  function findZshPath(customZshPath) {
2500
- if (customZshPath && existsSync9(customZshPath)) {
2641
+ if (customZshPath && existsSync11(customZshPath)) {
2501
2642
  return customZshPath;
2502
2643
  }
2503
2644
  for (const path3 of DEFAULT_ZSH_PATHS) {
2504
- if (existsSync9(path3)) {
2645
+ if (existsSync11(path3)) {
2505
2646
  return path3;
2506
2647
  }
2507
2648
  }
@@ -2519,7 +2660,7 @@ async function executeHookCommand(command, stdin, cwd, options) {
2519
2660
  finalCommand = `${zshPath} -lc '${escapedCommand}'`;
2520
2661
  }
2521
2662
  }
2522
- return new Promise((resolve2) => {
2663
+ return new Promise((resolve3) => {
2523
2664
  const proc = spawn3(finalCommand, {
2524
2665
  cwd,
2525
2666
  shell: true,
@@ -2536,14 +2677,14 @@ async function executeHookCommand(command, stdin, cwd, options) {
2536
2677
  proc.stdin?.write(stdin);
2537
2678
  proc.stdin?.end();
2538
2679
  proc.on("close", (code) => {
2539
- resolve2({
2680
+ resolve3({
2540
2681
  exitCode: code ?? 0,
2541
2682
  stdout: stdout.trim(),
2542
2683
  stderr: stderr.trim()
2543
2684
  });
2544
2685
  });
2545
2686
  proc.on("error", (err) => {
2546
- resolve2({
2687
+ resolve3({
2547
2688
  exitCode: 1,
2548
2689
  stderr: err.message
2549
2690
  });
@@ -2619,8 +2760,8 @@ async function resolveCommandsInText(text, depth = 0, maxDepth = 3) {
2619
2760
  return resolved;
2620
2761
  }
2621
2762
  // src/shared/file-reference-resolver.ts
2622
- import { existsSync as existsSync10, readFileSync as readFileSync4, statSync } from "fs";
2623
- import { join as join11, isAbsolute } from "path";
2763
+ import { existsSync as existsSync12, readFileSync as readFileSync6, statSync } from "fs";
2764
+ import { join as join14, isAbsolute } from "path";
2624
2765
  var FILE_REFERENCE_PATTERN = /@([^\s@]+)/g;
2625
2766
  function findFileReferences(text) {
2626
2767
  const matches = [];
@@ -2640,17 +2781,17 @@ function resolveFilePath(filePath, cwd) {
2640
2781
  if (isAbsolute(filePath)) {
2641
2782
  return filePath;
2642
2783
  }
2643
- return join11(cwd, filePath);
2784
+ return join14(cwd, filePath);
2644
2785
  }
2645
2786
  function readFileContent(resolvedPath) {
2646
- if (!existsSync10(resolvedPath)) {
2787
+ if (!existsSync12(resolvedPath)) {
2647
2788
  return `[file not found: ${resolvedPath}]`;
2648
2789
  }
2649
2790
  const stat = statSync(resolvedPath);
2650
2791
  if (stat.isDirectory()) {
2651
2792
  return `[cannot read directory: ${resolvedPath}]`;
2652
2793
  }
2653
- const content = readFileSync4(resolvedPath, "utf-8");
2794
+ const content = readFileSync6(resolvedPath, "utf-8");
2654
2795
  return content;
2655
2796
  }
2656
2797
  async function resolveFileReferencesInText(text, cwd = process.cwd(), depth = 0, maxDepth = 3) {
@@ -2873,17 +3014,17 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
2873
3014
  }
2874
3015
 
2875
3016
  // src/hooks/claude-code-hooks/transcript.ts
2876
- import { join as join12 } from "path";
2877
- import { mkdirSync as mkdirSync4, appendFileSync as appendFileSync5, existsSync as existsSync11, writeFileSync as writeFileSync3, unlinkSync as unlinkSync4 } from "fs";
3017
+ import { join as join15 } from "path";
3018
+ import { mkdirSync as mkdirSync5, appendFileSync as appendFileSync5, existsSync as existsSync13, writeFileSync as writeFileSync4, unlinkSync as unlinkSync5 } from "fs";
2878
3019
  import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
2879
3020
  import { randomUUID } from "crypto";
2880
- var TRANSCRIPT_DIR = join12(homedir4(), ".claude", "transcripts");
3021
+ var TRANSCRIPT_DIR = join15(homedir4(), ".claude", "transcripts");
2881
3022
  function getTranscriptPath(sessionId) {
2882
- return join12(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
3023
+ return join15(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
2883
3024
  }
2884
3025
  function ensureTranscriptDir() {
2885
- if (!existsSync11(TRANSCRIPT_DIR)) {
2886
- mkdirSync4(TRANSCRIPT_DIR, { recursive: true });
3026
+ if (!existsSync13(TRANSCRIPT_DIR)) {
3027
+ mkdirSync5(TRANSCRIPT_DIR, { recursive: true });
2887
3028
  }
2888
3029
  }
2889
3030
  function appendTranscriptEntry(sessionId, entry) {
@@ -2969,8 +3110,8 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
2969
3110
  }
2970
3111
  };
2971
3112
  entries.push(JSON.stringify(currentEntry));
2972
- const tempPath = join12(tmpdir2(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
2973
- writeFileSync3(tempPath, entries.join(`
3113
+ const tempPath = join15(tmpdir2(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
3114
+ writeFileSync4(tempPath, entries.join(`
2974
3115
  `) + `
2975
3116
  `);
2976
3117
  return tempPath;
@@ -2989,8 +3130,8 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
2989
3130
  ]
2990
3131
  }
2991
3132
  };
2992
- const tempPath = join12(tmpdir2(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
2993
- writeFileSync3(tempPath, JSON.stringify(currentEntry) + `
3133
+ const tempPath = join15(tmpdir2(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
3134
+ writeFileSync4(tempPath, JSON.stringify(currentEntry) + `
2994
3135
  `);
2995
3136
  return tempPath;
2996
3137
  } catch {
@@ -3002,7 +3143,7 @@ function deleteTempTranscript(path3) {
3002
3143
  if (!path3)
3003
3144
  return;
3004
3145
  try {
3005
- unlinkSync4(path3);
3146
+ unlinkSync5(path3);
3006
3147
  } catch {}
3007
3148
  }
3008
3149
 
@@ -3201,11 +3342,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
3201
3342
  }
3202
3343
 
3203
3344
  // src/hooks/claude-code-hooks/todo.ts
3204
- import { join as join13 } from "path";
3345
+ import { join as join16 } from "path";
3205
3346
  import { homedir as homedir5 } from "os";
3206
- var TODO_DIR = join13(homedir5(), ".claude", "todos");
3347
+ var TODO_DIR = join16(homedir5(), ".claude", "todos");
3207
3348
  function getTodoPath(sessionId) {
3208
- return join13(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
3349
+ return join16(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
3209
3350
  }
3210
3351
 
3211
3352
  // src/hooks/claude-code-hooks/stop.ts
@@ -3297,16 +3438,16 @@ setInterval(() => {
3297
3438
  }, CACHE_TTL);
3298
3439
 
3299
3440
  // src/features/hook-message-injector/injector.ts
3300
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync5, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
3301
- import { join as join15 } from "path";
3441
+ import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync7, readdirSync as readdirSync2, writeFileSync as writeFileSync5 } from "fs";
3442
+ import { join as join18 } from "path";
3302
3443
 
3303
3444
  // src/features/hook-message-injector/constants.ts
3304
- import { join as join14 } from "path";
3445
+ import { join as join17 } from "path";
3305
3446
  import { homedir as homedir6 } from "os";
3306
- var xdgData2 = process.env.XDG_DATA_HOME || join14(homedir6(), ".local", "share");
3307
- var OPENCODE_STORAGE3 = join14(xdgData2, "opencode", "storage");
3308
- var MESSAGE_STORAGE2 = join14(OPENCODE_STORAGE3, "message");
3309
- var PART_STORAGE2 = join14(OPENCODE_STORAGE3, "part");
3447
+ var xdgData2 = process.env.XDG_DATA_HOME || join17(homedir6(), ".local", "share");
3448
+ var OPENCODE_STORAGE4 = join17(xdgData2, "opencode", "storage");
3449
+ var MESSAGE_STORAGE2 = join17(OPENCODE_STORAGE4, "message");
3450
+ var PART_STORAGE2 = join17(OPENCODE_STORAGE4, "part");
3310
3451
 
3311
3452
  // src/features/hook-message-injector/injector.ts
3312
3453
  function findNearestMessageWithFields(messageDir) {
@@ -3314,7 +3455,7 @@ function findNearestMessageWithFields(messageDir) {
3314
3455
  const files = readdirSync2(messageDir).filter((f) => f.endsWith(".json")).sort().reverse();
3315
3456
  for (const file of files) {
3316
3457
  try {
3317
- const content = readFileSync5(join15(messageDir, file), "utf-8");
3458
+ const content = readFileSync7(join18(messageDir, file), "utf-8");
3318
3459
  const msg = JSON.parse(content);
3319
3460
  if (msg.agent && msg.model?.providerID && msg.model?.modelID) {
3320
3461
  return msg;
@@ -3339,20 +3480,20 @@ function generatePartId2() {
3339
3480
  return `prt_${timestamp}${random}`;
3340
3481
  }
3341
3482
  function getOrCreateMessageDir(sessionID) {
3342
- if (!existsSync12(MESSAGE_STORAGE2)) {
3343
- mkdirSync5(MESSAGE_STORAGE2, { recursive: true });
3483
+ if (!existsSync14(MESSAGE_STORAGE2)) {
3484
+ mkdirSync6(MESSAGE_STORAGE2, { recursive: true });
3344
3485
  }
3345
- const directPath = join15(MESSAGE_STORAGE2, sessionID);
3346
- if (existsSync12(directPath)) {
3486
+ const directPath = join18(MESSAGE_STORAGE2, sessionID);
3487
+ if (existsSync14(directPath)) {
3347
3488
  return directPath;
3348
3489
  }
3349
3490
  for (const dir of readdirSync2(MESSAGE_STORAGE2)) {
3350
- const sessionPath = join15(MESSAGE_STORAGE2, dir, sessionID);
3351
- if (existsSync12(sessionPath)) {
3491
+ const sessionPath = join18(MESSAGE_STORAGE2, dir, sessionID);
3492
+ if (existsSync14(sessionPath)) {
3352
3493
  return sessionPath;
3353
3494
  }
3354
3495
  }
3355
- mkdirSync5(directPath, { recursive: true });
3496
+ mkdirSync6(directPath, { recursive: true });
3356
3497
  return directPath;
3357
3498
  }
3358
3499
  function injectHookMessage(sessionID, hookContent, originalMessage) {
@@ -3393,12 +3534,12 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
3393
3534
  sessionID
3394
3535
  };
3395
3536
  try {
3396
- writeFileSync4(join15(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
3397
- const partDir = join15(PART_STORAGE2, messageID);
3398
- if (!existsSync12(partDir)) {
3399
- mkdirSync5(partDir, { recursive: true });
3537
+ writeFileSync5(join18(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
3538
+ const partDir = join18(PART_STORAGE2, messageID);
3539
+ if (!existsSync14(partDir)) {
3540
+ mkdirSync6(partDir, { recursive: true });
3400
3541
  }
3401
- writeFileSync4(join15(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
3542
+ writeFileSync5(join18(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
3402
3543
  return true;
3403
3544
  } catch {
3404
3545
  return false;
@@ -3644,14 +3785,14 @@ ${result.message}`;
3644
3785
  };
3645
3786
  }
3646
3787
  // src/features/claude-code-command-loader/loader.ts
3647
- import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "fs";
3788
+ import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "fs";
3648
3789
  import { homedir as homedir7 } from "os";
3649
- import { join as join16, basename } from "path";
3790
+ import { join as join19, basename } from "path";
3650
3791
  function isMarkdownFile(entry) {
3651
3792
  return !entry.name.startsWith(".") && entry.name.endsWith(".md") && entry.isFile();
3652
3793
  }
3653
3794
  function loadCommandsFromDir(commandsDir, scope) {
3654
- if (!existsSync13(commandsDir)) {
3795
+ if (!existsSync15(commandsDir)) {
3655
3796
  return [];
3656
3797
  }
3657
3798
  const entries = readdirSync3(commandsDir, { withFileTypes: true });
@@ -3659,10 +3800,10 @@ function loadCommandsFromDir(commandsDir, scope) {
3659
3800
  for (const entry of entries) {
3660
3801
  if (!isMarkdownFile(entry))
3661
3802
  continue;
3662
- const commandPath = join16(commandsDir, entry.name);
3803
+ const commandPath = join19(commandsDir, entry.name);
3663
3804
  const commandName = basename(entry.name, ".md");
3664
3805
  try {
3665
- const content = readFileSync6(commandPath, "utf-8");
3806
+ const content = readFileSync8(commandPath, "utf-8");
3666
3807
  const { data, body } = parseFrontmatter(content);
3667
3808
  const wrappedTemplate = `<command-instruction>
3668
3809
  ${body.trim()}
@@ -3701,31 +3842,31 @@ function commandsToRecord(commands) {
3701
3842
  return result;
3702
3843
  }
3703
3844
  function loadUserCommands() {
3704
- const userCommandsDir = join16(homedir7(), ".claude", "commands");
3845
+ const userCommandsDir = join19(homedir7(), ".claude", "commands");
3705
3846
  const commands = loadCommandsFromDir(userCommandsDir, "user");
3706
3847
  return commandsToRecord(commands);
3707
3848
  }
3708
3849
  function loadProjectCommands() {
3709
- const projectCommandsDir = join16(process.cwd(), ".claude", "commands");
3850
+ const projectCommandsDir = join19(process.cwd(), ".claude", "commands");
3710
3851
  const commands = loadCommandsFromDir(projectCommandsDir, "project");
3711
3852
  return commandsToRecord(commands);
3712
3853
  }
3713
3854
  function loadOpencodeGlobalCommands() {
3714
- const opencodeCommandsDir = join16(homedir7(), ".config", "opencode", "command");
3855
+ const opencodeCommandsDir = join19(homedir7(), ".config", "opencode", "command");
3715
3856
  const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
3716
3857
  return commandsToRecord(commands);
3717
3858
  }
3718
3859
  function loadOpencodeProjectCommands() {
3719
- const opencodeProjectDir = join16(process.cwd(), ".opencode", "command");
3860
+ const opencodeProjectDir = join19(process.cwd(), ".opencode", "command");
3720
3861
  const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
3721
3862
  return commandsToRecord(commands);
3722
3863
  }
3723
3864
  // src/features/claude-code-skill-loader/loader.ts
3724
- import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync2, readlinkSync } from "fs";
3865
+ import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync2, readlinkSync } from "fs";
3725
3866
  import { homedir as homedir8 } from "os";
3726
- import { join as join17, resolve as resolve2 } from "path";
3867
+ import { join as join20, resolve as resolve3 } from "path";
3727
3868
  function loadSkillsFromDir(skillsDir, scope) {
3728
- if (!existsSync14(skillsDir)) {
3869
+ if (!existsSync16(skillsDir)) {
3729
3870
  return [];
3730
3871
  }
3731
3872
  const entries = readdirSync4(skillsDir, { withFileTypes: true });
@@ -3733,18 +3874,18 @@ function loadSkillsFromDir(skillsDir, scope) {
3733
3874
  for (const entry of entries) {
3734
3875
  if (entry.name.startsWith("."))
3735
3876
  continue;
3736
- const skillPath = join17(skillsDir, entry.name);
3877
+ const skillPath = join20(skillsDir, entry.name);
3737
3878
  if (!entry.isDirectory() && !entry.isSymbolicLink())
3738
3879
  continue;
3739
3880
  let resolvedPath = skillPath;
3740
3881
  if (statSync2(skillPath, { throwIfNoEntry: false })?.isSymbolicLink()) {
3741
- resolvedPath = resolve2(skillPath, "..", readlinkSync(skillPath));
3882
+ resolvedPath = resolve3(skillPath, "..", readlinkSync(skillPath));
3742
3883
  }
3743
- const skillMdPath = join17(resolvedPath, "SKILL.md");
3744
- if (!existsSync14(skillMdPath))
3884
+ const skillMdPath = join20(resolvedPath, "SKILL.md");
3885
+ if (!existsSync16(skillMdPath))
3745
3886
  continue;
3746
3887
  try {
3747
- const content = readFileSync7(skillMdPath, "utf-8");
3888
+ const content = readFileSync9(skillMdPath, "utf-8");
3748
3889
  const { data, body } = parseFrontmatter(content);
3749
3890
  const skillName = data.name || entry.name;
3750
3891
  const originalDescription = data.description || "";
@@ -3775,7 +3916,7 @@ $ARGUMENTS
3775
3916
  return skills;
3776
3917
  }
3777
3918
  function loadUserSkillsAsCommands() {
3778
- const userSkillsDir = join17(homedir8(), ".claude", "skills");
3919
+ const userSkillsDir = join20(homedir8(), ".claude", "skills");
3779
3920
  const skills = loadSkillsFromDir(userSkillsDir, "user");
3780
3921
  return skills.reduce((acc, skill) => {
3781
3922
  acc[skill.name] = skill.definition;
@@ -3783,7 +3924,7 @@ function loadUserSkillsAsCommands() {
3783
3924
  }, {});
3784
3925
  }
3785
3926
  function loadProjectSkillsAsCommands() {
3786
- const projectSkillsDir = join17(process.cwd(), ".claude", "skills");
3927
+ const projectSkillsDir = join20(process.cwd(), ".claude", "skills");
3787
3928
  const skills = loadSkillsFromDir(projectSkillsDir, "project");
3788
3929
  return skills.reduce((acc, skill) => {
3789
3930
  acc[skill.name] = skill.definition;
@@ -3791,9 +3932,9 @@ function loadProjectSkillsAsCommands() {
3791
3932
  }, {});
3792
3933
  }
3793
3934
  // src/features/claude-code-agent-loader/loader.ts
3794
- import { existsSync as existsSync15, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "fs";
3935
+ import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
3795
3936
  import { homedir as homedir9 } from "os";
3796
- import { join as join18, basename as basename2 } from "path";
3937
+ import { join as join21, basename as basename2 } from "path";
3797
3938
  function parseToolsConfig(toolsStr) {
3798
3939
  if (!toolsStr)
3799
3940
  return;
@@ -3810,7 +3951,7 @@ function isMarkdownFile2(entry) {
3810
3951
  return !entry.name.startsWith(".") && entry.name.endsWith(".md") && entry.isFile();
3811
3952
  }
3812
3953
  function loadAgentsFromDir(agentsDir, scope) {
3813
- if (!existsSync15(agentsDir)) {
3954
+ if (!existsSync17(agentsDir)) {
3814
3955
  return [];
3815
3956
  }
3816
3957
  const entries = readdirSync5(agentsDir, { withFileTypes: true });
@@ -3818,10 +3959,10 @@ function loadAgentsFromDir(agentsDir, scope) {
3818
3959
  for (const entry of entries) {
3819
3960
  if (!isMarkdownFile2(entry))
3820
3961
  continue;
3821
- const agentPath = join18(agentsDir, entry.name);
3962
+ const agentPath = join21(agentsDir, entry.name);
3822
3963
  const agentName = basename2(entry.name, ".md");
3823
3964
  try {
3824
- const content = readFileSync8(agentPath, "utf-8");
3965
+ const content = readFileSync10(agentPath, "utf-8");
3825
3966
  const { data, body } = parseFrontmatter(content);
3826
3967
  const name = data.name || agentName;
3827
3968
  const originalDescription = data.description || "";
@@ -3848,7 +3989,7 @@ function loadAgentsFromDir(agentsDir, scope) {
3848
3989
  return agents;
3849
3990
  }
3850
3991
  function loadUserAgents() {
3851
- const userAgentsDir = join18(homedir9(), ".claude", "agents");
3992
+ const userAgentsDir = join21(homedir9(), ".claude", "agents");
3852
3993
  const agents = loadAgentsFromDir(userAgentsDir, "user");
3853
3994
  const result = {};
3854
3995
  for (const agent of agents) {
@@ -3857,7 +3998,7 @@ function loadUserAgents() {
3857
3998
  return result;
3858
3999
  }
3859
4000
  function loadProjectAgents() {
3860
- const projectAgentsDir = join18(process.cwd(), ".claude", "agents");
4001
+ const projectAgentsDir = join21(process.cwd(), ".claude", "agents");
3861
4002
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
3862
4003
  const result = {};
3863
4004
  for (const agent of agents) {
@@ -3866,9 +4007,9 @@ function loadProjectAgents() {
3866
4007
  return result;
3867
4008
  }
3868
4009
  // src/features/claude-code-mcp-loader/loader.ts
3869
- import { existsSync as existsSync16 } from "fs";
4010
+ import { existsSync as existsSync18 } from "fs";
3870
4011
  import { homedir as homedir10 } from "os";
3871
- import { join as join19 } from "path";
4012
+ import { join as join22 } from "path";
3872
4013
 
3873
4014
  // src/features/claude-code-mcp-loader/env-expander.ts
3874
4015
  function expandEnvVars(value) {
@@ -3937,13 +4078,13 @@ function getMcpConfigPaths() {
3937
4078
  const home = homedir10();
3938
4079
  const cwd = process.cwd();
3939
4080
  return [
3940
- { path: join19(home, ".claude", ".mcp.json"), scope: "user" },
3941
- { path: join19(cwd, ".mcp.json"), scope: "project" },
3942
- { path: join19(cwd, ".claude", ".mcp.json"), scope: "local" }
4081
+ { path: join22(home, ".claude", ".mcp.json"), scope: "user" },
4082
+ { path: join22(cwd, ".mcp.json"), scope: "project" },
4083
+ { path: join22(cwd, ".claude", ".mcp.json"), scope: "local" }
3943
4084
  ];
3944
4085
  }
3945
4086
  async function loadMcpConfigFile(filePath) {
3946
- if (!existsSync16(filePath)) {
4087
+ if (!existsSync18(filePath)) {
3947
4088
  return null;
3948
4089
  }
3949
4090
  try {
@@ -4229,14 +4370,14 @@ var EXT_TO_LANG = {
4229
4370
  ".tfvars": "terraform"
4230
4371
  };
4231
4372
  // src/tools/lsp/config.ts
4232
- import { existsSync as existsSync17, readFileSync as readFileSync9 } from "fs";
4233
- import { join as join20 } from "path";
4373
+ import { existsSync as existsSync19, readFileSync as readFileSync11 } from "fs";
4374
+ import { join as join23 } from "path";
4234
4375
  import { homedir as homedir11 } from "os";
4235
4376
  function loadJsonFile(path3) {
4236
- if (!existsSync17(path3))
4377
+ if (!existsSync19(path3))
4237
4378
  return null;
4238
4379
  try {
4239
- return JSON.parse(readFileSync9(path3, "utf-8"));
4380
+ return JSON.parse(readFileSync11(path3, "utf-8"));
4240
4381
  } catch {
4241
4382
  return null;
4242
4383
  }
@@ -4244,9 +4385,9 @@ function loadJsonFile(path3) {
4244
4385
  function getConfigPaths() {
4245
4386
  const cwd = process.cwd();
4246
4387
  return {
4247
- project: join20(cwd, ".opencode", "oh-my-opencode.json"),
4248
- user: join20(homedir11(), ".config", "opencode", "oh-my-opencode.json"),
4249
- opencode: join20(homedir11(), ".config", "opencode", "opencode.json")
4388
+ project: join23(cwd, ".opencode", "oh-my-opencode.json"),
4389
+ user: join23(homedir11(), ".config", "opencode", "oh-my-opencode.json"),
4390
+ opencode: join23(homedir11(), ".config", "opencode", "opencode.json")
4250
4391
  };
4251
4392
  }
4252
4393
  function loadAllConfigs() {
@@ -4339,7 +4480,7 @@ function isServerInstalled(command) {
4339
4480
  const pathEnv = process.env.PATH || "";
4340
4481
  const paths = pathEnv.split(":");
4341
4482
  for (const p of paths) {
4342
- if (existsSync17(join20(p, cmd))) {
4483
+ if (existsSync19(join23(p, cmd))) {
4343
4484
  return true;
4344
4485
  }
4345
4486
  }
@@ -4389,8 +4530,8 @@ function getAllServers() {
4389
4530
  }
4390
4531
  // src/tools/lsp/client.ts
4391
4532
  var {spawn: spawn4 } = globalThis.Bun;
4392
- import { readFileSync as readFileSync10 } from "fs";
4393
- import { extname, resolve as resolve3 } from "path";
4533
+ import { readFileSync as readFileSync12 } from "fs";
4534
+ import { extname, resolve as resolve4 } from "path";
4394
4535
  class LSPServerManager {
4395
4536
  static instance;
4396
4537
  clients = new Map;
@@ -4540,7 +4681,7 @@ class LSPClient {
4540
4681
  }
4541
4682
  this.startReading();
4542
4683
  this.startStderrReading();
4543
- await new Promise((resolve4) => setTimeout(resolve4, 100));
4684
+ await new Promise((resolve5) => setTimeout(resolve5, 100));
4544
4685
  if (this.proc.exitCode !== null) {
4545
4686
  const stderr = this.stderrBuffer.join(`
4546
4687
  `);
@@ -4677,8 +4818,8 @@ stderr: ${stderr}` : ""));
4677
4818
  \r
4678
4819
  `;
4679
4820
  this.proc.stdin.write(header + msg);
4680
- return new Promise((resolve4, reject) => {
4681
- this.pending.set(id, { resolve: resolve4, reject });
4821
+ return new Promise((resolve5, reject) => {
4822
+ this.pending.set(id, { resolve: resolve5, reject });
4682
4823
  setTimeout(() => {
4683
4824
  if (this.pending.has(id)) {
4684
4825
  this.pending.delete(id);
@@ -4786,10 +4927,10 @@ ${msg}`);
4786
4927
  await new Promise((r) => setTimeout(r, 300));
4787
4928
  }
4788
4929
  async openFile(filePath) {
4789
- const absPath = resolve3(filePath);
4930
+ const absPath = resolve4(filePath);
4790
4931
  if (this.openedFiles.has(absPath))
4791
4932
  return;
4792
- const text = readFileSync10(absPath, "utf-8");
4933
+ const text = readFileSync12(absPath, "utf-8");
4793
4934
  const ext = extname(absPath);
4794
4935
  const languageId = getLanguageId(ext);
4795
4936
  this.notify("textDocument/didOpen", {
@@ -4804,7 +4945,7 @@ ${msg}`);
4804
4945
  await new Promise((r) => setTimeout(r, 1000));
4805
4946
  }
4806
4947
  async hover(filePath, line, character) {
4807
- const absPath = resolve3(filePath);
4948
+ const absPath = resolve4(filePath);
4808
4949
  await this.openFile(absPath);
4809
4950
  return this.send("textDocument/hover", {
4810
4951
  textDocument: { uri: `file://${absPath}` },
@@ -4812,7 +4953,7 @@ ${msg}`);
4812
4953
  });
4813
4954
  }
4814
4955
  async definition(filePath, line, character) {
4815
- const absPath = resolve3(filePath);
4956
+ const absPath = resolve4(filePath);
4816
4957
  await this.openFile(absPath);
4817
4958
  return this.send("textDocument/definition", {
4818
4959
  textDocument: { uri: `file://${absPath}` },
@@ -4820,7 +4961,7 @@ ${msg}`);
4820
4961
  });
4821
4962
  }
4822
4963
  async references(filePath, line, character, includeDeclaration = true) {
4823
- const absPath = resolve3(filePath);
4964
+ const absPath = resolve4(filePath);
4824
4965
  await this.openFile(absPath);
4825
4966
  return this.send("textDocument/references", {
4826
4967
  textDocument: { uri: `file://${absPath}` },
@@ -4829,7 +4970,7 @@ ${msg}`);
4829
4970
  });
4830
4971
  }
4831
4972
  async documentSymbols(filePath) {
4832
- const absPath = resolve3(filePath);
4973
+ const absPath = resolve4(filePath);
4833
4974
  await this.openFile(absPath);
4834
4975
  return this.send("textDocument/documentSymbol", {
4835
4976
  textDocument: { uri: `file://${absPath}` }
@@ -4839,7 +4980,7 @@ ${msg}`);
4839
4980
  return this.send("workspace/symbol", { query });
4840
4981
  }
4841
4982
  async diagnostics(filePath) {
4842
- const absPath = resolve3(filePath);
4983
+ const absPath = resolve4(filePath);
4843
4984
  const uri = `file://${absPath}`;
4844
4985
  await this.openFile(absPath);
4845
4986
  await new Promise((r) => setTimeout(r, 500));
@@ -4854,7 +4995,7 @@ ${msg}`);
4854
4995
  return { items: this.diagnosticsStore.get(uri) ?? [] };
4855
4996
  }
4856
4997
  async prepareRename(filePath, line, character) {
4857
- const absPath = resolve3(filePath);
4998
+ const absPath = resolve4(filePath);
4858
4999
  await this.openFile(absPath);
4859
5000
  return this.send("textDocument/prepareRename", {
4860
5001
  textDocument: { uri: `file://${absPath}` },
@@ -4862,7 +5003,7 @@ ${msg}`);
4862
5003
  });
4863
5004
  }
4864
5005
  async rename(filePath, line, character, newName) {
4865
- const absPath = resolve3(filePath);
5006
+ const absPath = resolve4(filePath);
4866
5007
  await this.openFile(absPath);
4867
5008
  return this.send("textDocument/rename", {
4868
5009
  textDocument: { uri: `file://${absPath}` },
@@ -4871,7 +5012,7 @@ ${msg}`);
4871
5012
  });
4872
5013
  }
4873
5014
  async codeAction(filePath, startLine, startChar, endLine, endChar, only) {
4874
- const absPath = resolve3(filePath);
5015
+ const absPath = resolve4(filePath);
4875
5016
  await this.openFile(absPath);
4876
5017
  return this.send("textDocument/codeAction", {
4877
5018
  textDocument: { uri: `file://${absPath}` },
@@ -4903,26 +5044,26 @@ ${msg}`);
4903
5044
  }
4904
5045
  }
4905
5046
  // src/tools/lsp/utils.ts
4906
- import { extname as extname2, resolve as resolve4 } from "path";
4907
- import { existsSync as existsSync18, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
5047
+ import { extname as extname2, resolve as resolve5 } from "path";
5048
+ import { existsSync as existsSync20, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
4908
5049
  function findWorkspaceRoot(filePath) {
4909
- let dir = resolve4(filePath);
4910
- if (!existsSync18(dir) || !__require("fs").statSync(dir).isDirectory()) {
5050
+ let dir = resolve5(filePath);
5051
+ if (!existsSync20(dir) || !__require("fs").statSync(dir).isDirectory()) {
4911
5052
  dir = __require("path").dirname(dir);
4912
5053
  }
4913
5054
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
4914
5055
  while (dir !== "/") {
4915
5056
  for (const marker of markers) {
4916
- if (existsSync18(__require("path").join(dir, marker))) {
5057
+ if (existsSync20(__require("path").join(dir, marker))) {
4917
5058
  return dir;
4918
5059
  }
4919
5060
  }
4920
5061
  dir = __require("path").dirname(dir);
4921
5062
  }
4922
- return __require("path").dirname(resolve4(filePath));
5063
+ return __require("path").dirname(resolve5(filePath));
4923
5064
  }
4924
5065
  async function withLspClient(filePath, fn) {
4925
- const absPath = resolve4(filePath);
5066
+ const absPath = resolve5(filePath);
4926
5067
  const ext = extname2(absPath);
4927
5068
  const server = findServerForExtension(ext);
4928
5069
  if (!server) {
@@ -5071,7 +5212,7 @@ function formatCodeActions(actions) {
5071
5212
  }
5072
5213
  function applyTextEditsToFile(filePath, edits) {
5073
5214
  try {
5074
- let content = readFileSync11(filePath, "utf-8");
5215
+ let content = readFileSync13(filePath, "utf-8");
5075
5216
  const lines = content.split(`
5076
5217
  `);
5077
5218
  const sortedEdits = [...edits].sort((a, b) => {
@@ -5096,7 +5237,7 @@ function applyTextEditsToFile(filePath, edits) {
5096
5237
  `));
5097
5238
  }
5098
5239
  }
5099
- writeFileSync5(filePath, lines.join(`
5240
+ writeFileSync6(filePath, lines.join(`
5100
5241
  `), "utf-8");
5101
5242
  return { success: true, editCount: edits.length };
5102
5243
  } catch (err) {
@@ -5127,7 +5268,7 @@ function applyWorkspaceEdit(edit) {
5127
5268
  if (change.kind === "create") {
5128
5269
  try {
5129
5270
  const filePath = change.uri.replace("file://", "");
5130
- writeFileSync5(filePath, "", "utf-8");
5271
+ writeFileSync6(filePath, "", "utf-8");
5131
5272
  result.filesModified.push(filePath);
5132
5273
  } catch (err) {
5133
5274
  result.success = false;
@@ -5137,8 +5278,8 @@ function applyWorkspaceEdit(edit) {
5137
5278
  try {
5138
5279
  const oldPath = change.oldUri.replace("file://", "");
5139
5280
  const newPath = change.newUri.replace("file://", "");
5140
- const content = readFileSync11(oldPath, "utf-8");
5141
- writeFileSync5(newPath, content, "utf-8");
5281
+ const content = readFileSync13(oldPath, "utf-8");
5282
+ writeFileSync6(newPath, content, "utf-8");
5142
5283
  __require("fs").unlinkSync(oldPath);
5143
5284
  result.filesModified.push(newPath);
5144
5285
  } catch (err) {
@@ -17838,13 +17979,13 @@ var lsp_code_action_resolve = tool({
17838
17979
  });
17839
17980
  // src/tools/ast-grep/constants.ts
17840
17981
  import { createRequire as createRequire4 } from "module";
17841
- import { dirname as dirname3, join as join22 } from "path";
17842
- import { existsSync as existsSync20, statSync as statSync3 } from "fs";
17982
+ import { dirname as dirname4, join as join25 } from "path";
17983
+ import { existsSync as existsSync22, statSync as statSync3 } from "fs";
17843
17984
 
17844
17985
  // src/tools/ast-grep/downloader.ts
17845
17986
  var {spawn: spawn5 } = globalThis.Bun;
17846
- import { existsSync as existsSync19, mkdirSync as mkdirSync6, chmodSync as chmodSync2, unlinkSync as unlinkSync5 } from "fs";
17847
- import { join as join21 } from "path";
17987
+ import { existsSync as existsSync21, mkdirSync as mkdirSync7, chmodSync as chmodSync2, unlinkSync as unlinkSync6 } from "fs";
17988
+ import { join as join24 } from "path";
17848
17989
  import { homedir as homedir12 } from "os";
17849
17990
  import { createRequire as createRequire3 } from "module";
17850
17991
  var REPO2 = "ast-grep/ast-grep";
@@ -17870,19 +18011,19 @@ var PLATFORM_MAP2 = {
17870
18011
  function getCacheDir2() {
17871
18012
  if (process.platform === "win32") {
17872
18013
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
17873
- const base2 = localAppData || join21(homedir12(), "AppData", "Local");
17874
- return join21(base2, "oh-my-opencode", "bin");
18014
+ const base2 = localAppData || join24(homedir12(), "AppData", "Local");
18015
+ return join24(base2, "oh-my-opencode", "bin");
17875
18016
  }
17876
18017
  const xdgCache2 = process.env.XDG_CACHE_HOME;
17877
- const base = xdgCache2 || join21(homedir12(), ".cache");
17878
- return join21(base, "oh-my-opencode", "bin");
18018
+ const base = xdgCache2 || join24(homedir12(), ".cache");
18019
+ return join24(base, "oh-my-opencode", "bin");
17879
18020
  }
17880
18021
  function getBinaryName3() {
17881
18022
  return process.platform === "win32" ? "sg.exe" : "sg";
17882
18023
  }
17883
18024
  function getCachedBinaryPath2() {
17884
- const binaryPath = join21(getCacheDir2(), getBinaryName3());
17885
- return existsSync19(binaryPath) ? binaryPath : null;
18025
+ const binaryPath = join24(getCacheDir2(), getBinaryName3());
18026
+ return existsSync21(binaryPath) ? binaryPath : null;
17886
18027
  }
17887
18028
  async function extractZip2(archivePath, destDir) {
17888
18029
  const proc = process.platform === "win32" ? spawn5([
@@ -17908,8 +18049,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
17908
18049
  }
17909
18050
  const cacheDir = getCacheDir2();
17910
18051
  const binaryName = getBinaryName3();
17911
- const binaryPath = join21(cacheDir, binaryName);
17912
- if (existsSync19(binaryPath)) {
18052
+ const binaryPath = join24(cacheDir, binaryName);
18053
+ if (existsSync21(binaryPath)) {
17913
18054
  return binaryPath;
17914
18055
  }
17915
18056
  const { arch, os: os3 } = platformInfo;
@@ -17917,21 +18058,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
17917
18058
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
17918
18059
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
17919
18060
  try {
17920
- if (!existsSync19(cacheDir)) {
17921
- mkdirSync6(cacheDir, { recursive: true });
18061
+ if (!existsSync21(cacheDir)) {
18062
+ mkdirSync7(cacheDir, { recursive: true });
17922
18063
  }
17923
18064
  const response = await fetch(downloadUrl, { redirect: "follow" });
17924
18065
  if (!response.ok) {
17925
18066
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
17926
18067
  }
17927
- const archivePath = join21(cacheDir, assetName);
18068
+ const archivePath = join24(cacheDir, assetName);
17928
18069
  const arrayBuffer = await response.arrayBuffer();
17929
18070
  await Bun.write(archivePath, arrayBuffer);
17930
18071
  await extractZip2(archivePath, cacheDir);
17931
- if (existsSync19(archivePath)) {
17932
- unlinkSync5(archivePath);
18072
+ if (existsSync21(archivePath)) {
18073
+ unlinkSync6(archivePath);
17933
18074
  }
17934
- if (process.platform !== "win32" && existsSync19(binaryPath)) {
18075
+ if (process.platform !== "win32" && existsSync21(binaryPath)) {
17935
18076
  chmodSync2(binaryPath, 493);
17936
18077
  }
17937
18078
  console.log(`[oh-my-opencode] ast-grep binary ready.`);
@@ -17981,9 +18122,9 @@ function findSgCliPathSync() {
17981
18122
  try {
17982
18123
  const require2 = createRequire4(import.meta.url);
17983
18124
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
17984
- const cliDir = dirname3(cliPkgPath);
17985
- const sgPath = join22(cliDir, binaryName);
17986
- if (existsSync20(sgPath) && isValidBinary(sgPath)) {
18125
+ const cliDir = dirname4(cliPkgPath);
18126
+ const sgPath = join25(cliDir, binaryName);
18127
+ if (existsSync22(sgPath) && isValidBinary(sgPath)) {
17987
18128
  return sgPath;
17988
18129
  }
17989
18130
  } catch {}
@@ -17992,10 +18133,10 @@ function findSgCliPathSync() {
17992
18133
  try {
17993
18134
  const require2 = createRequire4(import.meta.url);
17994
18135
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
17995
- const pkgDir = dirname3(pkgPath);
18136
+ const pkgDir = dirname4(pkgPath);
17996
18137
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
17997
- const binaryPath = join22(pkgDir, astGrepName);
17998
- if (existsSync20(binaryPath) && isValidBinary(binaryPath)) {
18138
+ const binaryPath = join25(pkgDir, astGrepName);
18139
+ if (existsSync22(binaryPath) && isValidBinary(binaryPath)) {
17999
18140
  return binaryPath;
18000
18141
  }
18001
18142
  } catch {}
@@ -18003,7 +18144,7 @@ function findSgCliPathSync() {
18003
18144
  if (process.platform === "darwin") {
18004
18145
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
18005
18146
  for (const path3 of homebrewPaths) {
18006
- if (existsSync20(path3) && isValidBinary(path3)) {
18147
+ if (existsSync22(path3) && isValidBinary(path3)) {
18007
18148
  return path3;
18008
18149
  }
18009
18150
  }
@@ -18059,11 +18200,11 @@ var DEFAULT_MAX_MATCHES = 500;
18059
18200
 
18060
18201
  // src/tools/ast-grep/cli.ts
18061
18202
  var {spawn: spawn6 } = globalThis.Bun;
18062
- import { existsSync as existsSync21 } from "fs";
18203
+ import { existsSync as existsSync23 } from "fs";
18063
18204
  var resolvedCliPath3 = null;
18064
18205
  var initPromise2 = null;
18065
18206
  async function getAstGrepPath() {
18066
- if (resolvedCliPath3 !== null && existsSync21(resolvedCliPath3)) {
18207
+ if (resolvedCliPath3 !== null && existsSync23(resolvedCliPath3)) {
18067
18208
  return resolvedCliPath3;
18068
18209
  }
18069
18210
  if (initPromise2) {
@@ -18071,7 +18212,7 @@ async function getAstGrepPath() {
18071
18212
  }
18072
18213
  initPromise2 = (async () => {
18073
18214
  const syncPath = findSgCliPathSync();
18074
- if (syncPath && existsSync21(syncPath)) {
18215
+ if (syncPath && existsSync23(syncPath)) {
18075
18216
  resolvedCliPath3 = syncPath;
18076
18217
  setSgCliPath(syncPath);
18077
18218
  return syncPath;
@@ -18105,7 +18246,7 @@ async function runSg(options) {
18105
18246
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
18106
18247
  args.push(...paths);
18107
18248
  let cliPath = getSgCliPath();
18108
- if (!existsSync21(cliPath) && cliPath !== "sg") {
18249
+ if (!existsSync23(cliPath) && cliPath !== "sg") {
18109
18250
  const downloadedPath = await getAstGrepPath();
18110
18251
  if (downloadedPath) {
18111
18252
  cliPath = downloadedPath;
@@ -18369,8 +18510,8 @@ var ast_grep_replace = tool({
18369
18510
  var {spawn: spawn7 } = globalThis.Bun;
18370
18511
 
18371
18512
  // src/tools/grep/constants.ts
18372
- import { existsSync as existsSync22 } from "fs";
18373
- import { join as join23, dirname as dirname4 } from "path";
18513
+ import { existsSync as existsSync24 } from "fs";
18514
+ import { join as join26, dirname as dirname5 } from "path";
18374
18515
  import { spawnSync } from "child_process";
18375
18516
  var cachedCli = null;
18376
18517
  function findExecutable(name) {
@@ -18387,17 +18528,17 @@ function findExecutable(name) {
18387
18528
  }
18388
18529
  function getOpenCodeBundledRg() {
18389
18530
  const execPath = process.execPath;
18390
- const execDir = dirname4(execPath);
18531
+ const execDir = dirname5(execPath);
18391
18532
  const isWindows = process.platform === "win32";
18392
18533
  const rgName = isWindows ? "rg.exe" : "rg";
18393
18534
  const candidates = [
18394
- join23(execDir, rgName),
18395
- join23(execDir, "bin", rgName),
18396
- join23(execDir, "..", "bin", rgName),
18397
- join23(execDir, "..", "libexec", rgName)
18535
+ join26(execDir, rgName),
18536
+ join26(execDir, "bin", rgName),
18537
+ join26(execDir, "..", "bin", rgName),
18538
+ join26(execDir, "..", "libexec", rgName)
18398
18539
  ];
18399
18540
  for (const candidate of candidates) {
18400
- if (existsSync22(candidate)) {
18541
+ if (existsSync24(candidate)) {
18401
18542
  return candidate;
18402
18543
  }
18403
18544
  }
@@ -18795,11 +18936,11 @@ var glob = tool({
18795
18936
  }
18796
18937
  });
18797
18938
  // src/tools/slashcommand/tools.ts
18798
- import { existsSync as existsSync23, readdirSync as readdirSync6, readFileSync as readFileSync12 } from "fs";
18939
+ import { existsSync as existsSync25, readdirSync as readdirSync6, readFileSync as readFileSync14 } from "fs";
18799
18940
  import { homedir as homedir13 } from "os";
18800
- import { join as join24, basename as basename3, dirname as dirname5 } from "path";
18941
+ import { join as join27, basename as basename3, dirname as dirname6 } from "path";
18801
18942
  function discoverCommandsFromDir(commandsDir, scope) {
18802
- if (!existsSync23(commandsDir)) {
18943
+ if (!existsSync25(commandsDir)) {
18803
18944
  return [];
18804
18945
  }
18805
18946
  const entries = readdirSync6(commandsDir, { withFileTypes: true });
@@ -18811,10 +18952,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
18811
18952
  continue;
18812
18953
  if (!entry.isFile())
18813
18954
  continue;
18814
- const commandPath = join24(commandsDir, entry.name);
18955
+ const commandPath = join27(commandsDir, entry.name);
18815
18956
  const commandName = basename3(entry.name, ".md");
18816
18957
  try {
18817
- const content = readFileSync12(commandPath, "utf-8");
18958
+ const content = readFileSync14(commandPath, "utf-8");
18818
18959
  const { data, body } = parseFrontmatter(content);
18819
18960
  const metadata = {
18820
18961
  name: commandName,
@@ -18838,10 +18979,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
18838
18979
  return commands;
18839
18980
  }
18840
18981
  function discoverCommandsSync() {
18841
- const userCommandsDir = join24(homedir13(), ".claude", "commands");
18842
- const projectCommandsDir = join24(process.cwd(), ".claude", "commands");
18843
- const opencodeGlobalDir = join24(homedir13(), ".config", "opencode", "command");
18844
- const opencodeProjectDir = join24(process.cwd(), ".opencode", "command");
18982
+ const userCommandsDir = join27(homedir13(), ".claude", "commands");
18983
+ const projectCommandsDir = join27(process.cwd(), ".claude", "commands");
18984
+ const opencodeGlobalDir = join27(homedir13(), ".config", "opencode", "command");
18985
+ const opencodeProjectDir = join27(process.cwd(), ".opencode", "command");
18845
18986
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
18846
18987
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
18847
18988
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -18884,7 +19025,7 @@ async function formatLoadedCommand(cmd) {
18884
19025
  `);
18885
19026
  sections.push(`## Command Instructions
18886
19027
  `);
18887
- const commandDir = dirname5(cmd.path);
19028
+ const commandDir = dirname6(cmd.path);
18888
19029
  const withFileRefs = await resolveFileReferencesInText(cmd.content, commandDir);
18889
19030
  const resolvedContent = await resolveCommandsInText(withFileRefs);
18890
19031
  sections.push(resolvedContent.trim());
@@ -18964,12 +19105,29 @@ Provide a command name to execute.`;
18964
19105
  Try a different command name.`;
18965
19106
  }
18966
19107
  });
19108
+ // src/tools/skill/types.ts
19109
+ var SkillFrontmatterSchema = exports_external.object({
19110
+ name: exports_external.string().regex(/^[a-z0-9-]+$/, "Name must be lowercase alphanumeric with hyphens only").min(1, "Name cannot be empty"),
19111
+ description: exports_external.string().min(20, "Description must be at least 20 characters for discoverability"),
19112
+ license: exports_external.string().optional(),
19113
+ "allowed-tools": exports_external.array(exports_external.string()).optional(),
19114
+ metadata: exports_external.record(exports_external.string(), exports_external.string()).optional()
19115
+ });
18967
19116
  // src/tools/skill/tools.ts
18968
- import { existsSync as existsSync24, readdirSync as readdirSync7, statSync as statSync4, readlinkSync as readlinkSync2, readFileSync as readFileSync13 } from "fs";
19117
+ import { existsSync as existsSync26, readdirSync as readdirSync7, statSync as statSync4, readlinkSync as readlinkSync2, readFileSync as readFileSync15 } from "fs";
18969
19118
  import { homedir as homedir14 } from "os";
18970
- import { join as join25, resolve as resolve5, basename as basename4 } from "path";
19119
+ import { join as join28, resolve as resolve6, basename as basename4 } from "path";
19120
+ function parseSkillFrontmatter(data) {
19121
+ return {
19122
+ name: typeof data.name === "string" ? data.name : "",
19123
+ description: typeof data.description === "string" ? data.description : "",
19124
+ license: typeof data.license === "string" ? data.license : undefined,
19125
+ "allowed-tools": Array.isArray(data["allowed-tools"]) ? data["allowed-tools"] : undefined,
19126
+ metadata: typeof data.metadata === "object" && data.metadata !== null ? data.metadata : undefined
19127
+ };
19128
+ }
18971
19129
  function discoverSkillsFromDir(skillsDir, scope) {
18972
- if (!existsSync24(skillsDir)) {
19130
+ if (!existsSync26(skillsDir)) {
18973
19131
  return [];
18974
19132
  }
18975
19133
  const entries = readdirSync7(skillsDir, { withFileTypes: true });
@@ -18977,22 +19135,22 @@ function discoverSkillsFromDir(skillsDir, scope) {
18977
19135
  for (const entry of entries) {
18978
19136
  if (entry.name.startsWith("."))
18979
19137
  continue;
18980
- const skillPath = join25(skillsDir, entry.name);
19138
+ const skillPath = join28(skillsDir, entry.name);
18981
19139
  if (entry.isDirectory() || entry.isSymbolicLink()) {
18982
19140
  let resolvedPath = skillPath;
18983
19141
  try {
18984
19142
  const stats = statSync4(skillPath, { throwIfNoEntry: false });
18985
19143
  if (stats?.isSymbolicLink()) {
18986
- resolvedPath = resolve5(skillPath, "..", readlinkSync2(skillPath));
19144
+ resolvedPath = resolve6(skillPath, "..", readlinkSync2(skillPath));
18987
19145
  }
18988
19146
  } catch {
18989
19147
  continue;
18990
19148
  }
18991
- const skillMdPath = join25(resolvedPath, "SKILL.md");
18992
- if (!existsSync24(skillMdPath))
19149
+ const skillMdPath = join28(resolvedPath, "SKILL.md");
19150
+ if (!existsSync26(skillMdPath))
18993
19151
  continue;
18994
19152
  try {
18995
- const content = readFileSync13(skillMdPath, "utf-8");
19153
+ const content = readFileSync15(skillMdPath, "utf-8");
18996
19154
  const { data } = parseFrontmatter(content);
18997
19155
  skills.push({
18998
19156
  name: data.name || entry.name,
@@ -19007,8 +19165,8 @@ function discoverSkillsFromDir(skillsDir, scope) {
19007
19165
  return skills;
19008
19166
  }
19009
19167
  function discoverSkillsSync() {
19010
- const userSkillsDir = join25(homedir14(), ".claude", "skills");
19011
- const projectSkillsDir = join25(process.cwd(), ".claude", "skills");
19168
+ const userSkillsDir = join28(homedir14(), ".claude", "skills");
19169
+ const projectSkillsDir = join28(process.cwd(), ".claude", "skills");
19012
19170
  const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
19013
19171
  const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
19014
19172
  return [...projectSkills, ...userSkills];
@@ -19020,7 +19178,7 @@ function resolveSymlink(skillPath) {
19020
19178
  try {
19021
19179
  const stats = statSync4(skillPath, { throwIfNoEntry: false });
19022
19180
  if (stats?.isSymbolicLink()) {
19023
- return resolve5(skillPath, "..", readlinkSync2(skillPath));
19181
+ return resolve6(skillPath, "..", readlinkSync2(skillPath));
19024
19182
  }
19025
19183
  return skillPath;
19026
19184
  } catch {
@@ -19029,28 +19187,32 @@ function resolveSymlink(skillPath) {
19029
19187
  }
19030
19188
  async function parseSkillMd(skillPath) {
19031
19189
  const resolvedPath = resolveSymlink(skillPath);
19032
- const skillMdPath = join25(resolvedPath, "SKILL.md");
19033
- if (!existsSync24(skillMdPath)) {
19190
+ const skillMdPath = join28(resolvedPath, "SKILL.md");
19191
+ if (!existsSync26(skillMdPath)) {
19034
19192
  return null;
19035
19193
  }
19036
19194
  try {
19037
- let content = readFileSync13(skillMdPath, "utf-8");
19195
+ let content = readFileSync15(skillMdPath, "utf-8");
19038
19196
  content = await resolveCommandsInText(content);
19039
19197
  const { data, body } = parseFrontmatter(content);
19198
+ const frontmatter2 = parseSkillFrontmatter(data);
19040
19199
  const metadata = {
19041
- name: data.name || basename4(skillPath),
19042
- description: data.description || "",
19043
- license: data.license
19200
+ name: frontmatter2.name || basename4(skillPath),
19201
+ description: frontmatter2.description,
19202
+ license: frontmatter2.license,
19203
+ allowedTools: frontmatter2["allowed-tools"],
19204
+ metadata: frontmatter2.metadata
19044
19205
  };
19045
- const referencesDir = join25(resolvedPath, "references");
19046
- const scriptsDir = join25(resolvedPath, "scripts");
19047
- const assetsDir = join25(resolvedPath, "assets");
19048
- const references = existsSync24(referencesDir) ? readdirSync7(referencesDir).filter((f) => !f.startsWith(".")) : [];
19049
- const scripts = existsSync24(scriptsDir) ? readdirSync7(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
19050
- const assets = existsSync24(assetsDir) ? readdirSync7(assetsDir).filter((f) => !f.startsWith(".")) : [];
19206
+ const referencesDir = join28(resolvedPath, "references");
19207
+ const scriptsDir = join28(resolvedPath, "scripts");
19208
+ const assetsDir = join28(resolvedPath, "assets");
19209
+ const references = existsSync26(referencesDir) ? readdirSync7(referencesDir).filter((f) => !f.startsWith(".")) : [];
19210
+ const scripts = existsSync26(scriptsDir) ? readdirSync7(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
19211
+ const assets = existsSync26(assetsDir) ? readdirSync7(assetsDir).filter((f) => !f.startsWith(".")) : [];
19051
19212
  return {
19052
19213
  name: metadata.name,
19053
19214
  path: resolvedPath,
19215
+ basePath: resolvedPath,
19054
19216
  metadata,
19055
19217
  content: body,
19056
19218
  references,
@@ -19062,7 +19224,7 @@ async function parseSkillMd(skillPath) {
19062
19224
  }
19063
19225
  }
19064
19226
  async function discoverSkillsFromDirAsync(skillsDir) {
19065
- if (!existsSync24(skillsDir)) {
19227
+ if (!existsSync26(skillsDir)) {
19066
19228
  return [];
19067
19229
  }
19068
19230
  const entries = readdirSync7(skillsDir, { withFileTypes: true });
@@ -19070,7 +19232,7 @@ async function discoverSkillsFromDirAsync(skillsDir) {
19070
19232
  for (const entry of entries) {
19071
19233
  if (entry.name.startsWith("."))
19072
19234
  continue;
19073
- const skillPath = join25(skillsDir, entry.name);
19235
+ const skillPath = join28(skillsDir, entry.name);
19074
19236
  if (entry.isDirectory() || entry.isSymbolicLink()) {
19075
19237
  const skillInfo = await parseSkillMd(skillPath);
19076
19238
  if (skillInfo) {
@@ -19081,8 +19243,8 @@ async function discoverSkillsFromDirAsync(skillsDir) {
19081
19243
  return skills;
19082
19244
  }
19083
19245
  async function discoverSkills() {
19084
- const userSkillsDir = join25(homedir14(), ".claude", "skills");
19085
- const projectSkillsDir = join25(process.cwd(), ".claude", "skills");
19246
+ const userSkillsDir = join28(homedir14(), ".claude", "skills");
19247
+ const projectSkillsDir = join28(process.cwd(), ".claude", "skills");
19086
19248
  const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
19087
19249
  const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
19088
19250
  return [...projectSkills, ...userSkills];
@@ -19111,9 +19273,9 @@ async function loadSkillWithReferences(skill, includeRefs) {
19111
19273
  const referencesLoaded = [];
19112
19274
  if (includeRefs && skill.references.length > 0) {
19113
19275
  for (const ref of skill.references) {
19114
- const refPath = join25(skill.path, "references", ref);
19276
+ const refPath = join28(skill.path, "references", ref);
19115
19277
  try {
19116
- let content = readFileSync13(refPath, "utf-8");
19278
+ let content = readFileSync15(refPath, "utf-8");
19117
19279
  content = await resolveCommandsInText(content);
19118
19280
  referencesLoaded.push({ path: ref, content });
19119
19281
  } catch {}
@@ -19122,6 +19284,7 @@ async function loadSkillWithReferences(skill, includeRefs) {
19122
19284
  return {
19123
19285
  name: skill.name,
19124
19286
  metadata: skill.metadata,
19287
+ basePath: skill.basePath,
19125
19288
  body: skill.content,
19126
19289
  referencesLoaded
19127
19290
  };
@@ -19144,62 +19307,34 @@ function formatLoadedSkills(loadedSkills) {
19144
19307
  if (loadedSkills.length === 0) {
19145
19308
  return "No skills loaded.";
19146
19309
  }
19147
- const sections = [`# Loaded Skills
19148
- `];
19149
- for (const skill of loadedSkills) {
19150
- sections.push(`## ${skill.metadata.name}
19151
- `);
19152
- sections.push(`**Description**: ${skill.metadata.description || "(no description)"}
19153
- `);
19154
- sections.push(`### Skill Instructions
19155
- `);
19156
- sections.push(skill.body.trim());
19157
- if (skill.referencesLoaded.length > 0) {
19158
- sections.push(`
19310
+ const skill = loadedSkills[0];
19311
+ const sections = [];
19312
+ sections.push(`Base directory for this skill: ${skill.basePath}/`);
19313
+ sections.push("");
19314
+ sections.push(skill.body.trim());
19315
+ if (skill.referencesLoaded.length > 0) {
19316
+ sections.push(`
19317
+ ---
19159
19318
  ### Loaded References
19160
19319
  `);
19161
- for (const ref of skill.referencesLoaded) {
19162
- sections.push(`#### ${ref.path}
19320
+ for (const ref of skill.referencesLoaded) {
19321
+ sections.push(`#### ${ref.path}
19163
19322
  `);
19164
- sections.push("```");
19165
- sections.push(ref.content.trim());
19166
- sections.push("```\n");
19167
- }
19323
+ sections.push("```");
19324
+ sections.push(ref.content.trim());
19325
+ sections.push("```\n");
19168
19326
  }
19169
- sections.push(`
19170
- ---
19171
- `);
19172
19327
  }
19173
- const skillNames = loadedSkills.map((s) => s.metadata.name).join(", ");
19174
- sections.push(`**Skills loaded**: ${skillNames}`);
19175
- sections.push(`**Total**: ${loadedSkills.length} skill(s)`);
19176
19328
  sections.push(`
19177
- Please confirm these skills match your needs before proceeding.`);
19329
+ ---
19330
+ **Launched skill**: ${skill.metadata.name}`);
19178
19331
  return sections.join(`
19179
19332
  `);
19180
19333
  }
19181
19334
  var skill = tool({
19182
19335
  description: `Execute a skill within the main conversation.
19183
19336
 
19184
- When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
19185
-
19186
- How to use skills:
19187
- - Invoke skills using this tool with the skill name only (no arguments)
19188
- - When you invoke a skill, the skill's prompt will expand and provide detailed instructions on how to complete the task
19189
-
19190
- Important:
19191
- - Only use skills listed in Available Skills below
19192
- - Do not invoke a skill that is already running
19193
-
19194
- Skills are loaded from:
19195
- - ~/.claude/skills/ (user scope - global skills)
19196
- - ./.claude/skills/ (project scope - project-specific skills)
19197
-
19198
- Each skill contains:
19199
- - SKILL.md: Main instructions with YAML frontmatter (name, description)
19200
- - references/: Documentation files loaded into context as needed
19201
- - scripts/: Executable code for deterministic operations
19202
- - assets/: Files used in output (templates, icons, etc.)
19337
+ When you invoke a skill, the skill's prompt will expand and provide detailed instructions on how to complete the task.
19203
19338
 
19204
19339
  Available Skills:
19205
19340
  ${skillListForDescription}`,
@@ -19324,26 +19459,62 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
19324
19459
  // src/index.ts
19325
19460
  import * as fs4 from "fs";
19326
19461
  import * as path3 from "path";
19462
+ import * as os3 from "os";
19463
+ function loadConfigFromPath2(configPath) {
19464
+ try {
19465
+ if (fs4.existsSync(configPath)) {
19466
+ const content = fs4.readFileSync(configPath, "utf-8");
19467
+ const rawConfig = JSON.parse(content);
19468
+ const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
19469
+ if (!result.success) {
19470
+ log(`Config validation error in ${configPath}:`, result.error.issues);
19471
+ return null;
19472
+ }
19473
+ log(`Config loaded from ${configPath}`, { agents: result.data.agents });
19474
+ return result.data;
19475
+ }
19476
+ } catch (err) {
19477
+ log(`Error loading config from ${configPath}:`, err);
19478
+ }
19479
+ return null;
19480
+ }
19481
+ function mergeConfigs(base, override) {
19482
+ return {
19483
+ ...base,
19484
+ ...override,
19485
+ agents: override.agents !== undefined ? { ...base.agents ?? {}, ...override.agents } : base.agents,
19486
+ disabled_agents: [
19487
+ ...new Set([...base.disabled_agents ?? [], ...override.disabled_agents ?? []])
19488
+ ],
19489
+ disabled_mcps: [
19490
+ ...new Set([...base.disabled_mcps ?? [], ...override.disabled_mcps ?? []])
19491
+ ]
19492
+ };
19493
+ }
19327
19494
  function loadPluginConfig(directory) {
19328
- const configPaths = [
19329
- path3.join(directory, "oh-my-opencode.json"),
19330
- path3.join(directory, ".oh-my-opencode.json")
19495
+ const userConfigPaths = [
19496
+ path3.join(os3.homedir(), ".config", "opencode", "oh-my-opencode.json")
19331
19497
  ];
19332
- for (const configPath of configPaths) {
19333
- try {
19334
- if (fs4.existsSync(configPath)) {
19335
- const content = fs4.readFileSync(configPath, "utf-8");
19336
- const rawConfig = JSON.parse(content);
19337
- const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
19338
- if (!result.success) {
19339
- log(`Config validation error in ${configPath}:`, result.error.issues);
19340
- return {};
19341
- }
19342
- return result.data;
19343
- }
19344
- } catch {}
19498
+ const projectConfigPaths = [
19499
+ path3.join(directory, ".opencode", "oh-my-opencode.json")
19500
+ ];
19501
+ let config3 = {};
19502
+ for (const configPath of userConfigPaths) {
19503
+ const userConfig = loadConfigFromPath2(configPath);
19504
+ if (userConfig) {
19505
+ config3 = userConfig;
19506
+ break;
19507
+ }
19508
+ }
19509
+ for (const configPath of projectConfigPaths) {
19510
+ const projectConfig = loadConfigFromPath2(configPath);
19511
+ if (projectConfig) {
19512
+ config3 = mergeConfigs(config3, projectConfig);
19513
+ break;
19514
+ }
19345
19515
  }
19346
- return {};
19516
+ log("Final merged config", { agents: config3.agents, disabled_agents: config3.disabled_agents, disabled_mcps: config3.disabled_mcps });
19517
+ return config3;
19347
19518
  }
19348
19519
  var OhMyOpenCodePlugin = async (ctx) => {
19349
19520
  const pluginConfig = loadPluginConfig(ctx.directory);
@@ -19353,6 +19524,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
19353
19524
  const commentChecker = createCommentCheckerHooks();
19354
19525
  const grepOutputTruncator = createGrepOutputTruncatorHook(ctx);
19355
19526
  const directoryAgentsInjector = createDirectoryAgentsInjectorHook(ctx);
19527
+ const directoryReadmeInjector = createDirectoryReadmeInjectorHook(ctx);
19356
19528
  const emptyTaskResponseDetector = createEmptyTaskResponseDetectorHook(ctx);
19357
19529
  const thinkMode = createThinkModeHook();
19358
19530
  const claudeCodeHooks = createClaudeCodeHooksHook(ctx, {});
@@ -19404,6 +19576,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
19404
19576
  await todoContinuationEnforcer(input);
19405
19577
  await contextWindowMonitor.event(input);
19406
19578
  await directoryAgentsInjector.event(input);
19579
+ await directoryReadmeInjector.event(input);
19407
19580
  await thinkMode.event(input);
19408
19581
  await anthropicAutoCompact.event(input);
19409
19582
  const { event } = input;
@@ -19503,6 +19676,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
19503
19676
  await contextWindowMonitor["tool.execute.after"](input, output);
19504
19677
  await commentChecker["tool.execute.after"](input, output);
19505
19678
  await directoryAgentsInjector["tool.execute.after"](input, output);
19679
+ await directoryReadmeInjector["tool.execute.after"](input, output);
19506
19680
  await emptyTaskResponseDetector["tool.execute.after"](input, output);
19507
19681
  if (input.sessionID === getMainSessionID()) {
19508
19682
  updateTerminalTitle({