oh-my-opencode 2.1.0 → 2.1.1

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
@@ -2257,7 +2257,7 @@ var oracleAgent = {
2257
2257
  temperature: 0.1,
2258
2258
  reasoningEffort: "medium",
2259
2259
  textVerbosity: "high",
2260
- tools: { write: false, edit: false, read: true, task: false, call_omo_agent: true, background_task: false },
2260
+ tools: { write: false, edit: false, task: false, background_task: false },
2261
2261
  prompt: `You are a strategic technical advisor with deep reasoning capabilities, operating as a specialized consultant within an AI-assisted development environment.
2262
2262
 
2263
2263
  ## Context
@@ -2331,7 +2331,7 @@ var librarianAgent = {
2331
2331
  mode: "subagent",
2332
2332
  model: "anthropic/claude-sonnet-4-5",
2333
2333
  temperature: 0.1,
2334
- tools: { write: false, edit: false, bash: true, read: true, background_task: false },
2334
+ tools: { write: false, edit: false, background_task: false },
2335
2335
  prompt: `# THE LIBRARIAN
2336
2336
 
2337
2337
  You are **THE LIBRARIAN**, a specialized open-source codebase understanding agent.
@@ -2570,7 +2570,7 @@ var exploreAgent = {
2570
2570
  mode: "subagent",
2571
2571
  model: "opencode/grok-code",
2572
2572
  temperature: 0.1,
2573
- tools: { write: false, edit: false, bash: true, read: true, background_task: false },
2573
+ tools: { write: false, edit: false, background_task: false },
2574
2574
  prompt: `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
2575
2575
 
2576
2576
  === CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
@@ -3119,7 +3119,7 @@ var multimodalLookerAgent = {
3119
3119
  mode: "subagent",
3120
3120
  model: "google/gemini-2.5-flash",
3121
3121
  temperature: 0.1,
3122
- tools: { Read: true, background_task: false },
3122
+ tools: { write: false, edit: false, bash: false, background_task: false },
3123
3123
  prompt: `You interpret media files that cannot be read as plain text.
3124
3124
 
3125
3125
  Your job: examine the attached file and extract ONLY what was requested.
@@ -3183,7 +3183,11 @@ import { spawn } from "child_process";
3183
3183
  import { exec } from "child_process";
3184
3184
  import { promisify } from "util";
3185
3185
  import { existsSync } from "fs";
3186
+ import { homedir } from "os";
3186
3187
  var DEFAULT_ZSH_PATHS = ["/bin/zsh", "/usr/bin/zsh", "/usr/local/bin/zsh"];
3188
+ function getHomeDir() {
3189
+ return process.env.HOME || process.env.USERPROFILE || homedir();
3190
+ }
3187
3191
  function findZshPath(customZshPath) {
3188
3192
  if (customZshPath && existsSync(customZshPath)) {
3189
3193
  return customZshPath;
@@ -3197,7 +3201,7 @@ function findZshPath(customZshPath) {
3197
3201
  }
3198
3202
  var execAsync = promisify(exec);
3199
3203
  async function executeHookCommand(command, stdin, cwd, options) {
3200
- const home = process.env.HOME ?? "";
3204
+ const home = getHomeDir();
3201
3205
  let expandedCommand = command.replace(/^~(?=\/|$)/g, home).replace(/\s~(?=\/)/g, ` ${home}`).replace(/\$CLAUDE_PROJECT_DIR/g, cwd).replace(/\$\{CLAUDE_PROJECT_DIR\}/g, cwd);
3202
3206
  let finalCommand = expandedCommand;
3203
3207
  if (options?.forceZsh) {
@@ -3692,8 +3696,8 @@ import { join as join4 } from "path";
3692
3696
 
3693
3697
  // src/features/hook-message-injector/constants.ts
3694
3698
  import { join as join3 } from "path";
3695
- import { homedir } from "os";
3696
- var xdgData = process.env.XDG_DATA_HOME || join3(homedir(), ".local", "share");
3699
+ import { homedir as homedir2 } from "os";
3700
+ var xdgData = process.env.XDG_DATA_HOME || join3(homedir2(), ".local", "share");
3697
3701
  var OPENCODE_STORAGE = join3(xdgData, "opencode", "storage");
3698
3702
  var MESSAGE_STORAGE = join3(OPENCODE_STORAGE, "message");
3699
3703
  var PART_STORAGE = join3(OPENCODE_STORAGE, "part");
@@ -4073,7 +4077,7 @@ async function sendNotification(ctx, p, title, message) {
4073
4077
  await ctx.$`osascript -e ${'display notification "' + escapedMessage + '" with title "' + escapedTitle + '"'}`;
4074
4078
  break;
4075
4079
  case "linux":
4076
- await ctx.$`notify-send ${escapedTitle} ${escapedMessage}`.catch(() => {});
4080
+ await ctx.$`notify-send ${escapedTitle} ${escapedMessage} 2>/dev/null`.catch(() => {});
4077
4081
  break;
4078
4082
  case "win32":
4079
4083
  await ctx.$`powershell -Command ${"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('" + escapedMessage + "', '" + escapedTitle + "')"}`;
@@ -4086,8 +4090,8 @@ async function playSound(ctx, p, soundPath) {
4086
4090
  ctx.$`afplay ${soundPath}`.catch(() => {});
4087
4091
  break;
4088
4092
  case "linux":
4089
- ctx.$`paplay ${soundPath}`.catch(() => {
4090
- ctx.$`aplay ${soundPath}`.catch(() => {});
4093
+ ctx.$`paplay ${soundPath} 2>/dev/null`.catch(() => {
4094
+ ctx.$`aplay ${soundPath} 2>/dev/null`.catch(() => {});
4091
4095
  });
4092
4096
  break;
4093
4097
  case "win32":
@@ -4516,7 +4520,25 @@ function getErrorMessage(error) {
4516
4520
  if (typeof error === "string")
4517
4521
  return error.toLowerCase();
4518
4522
  const errorObj = error;
4519
- return (errorObj.data?.message || errorObj.error?.message || errorObj.message || "").toLowerCase();
4523
+ const paths = [
4524
+ errorObj.data,
4525
+ errorObj.error,
4526
+ errorObj,
4527
+ errorObj.data?.error
4528
+ ];
4529
+ for (const obj of paths) {
4530
+ if (obj && typeof obj === "object") {
4531
+ const msg = obj.message;
4532
+ if (typeof msg === "string" && msg.length > 0) {
4533
+ return msg.toLowerCase();
4534
+ }
4535
+ }
4536
+ }
4537
+ try {
4538
+ return JSON.stringify(error).toLowerCase();
4539
+ } catch {
4540
+ return "";
4541
+ }
4520
4542
  }
4521
4543
  function extractMessageIndex(error) {
4522
4544
  const message = getErrorMessage(error);
@@ -4534,7 +4556,7 @@ function detectErrorType(error) {
4534
4556
  if (message.includes("thinking is disabled") && message.includes("cannot contain")) {
4535
4557
  return "thinking_disabled_violation";
4536
4558
  }
4537
- if (message.includes("non-empty content") || message.includes("must have non-empty content")) {
4559
+ if (message.includes("non-empty content") || message.includes("must have non-empty content") || message.includes("content") && message.includes("is empty") || message.includes("content field") && message.includes("empty")) {
4538
4560
  return "empty_content_message";
4539
4561
  }
4540
4562
  return null;
@@ -4727,15 +4749,16 @@ import { createRequire as createRequire2 } from "module";
4727
4749
  import { dirname, join as join9 } from "path";
4728
4750
  import { existsSync as existsSync7 } from "fs";
4729
4751
  import * as fs2 from "fs";
4752
+ import { tmpdir as tmpdir3 } from "os";
4730
4753
 
4731
4754
  // src/hooks/comment-checker/downloader.ts
4732
4755
  var {spawn: spawn2 } = globalThis.Bun;
4733
4756
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync2 } from "fs";
4734
4757
  import { join as join8 } from "path";
4735
- import { homedir as homedir2 } from "os";
4758
+ import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
4736
4759
  import { createRequire } from "module";
4737
4760
  var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
4738
- var DEBUG_FILE = "/tmp/comment-checker-debug.log";
4761
+ var DEBUG_FILE = join8(tmpdir2(), "comment-checker-debug.log");
4739
4762
  function debugLog(...args) {
4740
4763
  if (DEBUG) {
4741
4764
  const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -4753,7 +4776,7 @@ var PLATFORM_MAP = {
4753
4776
  };
4754
4777
  function getCacheDir() {
4755
4778
  const xdgCache2 = process.env.XDG_CACHE_HOME;
4756
- const base = xdgCache2 || join8(homedir2(), ".cache");
4779
+ const base = xdgCache2 || join8(homedir3(), ".cache");
4757
4780
  return join8(base, "oh-my-opencode", "bin");
4758
4781
  }
4759
4782
  function getBinaryName() {
@@ -4863,7 +4886,7 @@ async function ensureCommentCheckerBinary() {
4863
4886
 
4864
4887
  // src/hooks/comment-checker/cli.ts
4865
4888
  var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
4866
- var DEBUG_FILE2 = "/tmp/comment-checker-debug.log";
4889
+ var DEBUG_FILE2 = join9(tmpdir3(), "comment-checker-debug.log");
4867
4890
  function debugLog2(...args) {
4868
4891
  if (DEBUG2) {
4869
4892
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -4976,8 +4999,10 @@ async function runCommentChecker(input, cliPath) {
4976
4999
  // src/hooks/comment-checker/index.ts
4977
5000
  import * as fs3 from "fs";
4978
5001
  import { existsSync as existsSync8 } from "fs";
5002
+ import { tmpdir as tmpdir4 } from "os";
5003
+ import { join as join10 } from "path";
4979
5004
  var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
4980
- var DEBUG_FILE3 = "/tmp/comment-checker-debug.log";
5005
+ var DEBUG_FILE3 = join10(tmpdir4(), "comment-checker-debug.log");
4981
5006
  function debugLog3(...args) {
4982
5007
  if (DEBUG3) {
4983
5008
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -5123,7 +5148,7 @@ function createToolOutputTruncatorHook(ctx) {
5123
5148
  }
5124
5149
  // src/hooks/directory-agents-injector/index.ts
5125
5150
  import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
5126
- import { dirname as dirname2, join as join12, resolve as resolve2 } from "path";
5151
+ import { dirname as dirname2, join as join13, resolve as resolve2 } from "path";
5127
5152
 
5128
5153
  // src/hooks/directory-agents-injector/storage.ts
5129
5154
  import {
@@ -5133,17 +5158,17 @@ import {
5133
5158
  writeFileSync as writeFileSync3,
5134
5159
  unlinkSync as unlinkSync3
5135
5160
  } from "fs";
5136
- import { join as join11 } from "path";
5161
+ import { join as join12 } from "path";
5137
5162
 
5138
5163
  // src/hooks/directory-agents-injector/constants.ts
5139
- import { join as join10 } from "path";
5140
- var OPENCODE_STORAGE3 = join10(xdgData2 ?? "", "opencode", "storage");
5141
- var AGENTS_INJECTOR_STORAGE = join10(OPENCODE_STORAGE3, "directory-agents");
5164
+ import { join as join11 } from "path";
5165
+ var OPENCODE_STORAGE3 = join11(xdgData2 ?? "", "opencode", "storage");
5166
+ var AGENTS_INJECTOR_STORAGE = join11(OPENCODE_STORAGE3, "directory-agents");
5142
5167
  var AGENTS_FILENAME = "AGENTS.md";
5143
5168
 
5144
5169
  // src/hooks/directory-agents-injector/storage.ts
5145
5170
  function getStoragePath(sessionID) {
5146
- return join11(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
5171
+ return join12(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
5147
5172
  }
5148
5173
  function loadInjectedPaths(sessionID) {
5149
5174
  const filePath = getStoragePath(sessionID);
@@ -5195,7 +5220,7 @@ function createDirectoryAgentsInjectorHook(ctx) {
5195
5220
  const found = [];
5196
5221
  let current = startDir;
5197
5222
  while (true) {
5198
- const agentsPath = join12(current, AGENTS_FILENAME);
5223
+ const agentsPath = join13(current, AGENTS_FILENAME);
5199
5224
  if (existsSync10(agentsPath)) {
5200
5225
  found.push(agentsPath);
5201
5226
  }
@@ -5264,7 +5289,7 @@ ${content}`;
5264
5289
  }
5265
5290
  // src/hooks/directory-readme-injector/index.ts
5266
5291
  import { existsSync as existsSync12, readFileSync as readFileSync7 } from "fs";
5267
- import { dirname as dirname3, join as join15, resolve as resolve3 } from "path";
5292
+ import { dirname as dirname3, join as join16, resolve as resolve3 } from "path";
5268
5293
 
5269
5294
  // src/hooks/directory-readme-injector/storage.ts
5270
5295
  import {
@@ -5274,17 +5299,17 @@ import {
5274
5299
  writeFileSync as writeFileSync4,
5275
5300
  unlinkSync as unlinkSync4
5276
5301
  } from "fs";
5277
- import { join as join14 } from "path";
5302
+ import { join as join15 } from "path";
5278
5303
 
5279
5304
  // src/hooks/directory-readme-injector/constants.ts
5280
- import { join as join13 } from "path";
5281
- var OPENCODE_STORAGE4 = join13(xdgData2 ?? "", "opencode", "storage");
5282
- var README_INJECTOR_STORAGE = join13(OPENCODE_STORAGE4, "directory-readme");
5305
+ import { join as join14 } from "path";
5306
+ var OPENCODE_STORAGE4 = join14(xdgData2 ?? "", "opencode", "storage");
5307
+ var README_INJECTOR_STORAGE = join14(OPENCODE_STORAGE4, "directory-readme");
5283
5308
  var README_FILENAME = "README.md";
5284
5309
 
5285
5310
  // src/hooks/directory-readme-injector/storage.ts
5286
5311
  function getStoragePath2(sessionID) {
5287
- return join14(README_INJECTOR_STORAGE, `${sessionID}.json`);
5312
+ return join15(README_INJECTOR_STORAGE, `${sessionID}.json`);
5288
5313
  }
5289
5314
  function loadInjectedPaths2(sessionID) {
5290
5315
  const filePath = getStoragePath2(sessionID);
@@ -5336,7 +5361,7 @@ function createDirectoryReadmeInjectorHook(ctx) {
5336
5361
  const found = [];
5337
5362
  let current = startDir;
5338
5363
  while (true) {
5339
- const readmePath = join15(current, README_FILENAME);
5364
+ const readmePath = join16(current, README_FILENAME);
5340
5365
  if (existsSync12(readmePath)) {
5341
5366
  found.push(readmePath);
5342
5367
  }
@@ -5565,11 +5590,15 @@ function parseAnthropicTokenLimitError(err) {
5565
5590
 
5566
5591
  // src/hooks/anthropic-auto-compact/types.ts
5567
5592
  var RETRY_CONFIG = {
5568
- maxAttempts: 5,
5593
+ maxAttempts: 2,
5569
5594
  initialDelayMs: 2000,
5570
5595
  backoffFactor: 2,
5571
5596
  maxDelayMs: 30000
5572
5597
  };
5598
+ var FALLBACK_CONFIG = {
5599
+ maxRevertAttempts: 3,
5600
+ minMessagesRequired: 2
5601
+ };
5573
5602
 
5574
5603
  // src/hooks/anthropic-auto-compact/executor.ts
5575
5604
  function calculateRetryDelay(attempt) {
@@ -5589,6 +5618,92 @@ function getOrCreateRetryState(autoCompactState, sessionID) {
5589
5618
  }
5590
5619
  return state;
5591
5620
  }
5621
+ function getOrCreateFallbackState(autoCompactState, sessionID) {
5622
+ let state = autoCompactState.fallbackStateBySession.get(sessionID);
5623
+ if (!state) {
5624
+ state = { revertAttempt: 0 };
5625
+ autoCompactState.fallbackStateBySession.set(sessionID, state);
5626
+ }
5627
+ return state;
5628
+ }
5629
+ async function getLastMessagePair(sessionID, client, directory) {
5630
+ try {
5631
+ const resp = await client.session.messages({
5632
+ path: { id: sessionID },
5633
+ query: { directory }
5634
+ });
5635
+ const data = resp.data;
5636
+ if (!Array.isArray(data) || data.length < FALLBACK_CONFIG.minMessagesRequired) {
5637
+ return null;
5638
+ }
5639
+ const reversed = [...data].reverse();
5640
+ const lastAssistant = reversed.find((m) => {
5641
+ const msg = m;
5642
+ const info = msg.info;
5643
+ return info?.role === "assistant";
5644
+ });
5645
+ const lastUser = reversed.find((m) => {
5646
+ const msg = m;
5647
+ const info = msg.info;
5648
+ return info?.role === "user";
5649
+ });
5650
+ if (!lastUser)
5651
+ return null;
5652
+ const userInfo = lastUser.info;
5653
+ const userMessageID = userInfo?.id;
5654
+ if (!userMessageID)
5655
+ return null;
5656
+ let assistantMessageID;
5657
+ if (lastAssistant) {
5658
+ const assistantInfo = lastAssistant.info;
5659
+ assistantMessageID = assistantInfo?.id;
5660
+ }
5661
+ return { userMessageID, assistantMessageID };
5662
+ } catch {
5663
+ return null;
5664
+ }
5665
+ }
5666
+ async function executeRevertFallback(sessionID, autoCompactState, client, directory) {
5667
+ const fallbackState = getOrCreateFallbackState(autoCompactState, sessionID);
5668
+ if (fallbackState.revertAttempt >= FALLBACK_CONFIG.maxRevertAttempts) {
5669
+ return false;
5670
+ }
5671
+ const pair = await getLastMessagePair(sessionID, client, directory);
5672
+ if (!pair) {
5673
+ return false;
5674
+ }
5675
+ await client.tui.showToast({
5676
+ body: {
5677
+ title: "\u26A0\uFE0F Emergency Recovery",
5678
+ message: `Context too large. Removing last message pair to recover session...`,
5679
+ variant: "warning",
5680
+ duration: 4000
5681
+ }
5682
+ }).catch(() => {});
5683
+ try {
5684
+ if (pair.assistantMessageID) {
5685
+ await client.session.revert({
5686
+ path: { id: sessionID },
5687
+ body: { messageID: pair.assistantMessageID },
5688
+ query: { directory }
5689
+ });
5690
+ }
5691
+ await client.session.revert({
5692
+ path: { id: sessionID },
5693
+ body: { messageID: pair.userMessageID },
5694
+ query: { directory }
5695
+ });
5696
+ fallbackState.revertAttempt++;
5697
+ fallbackState.lastRevertedMessageID = pair.userMessageID;
5698
+ const retryState = autoCompactState.retryStateBySession.get(sessionID);
5699
+ if (retryState) {
5700
+ retryState.attempt = 0;
5701
+ }
5702
+ return true;
5703
+ } catch {
5704
+ return false;
5705
+ }
5706
+ }
5592
5707
  async function getLastAssistant(sessionID, client, directory) {
5593
5708
  try {
5594
5709
  const resp = await client.session.messages({
@@ -5615,15 +5730,34 @@ function clearSessionState(autoCompactState, sessionID) {
5615
5730
  autoCompactState.pendingCompact.delete(sessionID);
5616
5731
  autoCompactState.errorDataBySession.delete(sessionID);
5617
5732
  autoCompactState.retryStateBySession.delete(sessionID);
5733
+ autoCompactState.fallbackStateBySession.delete(sessionID);
5618
5734
  }
5619
5735
  async function executeCompact(sessionID, msg, autoCompactState, client, directory) {
5620
5736
  const retryState = getOrCreateRetryState(autoCompactState, sessionID);
5621
5737
  if (!shouldRetry(retryState)) {
5738
+ const fallbackState = getOrCreateFallbackState(autoCompactState, sessionID);
5739
+ if (fallbackState.revertAttempt < FALLBACK_CONFIG.maxRevertAttempts) {
5740
+ const reverted = await executeRevertFallback(sessionID, autoCompactState, client, directory);
5741
+ if (reverted) {
5742
+ await client.tui.showToast({
5743
+ body: {
5744
+ title: "Recovery Attempt",
5745
+ message: "Message removed. Retrying compaction...",
5746
+ variant: "info",
5747
+ duration: 3000
5748
+ }
5749
+ }).catch(() => {});
5750
+ setTimeout(() => {
5751
+ executeCompact(sessionID, msg, autoCompactState, client, directory);
5752
+ }, 1000);
5753
+ return;
5754
+ }
5755
+ }
5622
5756
  clearSessionState(autoCompactState, sessionID);
5623
5757
  await client.tui.showToast({
5624
5758
  body: {
5625
5759
  title: "Auto Compact Failed",
5626
- message: `Failed after ${RETRY_CONFIG.maxAttempts} attempts. Please try manual compact.`,
5760
+ message: `Failed after ${RETRY_CONFIG.maxAttempts} retries and ${FALLBACK_CONFIG.maxRevertAttempts} message removals. Please start a new session.`,
5627
5761
  variant: "error",
5628
5762
  duration: 5000
5629
5763
  }
@@ -5669,7 +5803,8 @@ function createAutoCompactState() {
5669
5803
  return {
5670
5804
  pendingCompact: new Set,
5671
5805
  errorDataBySession: new Map,
5672
- retryStateBySession: new Map
5806
+ retryStateBySession: new Map,
5807
+ fallbackStateBySession: new Map
5673
5808
  };
5674
5809
  }
5675
5810
  function createAnthropicAutoCompactHook(ctx) {
@@ -5682,6 +5817,7 @@ function createAnthropicAutoCompactHook(ctx) {
5682
5817
  autoCompactState.pendingCompact.delete(sessionInfo.id);
5683
5818
  autoCompactState.errorDataBySession.delete(sessionInfo.id);
5684
5819
  autoCompactState.retryStateBySession.delete(sessionInfo.id);
5820
+ autoCompactState.fallbackStateBySession.delete(sessionInfo.id);
5685
5821
  }
5686
5822
  return;
5687
5823
  }
@@ -6024,8 +6160,8 @@ function createThinkModeHook() {
6024
6160
  };
6025
6161
  }
6026
6162
  // src/hooks/claude-code-hooks/config.ts
6027
- import { homedir as homedir3 } from "os";
6028
- import { join as join16 } from "path";
6163
+ import { homedir as homedir4 } from "os";
6164
+ import { join as join17 } from "path";
6029
6165
  import { existsSync as existsSync13 } from "fs";
6030
6166
  function normalizeHookMatcher(raw) {
6031
6167
  return {
@@ -6049,11 +6185,11 @@ function normalizeHooksConfig(raw) {
6049
6185
  return result;
6050
6186
  }
6051
6187
  function getClaudeSettingsPaths(customPath) {
6052
- const home = homedir3();
6188
+ const home = homedir4();
6053
6189
  const paths = [
6054
- join16(home, ".claude", "settings.json"),
6055
- join16(process.cwd(), ".claude", "settings.json"),
6056
- join16(process.cwd(), ".claude", "settings.local.json")
6190
+ join17(home, ".claude", "settings.json"),
6191
+ join17(process.cwd(), ".claude", "settings.json"),
6192
+ join17(process.cwd(), ".claude", "settings.local.json")
6057
6193
  ];
6058
6194
  if (customPath && existsSync13(customPath)) {
6059
6195
  paths.unshift(customPath);
@@ -6097,11 +6233,11 @@ async function loadClaudeHooksConfig(customSettingsPath) {
6097
6233
 
6098
6234
  // src/hooks/claude-code-hooks/config-loader.ts
6099
6235
  import { existsSync as existsSync14 } from "fs";
6100
- import { homedir as homedir4 } from "os";
6101
- import { join as join17 } from "path";
6102
- var USER_CONFIG_PATH = join17(homedir4(), ".config", "opencode", "opencode-cc-plugin.json");
6236
+ import { homedir as homedir5 } from "os";
6237
+ import { join as join18 } from "path";
6238
+ var USER_CONFIG_PATH = join18(homedir5(), ".config", "opencode", "opencode-cc-plugin.json");
6103
6239
  function getProjectConfigPath() {
6104
- return join17(process.cwd(), ".opencode", "opencode-cc-plugin.json");
6240
+ return join18(process.cwd(), ".opencode", "opencode-cc-plugin.json");
6105
6241
  }
6106
6242
  async function loadConfigFromPath(path3) {
6107
6243
  if (!existsSync14(path3)) {
@@ -6169,8 +6305,9 @@ function isHookCommandDisabled(eventType, command, config) {
6169
6305
  }
6170
6306
 
6171
6307
  // src/hooks/claude-code-hooks/plugin-config.ts
6308
+ var isWindows = process.platform === "win32";
6172
6309
  var DEFAULT_CONFIG = {
6173
- forceZsh: true,
6310
+ forceZsh: !isWindows,
6174
6311
  zshPath: "/bin/zsh"
6175
6312
  };
6176
6313
 
@@ -6282,13 +6419,13 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
6282
6419
  }
6283
6420
 
6284
6421
  // src/hooks/claude-code-hooks/transcript.ts
6285
- import { join as join18 } from "path";
6422
+ import { join as join19 } from "path";
6286
6423
  import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync15, writeFileSync as writeFileSync5, unlinkSync as unlinkSync5 } from "fs";
6287
- import { homedir as homedir5, tmpdir as tmpdir2 } from "os";
6424
+ import { homedir as homedir6, tmpdir as tmpdir5 } from "os";
6288
6425
  import { randomUUID } from "crypto";
6289
- var TRANSCRIPT_DIR = join18(homedir5(), ".claude", "transcripts");
6426
+ var TRANSCRIPT_DIR = join19(homedir6(), ".claude", "transcripts");
6290
6427
  function getTranscriptPath(sessionId) {
6291
- return join18(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
6428
+ return join19(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
6292
6429
  }
6293
6430
  function ensureTranscriptDir() {
6294
6431
  if (!existsSync15(TRANSCRIPT_DIR)) {
@@ -6378,7 +6515,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
6378
6515
  }
6379
6516
  };
6380
6517
  entries.push(JSON.stringify(currentEntry));
6381
- const tempPath = join18(tmpdir2(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6518
+ const tempPath = join19(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6382
6519
  writeFileSync5(tempPath, entries.join(`
6383
6520
  `) + `
6384
6521
  `);
@@ -6398,7 +6535,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
6398
6535
  ]
6399
6536
  }
6400
6537
  };
6401
- const tempPath = join18(tmpdir2(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6538
+ const tempPath = join19(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
6402
6539
  writeFileSync5(tempPath, JSON.stringify(currentEntry) + `
6403
6540
  `);
6404
6541
  return tempPath;
@@ -6610,11 +6747,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
6610
6747
  }
6611
6748
 
6612
6749
  // src/hooks/claude-code-hooks/todo.ts
6613
- import { join as join19 } from "path";
6614
- import { homedir as homedir6 } from "os";
6615
- var TODO_DIR = join19(homedir6(), ".claude", "todos");
6750
+ import { join as join20 } from "path";
6751
+ import { homedir as homedir7 } from "os";
6752
+ var TODO_DIR = join20(homedir7(), ".claude", "todos");
6616
6753
  function getTodoPath(sessionId) {
6617
- return join19(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
6754
+ return join20(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
6618
6755
  }
6619
6756
 
6620
6757
  // src/hooks/claude-code-hooks/stop.ts
@@ -6946,7 +7083,7 @@ ${result.message}`;
6946
7083
  }
6947
7084
  // src/hooks/rules-injector/index.ts
6948
7085
  import { readFileSync as readFileSync9 } from "fs";
6949
- import { homedir as homedir7 } from "os";
7086
+ import { homedir as homedir8 } from "os";
6950
7087
  import { relative as relative3, resolve as resolve4 } from "path";
6951
7088
 
6952
7089
  // src/hooks/rules-injector/finder.ts
@@ -6956,12 +7093,12 @@ import {
6956
7093
  realpathSync,
6957
7094
  statSync as statSync2
6958
7095
  } from "fs";
6959
- import { dirname as dirname4, join as join21, relative } from "path";
7096
+ import { dirname as dirname4, join as join22, relative } from "path";
6960
7097
 
6961
7098
  // src/hooks/rules-injector/constants.ts
6962
- import { join as join20 } from "path";
6963
- var OPENCODE_STORAGE5 = join20(xdgData2 ?? "", "opencode", "storage");
6964
- var RULES_INJECTOR_STORAGE = join20(OPENCODE_STORAGE5, "rules-injector");
7099
+ import { join as join21 } from "path";
7100
+ var OPENCODE_STORAGE5 = join21(xdgData2 ?? "", "opencode", "storage");
7101
+ var RULES_INJECTOR_STORAGE = join21(OPENCODE_STORAGE5, "rules-injector");
6965
7102
  var PROJECT_MARKERS = [
6966
7103
  ".git",
6967
7104
  "pyproject.toml",
@@ -6988,7 +7125,7 @@ function findProjectRoot(startPath) {
6988
7125
  }
6989
7126
  while (true) {
6990
7127
  for (const marker of PROJECT_MARKERS) {
6991
- const markerPath = join21(current, marker);
7128
+ const markerPath = join22(current, marker);
6992
7129
  if (existsSync16(markerPath)) {
6993
7130
  return current;
6994
7131
  }
@@ -7006,7 +7143,7 @@ function findRuleFilesRecursive(dir, results) {
7006
7143
  try {
7007
7144
  const entries = readdirSync4(dir, { withFileTypes: true });
7008
7145
  for (const entry of entries) {
7009
- const fullPath = join21(dir, entry.name);
7146
+ const fullPath = join22(dir, entry.name);
7010
7147
  if (entry.isDirectory()) {
7011
7148
  findRuleFilesRecursive(fullPath, results);
7012
7149
  } else if (entry.isFile()) {
@@ -7032,7 +7169,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
7032
7169
  let distance = 0;
7033
7170
  while (true) {
7034
7171
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
7035
- const ruleDir = join21(currentDir, parent, subdir);
7172
+ const ruleDir = join22(currentDir, parent, subdir);
7036
7173
  const files = [];
7037
7174
  findRuleFilesRecursive(ruleDir, files);
7038
7175
  for (const filePath of files) {
@@ -7056,7 +7193,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
7056
7193
  currentDir = parentDir;
7057
7194
  distance++;
7058
7195
  }
7059
- const userRuleDir = join21(homeDir, USER_RULE_DIR);
7196
+ const userRuleDir = join22(homeDir, USER_RULE_DIR);
7060
7197
  const userFiles = [];
7061
7198
  findRuleFilesRecursive(userRuleDir, userFiles);
7062
7199
  for (const filePath of userFiles) {
@@ -7251,9 +7388,9 @@ import {
7251
7388
  writeFileSync as writeFileSync6,
7252
7389
  unlinkSync as unlinkSync6
7253
7390
  } from "fs";
7254
- import { join as join22 } from "path";
7391
+ import { join as join23 } from "path";
7255
7392
  function getStoragePath3(sessionID) {
7256
- return join22(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
7393
+ return join23(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
7257
7394
  }
7258
7395
  function loadInjectedRules(sessionID) {
7259
7396
  const filePath = getStoragePath3(sessionID);
@@ -7314,7 +7451,7 @@ function createRulesInjectorHook(ctx) {
7314
7451
  return;
7315
7452
  const projectRoot = findProjectRoot(filePath);
7316
7453
  const cache2 = getSessionCache(input.sessionID);
7317
- const home = homedir7();
7454
+ const home = homedir8();
7318
7455
  const ruleFileCandidates = findRuleFiles(projectRoot, home, filePath);
7319
7456
  const toInject = [];
7320
7457
  for (const candidate of ruleFileCandidates) {
@@ -7692,12 +7829,12 @@ import {
7692
7829
  writeFileSync as writeFileSync8,
7693
7830
  unlinkSync as unlinkSync7
7694
7831
  } from "fs";
7695
- import { join as join27 } from "path";
7832
+ import { join as join28 } from "path";
7696
7833
 
7697
7834
  // src/hooks/agent-usage-reminder/constants.ts
7698
- import { join as join26 } from "path";
7699
- var OPENCODE_STORAGE6 = join26(xdgData2 ?? "", "opencode", "storage");
7700
- var AGENT_USAGE_REMINDER_STORAGE = join26(OPENCODE_STORAGE6, "agent-usage-reminder");
7835
+ import { join as join27 } from "path";
7836
+ var OPENCODE_STORAGE6 = join27(xdgData2 ?? "", "opencode", "storage");
7837
+ var AGENT_USAGE_REMINDER_STORAGE = join27(OPENCODE_STORAGE6, "agent-usage-reminder");
7701
7838
  var TARGET_TOOLS = new Set([
7702
7839
  "grep",
7703
7840
  "safe_grep",
@@ -7742,7 +7879,7 @@ ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
7742
7879
 
7743
7880
  // src/hooks/agent-usage-reminder/storage.ts
7744
7881
  function getStoragePath4(sessionID) {
7745
- return join27(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
7882
+ return join28(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
7746
7883
  }
7747
7884
  function loadAgentUsageState(sessionID) {
7748
7885
  const filePath = getStoragePath4(sessionID);
@@ -7991,12 +8128,12 @@ import {
7991
8128
  writeFileSync as writeFileSync9,
7992
8129
  unlinkSync as unlinkSync8
7993
8130
  } from "fs";
7994
- import { join as join29 } from "path";
8131
+ import { join as join30 } from "path";
7995
8132
 
7996
8133
  // src/hooks/interactive-bash-session/constants.ts
7997
- import { join as join28 } from "path";
7998
- var OPENCODE_STORAGE7 = join28(xdgData2 ?? "", "opencode", "storage");
7999
- var INTERACTIVE_BASH_SESSION_STORAGE = join28(OPENCODE_STORAGE7, "interactive-bash-session");
8134
+ import { join as join29 } from "path";
8135
+ var OPENCODE_STORAGE7 = join29(xdgData2 ?? "", "opencode", "storage");
8136
+ var INTERACTIVE_BASH_SESSION_STORAGE = join29(OPENCODE_STORAGE7, "interactive-bash-session");
8000
8137
  var OMO_SESSION_PREFIX = "omo-";
8001
8138
  function buildSessionReminderMessage(sessions) {
8002
8139
  if (sessions.length === 0)
@@ -8008,7 +8145,7 @@ function buildSessionReminderMessage(sessions) {
8008
8145
 
8009
8146
  // src/hooks/interactive-bash-session/storage.ts
8010
8147
  function getStoragePath5(sessionID) {
8011
- return join29(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
8148
+ return join30(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
8012
8149
  }
8013
8150
  function loadInteractiveBashSessionState(sessionID) {
8014
8151
  const filePath = getStoragePath5(sessionID);
@@ -9782,8 +9919,8 @@ async function createGoogleAntigravityAuthPlugin({
9782
9919
  }
9783
9920
  // src/features/claude-code-command-loader/loader.ts
9784
9921
  import { existsSync as existsSync22, readdirSync as readdirSync5, readFileSync as readFileSync14 } from "fs";
9785
- import { homedir as homedir9 } from "os";
9786
- import { join as join30, basename } from "path";
9922
+ import { homedir as homedir10 } from "os";
9923
+ import { join as join31, basename } from "path";
9787
9924
  function loadCommandsFromDir(commandsDir, scope) {
9788
9925
  if (!existsSync22(commandsDir)) {
9789
9926
  return [];
@@ -9793,7 +9930,7 @@ function loadCommandsFromDir(commandsDir, scope) {
9793
9930
  for (const entry of entries) {
9794
9931
  if (!isMarkdownFile(entry))
9795
9932
  continue;
9796
- const commandPath = join30(commandsDir, entry.name);
9933
+ const commandPath = join31(commandsDir, entry.name);
9797
9934
  const commandName = basename(entry.name, ".md");
9798
9935
  try {
9799
9936
  const content = readFileSync14(commandPath, "utf-8");
@@ -9836,29 +9973,29 @@ function commandsToRecord(commands) {
9836
9973
  return result;
9837
9974
  }
9838
9975
  function loadUserCommands() {
9839
- const userCommandsDir = join30(homedir9(), ".claude", "commands");
9976
+ const userCommandsDir = join31(homedir10(), ".claude", "commands");
9840
9977
  const commands = loadCommandsFromDir(userCommandsDir, "user");
9841
9978
  return commandsToRecord(commands);
9842
9979
  }
9843
9980
  function loadProjectCommands() {
9844
- const projectCommandsDir = join30(process.cwd(), ".claude", "commands");
9981
+ const projectCommandsDir = join31(process.cwd(), ".claude", "commands");
9845
9982
  const commands = loadCommandsFromDir(projectCommandsDir, "project");
9846
9983
  return commandsToRecord(commands);
9847
9984
  }
9848
9985
  function loadOpencodeGlobalCommands() {
9849
- const opencodeCommandsDir = join30(homedir9(), ".config", "opencode", "command");
9986
+ const opencodeCommandsDir = join31(homedir10(), ".config", "opencode", "command");
9850
9987
  const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
9851
9988
  return commandsToRecord(commands);
9852
9989
  }
9853
9990
  function loadOpencodeProjectCommands() {
9854
- const opencodeProjectDir = join30(process.cwd(), ".opencode", "command");
9991
+ const opencodeProjectDir = join31(process.cwd(), ".opencode", "command");
9855
9992
  const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
9856
9993
  return commandsToRecord(commands);
9857
9994
  }
9858
9995
  // src/features/claude-code-skill-loader/loader.ts
9859
9996
  import { existsSync as existsSync23, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "fs";
9860
- import { homedir as homedir10 } from "os";
9861
- import { join as join31 } from "path";
9997
+ import { homedir as homedir11 } from "os";
9998
+ import { join as join32 } from "path";
9862
9999
  function loadSkillsFromDir(skillsDir, scope) {
9863
10000
  if (!existsSync23(skillsDir)) {
9864
10001
  return [];
@@ -9868,11 +10005,11 @@ function loadSkillsFromDir(skillsDir, scope) {
9868
10005
  for (const entry of entries) {
9869
10006
  if (entry.name.startsWith("."))
9870
10007
  continue;
9871
- const skillPath = join31(skillsDir, entry.name);
10008
+ const skillPath = join32(skillsDir, entry.name);
9872
10009
  if (!entry.isDirectory() && !entry.isSymbolicLink())
9873
10010
  continue;
9874
10011
  const resolvedPath = resolveSymlink(skillPath);
9875
- const skillMdPath = join31(resolvedPath, "SKILL.md");
10012
+ const skillMdPath = join32(resolvedPath, "SKILL.md");
9876
10013
  if (!existsSync23(skillMdPath))
9877
10014
  continue;
9878
10015
  try {
@@ -9907,7 +10044,7 @@ $ARGUMENTS
9907
10044
  return skills;
9908
10045
  }
9909
10046
  function loadUserSkillsAsCommands() {
9910
- const userSkillsDir = join31(homedir10(), ".claude", "skills");
10047
+ const userSkillsDir = join32(homedir11(), ".claude", "skills");
9911
10048
  const skills = loadSkillsFromDir(userSkillsDir, "user");
9912
10049
  return skills.reduce((acc, skill) => {
9913
10050
  acc[skill.name] = skill.definition;
@@ -9915,7 +10052,7 @@ function loadUserSkillsAsCommands() {
9915
10052
  }, {});
9916
10053
  }
9917
10054
  function loadProjectSkillsAsCommands() {
9918
- const projectSkillsDir = join31(process.cwd(), ".claude", "skills");
10055
+ const projectSkillsDir = join32(process.cwd(), ".claude", "skills");
9919
10056
  const skills = loadSkillsFromDir(projectSkillsDir, "project");
9920
10057
  return skills.reduce((acc, skill) => {
9921
10058
  acc[skill.name] = skill.definition;
@@ -9924,8 +10061,8 @@ function loadProjectSkillsAsCommands() {
9924
10061
  }
9925
10062
  // src/features/claude-code-agent-loader/loader.ts
9926
10063
  import { existsSync as existsSync24, readdirSync as readdirSync7, readFileSync as readFileSync16 } from "fs";
9927
- import { homedir as homedir11 } from "os";
9928
- import { join as join32, basename as basename2 } from "path";
10064
+ import { homedir as homedir12 } from "os";
10065
+ import { join as join33, basename as basename2 } from "path";
9929
10066
  function parseToolsConfig(toolsStr) {
9930
10067
  if (!toolsStr)
9931
10068
  return;
@@ -9947,7 +10084,7 @@ function loadAgentsFromDir(agentsDir, scope) {
9947
10084
  for (const entry of entries) {
9948
10085
  if (!isMarkdownFile(entry))
9949
10086
  continue;
9950
- const agentPath = join32(agentsDir, entry.name);
10087
+ const agentPath = join33(agentsDir, entry.name);
9951
10088
  const agentName = basename2(entry.name, ".md");
9952
10089
  try {
9953
10090
  const content = readFileSync16(agentPath, "utf-8");
@@ -9977,7 +10114,7 @@ function loadAgentsFromDir(agentsDir, scope) {
9977
10114
  return agents;
9978
10115
  }
9979
10116
  function loadUserAgents() {
9980
- const userAgentsDir = join32(homedir11(), ".claude", "agents");
10117
+ const userAgentsDir = join33(homedir12(), ".claude", "agents");
9981
10118
  const agents = loadAgentsFromDir(userAgentsDir, "user");
9982
10119
  const result = {};
9983
10120
  for (const agent of agents) {
@@ -9986,7 +10123,7 @@ function loadUserAgents() {
9986
10123
  return result;
9987
10124
  }
9988
10125
  function loadProjectAgents() {
9989
- const projectAgentsDir = join32(process.cwd(), ".claude", "agents");
10126
+ const projectAgentsDir = join33(process.cwd(), ".claude", "agents");
9990
10127
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
9991
10128
  const result = {};
9992
10129
  for (const agent of agents) {
@@ -9996,8 +10133,8 @@ function loadProjectAgents() {
9996
10133
  }
9997
10134
  // src/features/claude-code-mcp-loader/loader.ts
9998
10135
  import { existsSync as existsSync25 } from "fs";
9999
- import { homedir as homedir12 } from "os";
10000
- import { join as join33 } from "path";
10136
+ import { homedir as homedir13 } from "os";
10137
+ import { join as join34 } from "path";
10001
10138
 
10002
10139
  // src/features/claude-code-mcp-loader/env-expander.ts
10003
10140
  function expandEnvVars(value) {
@@ -10063,12 +10200,12 @@ function transformMcpServer(name, server) {
10063
10200
 
10064
10201
  // src/features/claude-code-mcp-loader/loader.ts
10065
10202
  function getMcpConfigPaths() {
10066
- const home = homedir12();
10203
+ const home = homedir13();
10067
10204
  const cwd = process.cwd();
10068
10205
  return [
10069
- { path: join33(home, ".claude", ".mcp.json"), scope: "user" },
10070
- { path: join33(cwd, ".mcp.json"), scope: "project" },
10071
- { path: join33(cwd, ".claude", ".mcp.json"), scope: "local" }
10206
+ { path: join34(home, ".claude", ".mcp.json"), scope: "user" },
10207
+ { path: join34(cwd, ".mcp.json"), scope: "project" },
10208
+ { path: join34(cwd, ".claude", ".mcp.json"), scope: "local" }
10072
10209
  ];
10073
10210
  }
10074
10211
  async function loadMcpConfigFile(filePath) {
@@ -10359,8 +10496,8 @@ var EXT_TO_LANG = {
10359
10496
  };
10360
10497
  // src/tools/lsp/config.ts
10361
10498
  import { existsSync as existsSync26, readFileSync as readFileSync17 } from "fs";
10362
- import { join as join34 } from "path";
10363
- import { homedir as homedir13 } from "os";
10499
+ import { join as join35 } from "path";
10500
+ import { homedir as homedir14 } from "os";
10364
10501
  function loadJsonFile(path6) {
10365
10502
  if (!existsSync26(path6))
10366
10503
  return null;
@@ -10373,9 +10510,9 @@ function loadJsonFile(path6) {
10373
10510
  function getConfigPaths2() {
10374
10511
  const cwd = process.cwd();
10375
10512
  return {
10376
- project: join34(cwd, ".opencode", "oh-my-opencode.json"),
10377
- user: join34(homedir13(), ".config", "opencode", "oh-my-opencode.json"),
10378
- opencode: join34(homedir13(), ".config", "opencode", "opencode.json")
10513
+ project: join35(cwd, ".opencode", "oh-my-opencode.json"),
10514
+ user: join35(homedir14(), ".config", "opencode", "oh-my-opencode.json"),
10515
+ opencode: join35(homedir14(), ".config", "opencode", "opencode.json")
10379
10516
  };
10380
10517
  }
10381
10518
  function loadAllConfigs() {
@@ -10468,7 +10605,7 @@ function isServerInstalled(command) {
10468
10605
  const pathEnv = process.env.PATH || "";
10469
10606
  const paths = pathEnv.split(":");
10470
10607
  for (const p of paths) {
10471
- if (existsSync26(join34(p, cmd))) {
10608
+ if (existsSync26(join35(p, cmd))) {
10472
10609
  return true;
10473
10610
  }
10474
10611
  }
@@ -23967,14 +24104,14 @@ var lsp_code_action_resolve = tool({
23967
24104
  });
23968
24105
  // src/tools/ast-grep/constants.ts
23969
24106
  import { createRequire as createRequire4 } from "module";
23970
- import { dirname as dirname6, join as join36 } from "path";
24107
+ import { dirname as dirname6, join as join37 } from "path";
23971
24108
  import { existsSync as existsSync29, statSync as statSync4 } from "fs";
23972
24109
 
23973
24110
  // src/tools/ast-grep/downloader.ts
23974
24111
  var {spawn: spawn5 } = globalThis.Bun;
23975
24112
  import { existsSync as existsSync28, mkdirSync as mkdirSync10, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
23976
- import { join as join35 } from "path";
23977
- import { homedir as homedir14 } from "os";
24113
+ import { join as join36 } from "path";
24114
+ import { homedir as homedir15 } from "os";
23978
24115
  import { createRequire as createRequire3 } from "module";
23979
24116
  var REPO2 = "ast-grep/ast-grep";
23980
24117
  var DEFAULT_VERSION = "0.40.0";
@@ -23999,18 +24136,18 @@ var PLATFORM_MAP2 = {
23999
24136
  function getCacheDir3() {
24000
24137
  if (process.platform === "win32") {
24001
24138
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
24002
- const base2 = localAppData || join35(homedir14(), "AppData", "Local");
24003
- return join35(base2, "oh-my-opencode", "bin");
24139
+ const base2 = localAppData || join36(homedir15(), "AppData", "Local");
24140
+ return join36(base2, "oh-my-opencode", "bin");
24004
24141
  }
24005
24142
  const xdgCache2 = process.env.XDG_CACHE_HOME;
24006
- const base = xdgCache2 || join35(homedir14(), ".cache");
24007
- return join35(base, "oh-my-opencode", "bin");
24143
+ const base = xdgCache2 || join36(homedir15(), ".cache");
24144
+ return join36(base, "oh-my-opencode", "bin");
24008
24145
  }
24009
24146
  function getBinaryName3() {
24010
24147
  return process.platform === "win32" ? "sg.exe" : "sg";
24011
24148
  }
24012
24149
  function getCachedBinaryPath2() {
24013
- const binaryPath = join35(getCacheDir3(), getBinaryName3());
24150
+ const binaryPath = join36(getCacheDir3(), getBinaryName3());
24014
24151
  return existsSync28(binaryPath) ? binaryPath : null;
24015
24152
  }
24016
24153
  async function extractZip2(archivePath, destDir) {
@@ -24037,7 +24174,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
24037
24174
  }
24038
24175
  const cacheDir = getCacheDir3();
24039
24176
  const binaryName = getBinaryName3();
24040
- const binaryPath = join35(cacheDir, binaryName);
24177
+ const binaryPath = join36(cacheDir, binaryName);
24041
24178
  if (existsSync28(binaryPath)) {
24042
24179
  return binaryPath;
24043
24180
  }
@@ -24053,7 +24190,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
24053
24190
  if (!response2.ok) {
24054
24191
  throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
24055
24192
  }
24056
- const archivePath = join35(cacheDir, assetName);
24193
+ const archivePath = join36(cacheDir, assetName);
24057
24194
  const arrayBuffer = await response2.arrayBuffer();
24058
24195
  await Bun.write(archivePath, arrayBuffer);
24059
24196
  await extractZip2(archivePath, cacheDir);
@@ -24111,7 +24248,7 @@ function findSgCliPathSync() {
24111
24248
  const require2 = createRequire4(import.meta.url);
24112
24249
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
24113
24250
  const cliDir = dirname6(cliPkgPath);
24114
- const sgPath = join36(cliDir, binaryName);
24251
+ const sgPath = join37(cliDir, binaryName);
24115
24252
  if (existsSync29(sgPath) && isValidBinary(sgPath)) {
24116
24253
  return sgPath;
24117
24254
  }
@@ -24123,7 +24260,7 @@ function findSgCliPathSync() {
24123
24260
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
24124
24261
  const pkgDir = dirname6(pkgPath);
24125
24262
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
24126
- const binaryPath = join36(pkgDir, astGrepName);
24263
+ const binaryPath = join37(pkgDir, astGrepName);
24127
24264
  if (existsSync29(binaryPath) && isValidBinary(binaryPath)) {
24128
24265
  return binaryPath;
24129
24266
  }
@@ -24499,19 +24636,19 @@ var {spawn: spawn7 } = globalThis.Bun;
24499
24636
 
24500
24637
  // src/tools/grep/constants.ts
24501
24638
  import { existsSync as existsSync32 } from "fs";
24502
- import { join as join38, dirname as dirname7 } from "path";
24639
+ import { join as join39, dirname as dirname7 } from "path";
24503
24640
  import { spawnSync } from "child_process";
24504
24641
 
24505
24642
  // src/tools/grep/downloader.ts
24506
24643
  import { existsSync as existsSync31, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync8 } from "fs";
24507
- import { join as join37 } from "path";
24644
+ import { join as join38 } from "path";
24508
24645
  function getInstallDir() {
24509
24646
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
24510
- return join37(homeDir, ".cache", "oh-my-opencode", "bin");
24647
+ return join38(homeDir, ".cache", "oh-my-opencode", "bin");
24511
24648
  }
24512
24649
  function getRgPath() {
24513
- const isWindows = process.platform === "win32";
24514
- return join37(getInstallDir(), isWindows ? "rg.exe" : "rg");
24650
+ const isWindows2 = process.platform === "win32";
24651
+ return join38(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
24515
24652
  }
24516
24653
  function getInstalledRipgrepPath() {
24517
24654
  const rgPath = getRgPath();
@@ -24521,8 +24658,8 @@ function getInstalledRipgrepPath() {
24521
24658
  // src/tools/grep/constants.ts
24522
24659
  var cachedCli = null;
24523
24660
  function findExecutable(name) {
24524
- const isWindows = process.platform === "win32";
24525
- const cmd = isWindows ? "where" : "which";
24661
+ const isWindows2 = process.platform === "win32";
24662
+ const cmd = isWindows2 ? "where" : "which";
24526
24663
  try {
24527
24664
  const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 });
24528
24665
  if (result.status === 0 && result.stdout.trim()) {
@@ -24535,13 +24672,13 @@ function findExecutable(name) {
24535
24672
  function getOpenCodeBundledRg() {
24536
24673
  const execPath = process.execPath;
24537
24674
  const execDir = dirname7(execPath);
24538
- const isWindows = process.platform === "win32";
24539
- const rgName = isWindows ? "rg.exe" : "rg";
24675
+ const isWindows2 = process.platform === "win32";
24676
+ const rgName = isWindows2 ? "rg.exe" : "rg";
24540
24677
  const candidates = [
24541
- join38(execDir, rgName),
24542
- join38(execDir, "bin", rgName),
24543
- join38(execDir, "..", "bin", rgName),
24544
- join38(execDir, "..", "libexec", rgName)
24678
+ join39(execDir, rgName),
24679
+ join39(execDir, "bin", rgName),
24680
+ join39(execDir, "..", "bin", rgName),
24681
+ join39(execDir, "..", "libexec", rgName)
24545
24682
  ];
24546
24683
  for (const candidate of candidates) {
24547
24684
  if (existsSync32(candidate)) {
@@ -24948,8 +25085,8 @@ var glob = tool({
24948
25085
  });
24949
25086
  // src/tools/slashcommand/tools.ts
24950
25087
  import { existsSync as existsSync33, readdirSync as readdirSync9, readFileSync as readFileSync20 } from "fs";
24951
- import { homedir as homedir15 } from "os";
24952
- import { join as join39, basename as basename3, dirname as dirname8 } from "path";
25088
+ import { homedir as homedir16 } from "os";
25089
+ import { join as join40, basename as basename3, dirname as dirname8 } from "path";
24953
25090
  function discoverCommandsFromDir(commandsDir, scope) {
24954
25091
  if (!existsSync33(commandsDir)) {
24955
25092
  return [];
@@ -24959,7 +25096,7 @@ function discoverCommandsFromDir(commandsDir, scope) {
24959
25096
  for (const entry of entries) {
24960
25097
  if (!isMarkdownFile(entry))
24961
25098
  continue;
24962
- const commandPath = join39(commandsDir, entry.name);
25099
+ const commandPath = join40(commandsDir, entry.name);
24963
25100
  const commandName = basename3(entry.name, ".md");
24964
25101
  try {
24965
25102
  const content = readFileSync20(commandPath, "utf-8");
@@ -24987,10 +25124,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
24987
25124
  return commands;
24988
25125
  }
24989
25126
  function discoverCommandsSync() {
24990
- const userCommandsDir = join39(homedir15(), ".claude", "commands");
24991
- const projectCommandsDir = join39(process.cwd(), ".claude", "commands");
24992
- const opencodeGlobalDir = join39(homedir15(), ".config", "opencode", "command");
24993
- const opencodeProjectDir = join39(process.cwd(), ".opencode", "command");
25127
+ const userCommandsDir = join40(homedir16(), ".claude", "commands");
25128
+ const projectCommandsDir = join40(process.cwd(), ".claude", "commands");
25129
+ const opencodeGlobalDir = join40(homedir16(), ".config", "opencode", "command");
25130
+ const opencodeProjectDir = join40(process.cwd(), ".opencode", "command");
24994
25131
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
24995
25132
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
24996
25133
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -25123,8 +25260,8 @@ var SkillFrontmatterSchema = exports_external.object({
25123
25260
  });
25124
25261
  // src/tools/skill/tools.ts
25125
25262
  import { existsSync as existsSync34, readdirSync as readdirSync10, readFileSync as readFileSync21 } from "fs";
25126
- import { homedir as homedir16 } from "os";
25127
- import { join as join40, basename as basename4 } from "path";
25263
+ import { homedir as homedir17 } from "os";
25264
+ import { join as join41, basename as basename4 } from "path";
25128
25265
  function parseSkillFrontmatter(data) {
25129
25266
  return {
25130
25267
  name: typeof data.name === "string" ? data.name : "",
@@ -25143,10 +25280,10 @@ function discoverSkillsFromDir(skillsDir, scope) {
25143
25280
  for (const entry of entries) {
25144
25281
  if (entry.name.startsWith("."))
25145
25282
  continue;
25146
- const skillPath = join40(skillsDir, entry.name);
25283
+ const skillPath = join41(skillsDir, entry.name);
25147
25284
  if (entry.isDirectory() || entry.isSymbolicLink()) {
25148
25285
  const resolvedPath = resolveSymlink(skillPath);
25149
- const skillMdPath = join40(resolvedPath, "SKILL.md");
25286
+ const skillMdPath = join41(resolvedPath, "SKILL.md");
25150
25287
  if (!existsSync34(skillMdPath))
25151
25288
  continue;
25152
25289
  try {
@@ -25165,8 +25302,8 @@ function discoverSkillsFromDir(skillsDir, scope) {
25165
25302
  return skills;
25166
25303
  }
25167
25304
  function discoverSkillsSync() {
25168
- const userSkillsDir = join40(homedir16(), ".claude", "skills");
25169
- const projectSkillsDir = join40(process.cwd(), ".claude", "skills");
25305
+ const userSkillsDir = join41(homedir17(), ".claude", "skills");
25306
+ const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
25170
25307
  const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
25171
25308
  const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
25172
25309
  return [...projectSkills, ...userSkills];
@@ -25176,7 +25313,7 @@ var skillListForDescription = availableSkills.map((s) => `- ${s.name}: ${s.descr
25176
25313
  `);
25177
25314
  async function parseSkillMd(skillPath) {
25178
25315
  const resolvedPath = resolveSymlink(skillPath);
25179
- const skillMdPath = join40(resolvedPath, "SKILL.md");
25316
+ const skillMdPath = join41(resolvedPath, "SKILL.md");
25180
25317
  if (!existsSync34(skillMdPath)) {
25181
25318
  return null;
25182
25319
  }
@@ -25192,9 +25329,9 @@ async function parseSkillMd(skillPath) {
25192
25329
  allowedTools: frontmatter2["allowed-tools"],
25193
25330
  metadata: frontmatter2.metadata
25194
25331
  };
25195
- const referencesDir = join40(resolvedPath, "references");
25196
- const scriptsDir = join40(resolvedPath, "scripts");
25197
- const assetsDir = join40(resolvedPath, "assets");
25332
+ const referencesDir = join41(resolvedPath, "references");
25333
+ const scriptsDir = join41(resolvedPath, "scripts");
25334
+ const assetsDir = join41(resolvedPath, "assets");
25198
25335
  const references = existsSync34(referencesDir) ? readdirSync10(referencesDir).filter((f) => !f.startsWith(".")) : [];
25199
25336
  const scripts = existsSync34(scriptsDir) ? readdirSync10(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
25200
25337
  const assets = existsSync34(assetsDir) ? readdirSync10(assetsDir).filter((f) => !f.startsWith(".")) : [];
@@ -25221,7 +25358,7 @@ async function discoverSkillsFromDirAsync(skillsDir) {
25221
25358
  for (const entry of entries) {
25222
25359
  if (entry.name.startsWith("."))
25223
25360
  continue;
25224
- const skillPath = join40(skillsDir, entry.name);
25361
+ const skillPath = join41(skillsDir, entry.name);
25225
25362
  if (entry.isDirectory() || entry.isSymbolicLink()) {
25226
25363
  const skillInfo = await parseSkillMd(skillPath);
25227
25364
  if (skillInfo) {
@@ -25232,8 +25369,8 @@ async function discoverSkillsFromDirAsync(skillsDir) {
25232
25369
  return skills;
25233
25370
  }
25234
25371
  async function discoverSkills() {
25235
- const userSkillsDir = join40(homedir16(), ".claude", "skills");
25236
- const projectSkillsDir = join40(process.cwd(), ".claude", "skills");
25372
+ const userSkillsDir = join41(homedir17(), ".claude", "skills");
25373
+ const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
25237
25374
  const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
25238
25375
  const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
25239
25376
  return [...projectSkills, ...userSkills];
@@ -25262,7 +25399,7 @@ async function loadSkillWithReferences(skill, includeRefs) {
25262
25399
  const referencesLoaded = [];
25263
25400
  if (includeRefs && skill.references.length > 0) {
25264
25401
  for (const ref of skill.references) {
25265
- const refPath = join40(skill.path, "references", ref);
25402
+ const refPath = join41(skill.path, "references", ref);
25266
25403
  try {
25267
25404
  let content = readFileSync21(refPath, "utf-8");
25268
25405
  content = await resolveCommandsInText(content);
@@ -25355,17 +25492,33 @@ Try a different skill name.`;
25355
25492
  });
25356
25493
  // src/tools/interactive-bash/constants.ts
25357
25494
  var DEFAULT_TIMEOUT_MS4 = 60000;
25495
+ var BLOCKED_TMUX_SUBCOMMANDS = [
25496
+ "capture-pane",
25497
+ "capturep",
25498
+ "save-buffer",
25499
+ "saveb",
25500
+ "show-buffer",
25501
+ "showb",
25502
+ "pipe-pane",
25503
+ "pipep"
25504
+ ];
25358
25505
  var INTERACTIVE_BASH_DESCRIPTION = `Execute tmux commands for interactive terminal session management.
25359
25506
 
25360
- Use session names following the pattern "omo-{name}" for automatic tracking.`;
25507
+ Use session names following the pattern "omo-{name}" for automatic tracking.
25508
+
25509
+ BLOCKED COMMANDS (use bash tool instead):
25510
+ - capture-pane / capturep: Use bash to read output files or pipe output
25511
+ - save-buffer / saveb: Use bash to save content to files
25512
+ - show-buffer / showb: Use bash to read buffer content
25513
+ - pipe-pane / pipep: Use bash for piping output`;
25361
25514
 
25362
25515
  // src/tools/interactive-bash/utils.ts
25363
25516
  var {spawn: spawn9 } = globalThis.Bun;
25364
25517
  var tmuxPath = null;
25365
25518
  var initPromise3 = null;
25366
25519
  async function findTmuxPath() {
25367
- const isWindows = process.platform === "win32";
25368
- const cmd = isWindows ? "where" : "which";
25520
+ const isWindows2 = process.platform === "win32";
25521
+ const cmd = isWindows2 ? "where" : "which";
25369
25522
  try {
25370
25523
  const proc = spawn9([cmd, "tmux"], {
25371
25524
  stdout: "pipe",
@@ -25461,6 +25614,10 @@ var interactive_bash = tool({
25461
25614
  if (parts.length === 0) {
25462
25615
  return "Error: Empty tmux command";
25463
25616
  }
25617
+ const subcommand = parts[0].toLowerCase();
25618
+ if (BLOCKED_TMUX_SUBCOMMANDS.includes(subcommand)) {
25619
+ return `Error: '${parts[0]}' is blocked. Use bash tool instead for capturing/printing terminal output.`;
25620
+ }
25464
25621
  const proc = Bun.spawn([tmuxPath2, ...parts], {
25465
25622
  stdout: "pipe",
25466
25623
  stderr: "pipe"
@@ -26041,15 +26198,15 @@ var builtinTools = {
26041
26198
  };
26042
26199
  // src/features/background-agent/manager.ts
26043
26200
  import { existsSync as existsSync35, readdirSync as readdirSync11 } from "fs";
26044
- import { join as join41 } from "path";
26201
+ import { join as join42 } from "path";
26045
26202
  function getMessageDir3(sessionID) {
26046
26203
  if (!existsSync35(MESSAGE_STORAGE))
26047
26204
  return null;
26048
- const directPath = join41(MESSAGE_STORAGE, sessionID);
26205
+ const directPath = join42(MESSAGE_STORAGE, sessionID);
26049
26206
  if (existsSync35(directPath))
26050
26207
  return directPath;
26051
26208
  for (const dir of readdirSync11(MESSAGE_STORAGE)) {
26052
- const sessionPath = join41(MESSAGE_STORAGE, dir, sessionID);
26209
+ const sessionPath = join42(MESSAGE_STORAGE, dir, sessionID);
26053
26210
  if (existsSync35(sessionPath))
26054
26211
  return sessionPath;
26055
26212
  }
@@ -26106,7 +26263,6 @@ class BackgroundManager {
26106
26263
  agent: input.agent,
26107
26264
  tools: {
26108
26265
  task: false,
26109
- call_omo_agent: false,
26110
26266
  background_task: false
26111
26267
  },
26112
26268
  parts: [{ type: "text", text: input.prompt }]
@@ -26149,6 +26305,20 @@ class BackgroundManager {
26149
26305
  }
26150
26306
  return;
26151
26307
  }
26308
+ async checkSessionTodos(sessionID) {
26309
+ try {
26310
+ const response2 = await this.client.session.todo({
26311
+ path: { id: sessionID }
26312
+ });
26313
+ const todos = response2.data ?? response2;
26314
+ if (!todos || todos.length === 0)
26315
+ return false;
26316
+ const incomplete = todos.filter((t) => t.status !== "completed" && t.status !== "cancelled");
26317
+ return incomplete.length > 0;
26318
+ } catch {
26319
+ return false;
26320
+ }
26321
+ }
26152
26322
  handleEvent(event) {
26153
26323
  const props = event.properties;
26154
26324
  if (event.type === "message.part.updated") {
@@ -26180,11 +26350,17 @@ class BackgroundManager {
26180
26350
  const task = this.findBySession(sessionID);
26181
26351
  if (!task || task.status !== "running")
26182
26352
  return;
26183
- task.status = "completed";
26184
- task.completedAt = new Date;
26185
- this.markForNotification(task);
26186
- this.notifyParentSession(task);
26187
- log("[background-agent] Task completed via session.idle event:", task.id);
26353
+ this.checkSessionTodos(sessionID).then((hasIncompleteTodos2) => {
26354
+ if (hasIncompleteTodos2) {
26355
+ log("[background-agent] Task has incomplete todos, waiting for todo-continuation:", task.id);
26356
+ return;
26357
+ }
26358
+ task.status = "completed";
26359
+ task.completedAt = new Date;
26360
+ this.markForNotification(task);
26361
+ this.notifyParentSession(task);
26362
+ log("[background-agent] Task completed via session.idle event:", task.id);
26363
+ });
26188
26364
  }
26189
26365
  if (event.type === "session.deleted") {
26190
26366
  const info = props?.info;
@@ -26304,6 +26480,11 @@ class BackgroundManager {
26304
26480
  continue;
26305
26481
  }
26306
26482
  if (sessionStatus.type === "idle") {
26483
+ const hasIncompleteTodos2 = await this.checkSessionTodos(task.sessionID);
26484
+ if (hasIncompleteTodos2) {
26485
+ log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
26486
+ continue;
26487
+ }
26307
26488
  task.status = "completed";
26308
26489
  task.completedAt = new Date;
26309
26490
  this.markForNotification(task);