oh-my-opencode 2.7.1 → 2.7.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/cli/index.js CHANGED
@@ -2244,7 +2244,7 @@ var require_picocolors = __commonJS((exports, module) => {
2244
2244
  var require_package = __commonJS((exports, module) => {
2245
2245
  module.exports = {
2246
2246
  name: "oh-my-opencode",
2247
- version: "2.7.0",
2247
+ version: "2.7.1",
2248
2248
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2249
2249
  main: "dist/index.js",
2250
2250
  types: "dist/index.d.ts",
@@ -3804,6 +3804,7 @@ var OPENCODE_JSON = join2(OPENCODE_CONFIG_DIR, "opencode.json");
3804
3804
  var OPENCODE_JSONC = join2(OPENCODE_CONFIG_DIR, "opencode.jsonc");
3805
3805
  var OPENCODE_PACKAGE_JSON = join2(OPENCODE_CONFIG_DIR, "package.json");
3806
3806
  var OMO_CONFIG = join2(OPENCODE_CONFIG_DIR, "oh-my-opencode.json");
3807
+ var OPENCODE_BINARIES = ["opencode", "opencode-desktop"];
3807
3808
  var CHATGPT_HOTFIX_REPO = "code-yeongyu/opencode-openai-codex-auth#fix/orphaned-function-call-output-with-tools";
3808
3809
  async function fetchLatestVersion(packageName) {
3809
3810
  try {
@@ -3957,30 +3958,31 @@ function writeOmoConfig(installConfig) {
3957
3958
  return { success: false, configPath: OMO_CONFIG, error: String(err) };
3958
3959
  }
3959
3960
  }
3960
- async function isOpenCodeInstalled() {
3961
- try {
3962
- const proc = Bun.spawn(["opencode", "--version"], {
3963
- stdout: "pipe",
3964
- stderr: "pipe"
3965
- });
3966
- await proc.exited;
3967
- return proc.exitCode === 0;
3968
- } catch {
3969
- return false;
3961
+ async function findOpenCodeBinaryWithVersion() {
3962
+ for (const binary of OPENCODE_BINARIES) {
3963
+ try {
3964
+ const proc = Bun.spawn([binary, "--version"], {
3965
+ stdout: "pipe",
3966
+ stderr: "pipe"
3967
+ });
3968
+ const output = await new Response(proc.stdout).text();
3969
+ await proc.exited;
3970
+ if (proc.exitCode === 0) {
3971
+ return { binary, version: output.trim() };
3972
+ }
3973
+ } catch {
3974
+ continue;
3975
+ }
3970
3976
  }
3977
+ return null;
3978
+ }
3979
+ async function isOpenCodeInstalled() {
3980
+ const result = await findOpenCodeBinaryWithVersion();
3981
+ return result !== null;
3971
3982
  }
3972
3983
  async function getOpenCodeVersion() {
3973
- try {
3974
- const proc = Bun.spawn(["opencode", "--version"], {
3975
- stdout: "pipe",
3976
- stderr: "pipe"
3977
- });
3978
- const output = await new Response(proc.stdout).text();
3979
- await proc.exited;
3980
- return proc.exitCode === 0 ? output.trim() : null;
3981
- } catch {
3982
- return null;
3983
- }
3984
+ const result = await findOpenCodeBinaryWithVersion();
3985
+ return result?.version ?? null;
3984
3986
  }
3985
3987
  async function addAuthPlugins(config) {
3986
3988
  ensureConfigDir();
package/dist/index.js CHANGED
@@ -4563,8 +4563,10 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
4563
4563
  return;
4564
4564
  log(`[${HOOK_NAME}] session.idle`, { sessionID });
4565
4565
  const mainSessionID2 = getMainSessionID();
4566
- if (mainSessionID2 && sessionID !== mainSessionID2) {
4567
- log(`[${HOOK_NAME}] Skipped: not main session`, { sessionID });
4566
+ const isMainSession = sessionID === mainSessionID2;
4567
+ const isBackgroundTaskSession = subagentSessions.has(sessionID);
4568
+ if (mainSessionID2 && !isMainSession && !isBackgroundTaskSession) {
4569
+ log(`[${HOOK_NAME}] Skipped: not main or background task session`, { sessionID });
4568
4570
  return;
4569
4571
  }
4570
4572
  const state2 = getState(sessionID);
@@ -14454,6 +14456,10 @@ function isServerInstalled(command) {
14454
14456
  if (command.length === 0)
14455
14457
  return false;
14456
14458
  const cmd = command[0];
14459
+ if (cmd.includes("/") || cmd.includes("\\")) {
14460
+ if (existsSync34(cmd))
14461
+ return true;
14462
+ }
14457
14463
  const isWindows2 = process.platform === "win32";
14458
14464
  const ext = isWindows2 ? ".exe" : "";
14459
14465
  const pathEnv = process.env.PATH || "";
@@ -14478,6 +14484,9 @@ function isServerInstalled(command) {
14478
14484
  return true;
14479
14485
  }
14480
14486
  }
14487
+ if (cmd === "bun" || cmd === "node") {
14488
+ return true;
14489
+ }
14481
14490
  return false;
14482
14491
  }
14483
14492
  function getAllServers() {
@@ -28566,7 +28575,7 @@ var ast_grep_replace = tool({
28566
28575
  }
28567
28576
  });
28568
28577
  // src/tools/grep/cli.ts
28569
- var {spawn: spawn8 } = globalThis.Bun;
28578
+ var {spawn: spawn9 } = globalThis.Bun;
28570
28579
 
28571
28580
  // src/tools/grep/constants.ts
28572
28581
  import { existsSync as existsSync40 } from "fs";
@@ -28576,6 +28585,31 @@ import { spawnSync } from "child_process";
28576
28585
  // src/tools/grep/downloader.ts
28577
28586
  import { existsSync as existsSync39, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync14 } from "fs";
28578
28587
  import { join as join47 } from "path";
28588
+ var {spawn: spawn8 } = globalThis.Bun;
28589
+ function findFileRecursive(dir, filename) {
28590
+ try {
28591
+ const entries = readdirSync14(dir, { withFileTypes: true, recursive: true });
28592
+ for (const entry of entries) {
28593
+ if (entry.isFile() && entry.name === filename) {
28594
+ return join47(entry.parentPath ?? dir, entry.name);
28595
+ }
28596
+ }
28597
+ } catch {
28598
+ return null;
28599
+ }
28600
+ return null;
28601
+ }
28602
+ var RG_VERSION = "14.1.1";
28603
+ var PLATFORM_CONFIG = {
28604
+ "arm64-darwin": { platform: "aarch64-apple-darwin", extension: "tar.gz" },
28605
+ "arm64-linux": { platform: "aarch64-unknown-linux-gnu", extension: "tar.gz" },
28606
+ "x64-darwin": { platform: "x86_64-apple-darwin", extension: "tar.gz" },
28607
+ "x64-linux": { platform: "x86_64-unknown-linux-musl", extension: "tar.gz" },
28608
+ "x64-win32": { platform: "x86_64-pc-windows-msvc", extension: "zip" }
28609
+ };
28610
+ function getPlatformKey() {
28611
+ return `${process.arch}-${process.platform}`;
28612
+ }
28579
28613
  function getInstallDir() {
28580
28614
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
28581
28615
  return join47(homeDir, ".cache", "oh-my-opencode", "bin");
@@ -28584,6 +28618,110 @@ function getRgPath() {
28584
28618
  const isWindows2 = process.platform === "win32";
28585
28619
  return join47(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
28586
28620
  }
28621
+ async function downloadFile(url2, destPath) {
28622
+ const response2 = await fetch(url2);
28623
+ if (!response2.ok) {
28624
+ throw new Error(`Failed to download: ${response2.status} ${response2.statusText}`);
28625
+ }
28626
+ const buffer = await response2.arrayBuffer();
28627
+ await Bun.write(destPath, buffer);
28628
+ }
28629
+ async function extractTarGz2(archivePath, destDir) {
28630
+ const platformKey = getPlatformKey();
28631
+ const args = ["tar", "-xzf", archivePath, "--strip-components=1"];
28632
+ if (platformKey.endsWith("-darwin")) {
28633
+ args.push("--include=*/rg");
28634
+ } else if (platformKey.endsWith("-linux")) {
28635
+ args.push("--wildcards", "*/rg");
28636
+ }
28637
+ const proc = spawn8(args, {
28638
+ cwd: destDir,
28639
+ stdout: "pipe",
28640
+ stderr: "pipe"
28641
+ });
28642
+ const exitCode = await proc.exited;
28643
+ if (exitCode !== 0) {
28644
+ const stderr = await new Response(proc.stderr).text();
28645
+ throw new Error(`Failed to extract tar.gz: ${stderr}`);
28646
+ }
28647
+ }
28648
+ async function extractZipWindows(archivePath, destDir) {
28649
+ const proc = spawn8(["powershell", "-Command", `Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force`], { stdout: "pipe", stderr: "pipe" });
28650
+ const exitCode = await proc.exited;
28651
+ if (exitCode !== 0) {
28652
+ throw new Error("Failed to extract zip with PowerShell");
28653
+ }
28654
+ const foundPath = findFileRecursive(destDir, "rg.exe");
28655
+ if (foundPath) {
28656
+ const destPath = join47(destDir, "rg.exe");
28657
+ if (foundPath !== destPath) {
28658
+ const { renameSync } = await import("fs");
28659
+ renameSync(foundPath, destPath);
28660
+ }
28661
+ }
28662
+ }
28663
+ async function extractZipUnix(archivePath, destDir) {
28664
+ const proc = spawn8(["unzip", "-o", archivePath, "-d", destDir], {
28665
+ stdout: "pipe",
28666
+ stderr: "pipe"
28667
+ });
28668
+ const exitCode = await proc.exited;
28669
+ if (exitCode !== 0) {
28670
+ throw new Error("Failed to extract zip");
28671
+ }
28672
+ const foundPath = findFileRecursive(destDir, "rg");
28673
+ if (foundPath) {
28674
+ const destPath = join47(destDir, "rg");
28675
+ if (foundPath !== destPath) {
28676
+ const { renameSync } = await import("fs");
28677
+ renameSync(foundPath, destPath);
28678
+ }
28679
+ }
28680
+ }
28681
+ async function extractZip3(archivePath, destDir) {
28682
+ if (process.platform === "win32") {
28683
+ await extractZipWindows(archivePath, destDir);
28684
+ } else {
28685
+ await extractZipUnix(archivePath, destDir);
28686
+ }
28687
+ }
28688
+ async function downloadAndInstallRipgrep() {
28689
+ const platformKey = getPlatformKey();
28690
+ const config3 = PLATFORM_CONFIG[platformKey];
28691
+ if (!config3) {
28692
+ throw new Error(`Unsupported platform: ${platformKey}`);
28693
+ }
28694
+ const installDir = getInstallDir();
28695
+ const rgPath = getRgPath();
28696
+ if (existsSync39(rgPath)) {
28697
+ return rgPath;
28698
+ }
28699
+ mkdirSync11(installDir, { recursive: true });
28700
+ const filename = `ripgrep-${RG_VERSION}-${config3.platform}.${config3.extension}`;
28701
+ const url2 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
28702
+ const archivePath = join47(installDir, filename);
28703
+ try {
28704
+ await downloadFile(url2, archivePath);
28705
+ if (config3.extension === "tar.gz") {
28706
+ await extractTarGz2(archivePath, installDir);
28707
+ } else {
28708
+ await extractZip3(archivePath, installDir);
28709
+ }
28710
+ if (process.platform !== "win32") {
28711
+ chmodSync3(rgPath, 493);
28712
+ }
28713
+ if (!existsSync39(rgPath)) {
28714
+ throw new Error("ripgrep binary not found after extraction");
28715
+ }
28716
+ return rgPath;
28717
+ } finally {
28718
+ if (existsSync39(archivePath)) {
28719
+ try {
28720
+ unlinkSync10(archivePath);
28721
+ } catch {}
28722
+ }
28723
+ }
28724
+ }
28587
28725
  function getInstalledRipgrepPath() {
28588
28726
  const rgPath = getRgPath();
28589
28727
  return existsSync39(rgPath) ? rgPath : null;
@@ -28591,6 +28729,7 @@ function getInstalledRipgrepPath() {
28591
28729
 
28592
28730
  // src/tools/grep/constants.ts
28593
28731
  var cachedCli = null;
28732
+ var autoInstallAttempted = false;
28594
28733
  function findExecutable(name) {
28595
28734
  const isWindows2 = process.platform === "win32";
28596
28735
  const cmd = isWindows2 ? "where" : "which";
@@ -28609,6 +28748,7 @@ function getOpenCodeBundledRg() {
28609
28748
  const isWindows2 = process.platform === "win32";
28610
28749
  const rgName = isWindows2 ? "rg.exe" : "rg";
28611
28750
  const candidates = [
28751
+ join48(getDataDir(), "opencode", "bin", rgName),
28612
28752
  join48(execDir, rgName),
28613
28753
  join48(execDir, "bin", rgName),
28614
28754
  join48(execDir, "..", "bin", rgName),
@@ -28647,6 +28787,23 @@ function resolveGrepCli() {
28647
28787
  cachedCli = { path: "rg", backend: "rg" };
28648
28788
  return cachedCli;
28649
28789
  }
28790
+ async function resolveGrepCliWithAutoInstall() {
28791
+ const current = resolveGrepCli();
28792
+ if (current.backend === "rg") {
28793
+ return current;
28794
+ }
28795
+ if (autoInstallAttempted) {
28796
+ return current;
28797
+ }
28798
+ autoInstallAttempted = true;
28799
+ try {
28800
+ const rgPath = await downloadAndInstallRipgrep();
28801
+ cachedCli = { path: rgPath, backend: "rg" };
28802
+ return cachedCli;
28803
+ } catch {
28804
+ return current;
28805
+ }
28806
+ }
28650
28807
  var DEFAULT_MAX_DEPTH = 20;
28651
28808
  var DEFAULT_MAX_FILESIZE = "10M";
28652
28809
  var DEFAULT_MAX_COUNT = 500;
@@ -28761,7 +28918,7 @@ async function runRg(options) {
28761
28918
  }
28762
28919
  const paths = options.paths?.length ? options.paths : ["."];
28763
28920
  args.push(...paths);
28764
- const proc = spawn8([cli.path, ...args], {
28921
+ const proc = spawn9([cli.path, ...args], {
28765
28922
  stdout: "pipe",
28766
28923
  stderr: "pipe"
28767
28924
  });
@@ -28863,7 +29020,7 @@ var grep = tool({
28863
29020
  });
28864
29021
 
28865
29022
  // src/tools/glob/cli.ts
28866
- var {spawn: spawn9 } = globalThis.Bun;
29023
+ var {spawn: spawn10 } = globalThis.Bun;
28867
29024
 
28868
29025
  // src/tools/glob/constants.ts
28869
29026
  var DEFAULT_TIMEOUT_MS3 = 60000;
@@ -28901,6 +29058,19 @@ function buildFindArgs(options) {
28901
29058
  }
28902
29059
  return args;
28903
29060
  }
29061
+ function buildPowerShellCommand(options) {
29062
+ const maxDepth = Math.min(options.maxDepth ?? DEFAULT_MAX_DEPTH2, DEFAULT_MAX_DEPTH2);
29063
+ const paths = options.paths?.length ? options.paths : ["."];
29064
+ const searchPath = paths[0] || ".";
29065
+ const escapedPath = searchPath.replace(/'/g, "''");
29066
+ const escapedPattern = options.pattern.replace(/'/g, "''");
29067
+ let psCommand = `Get-ChildItem -Path '${escapedPath}' -File -Recurse -Depth ${maxDepth - 1} -Filter '${escapedPattern}'`;
29068
+ if (options.hidden) {
29069
+ psCommand += " -Force";
29070
+ }
29071
+ psCommand += " -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName";
29072
+ return ["powershell", "-NoProfile", "-Command", psCommand];
29073
+ }
28904
29074
  async function getFileMtime(filePath) {
28905
29075
  try {
28906
29076
  const stats = await stat(filePath);
@@ -28909,21 +29079,33 @@ async function getFileMtime(filePath) {
28909
29079
  return 0;
28910
29080
  }
28911
29081
  }
28912
- async function runRgFiles(options) {
28913
- const cli = resolveGrepCli();
29082
+ async function runRgFiles(options, resolvedCli) {
29083
+ const cli = resolvedCli ?? resolveGrepCli();
28914
29084
  const timeout = Math.min(options.timeout ?? DEFAULT_TIMEOUT_MS3, DEFAULT_TIMEOUT_MS3);
28915
29085
  const limit = Math.min(options.limit ?? DEFAULT_LIMIT, DEFAULT_LIMIT);
28916
29086
  const isRg = cli.backend === "rg";
28917
- const args = isRg ? buildRgArgs2(options) : buildFindArgs(options);
28918
- const paths = options.paths?.length ? options.paths : ["."];
29087
+ const isWindows2 = process.platform === "win32";
29088
+ let command;
29089
+ let cwd;
28919
29090
  if (isRg) {
29091
+ const args = buildRgArgs2(options);
29092
+ const paths = options.paths?.length ? options.paths : ["."];
28920
29093
  args.push(...paths);
29094
+ command = [cli.path, ...args];
29095
+ cwd = undefined;
29096
+ } else if (isWindows2) {
29097
+ command = buildPowerShellCommand(options);
29098
+ cwd = undefined;
29099
+ } else {
29100
+ const args = buildFindArgs(options);
29101
+ const paths = options.paths?.length ? options.paths : ["."];
29102
+ cwd = paths[0] || ".";
29103
+ command = [cli.path, ...args];
28921
29104
  }
28922
- const cwd = paths[0] || ".";
28923
- const proc = spawn9([cli.path, ...args], {
29105
+ const proc = spawn10(command, {
28924
29106
  stdout: "pipe",
28925
29107
  stderr: "pipe",
28926
- cwd: isRg ? undefined : cwd
29108
+ cwd
28927
29109
  });
28928
29110
  const timeoutPromise = new Promise((_, reject) => {
28929
29111
  const id = setTimeout(() => {
@@ -28955,7 +29137,14 @@ async function runRgFiles(options) {
28955
29137
  truncated = true;
28956
29138
  break;
28957
29139
  }
28958
- const filePath = isRg ? line : `${cwd}/${line}`;
29140
+ let filePath;
29141
+ if (isRg) {
29142
+ filePath = line;
29143
+ } else if (isWindows2) {
29144
+ filePath = line.trim();
29145
+ } else {
29146
+ filePath = `${cwd}/${line}`;
29147
+ }
28959
29148
  const mtime = await getFileMtime(filePath);
28960
29149
  files.push({ path: filePath, mtime });
28961
29150
  }
@@ -29006,11 +29195,12 @@ var glob = tool({
29006
29195
  },
29007
29196
  execute: async (args) => {
29008
29197
  try {
29198
+ const cli = await resolveGrepCliWithAutoInstall();
29009
29199
  const paths = args.path ? [args.path] : undefined;
29010
29200
  const result = await runRgFiles({
29011
29201
  pattern: args.pattern,
29012
29202
  paths
29013
- });
29203
+ }, cli);
29014
29204
  return formatGlobResult(result);
29015
29205
  } catch (e) {
29016
29206
  return `Error: ${e instanceof Error ? e.message : String(e)}`;
@@ -29726,14 +29916,14 @@ var INTERACTIVE_BASH_DESCRIPTION = `Execute tmux commands. Use "omo-{name}" sess
29726
29916
  Blocked (use bash instead): capture-pane, save-buffer, show-buffer, pipe-pane.`;
29727
29917
 
29728
29918
  // src/tools/interactive-bash/utils.ts
29729
- var {spawn: spawn10 } = globalThis.Bun;
29919
+ var {spawn: spawn11 } = globalThis.Bun;
29730
29920
  var tmuxPath = null;
29731
29921
  var initPromise3 = null;
29732
29922
  async function findTmuxPath() {
29733
29923
  const isWindows2 = process.platform === "win32";
29734
29924
  const cmd = isWindows2 ? "where" : "which";
29735
29925
  try {
29736
- const proc = spawn10([cmd, "tmux"], {
29926
+ const proc = spawn11([cmd, "tmux"], {
29737
29927
  stdout: "pipe",
29738
29928
  stderr: "pipe"
29739
29929
  });
@@ -29747,7 +29937,7 @@ async function findTmuxPath() {
29747
29937
  if (!path7) {
29748
29938
  return null;
29749
29939
  }
29750
- const verifyProc = spawn10([path7, "-V"], {
29940
+ const verifyProc = spawn11([path7, "-V"], {
29751
29941
  stdout: "pipe",
29752
29942
  stderr: "pipe"
29753
29943
  });
@@ -1,2 +1,7 @@
1
+ import { type GrepBackend } from "./constants";
1
2
  import type { GlobOptions, GlobResult } from "./types";
2
- export declare function runRgFiles(options: GlobOptions): Promise<GlobResult>;
3
+ export interface ResolvedCli {
4
+ path: string;
5
+ backend: GrepBackend;
6
+ }
7
+ export declare function runRgFiles(options: GlobOptions, resolvedCli?: ResolvedCli): Promise<GlobResult>;
@@ -1,4 +1,4 @@
1
- export { resolveGrepCli, type GrepBackend } from "../grep/constants";
1
+ export { resolveGrepCli, resolveGrepCliWithAutoInstall, type GrepBackend } from "../grep/constants";
2
2
  export declare const DEFAULT_TIMEOUT_MS = 60000;
3
3
  export declare const DEFAULT_LIMIT = 100;
4
4
  export declare const DEFAULT_MAX_DEPTH = 20;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "2.7.1",
3
+ "version": "2.7.2",
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",