oh-my-opencode 2.5.2 → 2.5.3

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
@@ -222,8 +222,8 @@ var require_utils = __commonJS((exports) => {
222
222
  }
223
223
  return output;
224
224
  };
225
- exports.basename = (path4, { windows } = {}) => {
226
- const segs = path4.split(windows ? /[\\/]/ : "/");
225
+ exports.basename = (path5, { windows } = {}) => {
226
+ const segs = path5.split(windows ? /[\\/]/ : "/");
227
227
  const last = segs[segs.length - 1];
228
228
  if (last === "") {
229
229
  return segs[segs.length - 2];
@@ -3269,6 +3269,18 @@ function getUserConfigDir() {
3269
3269
  }
3270
3270
  return process.env.XDG_CONFIG_HOME || path2.join(os2.homedir(), ".config");
3271
3271
  }
3272
+ // src/shared/data-path.ts
3273
+ import * as path3 from "path";
3274
+ import * as os3 from "os";
3275
+ function getDataDir() {
3276
+ if (process.platform === "win32") {
3277
+ return process.env.LOCALAPPDATA ?? path3.join(os3.homedir(), "AppData", "Local");
3278
+ }
3279
+ return process.env.XDG_DATA_HOME ?? path3.join(os3.homedir(), ".local", "share");
3280
+ }
3281
+ function getOpenCodeStorageDir() {
3282
+ return path3.join(getDataDir(), "opencode", "storage");
3283
+ }
3272
3284
  // src/shared/config-errors.ts
3273
3285
  var configLoadErrors = [];
3274
3286
  function getConfigLoadErrors() {
@@ -3356,7 +3368,7 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory
3356
3368
  }
3357
3369
  // src/hooks/todo-continuation-enforcer.ts
3358
3370
  import { existsSync as existsSync5, readdirSync as readdirSync2 } from "fs";
3359
- import { join as join6 } from "path";
3371
+ import { join as join7 } from "path";
3360
3372
 
3361
3373
  // src/features/claude-code-session-state/state.ts
3362
3374
  var subagentSessions = new Set;
@@ -3369,15 +3381,13 @@ function getMainSessionID() {
3369
3381
  }
3370
3382
  // src/features/hook-message-injector/injector.ts
3371
3383
  import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync2, readdirSync, writeFileSync } from "fs";
3372
- import { join as join5 } from "path";
3384
+ import { join as join6 } from "path";
3373
3385
 
3374
3386
  // src/features/hook-message-injector/constants.ts
3375
- import { join as join4 } from "path";
3376
- import { homedir as homedir3 } from "os";
3377
- var xdgData = process.env.XDG_DATA_HOME || join4(homedir3(), ".local", "share");
3378
- var OPENCODE_STORAGE = join4(xdgData, "opencode", "storage");
3379
- var MESSAGE_STORAGE = join4(OPENCODE_STORAGE, "message");
3380
- var PART_STORAGE = join4(OPENCODE_STORAGE, "part");
3387
+ import { join as join5 } from "path";
3388
+ var OPENCODE_STORAGE = getOpenCodeStorageDir();
3389
+ var MESSAGE_STORAGE = join5(OPENCODE_STORAGE, "message");
3390
+ var PART_STORAGE = join5(OPENCODE_STORAGE, "part");
3381
3391
 
3382
3392
  // src/features/hook-message-injector/injector.ts
3383
3393
  function findNearestMessageWithFields(messageDir) {
@@ -3385,7 +3395,7 @@ function findNearestMessageWithFields(messageDir) {
3385
3395
  const files = readdirSync(messageDir).filter((f) => f.endsWith(".json")).sort().reverse();
3386
3396
  for (const file of files) {
3387
3397
  try {
3388
- const content = readFileSync2(join5(messageDir, file), "utf-8");
3398
+ const content = readFileSync2(join6(messageDir, file), "utf-8");
3389
3399
  const msg = JSON.parse(content);
3390
3400
  if (msg.agent && msg.model?.providerID && msg.model?.modelID) {
3391
3401
  return msg;
@@ -3413,12 +3423,12 @@ function getOrCreateMessageDir(sessionID) {
3413
3423
  if (!existsSync4(MESSAGE_STORAGE)) {
3414
3424
  mkdirSync(MESSAGE_STORAGE, { recursive: true });
3415
3425
  }
3416
- const directPath = join5(MESSAGE_STORAGE, sessionID);
3426
+ const directPath = join6(MESSAGE_STORAGE, sessionID);
3417
3427
  if (existsSync4(directPath)) {
3418
3428
  return directPath;
3419
3429
  }
3420
3430
  for (const dir of readdirSync(MESSAGE_STORAGE)) {
3421
- const sessionPath = join5(MESSAGE_STORAGE, dir, sessionID);
3431
+ const sessionPath = join6(MESSAGE_STORAGE, dir, sessionID);
3422
3432
  if (existsSync4(sessionPath)) {
3423
3433
  return sessionPath;
3424
3434
  }
@@ -3472,12 +3482,12 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
3472
3482
  sessionID
3473
3483
  };
3474
3484
  try {
3475
- writeFileSync(join5(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
3476
- const partDir = join5(PART_STORAGE, messageID);
3485
+ writeFileSync(join6(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
3486
+ const partDir = join6(PART_STORAGE, messageID);
3477
3487
  if (!existsSync4(partDir)) {
3478
3488
  mkdirSync(partDir, { recursive: true });
3479
3489
  }
3480
- writeFileSync(join5(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
3490
+ writeFileSync(join6(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
3481
3491
  return true;
3482
3492
  } catch {
3483
3493
  return false;
@@ -3512,11 +3522,11 @@ Incomplete tasks remain in your todo list. Continue working on the next pending
3512
3522
  function getMessageDir(sessionID) {
3513
3523
  if (!existsSync5(MESSAGE_STORAGE))
3514
3524
  return null;
3515
- const directPath = join6(MESSAGE_STORAGE, sessionID);
3525
+ const directPath = join7(MESSAGE_STORAGE, sessionID);
3516
3526
  if (existsSync5(directPath))
3517
3527
  return directPath;
3518
3528
  for (const dir of readdirSync2(MESSAGE_STORAGE)) {
3519
- const sessionPath = join6(MESSAGE_STORAGE, dir, sessionID);
3529
+ const sessionPath = join7(MESSAGE_STORAGE, dir, sessionID);
3520
3530
  if (existsSync5(sessionPath))
3521
3531
  return sessionPath;
3522
3532
  }
@@ -3723,7 +3733,8 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
3723
3733
  }
3724
3734
  if (sessionID && role === "assistant" && finish) {
3725
3735
  remindedSessions.delete(sessionID);
3726
- log(`[${HOOK_NAME}] Cleared reminded state on assistant finish`, { sessionID });
3736
+ preemptivelyInjectedSessions.delete(sessionID);
3737
+ log(`[${HOOK_NAME}] Cleared reminded/preemptive state on assistant finish`, { sessionID });
3727
3738
  const isTerminalFinish = finish && !["tool-calls", "unknown"].includes(finish);
3728
3739
  if (isTerminalFinish && isNonInteractive()) {
3729
3740
  log(`[${HOOK_NAME}] Terminal finish in non-interactive mode`, { sessionID, finish });
@@ -4090,24 +4101,24 @@ function createSessionNotification(ctx, config = {}) {
4090
4101
  }
4091
4102
  // src/hooks/session-recovery/storage.ts
4092
4103
  import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
4093
- import { join as join8 } from "path";
4104
+ import { join as join9 } from "path";
4094
4105
 
4095
4106
  // src/hooks/session-recovery/constants.ts
4096
- import { join as join7 } from "path";
4107
+ import { join as join8 } from "path";
4097
4108
 
4098
4109
  // node_modules/xdg-basedir/index.js
4099
- import os3 from "os";
4100
- import path3 from "path";
4101
- var homeDirectory = os3.homedir();
4110
+ import os4 from "os";
4111
+ import path4 from "path";
4112
+ var homeDirectory = os4.homedir();
4102
4113
  var { env } = process;
4103
- var xdgData2 = env.XDG_DATA_HOME || (homeDirectory ? path3.join(homeDirectory, ".local", "share") : undefined);
4104
- var xdgConfig = env.XDG_CONFIG_HOME || (homeDirectory ? path3.join(homeDirectory, ".config") : undefined);
4105
- var xdgState = env.XDG_STATE_HOME || (homeDirectory ? path3.join(homeDirectory, ".local", "state") : undefined);
4106
- var xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? path3.join(homeDirectory, ".cache") : undefined);
4114
+ var xdgData = env.XDG_DATA_HOME || (homeDirectory ? path4.join(homeDirectory, ".local", "share") : undefined);
4115
+ var xdgConfig = env.XDG_CONFIG_HOME || (homeDirectory ? path4.join(homeDirectory, ".config") : undefined);
4116
+ var xdgState = env.XDG_STATE_HOME || (homeDirectory ? path4.join(homeDirectory, ".local", "state") : undefined);
4117
+ var xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? path4.join(homeDirectory, ".cache") : undefined);
4107
4118
  var xdgRuntime = env.XDG_RUNTIME_DIR || undefined;
4108
4119
  var xdgDataDirectories = (env.XDG_DATA_DIRS || "/usr/local/share/:/usr/share/").split(":");
4109
- if (xdgData2) {
4110
- xdgDataDirectories.unshift(xdgData2);
4120
+ if (xdgData) {
4121
+ xdgDataDirectories.unshift(xdgData);
4111
4122
  }
4112
4123
  var xdgConfigDirectories = (env.XDG_CONFIG_DIRS || "/etc/xdg").split(":");
4113
4124
  if (xdgConfig) {
@@ -4115,9 +4126,9 @@ if (xdgConfig) {
4115
4126
  }
4116
4127
 
4117
4128
  // src/hooks/session-recovery/constants.ts
4118
- var OPENCODE_STORAGE2 = join7(xdgData2 ?? "", "opencode", "storage");
4119
- var MESSAGE_STORAGE2 = join7(OPENCODE_STORAGE2, "message");
4120
- var PART_STORAGE2 = join7(OPENCODE_STORAGE2, "part");
4129
+ var OPENCODE_STORAGE2 = join8(xdgData ?? "", "opencode", "storage");
4130
+ var MESSAGE_STORAGE2 = join8(OPENCODE_STORAGE2, "message");
4131
+ var PART_STORAGE2 = join8(OPENCODE_STORAGE2, "part");
4121
4132
  var THINKING_TYPES = new Set(["thinking", "redacted_thinking", "reasoning"]);
4122
4133
  var META_TYPES = new Set(["step-start", "step-finish"]);
4123
4134
  var CONTENT_TYPES = new Set(["text", "tool", "tool_use", "tool_result"]);
@@ -4131,12 +4142,12 @@ function generatePartId2() {
4131
4142
  function getMessageDir2(sessionID) {
4132
4143
  if (!existsSync6(MESSAGE_STORAGE2))
4133
4144
  return "";
4134
- const directPath = join8(MESSAGE_STORAGE2, sessionID);
4145
+ const directPath = join9(MESSAGE_STORAGE2, sessionID);
4135
4146
  if (existsSync6(directPath)) {
4136
4147
  return directPath;
4137
4148
  }
4138
4149
  for (const dir of readdirSync3(MESSAGE_STORAGE2)) {
4139
- const sessionPath = join8(MESSAGE_STORAGE2, dir, sessionID);
4150
+ const sessionPath = join9(MESSAGE_STORAGE2, dir, sessionID);
4140
4151
  if (existsSync6(sessionPath)) {
4141
4152
  return sessionPath;
4142
4153
  }
@@ -4152,7 +4163,7 @@ function readMessages(sessionID) {
4152
4163
  if (!file.endsWith(".json"))
4153
4164
  continue;
4154
4165
  try {
4155
- const content = readFileSync3(join8(messageDir, file), "utf-8");
4166
+ const content = readFileSync3(join9(messageDir, file), "utf-8");
4156
4167
  messages.push(JSON.parse(content));
4157
4168
  } catch {
4158
4169
  continue;
@@ -4167,7 +4178,7 @@ function readMessages(sessionID) {
4167
4178
  });
4168
4179
  }
4169
4180
  function readParts(messageID) {
4170
- const partDir = join8(PART_STORAGE2, messageID);
4181
+ const partDir = join9(PART_STORAGE2, messageID);
4171
4182
  if (!existsSync6(partDir))
4172
4183
  return [];
4173
4184
  const parts = [];
@@ -4175,7 +4186,7 @@ function readParts(messageID) {
4175
4186
  if (!file.endsWith(".json"))
4176
4187
  continue;
4177
4188
  try {
4178
- const content = readFileSync3(join8(partDir, file), "utf-8");
4189
+ const content = readFileSync3(join9(partDir, file), "utf-8");
4179
4190
  parts.push(JSON.parse(content));
4180
4191
  } catch {
4181
4192
  continue;
@@ -4205,7 +4216,7 @@ function messageHasContent(messageID) {
4205
4216
  return parts.some(hasContent);
4206
4217
  }
4207
4218
  function injectTextPart(sessionID, messageID, text) {
4208
- const partDir = join8(PART_STORAGE2, messageID);
4219
+ const partDir = join9(PART_STORAGE2, messageID);
4209
4220
  if (!existsSync6(partDir)) {
4210
4221
  mkdirSync2(partDir, { recursive: true });
4211
4222
  }
@@ -4219,7 +4230,7 @@ function injectTextPart(sessionID, messageID, text) {
4219
4230
  synthetic: true
4220
4231
  };
4221
4232
  try {
4222
- writeFileSync2(join8(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
4233
+ writeFileSync2(join9(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
4223
4234
  return true;
4224
4235
  } catch {
4225
4236
  return false;
@@ -4282,7 +4293,7 @@ function findMessagesWithOrphanThinking(sessionID) {
4282
4293
  return result;
4283
4294
  }
4284
4295
  function prependThinkingPart(sessionID, messageID) {
4285
- const partDir = join8(PART_STORAGE2, messageID);
4296
+ const partDir = join9(PART_STORAGE2, messageID);
4286
4297
  if (!existsSync6(partDir)) {
4287
4298
  mkdirSync2(partDir, { recursive: true });
4288
4299
  }
@@ -4296,14 +4307,14 @@ function prependThinkingPart(sessionID, messageID) {
4296
4307
  synthetic: true
4297
4308
  };
4298
4309
  try {
4299
- writeFileSync2(join8(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
4310
+ writeFileSync2(join9(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
4300
4311
  return true;
4301
4312
  } catch {
4302
4313
  return false;
4303
4314
  }
4304
4315
  }
4305
4316
  function stripThinkingParts(messageID) {
4306
- const partDir = join8(PART_STORAGE2, messageID);
4317
+ const partDir = join9(PART_STORAGE2, messageID);
4307
4318
  if (!existsSync6(partDir))
4308
4319
  return false;
4309
4320
  let anyRemoved = false;
@@ -4311,7 +4322,7 @@ function stripThinkingParts(messageID) {
4311
4322
  if (!file.endsWith(".json"))
4312
4323
  continue;
4313
4324
  try {
4314
- const filePath = join8(partDir, file);
4325
+ const filePath = join9(partDir, file);
4315
4326
  const content = readFileSync3(filePath, "utf-8");
4316
4327
  const part = JSON.parse(content);
4317
4328
  if (THINKING_TYPES.has(part.type)) {
@@ -4325,7 +4336,7 @@ function stripThinkingParts(messageID) {
4325
4336
  return anyRemoved;
4326
4337
  }
4327
4338
  function replaceEmptyTextParts(messageID, replacementText) {
4328
- const partDir = join8(PART_STORAGE2, messageID);
4339
+ const partDir = join9(PART_STORAGE2, messageID);
4329
4340
  if (!existsSync6(partDir))
4330
4341
  return false;
4331
4342
  let anyReplaced = false;
@@ -4333,7 +4344,7 @@ function replaceEmptyTextParts(messageID, replacementText) {
4333
4344
  if (!file.endsWith(".json"))
4334
4345
  continue;
4335
4346
  try {
4336
- const filePath = join8(partDir, file);
4347
+ const filePath = join9(partDir, file);
4337
4348
  const content = readFileSync3(filePath, "utf-8");
4338
4349
  const part = JSON.parse(content);
4339
4350
  if (part.type === "text") {
@@ -4610,7 +4621,7 @@ function createSessionRecoveryHook(ctx, options) {
4610
4621
  // src/hooks/comment-checker/cli.ts
4611
4622
  var {spawn: spawn3 } = globalThis.Bun;
4612
4623
  import { createRequire as createRequire2 } from "module";
4613
- import { dirname, join as join10 } from "path";
4624
+ import { dirname, join as join11 } from "path";
4614
4625
  import { existsSync as existsSync8 } from "fs";
4615
4626
  import * as fs3 from "fs";
4616
4627
  import { tmpdir as tmpdir3 } from "os";
@@ -4618,11 +4629,11 @@ import { tmpdir as tmpdir3 } from "os";
4618
4629
  // src/hooks/comment-checker/downloader.ts
4619
4630
  var {spawn: spawn2 } = globalThis.Bun;
4620
4631
  import { existsSync as existsSync7, mkdirSync as mkdirSync3, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync2 } from "fs";
4621
- import { join as join9 } from "path";
4632
+ import { join as join10 } from "path";
4622
4633
  import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
4623
4634
  import { createRequire } from "module";
4624
4635
  var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
4625
- var DEBUG_FILE = join9(tmpdir2(), "comment-checker-debug.log");
4636
+ var DEBUG_FILE = join10(tmpdir2(), "comment-checker-debug.log");
4626
4637
  function debugLog(...args) {
4627
4638
  if (DEBUG) {
4628
4639
  const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -4640,14 +4651,14 @@ var PLATFORM_MAP = {
4640
4651
  };
4641
4652
  function getCacheDir() {
4642
4653
  const xdgCache2 = process.env.XDG_CACHE_HOME;
4643
- const base = xdgCache2 || join9(homedir4(), ".cache");
4644
- return join9(base, "oh-my-opencode", "bin");
4654
+ const base = xdgCache2 || join10(homedir4(), ".cache");
4655
+ return join10(base, "oh-my-opencode", "bin");
4645
4656
  }
4646
4657
  function getBinaryName() {
4647
4658
  return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
4648
4659
  }
4649
4660
  function getCachedBinaryPath() {
4650
- const binaryPath = join9(getCacheDir(), getBinaryName());
4661
+ const binaryPath = join10(getCacheDir(), getBinaryName());
4651
4662
  return existsSync7(binaryPath) ? binaryPath : null;
4652
4663
  }
4653
4664
  function getPackageVersion() {
@@ -4695,14 +4706,14 @@ async function downloadCommentChecker() {
4695
4706
  }
4696
4707
  const cacheDir = getCacheDir();
4697
4708
  const binaryName = getBinaryName();
4698
- const binaryPath = join9(cacheDir, binaryName);
4709
+ const binaryPath = join10(cacheDir, binaryName);
4699
4710
  if (existsSync7(binaryPath)) {
4700
4711
  debugLog("Binary already cached at:", binaryPath);
4701
4712
  return binaryPath;
4702
4713
  }
4703
4714
  const version = getPackageVersion();
4704
- const { os: os4, arch, ext } = platformInfo;
4705
- const assetName = `comment-checker_v${version}_${os4}_${arch}.${ext}`;
4715
+ const { os: os5, arch, ext } = platformInfo;
4716
+ const assetName = `comment-checker_v${version}_${os5}_${arch}.${ext}`;
4706
4717
  const downloadUrl = `https://github.com/${REPO}/releases/download/v${version}/${assetName}`;
4707
4718
  debugLog(`Downloading from: ${downloadUrl}`);
4708
4719
  console.log(`[oh-my-opencode] Downloading comment-checker binary...`);
@@ -4714,7 +4725,7 @@ async function downloadCommentChecker() {
4714
4725
  if (!response.ok) {
4715
4726
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4716
4727
  }
4717
- const archivePath = join9(cacheDir, assetName);
4728
+ const archivePath = join10(cacheDir, assetName);
4718
4729
  const arrayBuffer = await response.arrayBuffer();
4719
4730
  await Bun.write(archivePath, arrayBuffer);
4720
4731
  debugLog(`Downloaded archive to: ${archivePath}`);
@@ -4750,7 +4761,7 @@ async function ensureCommentCheckerBinary() {
4750
4761
 
4751
4762
  // src/hooks/comment-checker/cli.ts
4752
4763
  var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
4753
- var DEBUG_FILE2 = join10(tmpdir3(), "comment-checker-debug.log");
4764
+ var DEBUG_FILE2 = join11(tmpdir3(), "comment-checker-debug.log");
4754
4765
  function debugLog2(...args) {
4755
4766
  if (DEBUG2) {
4756
4767
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -4767,7 +4778,7 @@ function findCommentCheckerPathSync() {
4767
4778
  const require2 = createRequire2(import.meta.url);
4768
4779
  const cliPkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
4769
4780
  const cliDir = dirname(cliPkgPath);
4770
- const binaryPath = join10(cliDir, "bin", binaryName);
4781
+ const binaryPath = join11(cliDir, "bin", binaryName);
4771
4782
  if (existsSync8(binaryPath)) {
4772
4783
  debugLog2("found binary in main package:", binaryPath);
4773
4784
  return binaryPath;
@@ -4814,8 +4825,8 @@ async function getCommentCheckerPath() {
4814
4825
  function startBackgroundInit() {
4815
4826
  if (!initPromise) {
4816
4827
  initPromise = getCommentCheckerPath();
4817
- initPromise.then((path4) => {
4818
- debugLog2("background init complete:", path4 || "no binary");
4828
+ initPromise.then((path5) => {
4829
+ debugLog2("background init complete:", path5 || "no binary");
4819
4830
  }).catch((err) => {
4820
4831
  debugLog2("background init error:", err);
4821
4832
  });
@@ -4864,9 +4875,9 @@ async function runCommentChecker(input, cliPath) {
4864
4875
  import * as fs4 from "fs";
4865
4876
  import { existsSync as existsSync9 } from "fs";
4866
4877
  import { tmpdir as tmpdir4 } from "os";
4867
- import { join as join11 } from "path";
4878
+ import { join as join12 } from "path";
4868
4879
  var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
4869
- var DEBUG_FILE3 = join11(tmpdir4(), "comment-checker-debug.log");
4880
+ var DEBUG_FILE3 = join12(tmpdir4(), "comment-checker-debug.log");
4870
4881
  function debugLog3(...args) {
4871
4882
  if (DEBUG3) {
4872
4883
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -4890,8 +4901,8 @@ function createCommentCheckerHooks() {
4890
4901
  debugLog3("createCommentCheckerHooks called");
4891
4902
  startBackgroundInit();
4892
4903
  cliPathPromise = getCommentCheckerPath();
4893
- cliPathPromise.then((path4) => {
4894
- debugLog3("CLI path resolved:", path4 || "disabled (no binary)");
4904
+ cliPathPromise.then((path5) => {
4905
+ debugLog3("CLI path resolved:", path5 || "disabled (no binary)");
4895
4906
  }).catch((err) => {
4896
4907
  debugLog3("CLI path resolution error:", err);
4897
4908
  });
@@ -4998,7 +5009,7 @@ var TRUNCATABLE_TOOLS = [
4998
5009
  ];
4999
5010
  function createToolOutputTruncatorHook(ctx, options) {
5000
5011
  const truncator = createDynamicTruncator(ctx);
5001
- const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? false;
5012
+ const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? true;
5002
5013
  const toolExecuteAfter = async (input, output) => {
5003
5014
  if (!truncateAll && !TRUNCATABLE_TOOLS.includes(input.tool))
5004
5015
  return;
@@ -5015,7 +5026,7 @@ function createToolOutputTruncatorHook(ctx, options) {
5015
5026
  }
5016
5027
  // src/hooks/directory-agents-injector/index.ts
5017
5028
  import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
5018
- import { dirname as dirname2, join as join14, resolve as resolve2 } from "path";
5029
+ import { dirname as dirname2, join as join15, resolve as resolve2 } from "path";
5019
5030
 
5020
5031
  // src/hooks/directory-agents-injector/storage.ts
5021
5032
  import {
@@ -5025,17 +5036,17 @@ import {
5025
5036
  writeFileSync as writeFileSync3,
5026
5037
  unlinkSync as unlinkSync3
5027
5038
  } from "fs";
5028
- import { join as join13 } from "path";
5039
+ import { join as join14 } from "path";
5029
5040
 
5030
5041
  // src/hooks/directory-agents-injector/constants.ts
5031
- import { join as join12 } from "path";
5032
- var OPENCODE_STORAGE3 = join12(xdgData2 ?? "", "opencode", "storage");
5033
- var AGENTS_INJECTOR_STORAGE = join12(OPENCODE_STORAGE3, "directory-agents");
5042
+ import { join as join13 } from "path";
5043
+ var OPENCODE_STORAGE3 = join13(xdgData ?? "", "opencode", "storage");
5044
+ var AGENTS_INJECTOR_STORAGE = join13(OPENCODE_STORAGE3, "directory-agents");
5034
5045
  var AGENTS_FILENAME = "AGENTS.md";
5035
5046
 
5036
5047
  // src/hooks/directory-agents-injector/storage.ts
5037
5048
  function getStoragePath(sessionID) {
5038
- return join13(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
5049
+ return join14(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
5039
5050
  }
5040
5051
  function loadInjectedPaths(sessionID) {
5041
5052
  const filePath = getStoragePath(sessionID);
@@ -5077,18 +5088,18 @@ function createDirectoryAgentsInjectorHook(ctx) {
5077
5088
  }
5078
5089
  return sessionCaches.get(sessionID);
5079
5090
  }
5080
- function resolveFilePath2(path4) {
5081
- if (!path4)
5091
+ function resolveFilePath2(path5) {
5092
+ if (!path5)
5082
5093
  return null;
5083
- if (path4.startsWith("/"))
5084
- return path4;
5085
- return resolve2(ctx.directory, path4);
5094
+ if (path5.startsWith("/"))
5095
+ return path5;
5096
+ return resolve2(ctx.directory, path5);
5086
5097
  }
5087
5098
  function findAgentsMdUp(startDir) {
5088
5099
  const found = [];
5089
5100
  let current = startDir;
5090
5101
  while (true) {
5091
- const agentsPath = join14(current, AGENTS_FILENAME);
5102
+ const agentsPath = join15(current, AGENTS_FILENAME);
5092
5103
  if (existsSync11(agentsPath)) {
5093
5104
  found.push(agentsPath);
5094
5105
  }
@@ -5182,7 +5193,7 @@ ${content}`;
5182
5193
  }
5183
5194
  // src/hooks/directory-readme-injector/index.ts
5184
5195
  import { existsSync as existsSync13, readFileSync as readFileSync7 } from "fs";
5185
- import { dirname as dirname3, join as join17, resolve as resolve3 } from "path";
5196
+ import { dirname as dirname3, join as join18, resolve as resolve3 } from "path";
5186
5197
 
5187
5198
  // src/hooks/directory-readme-injector/storage.ts
5188
5199
  import {
@@ -5192,17 +5203,17 @@ import {
5192
5203
  writeFileSync as writeFileSync4,
5193
5204
  unlinkSync as unlinkSync4
5194
5205
  } from "fs";
5195
- import { join as join16 } from "path";
5206
+ import { join as join17 } from "path";
5196
5207
 
5197
5208
  // src/hooks/directory-readme-injector/constants.ts
5198
- import { join as join15 } from "path";
5199
- var OPENCODE_STORAGE4 = join15(xdgData2 ?? "", "opencode", "storage");
5200
- var README_INJECTOR_STORAGE = join15(OPENCODE_STORAGE4, "directory-readme");
5209
+ import { join as join16 } from "path";
5210
+ var OPENCODE_STORAGE4 = join16(xdgData ?? "", "opencode", "storage");
5211
+ var README_INJECTOR_STORAGE = join16(OPENCODE_STORAGE4, "directory-readme");
5201
5212
  var README_FILENAME = "README.md";
5202
5213
 
5203
5214
  // src/hooks/directory-readme-injector/storage.ts
5204
5215
  function getStoragePath2(sessionID) {
5205
- return join16(README_INJECTOR_STORAGE, `${sessionID}.json`);
5216
+ return join17(README_INJECTOR_STORAGE, `${sessionID}.json`);
5206
5217
  }
5207
5218
  function loadInjectedPaths2(sessionID) {
5208
5219
  const filePath = getStoragePath2(sessionID);
@@ -5244,18 +5255,18 @@ function createDirectoryReadmeInjectorHook(ctx) {
5244
5255
  }
5245
5256
  return sessionCaches.get(sessionID);
5246
5257
  }
5247
- function resolveFilePath2(path4) {
5248
- if (!path4)
5258
+ function resolveFilePath2(path5) {
5259
+ if (!path5)
5249
5260
  return null;
5250
- if (path4.startsWith("/"))
5251
- return path4;
5252
- return resolve3(ctx.directory, path4);
5261
+ if (path5.startsWith("/"))
5262
+ return path5;
5263
+ return resolve3(ctx.directory, path5);
5253
5264
  }
5254
5265
  function findReadmeMdUp(startDir) {
5255
5266
  const found = [];
5256
5267
  let current = startDir;
5257
5268
  while (true) {
5258
- const readmePath = join17(current, README_FILENAME);
5269
+ const readmePath = join18(current, README_FILENAME);
5259
5270
  if (existsSync13(readmePath)) {
5260
5271
  found.push(readmePath);
5261
5272
  }
@@ -5553,26 +5564,26 @@ var TRUNCATE_CONFIG = {
5553
5564
  // src/hooks/anthropic-auto-compact/storage.ts
5554
5565
  import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
5555
5566
  import { homedir as homedir5 } from "os";
5556
- import { join as join18 } from "path";
5557
- var OPENCODE_STORAGE5 = join18(xdgData2 ?? "", "opencode", "storage");
5567
+ import { join as join19 } from "path";
5568
+ var OPENCODE_STORAGE5 = join19(xdgData ?? "", "opencode", "storage");
5558
5569
  if (process.platform === "darwin" && !existsSync14(OPENCODE_STORAGE5)) {
5559
- const localShare = join18(homedir5(), ".local", "share", "opencode", "storage");
5570
+ const localShare = join19(homedir5(), ".local", "share", "opencode", "storage");
5560
5571
  if (existsSync14(localShare)) {
5561
5572
  OPENCODE_STORAGE5 = localShare;
5562
5573
  }
5563
5574
  }
5564
- var MESSAGE_STORAGE3 = join18(OPENCODE_STORAGE5, "message");
5565
- var PART_STORAGE3 = join18(OPENCODE_STORAGE5, "part");
5575
+ var MESSAGE_STORAGE3 = join19(OPENCODE_STORAGE5, "message");
5576
+ var PART_STORAGE3 = join19(OPENCODE_STORAGE5, "part");
5566
5577
  var TRUNCATION_MESSAGE = "[TOOL RESULT TRUNCATED - Context limit exceeded. Original output was too large and has been truncated to recover the session. Please re-run this tool if you need the full output.]";
5567
5578
  function getMessageDir3(sessionID) {
5568
5579
  if (!existsSync14(MESSAGE_STORAGE3))
5569
5580
  return "";
5570
- const directPath = join18(MESSAGE_STORAGE3, sessionID);
5581
+ const directPath = join19(MESSAGE_STORAGE3, sessionID);
5571
5582
  if (existsSync14(directPath)) {
5572
5583
  return directPath;
5573
5584
  }
5574
5585
  for (const dir of readdirSync4(MESSAGE_STORAGE3)) {
5575
- const sessionPath = join18(MESSAGE_STORAGE3, dir, sessionID);
5586
+ const sessionPath = join19(MESSAGE_STORAGE3, dir, sessionID);
5576
5587
  if (existsSync14(sessionPath)) {
5577
5588
  return sessionPath;
5578
5589
  }
@@ -5596,14 +5607,14 @@ function findToolResultsBySize(sessionID) {
5596
5607
  const messageIds = getMessageIds(sessionID);
5597
5608
  const results = [];
5598
5609
  for (const messageID of messageIds) {
5599
- const partDir = join18(PART_STORAGE3, messageID);
5610
+ const partDir = join19(PART_STORAGE3, messageID);
5600
5611
  if (!existsSync14(partDir))
5601
5612
  continue;
5602
5613
  for (const file of readdirSync4(partDir)) {
5603
5614
  if (!file.endsWith(".json"))
5604
5615
  continue;
5605
5616
  try {
5606
- const partPath = join18(partDir, file);
5617
+ const partPath = join19(partDir, file);
5607
5618
  const content = readFileSync8(partPath, "utf-8");
5608
5619
  const part = JSON.parse(content);
5609
5620
  if (part.type === "tool" && part.state?.output && !part.truncated) {
@@ -6211,7 +6222,7 @@ function createAnthropicAutoCompactHook(ctx, options) {
6211
6222
  }
6212
6223
  // src/hooks/preemptive-compaction/index.ts
6213
6224
  import { existsSync as existsSync15, readdirSync as readdirSync5 } from "fs";
6214
- import { join as join19 } from "path";
6225
+ import { join as join20 } from "path";
6215
6226
 
6216
6227
  // src/hooks/preemptive-compaction/constants.ts
6217
6228
  var DEFAULT_THRESHOLD = 0.85;
@@ -6227,11 +6238,11 @@ function isSupportedModel(modelID) {
6227
6238
  function getMessageDir4(sessionID) {
6228
6239
  if (!existsSync15(MESSAGE_STORAGE))
6229
6240
  return null;
6230
- const directPath = join19(MESSAGE_STORAGE, sessionID);
6241
+ const directPath = join20(MESSAGE_STORAGE, sessionID);
6231
6242
  if (existsSync15(directPath))
6232
6243
  return directPath;
6233
6244
  for (const dir of readdirSync5(MESSAGE_STORAGE)) {
6234
- const sessionPath = join19(MESSAGE_STORAGE, dir, sessionID);
6245
+ const sessionPath = join20(MESSAGE_STORAGE, dir, sessionID);
6235
6246
  if (existsSync15(sessionPath))
6236
6247
  return sessionPath;
6237
6248
  }
@@ -6717,7 +6728,7 @@ function createThinkModeHook() {
6717
6728
  }
6718
6729
  // src/hooks/claude-code-hooks/config.ts
6719
6730
  import { homedir as homedir6 } from "os";
6720
- import { join as join20 } from "path";
6731
+ import { join as join21 } from "path";
6721
6732
  import { existsSync as existsSync16 } from "fs";
6722
6733
  function normalizeHookMatcher(raw) {
6723
6734
  return {
@@ -6744,9 +6755,9 @@ function normalizeHooksConfig(raw) {
6744
6755
  function getClaudeSettingsPaths(customPath) {
6745
6756
  const home = homedir6();
6746
6757
  const paths = [
6747
- join20(home, ".claude", "settings.json"),
6748
- join20(process.cwd(), ".claude", "settings.json"),
6749
- join20(process.cwd(), ".claude", "settings.local.json")
6758
+ join21(home, ".claude", "settings.json"),
6759
+ join21(process.cwd(), ".claude", "settings.json"),
6760
+ join21(process.cwd(), ".claude", "settings.local.json")
6750
6761
  ];
6751
6762
  if (customPath && existsSync16(customPath)) {
6752
6763
  paths.unshift(customPath);
@@ -6792,20 +6803,20 @@ async function loadClaudeHooksConfig(customSettingsPath) {
6792
6803
  // src/hooks/claude-code-hooks/config-loader.ts
6793
6804
  import { existsSync as existsSync17 } from "fs";
6794
6805
  import { homedir as homedir7 } from "os";
6795
- import { join as join21 } from "path";
6796
- var USER_CONFIG_PATH = join21(homedir7(), ".config", "opencode", "opencode-cc-plugin.json");
6806
+ import { join as join22 } from "path";
6807
+ var USER_CONFIG_PATH = join22(homedir7(), ".config", "opencode", "opencode-cc-plugin.json");
6797
6808
  function getProjectConfigPath() {
6798
- return join21(process.cwd(), ".opencode", "opencode-cc-plugin.json");
6809
+ return join22(process.cwd(), ".opencode", "opencode-cc-plugin.json");
6799
6810
  }
6800
- async function loadConfigFromPath(path4) {
6801
- if (!existsSync17(path4)) {
6811
+ async function loadConfigFromPath(path5) {
6812
+ if (!existsSync17(path5)) {
6802
6813
  return null;
6803
6814
  }
6804
6815
  try {
6805
- const content = await Bun.file(path4).text();
6816
+ const content = await Bun.file(path5).text();
6806
6817
  return JSON.parse(content);
6807
6818
  } catch (error) {
6808
- log("Failed to load config", { path: path4, error });
6819
+ log("Failed to load config", { path: path5, error });
6809
6820
  return null;
6810
6821
  }
6811
6822
  }
@@ -6978,13 +6989,13 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
6978
6989
  }
6979
6990
 
6980
6991
  // src/hooks/claude-code-hooks/transcript.ts
6981
- import { join as join22 } from "path";
6992
+ import { join as join23 } from "path";
6982
6993
  import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync18, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5 } from "fs";
6983
6994
  import { homedir as homedir8, tmpdir as tmpdir5 } from "os";
6984
6995
  import { randomUUID } from "crypto";
6985
- var TRANSCRIPT_DIR = join22(homedir8(), ".claude", "transcripts");
6996
+ var TRANSCRIPT_DIR = join23(homedir8(), ".claude", "transcripts");
6986
6997
  function getTranscriptPath(sessionId) {
6987
- return join22(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
6998
+ return join23(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
6988
6999
  }
6989
7000
  function ensureTranscriptDir() {
6990
7001
  if (!existsSync18(TRANSCRIPT_DIR)) {
@@ -6993,10 +7004,10 @@ function ensureTranscriptDir() {
6993
7004
  }
6994
7005
  function appendTranscriptEntry(sessionId, entry) {
6995
7006
  ensureTranscriptDir();
6996
- const path4 = getTranscriptPath(sessionId);
7007
+ const path5 = getTranscriptPath(sessionId);
6997
7008
  const line = JSON.stringify(entry) + `
6998
7009
  `;
6999
- appendFileSync5(path4, line);
7010
+ appendFileSync5(path5, line);
7000
7011
  }
7001
7012
  function recordToolUse(sessionId, toolName, toolInput) {
7002
7013
  appendTranscriptEntry(sessionId, {
@@ -7074,7 +7085,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
7074
7085
  }
7075
7086
  };
7076
7087
  entries.push(JSON.stringify(currentEntry));
7077
- const tempPath = join22(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
7088
+ const tempPath = join23(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
7078
7089
  writeFileSync6(tempPath, entries.join(`
7079
7090
  `) + `
7080
7091
  `);
@@ -7094,7 +7105,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
7094
7105
  ]
7095
7106
  }
7096
7107
  };
7097
- const tempPath = join22(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
7108
+ const tempPath = join23(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
7098
7109
  writeFileSync6(tempPath, JSON.stringify(currentEntry) + `
7099
7110
  `);
7100
7111
  return tempPath;
@@ -7103,11 +7114,11 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
7103
7114
  }
7104
7115
  }
7105
7116
  }
7106
- function deleteTempTranscript(path4) {
7107
- if (!path4)
7117
+ function deleteTempTranscript(path5) {
7118
+ if (!path5)
7108
7119
  return;
7109
7120
  try {
7110
- unlinkSync5(path4);
7121
+ unlinkSync5(path5);
7111
7122
  } catch {}
7112
7123
  }
7113
7124
 
@@ -7306,11 +7317,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
7306
7317
  }
7307
7318
 
7308
7319
  // src/hooks/claude-code-hooks/todo.ts
7309
- import { join as join23 } from "path";
7320
+ import { join as join24 } from "path";
7310
7321
  import { homedir as homedir9 } from "os";
7311
- var TODO_DIR = join23(homedir9(), ".claude", "todos");
7322
+ var TODO_DIR = join24(homedir9(), ".claude", "todos");
7312
7323
  function getTodoPath(sessionId) {
7313
- return join23(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
7324
+ return join24(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
7314
7325
  }
7315
7326
 
7316
7327
  // src/hooks/claude-code-hooks/stop.ts
@@ -7745,12 +7756,12 @@ import {
7745
7756
  realpathSync,
7746
7757
  statSync as statSync2
7747
7758
  } from "fs";
7748
- import { dirname as dirname4, join as join25, relative } from "path";
7759
+ import { dirname as dirname4, join as join26, relative } from "path";
7749
7760
 
7750
7761
  // src/hooks/rules-injector/constants.ts
7751
- import { join as join24 } from "path";
7752
- var OPENCODE_STORAGE6 = join24(xdgData2 ?? "", "opencode", "storage");
7753
- var RULES_INJECTOR_STORAGE = join24(OPENCODE_STORAGE6, "rules-injector");
7762
+ import { join as join25 } from "path";
7763
+ var OPENCODE_STORAGE6 = join25(xdgData ?? "", "opencode", "storage");
7764
+ var RULES_INJECTOR_STORAGE = join25(OPENCODE_STORAGE6, "rules-injector");
7754
7765
  var PROJECT_MARKERS = [
7755
7766
  ".git",
7756
7767
  "pyproject.toml",
@@ -7777,7 +7788,7 @@ function findProjectRoot(startPath) {
7777
7788
  }
7778
7789
  while (true) {
7779
7790
  for (const marker of PROJECT_MARKERS) {
7780
- const markerPath = join25(current, marker);
7791
+ const markerPath = join26(current, marker);
7781
7792
  if (existsSync19(markerPath)) {
7782
7793
  return current;
7783
7794
  }
@@ -7795,7 +7806,7 @@ function findRuleFilesRecursive(dir, results) {
7795
7806
  try {
7796
7807
  const entries = readdirSync6(dir, { withFileTypes: true });
7797
7808
  for (const entry of entries) {
7798
- const fullPath = join25(dir, entry.name);
7809
+ const fullPath = join26(dir, entry.name);
7799
7810
  if (entry.isDirectory()) {
7800
7811
  findRuleFilesRecursive(fullPath, results);
7801
7812
  } else if (entry.isFile()) {
@@ -7821,7 +7832,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
7821
7832
  let distance = 0;
7822
7833
  while (true) {
7823
7834
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
7824
- const ruleDir = join25(currentDir, parent, subdir);
7835
+ const ruleDir = join26(currentDir, parent, subdir);
7825
7836
  const files = [];
7826
7837
  findRuleFilesRecursive(ruleDir, files);
7827
7838
  for (const filePath of files) {
@@ -7845,7 +7856,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
7845
7856
  currentDir = parentDir;
7846
7857
  distance++;
7847
7858
  }
7848
- const userRuleDir = join25(homeDir, USER_RULE_DIR);
7859
+ const userRuleDir = join26(homeDir, USER_RULE_DIR);
7849
7860
  const userFiles = [];
7850
7861
  findRuleFilesRecursive(userRuleDir, userFiles);
7851
7862
  for (const filePath of userFiles) {
@@ -8040,9 +8051,9 @@ import {
8040
8051
  writeFileSync as writeFileSync7,
8041
8052
  unlinkSync as unlinkSync6
8042
8053
  } from "fs";
8043
- import { join as join26 } from "path";
8054
+ import { join as join27 } from "path";
8044
8055
  function getStoragePath3(sessionID) {
8045
- return join26(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
8056
+ return join27(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
8046
8057
  }
8047
8058
  function loadInjectedRules(sessionID) {
8048
8059
  const filePath = getStoragePath3(sessionID);
@@ -8089,12 +8100,12 @@ function createRulesInjectorHook(ctx) {
8089
8100
  }
8090
8101
  return sessionCaches.get(sessionID);
8091
8102
  }
8092
- function resolveFilePath2(path4) {
8093
- if (!path4)
8103
+ function resolveFilePath2(path5) {
8104
+ if (!path5)
8094
8105
  return null;
8095
- if (path4.startsWith("/"))
8096
- return path4;
8097
- return resolve4(ctx.directory, path4);
8106
+ if (path5.startsWith("/"))
8107
+ return path5;
8108
+ return resolve4(ctx.directory, path5);
8098
8109
  }
8099
8110
  function processFilePathForInjection(filePath, sessionID, output) {
8100
8111
  const resolved = resolveFilePath2(filePath);
@@ -8213,33 +8224,33 @@ function createBackgroundNotificationHook(manager) {
8213
8224
  }
8214
8225
  // src/hooks/auto-update-checker/checker.ts
8215
8226
  import * as fs5 from "fs";
8216
- import * as path5 from "path";
8227
+ import * as path6 from "path";
8217
8228
  import { fileURLToPath } from "url";
8218
8229
 
8219
8230
  // src/hooks/auto-update-checker/constants.ts
8220
- import * as path4 from "path";
8221
- import * as os4 from "os";
8231
+ import * as path5 from "path";
8232
+ import * as os5 from "os";
8222
8233
  var PACKAGE_NAME = "oh-my-opencode";
8223
8234
  var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
8224
8235
  var NPM_FETCH_TIMEOUT = 5000;
8225
8236
  function getCacheDir2() {
8226
8237
  if (process.platform === "win32") {
8227
- return path4.join(process.env.LOCALAPPDATA ?? os4.homedir(), "opencode");
8238
+ return path5.join(process.env.LOCALAPPDATA ?? os5.homedir(), "opencode");
8228
8239
  }
8229
- return path4.join(os4.homedir(), ".cache", "opencode");
8240
+ return path5.join(os5.homedir(), ".cache", "opencode");
8230
8241
  }
8231
8242
  var CACHE_DIR = getCacheDir2();
8232
- var VERSION_FILE = path4.join(CACHE_DIR, "version");
8233
- var INSTALLED_PACKAGE_JSON = path4.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
8243
+ var VERSION_FILE = path5.join(CACHE_DIR, "version");
8244
+ var INSTALLED_PACKAGE_JSON = path5.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
8234
8245
  function getUserConfigDir2() {
8235
8246
  if (process.platform === "win32") {
8236
- return process.env.APPDATA ?? path4.join(os4.homedir(), "AppData", "Roaming");
8247
+ return process.env.APPDATA ?? path5.join(os5.homedir(), "AppData", "Roaming");
8237
8248
  }
8238
- return process.env.XDG_CONFIG_HOME ?? path4.join(os4.homedir(), ".config");
8249
+ return process.env.XDG_CONFIG_HOME ?? path5.join(os5.homedir(), ".config");
8239
8250
  }
8240
8251
  var USER_CONFIG_DIR = getUserConfigDir2();
8241
- var USER_OPENCODE_CONFIG = path4.join(USER_CONFIG_DIR, "opencode", "opencode.json");
8242
- var USER_OPENCODE_CONFIG_JSONC = path4.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
8252
+ var USER_OPENCODE_CONFIG = path5.join(USER_CONFIG_DIR, "opencode", "opencode.json");
8253
+ var USER_OPENCODE_CONFIG_JSONC = path5.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
8243
8254
 
8244
8255
  // src/hooks/auto-update-checker/checker.ts
8245
8256
  function stripJsonComments(json) {
@@ -8247,8 +8258,8 @@ function stripJsonComments(json) {
8247
8258
  }
8248
8259
  function getConfigPaths(directory) {
8249
8260
  return [
8250
- path5.join(directory, ".opencode", "opencode.json"),
8251
- path5.join(directory, ".opencode", "opencode.jsonc"),
8261
+ path6.join(directory, ".opencode", "opencode.json"),
8262
+ path6.join(directory, ".opencode", "opencode.jsonc"),
8252
8263
  USER_OPENCODE_CONFIG,
8253
8264
  USER_OPENCODE_CONFIG_JSONC
8254
8265
  ];
@@ -8279,9 +8290,9 @@ function getLocalDevPath(directory) {
8279
8290
  function findPackageJsonUp(startPath) {
8280
8291
  try {
8281
8292
  const stat = fs5.statSync(startPath);
8282
- let dir = stat.isDirectory() ? startPath : path5.dirname(startPath);
8293
+ let dir = stat.isDirectory() ? startPath : path6.dirname(startPath);
8283
8294
  for (let i = 0;i < 10; i++) {
8284
- const pkgPath = path5.join(dir, "package.json");
8295
+ const pkgPath = path6.join(dir, "package.json");
8285
8296
  if (fs5.existsSync(pkgPath)) {
8286
8297
  try {
8287
8298
  const content = fs5.readFileSync(pkgPath, "utf-8");
@@ -8290,7 +8301,7 @@ function findPackageJsonUp(startPath) {
8290
8301
  return pkgPath;
8291
8302
  } catch {}
8292
8303
  }
8293
- const parent = path5.dirname(dir);
8304
+ const parent = path6.dirname(dir);
8294
8305
  if (parent === dir)
8295
8306
  break;
8296
8307
  dir = parent;
@@ -8347,7 +8358,7 @@ function getCachedVersion() {
8347
8358
  }
8348
8359
  } catch {}
8349
8360
  try {
8350
- const currentDir = path5.dirname(fileURLToPath(import.meta.url));
8361
+ const currentDir = path6.dirname(fileURLToPath(import.meta.url));
8351
8362
  const pkgPath = findPackageJsonUp(currentDir);
8352
8363
  if (pkgPath) {
8353
8364
  const content = fs5.readFileSync(pkgPath, "utf-8");
@@ -8423,12 +8434,12 @@ async function getLatestVersion() {
8423
8434
 
8424
8435
  // src/hooks/auto-update-checker/cache.ts
8425
8436
  import * as fs6 from "fs";
8426
- import * as path6 from "path";
8437
+ import * as path7 from "path";
8427
8438
  function stripTrailingCommas(json) {
8428
8439
  return json.replace(/,(\s*[}\]])/g, "$1");
8429
8440
  }
8430
8441
  function removeFromBunLock(packageName) {
8431
- const lockPath = path6.join(CACHE_DIR, "bun.lock");
8442
+ const lockPath = path7.join(CACHE_DIR, "bun.lock");
8432
8443
  if (!fs6.existsSync(lockPath))
8433
8444
  return false;
8434
8445
  try {
@@ -8454,8 +8465,8 @@ function removeFromBunLock(packageName) {
8454
8465
  }
8455
8466
  function invalidatePackage(packageName = PACKAGE_NAME) {
8456
8467
  try {
8457
- const pkgDir = path6.join(CACHE_DIR, "node_modules", packageName);
8458
- const pkgJsonPath = path6.join(CACHE_DIR, "package.json");
8468
+ const pkgDir = path7.join(CACHE_DIR, "node_modules", packageName);
8469
+ const pkgJsonPath = path7.join(CACHE_DIR, "package.json");
8459
8470
  let packageRemoved = false;
8460
8471
  let dependencyRemoved = false;
8461
8472
  let lockRemoved = false;
@@ -8649,12 +8660,12 @@ import {
8649
8660
  writeFileSync as writeFileSync10,
8650
8661
  unlinkSync as unlinkSync7
8651
8662
  } from "fs";
8652
- import { join as join31 } from "path";
8663
+ import { join as join32 } from "path";
8653
8664
 
8654
8665
  // src/hooks/agent-usage-reminder/constants.ts
8655
- import { join as join30 } from "path";
8656
- var OPENCODE_STORAGE7 = join30(xdgData2 ?? "", "opencode", "storage");
8657
- var AGENT_USAGE_REMINDER_STORAGE = join30(OPENCODE_STORAGE7, "agent-usage-reminder");
8666
+ import { join as join31 } from "path";
8667
+ var OPENCODE_STORAGE7 = join31(xdgData ?? "", "opencode", "storage");
8668
+ var AGENT_USAGE_REMINDER_STORAGE = join31(OPENCODE_STORAGE7, "agent-usage-reminder");
8658
8669
  var TARGET_TOOLS = new Set([
8659
8670
  "grep",
8660
8671
  "safe_grep",
@@ -8699,7 +8710,7 @@ ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
8699
8710
 
8700
8711
  // src/hooks/agent-usage-reminder/storage.ts
8701
8712
  function getStoragePath4(sessionID) {
8702
- return join31(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
8713
+ return join32(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
8703
8714
  }
8704
8715
  function loadAgentUsageState(sessionID) {
8705
8716
  const filePath = getStoragePath4(sessionID);
@@ -9021,12 +9032,12 @@ import {
9021
9032
  writeFileSync as writeFileSync11,
9022
9033
  unlinkSync as unlinkSync8
9023
9034
  } from "fs";
9024
- import { join as join33 } from "path";
9035
+ import { join as join34 } from "path";
9025
9036
 
9026
9037
  // src/hooks/interactive-bash-session/constants.ts
9027
- import { join as join32 } from "path";
9028
- var OPENCODE_STORAGE8 = join32(xdgData2 ?? "", "opencode", "storage");
9029
- var INTERACTIVE_BASH_SESSION_STORAGE = join32(OPENCODE_STORAGE8, "interactive-bash-session");
9038
+ import { join as join33 } from "path";
9039
+ var OPENCODE_STORAGE8 = join33(xdgData ?? "", "opencode", "storage");
9040
+ var INTERACTIVE_BASH_SESSION_STORAGE = join33(OPENCODE_STORAGE8, "interactive-bash-session");
9030
9041
  var OMO_SESSION_PREFIX = "omo-";
9031
9042
  function buildSessionReminderMessage(sessions) {
9032
9043
  if (sessions.length === 0)
@@ -9038,7 +9049,7 @@ function buildSessionReminderMessage(sessions) {
9038
9049
 
9039
9050
  // src/hooks/interactive-bash-session/storage.ts
9040
9051
  function getStoragePath5(sessionID) {
9041
- return join33(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
9052
+ return join34(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
9042
9053
  }
9043
9054
  function loadInteractiveBashSessionState(sessionID) {
9044
9055
  const filePath = getStoragePath5(sessionID);
@@ -11016,7 +11027,7 @@ async function createGoogleAntigravityAuthPlugin({
11016
11027
  // src/features/claude-code-command-loader/loader.ts
11017
11028
  import { existsSync as existsSync25, readdirSync as readdirSync7, readFileSync as readFileSync15 } from "fs";
11018
11029
  import { homedir as homedir12 } from "os";
11019
- import { join as join34, basename } from "path";
11030
+ import { join as join35, basename } from "path";
11020
11031
  function loadCommandsFromDir(commandsDir, scope) {
11021
11032
  if (!existsSync25(commandsDir)) {
11022
11033
  return [];
@@ -11026,7 +11037,7 @@ function loadCommandsFromDir(commandsDir, scope) {
11026
11037
  for (const entry of entries) {
11027
11038
  if (!isMarkdownFile(entry))
11028
11039
  continue;
11029
- const commandPath = join34(commandsDir, entry.name);
11040
+ const commandPath = join35(commandsDir, entry.name);
11030
11041
  const commandName = basename(entry.name, ".md");
11031
11042
  try {
11032
11043
  const content = readFileSync15(commandPath, "utf-8");
@@ -11069,29 +11080,29 @@ function commandsToRecord(commands) {
11069
11080
  return result;
11070
11081
  }
11071
11082
  function loadUserCommands() {
11072
- const userCommandsDir = join34(homedir12(), ".claude", "commands");
11083
+ const userCommandsDir = join35(homedir12(), ".claude", "commands");
11073
11084
  const commands = loadCommandsFromDir(userCommandsDir, "user");
11074
11085
  return commandsToRecord(commands);
11075
11086
  }
11076
11087
  function loadProjectCommands() {
11077
- const projectCommandsDir = join34(process.cwd(), ".claude", "commands");
11088
+ const projectCommandsDir = join35(process.cwd(), ".claude", "commands");
11078
11089
  const commands = loadCommandsFromDir(projectCommandsDir, "project");
11079
11090
  return commandsToRecord(commands);
11080
11091
  }
11081
11092
  function loadOpencodeGlobalCommands() {
11082
- const opencodeCommandsDir = join34(homedir12(), ".config", "opencode", "command");
11093
+ const opencodeCommandsDir = join35(homedir12(), ".config", "opencode", "command");
11083
11094
  const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
11084
11095
  return commandsToRecord(commands);
11085
11096
  }
11086
11097
  function loadOpencodeProjectCommands() {
11087
- const opencodeProjectDir = join34(process.cwd(), ".opencode", "command");
11098
+ const opencodeProjectDir = join35(process.cwd(), ".opencode", "command");
11088
11099
  const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
11089
11100
  return commandsToRecord(commands);
11090
11101
  }
11091
11102
  // src/features/claude-code-skill-loader/loader.ts
11092
11103
  import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync16 } from "fs";
11093
11104
  import { homedir as homedir13 } from "os";
11094
- import { join as join35 } from "path";
11105
+ import { join as join36 } from "path";
11095
11106
  function loadSkillsFromDir(skillsDir, scope) {
11096
11107
  if (!existsSync26(skillsDir)) {
11097
11108
  return [];
@@ -11101,11 +11112,11 @@ function loadSkillsFromDir(skillsDir, scope) {
11101
11112
  for (const entry of entries) {
11102
11113
  if (entry.name.startsWith("."))
11103
11114
  continue;
11104
- const skillPath = join35(skillsDir, entry.name);
11115
+ const skillPath = join36(skillsDir, entry.name);
11105
11116
  if (!entry.isDirectory() && !entry.isSymbolicLink())
11106
11117
  continue;
11107
11118
  const resolvedPath = resolveSymlink(skillPath);
11108
- const skillMdPath = join35(resolvedPath, "SKILL.md");
11119
+ const skillMdPath = join36(resolvedPath, "SKILL.md");
11109
11120
  if (!existsSync26(skillMdPath))
11110
11121
  continue;
11111
11122
  try {
@@ -11143,7 +11154,7 @@ $ARGUMENTS
11143
11154
  return skills;
11144
11155
  }
11145
11156
  function loadUserSkillsAsCommands() {
11146
- const userSkillsDir = join35(homedir13(), ".claude", "skills");
11157
+ const userSkillsDir = join36(homedir13(), ".claude", "skills");
11147
11158
  const skills = loadSkillsFromDir(userSkillsDir, "user");
11148
11159
  return skills.reduce((acc, skill) => {
11149
11160
  acc[skill.name] = skill.definition;
@@ -11151,7 +11162,7 @@ function loadUserSkillsAsCommands() {
11151
11162
  }, {});
11152
11163
  }
11153
11164
  function loadProjectSkillsAsCommands() {
11154
- const projectSkillsDir = join35(process.cwd(), ".claude", "skills");
11165
+ const projectSkillsDir = join36(process.cwd(), ".claude", "skills");
11155
11166
  const skills = loadSkillsFromDir(projectSkillsDir, "project");
11156
11167
  return skills.reduce((acc, skill) => {
11157
11168
  acc[skill.name] = skill.definition;
@@ -11161,7 +11172,7 @@ function loadProjectSkillsAsCommands() {
11161
11172
  // src/features/claude-code-agent-loader/loader.ts
11162
11173
  import { existsSync as existsSync27, readdirSync as readdirSync9, readFileSync as readFileSync17 } from "fs";
11163
11174
  import { homedir as homedir14 } from "os";
11164
- import { join as join36, basename as basename2 } from "path";
11175
+ import { join as join37, basename as basename2 } from "path";
11165
11176
  function parseToolsConfig(toolsStr) {
11166
11177
  if (!toolsStr)
11167
11178
  return;
@@ -11183,7 +11194,7 @@ function loadAgentsFromDir(agentsDir, scope) {
11183
11194
  for (const entry of entries) {
11184
11195
  if (!isMarkdownFile(entry))
11185
11196
  continue;
11186
- const agentPath = join36(agentsDir, entry.name);
11197
+ const agentPath = join37(agentsDir, entry.name);
11187
11198
  const agentName = basename2(entry.name, ".md");
11188
11199
  try {
11189
11200
  const content = readFileSync17(agentPath, "utf-8");
@@ -11213,7 +11224,7 @@ function loadAgentsFromDir(agentsDir, scope) {
11213
11224
  return agents;
11214
11225
  }
11215
11226
  function loadUserAgents() {
11216
- const userAgentsDir = join36(homedir14(), ".claude", "agents");
11227
+ const userAgentsDir = join37(homedir14(), ".claude", "agents");
11217
11228
  const agents = loadAgentsFromDir(userAgentsDir, "user");
11218
11229
  const result = {};
11219
11230
  for (const agent of agents) {
@@ -11222,7 +11233,7 @@ function loadUserAgents() {
11222
11233
  return result;
11223
11234
  }
11224
11235
  function loadProjectAgents() {
11225
- const projectAgentsDir = join36(process.cwd(), ".claude", "agents");
11236
+ const projectAgentsDir = join37(process.cwd(), ".claude", "agents");
11226
11237
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
11227
11238
  const result = {};
11228
11239
  for (const agent of agents) {
@@ -11233,7 +11244,7 @@ function loadProjectAgents() {
11233
11244
  // src/features/claude-code-mcp-loader/loader.ts
11234
11245
  import { existsSync as existsSync28 } from "fs";
11235
11246
  import { homedir as homedir15 } from "os";
11236
- import { join as join37 } from "path";
11247
+ import { join as join38 } from "path";
11237
11248
 
11238
11249
  // src/features/claude-code-mcp-loader/env-expander.ts
11239
11250
  function expandEnvVars(value) {
@@ -11302,9 +11313,9 @@ function getMcpConfigPaths() {
11302
11313
  const home = homedir15();
11303
11314
  const cwd = process.cwd();
11304
11315
  return [
11305
- { path: join37(home, ".claude", ".mcp.json"), scope: "user" },
11306
- { path: join37(cwd, ".mcp.json"), scope: "project" },
11307
- { path: join37(cwd, ".claude", ".mcp.json"), scope: "local" }
11316
+ { path: join38(home, ".claude", ".mcp.json"), scope: "user" },
11317
+ { path: join38(cwd, ".mcp.json"), scope: "project" },
11318
+ { path: join38(cwd, ".claude", ".mcp.json"), scope: "local" }
11308
11319
  ];
11309
11320
  }
11310
11321
  async function loadMcpConfigFile(filePath) {
@@ -11323,13 +11334,13 @@ async function loadMcpConfigs() {
11323
11334
  const servers = {};
11324
11335
  const loadedServers = [];
11325
11336
  const paths = getMcpConfigPaths();
11326
- for (const { path: path7, scope } of paths) {
11327
- const config = await loadMcpConfigFile(path7);
11337
+ for (const { path: path8, scope } of paths) {
11338
+ const config = await loadMcpConfigFile(path8);
11328
11339
  if (!config?.mcpServers)
11329
11340
  continue;
11330
11341
  for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
11331
11342
  if (serverConfig.disabled) {
11332
- log(`Skipping disabled MCP server "${name}"`, { path: path7 });
11343
+ log(`Skipping disabled MCP server "${name}"`, { path: path8 });
11333
11344
  continue;
11334
11345
  }
11335
11346
  try {
@@ -11340,7 +11351,7 @@ async function loadMcpConfigs() {
11340
11351
  loadedServers.splice(existingIndex, 1);
11341
11352
  }
11342
11353
  loadedServers.push({ name, scope, config: transformed });
11343
- log(`Loaded MCP server "${name}" from ${scope}`, { path: path7 });
11354
+ log(`Loaded MCP server "${name}" from ${scope}`, { path: path8 });
11344
11355
  } catch (error) {
11345
11356
  log(`Failed to transform MCP server "${name}"`, error);
11346
11357
  }
@@ -11644,13 +11655,13 @@ var EXT_TO_LANG = {
11644
11655
  };
11645
11656
  // src/tools/lsp/config.ts
11646
11657
  import { existsSync as existsSync29, readFileSync as readFileSync18 } from "fs";
11647
- import { join as join38 } from "path";
11658
+ import { join as join39 } from "path";
11648
11659
  import { homedir as homedir16 } from "os";
11649
- function loadJsonFile(path7) {
11650
- if (!existsSync29(path7))
11660
+ function loadJsonFile(path8) {
11661
+ if (!existsSync29(path8))
11651
11662
  return null;
11652
11663
  try {
11653
- return JSON.parse(readFileSync18(path7, "utf-8"));
11664
+ return JSON.parse(readFileSync18(path8, "utf-8"));
11654
11665
  } catch {
11655
11666
  return null;
11656
11667
  }
@@ -11658,9 +11669,9 @@ function loadJsonFile(path7) {
11658
11669
  function getConfigPaths2() {
11659
11670
  const cwd = process.cwd();
11660
11671
  return {
11661
- project: join38(cwd, ".opencode", "oh-my-opencode.json"),
11662
- user: join38(homedir16(), ".config", "opencode", "oh-my-opencode.json"),
11663
- opencode: join38(homedir16(), ".config", "opencode", "opencode.json")
11672
+ project: join39(cwd, ".opencode", "oh-my-opencode.json"),
11673
+ user: join39(homedir16(), ".config", "opencode", "oh-my-opencode.json"),
11674
+ opencode: join39(homedir16(), ".config", "opencode", "opencode.json")
11664
11675
  };
11665
11676
  }
11666
11677
  function loadAllConfigs() {
@@ -11756,18 +11767,18 @@ function isServerInstalled(command) {
11756
11767
  const pathSeparator = isWindows2 ? ";" : ":";
11757
11768
  const paths = pathEnv.split(pathSeparator);
11758
11769
  for (const p of paths) {
11759
- if (existsSync29(join38(p, cmd)) || existsSync29(join38(p, cmd + ext))) {
11770
+ if (existsSync29(join39(p, cmd)) || existsSync29(join39(p, cmd + ext))) {
11760
11771
  return true;
11761
11772
  }
11762
11773
  }
11763
11774
  const cwd = process.cwd();
11764
11775
  const additionalPaths = [
11765
- join38(cwd, "node_modules", ".bin", cmd),
11766
- join38(cwd, "node_modules", ".bin", cmd + ext),
11767
- join38(homedir16(), ".config", "opencode", "bin", cmd),
11768
- join38(homedir16(), ".config", "opencode", "bin", cmd + ext),
11769
- join38(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd),
11770
- join38(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd + ext)
11776
+ join39(cwd, "node_modules", ".bin", cmd),
11777
+ join39(cwd, "node_modules", ".bin", cmd + ext),
11778
+ join39(homedir16(), ".config", "opencode", "bin", cmd),
11779
+ join39(homedir16(), ".config", "opencode", "bin", cmd + ext),
11780
+ join39(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd),
11781
+ join39(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd + ext)
11771
11782
  ];
11772
11783
  for (const p of additionalPaths) {
11773
11784
  if (existsSync29(p)) {
@@ -13379,10 +13390,10 @@ function mergeDefs(...defs) {
13379
13390
  function cloneDef(schema) {
13380
13391
  return mergeDefs(schema._zod.def);
13381
13392
  }
13382
- function getElementAtPath(obj, path7) {
13383
- if (!path7)
13393
+ function getElementAtPath(obj, path8) {
13394
+ if (!path8)
13384
13395
  return obj;
13385
- return path7.reduce((acc, key) => acc?.[key], obj);
13396
+ return path8.reduce((acc, key) => acc?.[key], obj);
13386
13397
  }
13387
13398
  function promiseAllObject(promisesObj) {
13388
13399
  const keys = Object.keys(promisesObj);
@@ -13741,11 +13752,11 @@ function aborted(x, startIndex = 0) {
13741
13752
  }
13742
13753
  return false;
13743
13754
  }
13744
- function prefixIssues(path7, issues) {
13755
+ function prefixIssues(path8, issues) {
13745
13756
  return issues.map((iss) => {
13746
13757
  var _a;
13747
13758
  (_a = iss).path ?? (_a.path = []);
13748
- iss.path.unshift(path7);
13759
+ iss.path.unshift(path8);
13749
13760
  return iss;
13750
13761
  });
13751
13762
  }
@@ -13913,7 +13924,7 @@ function treeifyError(error, _mapper) {
13913
13924
  return issue2.message;
13914
13925
  };
13915
13926
  const result = { errors: [] };
13916
- const processError = (error2, path7 = []) => {
13927
+ const processError = (error2, path8 = []) => {
13917
13928
  var _a, _b;
13918
13929
  for (const issue2 of error2.issues) {
13919
13930
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -13923,7 +13934,7 @@ function treeifyError(error, _mapper) {
13923
13934
  } else if (issue2.code === "invalid_element") {
13924
13935
  processError({ issues: issue2.issues }, issue2.path);
13925
13936
  } else {
13926
- const fullpath = [...path7, ...issue2.path];
13937
+ const fullpath = [...path8, ...issue2.path];
13927
13938
  if (fullpath.length === 0) {
13928
13939
  result.errors.push(mapper(issue2));
13929
13940
  continue;
@@ -13955,8 +13966,8 @@ function treeifyError(error, _mapper) {
13955
13966
  }
13956
13967
  function toDotPath(_path) {
13957
13968
  const segs = [];
13958
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
13959
- for (const seg of path7) {
13969
+ const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
13970
+ for (const seg of path8) {
13960
13971
  if (typeof seg === "number")
13961
13972
  segs.push(`[${seg}]`);
13962
13973
  else if (typeof seg === "symbol")
@@ -25299,13 +25310,13 @@ var lsp_code_action_resolve = tool({
25299
25310
  });
25300
25311
  // src/tools/ast-grep/constants.ts
25301
25312
  import { createRequire as createRequire4 } from "module";
25302
- import { dirname as dirname6, join as join40 } from "path";
25313
+ import { dirname as dirname6, join as join41 } from "path";
25303
25314
  import { existsSync as existsSync32, statSync as statSync4 } from "fs";
25304
25315
 
25305
25316
  // src/tools/ast-grep/downloader.ts
25306
25317
  var {spawn: spawn5 } = globalThis.Bun;
25307
25318
  import { existsSync as existsSync31, mkdirSync as mkdirSync10, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
25308
- import { join as join39 } from "path";
25319
+ import { join as join40 } from "path";
25309
25320
  import { homedir as homedir17 } from "os";
25310
25321
  import { createRequire as createRequire3 } from "module";
25311
25322
  var REPO2 = "ast-grep/ast-grep";
@@ -25331,18 +25342,18 @@ var PLATFORM_MAP2 = {
25331
25342
  function getCacheDir3() {
25332
25343
  if (process.platform === "win32") {
25333
25344
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
25334
- const base2 = localAppData || join39(homedir17(), "AppData", "Local");
25335
- return join39(base2, "oh-my-opencode", "bin");
25345
+ const base2 = localAppData || join40(homedir17(), "AppData", "Local");
25346
+ return join40(base2, "oh-my-opencode", "bin");
25336
25347
  }
25337
25348
  const xdgCache2 = process.env.XDG_CACHE_HOME;
25338
- const base = xdgCache2 || join39(homedir17(), ".cache");
25339
- return join39(base, "oh-my-opencode", "bin");
25349
+ const base = xdgCache2 || join40(homedir17(), ".cache");
25350
+ return join40(base, "oh-my-opencode", "bin");
25340
25351
  }
25341
25352
  function getBinaryName3() {
25342
25353
  return process.platform === "win32" ? "sg.exe" : "sg";
25343
25354
  }
25344
25355
  function getCachedBinaryPath2() {
25345
- const binaryPath = join39(getCacheDir3(), getBinaryName3());
25356
+ const binaryPath = join40(getCacheDir3(), getBinaryName3());
25346
25357
  return existsSync31(binaryPath) ? binaryPath : null;
25347
25358
  }
25348
25359
  async function extractZip2(archivePath, destDir) {
@@ -25369,12 +25380,12 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
25369
25380
  }
25370
25381
  const cacheDir = getCacheDir3();
25371
25382
  const binaryName = getBinaryName3();
25372
- const binaryPath = join39(cacheDir, binaryName);
25383
+ const binaryPath = join40(cacheDir, binaryName);
25373
25384
  if (existsSync31(binaryPath)) {
25374
25385
  return binaryPath;
25375
25386
  }
25376
- const { arch, os: os5 } = platformInfo;
25377
- const assetName = `app-${arch}-${os5}.zip`;
25387
+ const { arch, os: os6 } = platformInfo;
25388
+ const assetName = `app-${arch}-${os6}.zip`;
25378
25389
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
25379
25390
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
25380
25391
  try {
@@ -25385,7 +25396,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
25385
25396
  if (!response2.ok) {
25386
25397
  throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
25387
25398
  }
25388
- const archivePath = join39(cacheDir, assetName);
25399
+ const archivePath = join40(cacheDir, assetName);
25389
25400
  const arrayBuffer = await response2.arrayBuffer();
25390
25401
  await Bun.write(archivePath, arrayBuffer);
25391
25402
  await extractZip2(archivePath, cacheDir);
@@ -25443,7 +25454,7 @@ function findSgCliPathSync() {
25443
25454
  const require2 = createRequire4(import.meta.url);
25444
25455
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
25445
25456
  const cliDir = dirname6(cliPkgPath);
25446
- const sgPath = join40(cliDir, binaryName);
25457
+ const sgPath = join41(cliDir, binaryName);
25447
25458
  if (existsSync32(sgPath) && isValidBinary(sgPath)) {
25448
25459
  return sgPath;
25449
25460
  }
@@ -25455,7 +25466,7 @@ function findSgCliPathSync() {
25455
25466
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
25456
25467
  const pkgDir = dirname6(pkgPath);
25457
25468
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
25458
- const binaryPath = join40(pkgDir, astGrepName);
25469
+ const binaryPath = join41(pkgDir, astGrepName);
25459
25470
  if (existsSync32(binaryPath) && isValidBinary(binaryPath)) {
25460
25471
  return binaryPath;
25461
25472
  }
@@ -25463,9 +25474,9 @@ function findSgCliPathSync() {
25463
25474
  }
25464
25475
  if (process.platform === "darwin") {
25465
25476
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
25466
- for (const path7 of homebrewPaths) {
25467
- if (existsSync32(path7) && isValidBinary(path7)) {
25468
- return path7;
25477
+ for (const path8 of homebrewPaths) {
25478
+ if (existsSync32(path8) && isValidBinary(path8)) {
25479
+ return path8;
25469
25480
  }
25470
25481
  }
25471
25482
  }
@@ -25483,8 +25494,8 @@ function getSgCliPath() {
25483
25494
  }
25484
25495
  return "sg";
25485
25496
  }
25486
- function setSgCliPath(path7) {
25487
- resolvedCliPath2 = path7;
25497
+ function setSgCliPath(path8) {
25498
+ resolvedCliPath2 = path8;
25488
25499
  }
25489
25500
  var SG_CLI_PATH = getSgCliPath();
25490
25501
  var CLI_LANGUAGES = [
@@ -25831,19 +25842,19 @@ var {spawn: spawn7 } = globalThis.Bun;
25831
25842
 
25832
25843
  // src/tools/grep/constants.ts
25833
25844
  import { existsSync as existsSync35 } from "fs";
25834
- import { join as join42, dirname as dirname7 } from "path";
25845
+ import { join as join43, dirname as dirname7 } from "path";
25835
25846
  import { spawnSync } from "child_process";
25836
25847
 
25837
25848
  // src/tools/grep/downloader.ts
25838
25849
  import { existsSync as existsSync34, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync10 } from "fs";
25839
- import { join as join41 } from "path";
25850
+ import { join as join42 } from "path";
25840
25851
  function getInstallDir() {
25841
25852
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
25842
- return join41(homeDir, ".cache", "oh-my-opencode", "bin");
25853
+ return join42(homeDir, ".cache", "oh-my-opencode", "bin");
25843
25854
  }
25844
25855
  function getRgPath() {
25845
25856
  const isWindows2 = process.platform === "win32";
25846
- return join41(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
25857
+ return join42(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
25847
25858
  }
25848
25859
  function getInstalledRipgrepPath() {
25849
25860
  const rgPath = getRgPath();
@@ -25870,10 +25881,10 @@ function getOpenCodeBundledRg() {
25870
25881
  const isWindows2 = process.platform === "win32";
25871
25882
  const rgName = isWindows2 ? "rg.exe" : "rg";
25872
25883
  const candidates = [
25873
- join42(execDir, rgName),
25874
- join42(execDir, "bin", rgName),
25875
- join42(execDir, "..", "bin", rgName),
25876
- join42(execDir, "..", "libexec", rgName)
25884
+ join43(execDir, rgName),
25885
+ join43(execDir, "bin", rgName),
25886
+ join43(execDir, "..", "bin", rgName),
25887
+ join43(execDir, "..", "libexec", rgName)
25877
25888
  ];
25878
25889
  for (const candidate of candidates) {
25879
25890
  if (existsSync35(candidate)) {
@@ -26281,7 +26292,7 @@ var glob = tool({
26281
26292
  // src/tools/slashcommand/tools.ts
26282
26293
  import { existsSync as existsSync36, readdirSync as readdirSync11, readFileSync as readFileSync21 } from "fs";
26283
26294
  import { homedir as homedir18 } from "os";
26284
- import { join as join43, basename as basename3, dirname as dirname8 } from "path";
26295
+ import { join as join44, basename as basename3, dirname as dirname8 } from "path";
26285
26296
  function discoverCommandsFromDir(commandsDir, scope) {
26286
26297
  if (!existsSync36(commandsDir)) {
26287
26298
  return [];
@@ -26291,7 +26302,7 @@ function discoverCommandsFromDir(commandsDir, scope) {
26291
26302
  for (const entry of entries) {
26292
26303
  if (!isMarkdownFile(entry))
26293
26304
  continue;
26294
- const commandPath = join43(commandsDir, entry.name);
26305
+ const commandPath = join44(commandsDir, entry.name);
26295
26306
  const commandName = basename3(entry.name, ".md");
26296
26307
  try {
26297
26308
  const content = readFileSync21(commandPath, "utf-8");
@@ -26319,10 +26330,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
26319
26330
  return commands;
26320
26331
  }
26321
26332
  function discoverCommandsSync() {
26322
- const userCommandsDir = join43(homedir18(), ".claude", "commands");
26323
- const projectCommandsDir = join43(process.cwd(), ".claude", "commands");
26324
- const opencodeGlobalDir = join43(homedir18(), ".config", "opencode", "command");
26325
- const opencodeProjectDir = join43(process.cwd(), ".opencode", "command");
26333
+ const userCommandsDir = join44(homedir18(), ".claude", "commands");
26334
+ const projectCommandsDir = join44(process.cwd(), ".claude", "commands");
26335
+ const opencodeGlobalDir = join44(homedir18(), ".config", "opencode", "command");
26336
+ const opencodeProjectDir = join44(process.cwd(), ".opencode", "command");
26326
26337
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
26327
26338
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
26328
26339
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -26445,6 +26456,484 @@ Provide a command name to execute.`;
26445
26456
  Try a different command name.`;
26446
26457
  }
26447
26458
  });
26459
+ // src/tools/session-manager/constants.ts
26460
+ import { join as join45 } from "path";
26461
+ import { homedir as homedir19 } from "os";
26462
+ var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
26463
+ var MESSAGE_STORAGE4 = join45(OPENCODE_STORAGE9, "message");
26464
+ var PART_STORAGE4 = join45(OPENCODE_STORAGE9, "part");
26465
+ var TODO_DIR2 = join45(homedir19(), ".claude", "todos");
26466
+ var TRANSCRIPT_DIR2 = join45(homedir19(), ".claude", "transcripts");
26467
+ var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
26468
+
26469
+ Returns a list of available session IDs with metadata including message count, date range, and agents used.
26470
+
26471
+ Arguments:
26472
+ - limit (optional): Maximum number of sessions to return
26473
+ - from_date (optional): Filter sessions from this date (ISO 8601 format)
26474
+ - to_date (optional): Filter sessions until this date (ISO 8601 format)
26475
+
26476
+ Example output:
26477
+ | Session ID | Messages | First | Last | Agents |
26478
+ |------------|----------|-------|------|--------|
26479
+ | ses_abc123 | 45 | 2025-12-20 | 2025-12-24 | build, oracle |
26480
+ | ses_def456 | 12 | 2025-12-19 | 2025-12-19 | build |`;
26481
+ var SESSION_READ_DESCRIPTION = `Read messages and history from an OpenCode session.
26482
+
26483
+ Returns a formatted view of session messages with role, timestamp, and content. Optionally includes todos and transcript data.
26484
+
26485
+ Arguments:
26486
+ - session_id (required): Session ID to read
26487
+ - include_todos (optional): Include todo list if available (default: false)
26488
+ - include_transcript (optional): Include transcript log if available (default: false)
26489
+ - limit (optional): Maximum number of messages to return (default: all)
26490
+
26491
+ Example output:
26492
+ Session: ses_abc123
26493
+ Messages: 45
26494
+ Date Range: 2025-12-20 to 2025-12-24
26495
+
26496
+ [Message 1] user (2025-12-20 10:30:00)
26497
+ Hello, can you help me with...
26498
+
26499
+ [Message 2] assistant (2025-12-20 10:30:15)
26500
+ Of course! Let me help you with...`;
26501
+ var SESSION_SEARCH_DESCRIPTION = `Search for content within OpenCode session messages.
26502
+
26503
+ Performs full-text search across session messages and returns matching excerpts with context.
26504
+
26505
+ Arguments:
26506
+ - query (required): Search query string
26507
+ - session_id (optional): Search within specific session only (default: all sessions)
26508
+ - case_sensitive (optional): Case-sensitive search (default: false)
26509
+ - limit (optional): Maximum number of results to return (default: 20)
26510
+
26511
+ Example output:
26512
+ Found 3 matches across 2 sessions:
26513
+
26514
+ [ses_abc123] Message msg_001 (user)
26515
+ ...implement the **session manager** tool...
26516
+
26517
+ [ses_abc123] Message msg_005 (assistant)
26518
+ ...I'll create a **session manager** with full search...
26519
+
26520
+ [ses_def456] Message msg_012 (user)
26521
+ ...use the **session manager** to find...`;
26522
+ var SESSION_INFO_DESCRIPTION = `Get metadata and statistics about an OpenCode session.
26523
+
26524
+ Returns detailed information about a session including message count, date range, agents used, and available data sources.
26525
+
26526
+ Arguments:
26527
+ - session_id (required): Session ID to inspect
26528
+
26529
+ Example output:
26530
+ Session ID: ses_abc123
26531
+ Messages: 45
26532
+ Date Range: 2025-12-20 10:30:00 to 2025-12-24 15:45:30
26533
+ Duration: 4 days, 5 hours
26534
+ Agents Used: build, oracle, librarian
26535
+ Has Todos: Yes (12 items, 8 completed)
26536
+ Has Transcript: Yes (234 entries)`;
26537
+
26538
+ // src/tools/session-manager/storage.ts
26539
+ import { existsSync as existsSync37, readdirSync as readdirSync12, readFileSync as readFileSync22 } from "fs";
26540
+ import { join as join46 } from "path";
26541
+ function getAllSessions() {
26542
+ if (!existsSync37(MESSAGE_STORAGE4))
26543
+ return [];
26544
+ const sessions = [];
26545
+ function scanDirectory(dir) {
26546
+ try {
26547
+ for (const entry of readdirSync12(dir, { withFileTypes: true })) {
26548
+ if (entry.isDirectory()) {
26549
+ const sessionPath = join46(dir, entry.name);
26550
+ const files = readdirSync12(sessionPath);
26551
+ if (files.some((f) => f.endsWith(".json"))) {
26552
+ sessions.push(entry.name);
26553
+ } else {
26554
+ scanDirectory(sessionPath);
26555
+ }
26556
+ }
26557
+ }
26558
+ } catch {
26559
+ return;
26560
+ }
26561
+ }
26562
+ scanDirectory(MESSAGE_STORAGE4);
26563
+ return [...new Set(sessions)];
26564
+ }
26565
+ function getMessageDir5(sessionID) {
26566
+ if (!existsSync37(MESSAGE_STORAGE4))
26567
+ return "";
26568
+ const directPath = join46(MESSAGE_STORAGE4, sessionID);
26569
+ if (existsSync37(directPath)) {
26570
+ return directPath;
26571
+ }
26572
+ for (const dir of readdirSync12(MESSAGE_STORAGE4)) {
26573
+ const sessionPath = join46(MESSAGE_STORAGE4, dir, sessionID);
26574
+ if (existsSync37(sessionPath)) {
26575
+ return sessionPath;
26576
+ }
26577
+ }
26578
+ return "";
26579
+ }
26580
+ function sessionExists(sessionID) {
26581
+ return getMessageDir5(sessionID) !== "";
26582
+ }
26583
+ function readSessionMessages(sessionID) {
26584
+ const messageDir = getMessageDir5(sessionID);
26585
+ if (!messageDir || !existsSync37(messageDir))
26586
+ return [];
26587
+ const messages = [];
26588
+ for (const file2 of readdirSync12(messageDir)) {
26589
+ if (!file2.endsWith(".json"))
26590
+ continue;
26591
+ try {
26592
+ const content = readFileSync22(join46(messageDir, file2), "utf-8");
26593
+ const meta = JSON.parse(content);
26594
+ const parts = readParts2(meta.id);
26595
+ messages.push({
26596
+ id: meta.id,
26597
+ role: meta.role,
26598
+ agent: meta.agent,
26599
+ time: meta.time,
26600
+ parts
26601
+ });
26602
+ } catch {
26603
+ continue;
26604
+ }
26605
+ }
26606
+ return messages.sort((a, b) => {
26607
+ const aTime = a.time?.created ?? 0;
26608
+ const bTime = b.time?.created ?? 0;
26609
+ if (aTime !== bTime)
26610
+ return aTime - bTime;
26611
+ return a.id.localeCompare(b.id);
26612
+ });
26613
+ }
26614
+ function readParts2(messageID) {
26615
+ const partDir = join46(PART_STORAGE4, messageID);
26616
+ if (!existsSync37(partDir))
26617
+ return [];
26618
+ const parts = [];
26619
+ for (const file2 of readdirSync12(partDir)) {
26620
+ if (!file2.endsWith(".json"))
26621
+ continue;
26622
+ try {
26623
+ const content = readFileSync22(join46(partDir, file2), "utf-8");
26624
+ parts.push(JSON.parse(content));
26625
+ } catch {
26626
+ continue;
26627
+ }
26628
+ }
26629
+ return parts.sort((a, b) => a.id.localeCompare(b.id));
26630
+ }
26631
+ function readSessionTodos(sessionID) {
26632
+ if (!existsSync37(TODO_DIR2))
26633
+ return [];
26634
+ const todoFiles = readdirSync12(TODO_DIR2).filter((f) => f.includes(sessionID) && f.endsWith(".json"));
26635
+ for (const file2 of todoFiles) {
26636
+ try {
26637
+ const content = readFileSync22(join46(TODO_DIR2, file2), "utf-8");
26638
+ const data = JSON.parse(content);
26639
+ if (Array.isArray(data)) {
26640
+ return data.map((item) => ({
26641
+ id: item.id || "",
26642
+ content: item.content || "",
26643
+ status: item.status || "pending",
26644
+ priority: item.priority
26645
+ }));
26646
+ }
26647
+ } catch {
26648
+ continue;
26649
+ }
26650
+ }
26651
+ return [];
26652
+ }
26653
+ function readSessionTranscript(sessionID) {
26654
+ if (!existsSync37(TRANSCRIPT_DIR2))
26655
+ return 0;
26656
+ const transcriptFile = join46(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
26657
+ if (!existsSync37(transcriptFile))
26658
+ return 0;
26659
+ try {
26660
+ const content = readFileSync22(transcriptFile, "utf-8");
26661
+ return content.trim().split(`
26662
+ `).filter(Boolean).length;
26663
+ } catch {
26664
+ return 0;
26665
+ }
26666
+ }
26667
+ function getSessionInfo(sessionID) {
26668
+ const messages = readSessionMessages(sessionID);
26669
+ if (messages.length === 0)
26670
+ return null;
26671
+ const agentsUsed = new Set;
26672
+ let firstMessage;
26673
+ let lastMessage;
26674
+ for (const msg of messages) {
26675
+ if (msg.agent)
26676
+ agentsUsed.add(msg.agent);
26677
+ if (msg.time?.created) {
26678
+ const date5 = new Date(msg.time.created);
26679
+ if (!firstMessage || date5 < firstMessage)
26680
+ firstMessage = date5;
26681
+ if (!lastMessage || date5 > lastMessage)
26682
+ lastMessage = date5;
26683
+ }
26684
+ }
26685
+ const todos = readSessionTodos(sessionID);
26686
+ const transcriptEntries = readSessionTranscript(sessionID);
26687
+ return {
26688
+ id: sessionID,
26689
+ message_count: messages.length,
26690
+ first_message: firstMessage,
26691
+ last_message: lastMessage,
26692
+ agents_used: Array.from(agentsUsed),
26693
+ has_todos: todos.length > 0,
26694
+ has_transcript: transcriptEntries > 0,
26695
+ todos,
26696
+ transcript_entries: transcriptEntries
26697
+ };
26698
+ }
26699
+
26700
+ // src/tools/session-manager/utils.ts
26701
+ function formatSessionList(sessionIDs) {
26702
+ if (sessionIDs.length === 0) {
26703
+ return "No sessions found.";
26704
+ }
26705
+ const infos = sessionIDs.map((id) => getSessionInfo(id)).filter((info) => info !== null);
26706
+ if (infos.length === 0) {
26707
+ return "No valid sessions found.";
26708
+ }
26709
+ const headers = ["Session ID", "Messages", "First", "Last", "Agents"];
26710
+ const rows = infos.map((info) => [
26711
+ info.id,
26712
+ info.message_count.toString(),
26713
+ info.first_message?.toISOString().split("T")[0] ?? "N/A",
26714
+ info.last_message?.toISOString().split("T")[0] ?? "N/A",
26715
+ info.agents_used.join(", ") || "none"
26716
+ ]);
26717
+ const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
26718
+ const formatRow = (cells) => {
26719
+ return "| " + cells.map((cell, i) => cell.padEnd(colWidths[i])).join(" | ").trim() + " |";
26720
+ };
26721
+ const separator = "|" + colWidths.map((w) => "-".repeat(w + 2)).join("|") + "|";
26722
+ return [formatRow(headers), separator, ...rows.map(formatRow)].join(`
26723
+ `);
26724
+ }
26725
+ function formatSessionMessages(messages, includeTodos, todos) {
26726
+ if (messages.length === 0) {
26727
+ return "No messages found in this session.";
26728
+ }
26729
+ const lines = [];
26730
+ for (const msg of messages) {
26731
+ const timestamp = msg.time?.created ? new Date(msg.time.created).toISOString() : "Unknown time";
26732
+ const agent = msg.agent ? ` (${msg.agent})` : "";
26733
+ lines.push(`
26734
+ [${msg.role}${agent}] ${timestamp}`);
26735
+ for (const part of msg.parts) {
26736
+ if (part.type === "text" && part.text) {
26737
+ lines.push(part.text.trim());
26738
+ } else if (part.type === "thinking" && part.thinking) {
26739
+ lines.push(`[thinking] ${part.thinking.substring(0, 200)}...`);
26740
+ } else if ((part.type === "tool_use" || part.type === "tool") && part.tool) {
26741
+ const input = part.input ? JSON.stringify(part.input).substring(0, 100) : "";
26742
+ lines.push(`[tool: ${part.tool}] ${input}`);
26743
+ } else if (part.type === "tool_result") {
26744
+ const output = part.output ? part.output.substring(0, 200) : "";
26745
+ lines.push(`[tool result] ${output}...`);
26746
+ }
26747
+ }
26748
+ }
26749
+ if (includeTodos && todos && todos.length > 0) {
26750
+ lines.push(`
26751
+
26752
+ === Todos ===`);
26753
+ for (const todo of todos) {
26754
+ const status = todo.status === "completed" ? "\u2713" : todo.status === "in_progress" ? "\u2192" : "\u25CB";
26755
+ lines.push(`${status} [${todo.status}] ${todo.content}`);
26756
+ }
26757
+ }
26758
+ return lines.join(`
26759
+ `);
26760
+ }
26761
+ function formatSessionInfo(info) {
26762
+ const lines = [
26763
+ `Session ID: ${info.id}`,
26764
+ `Messages: ${info.message_count}`,
26765
+ `Date Range: ${info.first_message?.toISOString() ?? "N/A"} to ${info.last_message?.toISOString() ?? "N/A"}`,
26766
+ `Agents Used: ${info.agents_used.join(", ") || "none"}`,
26767
+ `Has Todos: ${info.has_todos ? `Yes (${info.todos?.length ?? 0} items)` : "No"}`,
26768
+ `Has Transcript: ${info.has_transcript ? `Yes (${info.transcript_entries} entries)` : "No"}`
26769
+ ];
26770
+ if (info.first_message && info.last_message) {
26771
+ const duration3 = info.last_message.getTime() - info.first_message.getTime();
26772
+ const days = Math.floor(duration3 / (1000 * 60 * 60 * 24));
26773
+ const hours = Math.floor(duration3 % (1000 * 60 * 60 * 24) / (1000 * 60 * 60));
26774
+ if (days > 0 || hours > 0) {
26775
+ lines.push(`Duration: ${days} days, ${hours} hours`);
26776
+ }
26777
+ }
26778
+ return lines.join(`
26779
+ `);
26780
+ }
26781
+ function formatSearchResults(results) {
26782
+ if (results.length === 0) {
26783
+ return "No matches found.";
26784
+ }
26785
+ const lines = [`Found ${results.length} matches:
26786
+ `];
26787
+ for (const result of results) {
26788
+ const timestamp = result.timestamp ? new Date(result.timestamp).toISOString() : "";
26789
+ lines.push(`[${result.session_id}] ${result.message_id} (${result.role}) ${timestamp}`);
26790
+ lines.push(` ${result.excerpt}`);
26791
+ lines.push(` Matches: ${result.match_count}
26792
+ `);
26793
+ }
26794
+ return lines.join(`
26795
+ `);
26796
+ }
26797
+ function filterSessionsByDate(sessionIDs, fromDate, toDate) {
26798
+ if (!fromDate && !toDate)
26799
+ return sessionIDs;
26800
+ const from = fromDate ? new Date(fromDate) : null;
26801
+ const to = toDate ? new Date(toDate) : null;
26802
+ return sessionIDs.filter((id) => {
26803
+ const info = getSessionInfo(id);
26804
+ if (!info || !info.last_message)
26805
+ return false;
26806
+ if (from && info.last_message < from)
26807
+ return false;
26808
+ if (to && info.last_message > to)
26809
+ return false;
26810
+ return true;
26811
+ });
26812
+ }
26813
+ function searchInSession(sessionID, query, caseSensitive = false) {
26814
+ const messages = readSessionMessages(sessionID);
26815
+ const results = [];
26816
+ const searchQuery = caseSensitive ? query : query.toLowerCase();
26817
+ for (const msg of messages) {
26818
+ let matchCount = 0;
26819
+ let excerpts = [];
26820
+ for (const part of msg.parts) {
26821
+ if (part.type === "text" && part.text) {
26822
+ const text = caseSensitive ? part.text : part.text.toLowerCase();
26823
+ const matches = text.split(searchQuery).length - 1;
26824
+ if (matches > 0) {
26825
+ matchCount += matches;
26826
+ const index = text.indexOf(searchQuery);
26827
+ if (index !== -1) {
26828
+ const start = Math.max(0, index - 50);
26829
+ const end = Math.min(text.length, index + searchQuery.length + 50);
26830
+ let excerpt = part.text.substring(start, end);
26831
+ if (start > 0)
26832
+ excerpt = "..." + excerpt;
26833
+ if (end < text.length)
26834
+ excerpt = excerpt + "...";
26835
+ excerpts.push(excerpt);
26836
+ }
26837
+ }
26838
+ }
26839
+ }
26840
+ if (matchCount > 0) {
26841
+ results.push({
26842
+ session_id: sessionID,
26843
+ message_id: msg.id,
26844
+ role: msg.role,
26845
+ excerpt: excerpts[0] || "",
26846
+ match_count: matchCount,
26847
+ timestamp: msg.time?.created
26848
+ });
26849
+ }
26850
+ }
26851
+ return results;
26852
+ }
26853
+
26854
+ // src/tools/session-manager/tools.ts
26855
+ var session_list = tool({
26856
+ description: SESSION_LIST_DESCRIPTION,
26857
+ args: {
26858
+ limit: tool.schema.number().optional().describe("Maximum number of sessions to return"),
26859
+ from_date: tool.schema.string().optional().describe("Filter sessions from this date (ISO 8601 format)"),
26860
+ to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)")
26861
+ },
26862
+ execute: async (args, _context) => {
26863
+ try {
26864
+ let sessions = getAllSessions();
26865
+ if (args.from_date || args.to_date) {
26866
+ sessions = filterSessionsByDate(sessions, args.from_date, args.to_date);
26867
+ }
26868
+ if (args.limit && args.limit > 0) {
26869
+ sessions = sessions.slice(0, args.limit);
26870
+ }
26871
+ return formatSessionList(sessions);
26872
+ } catch (e) {
26873
+ return `Error: ${e instanceof Error ? e.message : String(e)}`;
26874
+ }
26875
+ }
26876
+ });
26877
+ var session_read = tool({
26878
+ description: SESSION_READ_DESCRIPTION,
26879
+ args: {
26880
+ session_id: tool.schema.string().describe("Session ID to read"),
26881
+ include_todos: tool.schema.boolean().optional().describe("Include todo list if available (default: false)"),
26882
+ include_transcript: tool.schema.boolean().optional().describe("Include transcript log if available (default: false)"),
26883
+ limit: tool.schema.number().optional().describe("Maximum number of messages to return (default: all)")
26884
+ },
26885
+ execute: async (args, _context) => {
26886
+ try {
26887
+ if (!sessionExists(args.session_id)) {
26888
+ return `Session not found: ${args.session_id}`;
26889
+ }
26890
+ let messages = readSessionMessages(args.session_id);
26891
+ if (args.limit && args.limit > 0) {
26892
+ messages = messages.slice(0, args.limit);
26893
+ }
26894
+ const todos = args.include_todos ? readSessionTodos(args.session_id) : undefined;
26895
+ return formatSessionMessages(messages, args.include_todos, todos);
26896
+ } catch (e) {
26897
+ return `Error: ${e instanceof Error ? e.message : String(e)}`;
26898
+ }
26899
+ }
26900
+ });
26901
+ var session_search = tool({
26902
+ description: SESSION_SEARCH_DESCRIPTION,
26903
+ args: {
26904
+ query: tool.schema.string().describe("Search query string"),
26905
+ session_id: tool.schema.string().optional().describe("Search within specific session only (default: all sessions)"),
26906
+ case_sensitive: tool.schema.boolean().optional().describe("Case-sensitive search (default: false)"),
26907
+ limit: tool.schema.number().optional().describe("Maximum number of results to return (default: 20)")
26908
+ },
26909
+ execute: async (args, _context) => {
26910
+ try {
26911
+ const sessions = args.session_id ? [args.session_id] : getAllSessions();
26912
+ const allResults = sessions.flatMap((sid) => searchInSession(sid, args.query, args.case_sensitive));
26913
+ const limited = args.limit && args.limit > 0 ? allResults.slice(0, args.limit) : allResults.slice(0, 20);
26914
+ return formatSearchResults(limited);
26915
+ } catch (e) {
26916
+ return `Error: ${e instanceof Error ? e.message : String(e)}`;
26917
+ }
26918
+ }
26919
+ });
26920
+ var session_info = tool({
26921
+ description: SESSION_INFO_DESCRIPTION,
26922
+ args: {
26923
+ session_id: tool.schema.string().describe("Session ID to inspect")
26924
+ },
26925
+ execute: async (args, _context) => {
26926
+ try {
26927
+ const info = getSessionInfo(args.session_id);
26928
+ if (!info) {
26929
+ return `Session not found: ${args.session_id}`;
26930
+ }
26931
+ return formatSessionInfo(info);
26932
+ } catch (e) {
26933
+ return `Error: ${e instanceof Error ? e.message : String(e)}`;
26934
+ }
26935
+ }
26936
+ });
26448
26937
  // src/tools/interactive-bash/constants.ts
26449
26938
  var DEFAULT_TIMEOUT_MS4 = 60000;
26450
26939
  var BLOCKED_TMUX_SUBCOMMANDS = [
@@ -26478,12 +26967,12 @@ async function findTmuxPath() {
26478
26967
  return null;
26479
26968
  }
26480
26969
  const stdout = await new Response(proc.stdout).text();
26481
- const path7 = stdout.trim().split(`
26970
+ const path8 = stdout.trim().split(`
26482
26971
  `)[0];
26483
- if (!path7) {
26972
+ if (!path8) {
26484
26973
  return null;
26485
26974
  }
26486
- const verifyProc = spawn9([path7, "-V"], {
26975
+ const verifyProc = spawn9([path8, "-V"], {
26487
26976
  stdout: "pipe",
26488
26977
  stderr: "pipe"
26489
26978
  });
@@ -26491,7 +26980,7 @@ async function findTmuxPath() {
26491
26980
  if (verifyExitCode !== 0) {
26492
26981
  return null;
26493
26982
  }
26494
- return path7;
26983
+ return path8;
26495
26984
  } catch {
26496
26985
  return null;
26497
26986
  }
@@ -26504,9 +26993,9 @@ async function getTmuxPath() {
26504
26993
  return initPromise3;
26505
26994
  }
26506
26995
  initPromise3 = (async () => {
26507
- const path7 = await findTmuxPath();
26508
- tmuxPath = path7;
26509
- return path7;
26996
+ const path8 = await findTmuxPath();
26997
+ tmuxPath = path8;
26998
+ return path8;
26510
26999
  })();
26511
27000
  return initPromise3;
26512
27001
  }
@@ -27145,20 +27634,24 @@ var builtinTools = {
27145
27634
  ast_grep_replace,
27146
27635
  grep,
27147
27636
  glob,
27148
- slashcommand
27637
+ slashcommand,
27638
+ session_list,
27639
+ session_read,
27640
+ session_search,
27641
+ session_info
27149
27642
  };
27150
27643
  // src/features/background-agent/manager.ts
27151
- import { existsSync as existsSync37, readdirSync as readdirSync12 } from "fs";
27152
- import { join as join44 } from "path";
27153
- function getMessageDir5(sessionID) {
27154
- if (!existsSync37(MESSAGE_STORAGE))
27644
+ import { existsSync as existsSync38, readdirSync as readdirSync13 } from "fs";
27645
+ import { join as join47 } from "path";
27646
+ function getMessageDir6(sessionID) {
27647
+ if (!existsSync38(MESSAGE_STORAGE))
27155
27648
  return null;
27156
- const directPath = join44(MESSAGE_STORAGE, sessionID);
27157
- if (existsSync37(directPath))
27649
+ const directPath = join47(MESSAGE_STORAGE, sessionID);
27650
+ if (existsSync38(directPath))
27158
27651
  return directPath;
27159
- for (const dir of readdirSync12(MESSAGE_STORAGE)) {
27160
- const sessionPath = join44(MESSAGE_STORAGE, dir, sessionID);
27161
- if (existsSync37(sessionPath))
27652
+ for (const dir of readdirSync13(MESSAGE_STORAGE)) {
27653
+ const sessionPath = join47(MESSAGE_STORAGE, dir, sessionID);
27654
+ if (existsSync38(sessionPath))
27162
27655
  return sessionPath;
27163
27656
  }
27164
27657
  return null;
@@ -27394,7 +27887,7 @@ class BackgroundManager {
27394
27887
  log("[background-agent] Sending notification to parent session:", { parentSessionID: task.parentSessionID });
27395
27888
  setTimeout(async () => {
27396
27889
  try {
27397
- const messageDir = getMessageDir5(task.parentSessionID);
27890
+ const messageDir = getMessageDir6(task.parentSessionID);
27398
27891
  const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
27399
27892
  await this.client.session.prompt({
27400
27893
  path: { id: task.parentSessionID },
@@ -27562,6 +28055,7 @@ var OverridableAgentNameSchema = exports_external.enum([
27562
28055
  "build",
27563
28056
  "plan",
27564
28057
  "Sisyphus",
28058
+ "Builder-Sisyphus",
27565
28059
  "Planner-Sisyphus",
27566
28060
  "oracle",
27567
28061
  "librarian",
@@ -27610,6 +28104,7 @@ var AgentOverridesSchema = exports_external.object({
27610
28104
  build: AgentOverrideConfigSchema.optional(),
27611
28105
  plan: AgentOverrideConfigSchema.optional(),
27612
28106
  Sisyphus: AgentOverrideConfigSchema.optional(),
28107
+ "Builder-Sisyphus": AgentOverrideConfigSchema.optional(),
27613
28108
  "Planner-Sisyphus": AgentOverrideConfigSchema.optional(),
27614
28109
  oracle: AgentOverrideConfigSchema.optional(),
27615
28110
  librarian: AgentOverrideConfigSchema.optional(),
@@ -27626,14 +28121,18 @@ var ClaudeCodeConfigSchema = exports_external.object({
27626
28121
  hooks: exports_external.boolean().optional()
27627
28122
  });
27628
28123
  var SisyphusAgentConfigSchema = exports_external.object({
27629
- disabled: exports_external.boolean().optional()
28124
+ disabled: exports_external.boolean().optional(),
28125
+ builder_enabled: exports_external.boolean().optional(),
28126
+ planner_enabled: exports_external.boolean().optional(),
28127
+ replace_build: exports_external.boolean().optional(),
28128
+ replace_plan: exports_external.boolean().optional()
27630
28129
  });
27631
28130
  var ExperimentalConfigSchema = exports_external.object({
27632
28131
  aggressive_truncation: exports_external.boolean().optional(),
27633
28132
  auto_resume: exports_external.boolean().optional(),
27634
28133
  preemptive_compaction: exports_external.boolean().optional(),
27635
28134
  preemptive_compaction_threshold: exports_external.number().min(0.5).max(0.95).optional(),
27636
- truncate_all_tool_outputs: exports_external.boolean().optional()
28135
+ truncate_all_tool_outputs: exports_external.boolean().default(true)
27637
28136
  });
27638
28137
  var OhMyOpenCodeConfigSchema = exports_external.object({
27639
28138
  $schema: exports_external.string().optional(),
@@ -27718,9 +28217,53 @@ var PLAN_PERMISSION = {
27718
28217
  webfetch: "allow"
27719
28218
  };
27720
28219
 
28220
+ // src/agents/build-prompt.ts
28221
+ var BUILD_SYSTEM_PROMPT = `<system-reminder>
28222
+ # Build Mode - System Reminder
28223
+
28224
+ BUILD MODE ACTIVE - you are in EXECUTION phase. Your responsibility is to:
28225
+ - Implement features and make code changes
28226
+ - Execute commands and run tests
28227
+ - Fix bugs and refactor code
28228
+ - Deploy and build systems
28229
+ - Make all necessary file modifications
28230
+
28231
+ You have FULL permissions to edit files, run commands, and make system changes.
28232
+ This is the implementation phase - execute decisively and thoroughly.
28233
+
28234
+ ---
28235
+
28236
+ ## Responsibility
28237
+
28238
+ Your current responsibility is to implement, build, and execute. You should:
28239
+ - Write and modify code to accomplish the user's goals
28240
+ - Run tests and builds to verify your changes
28241
+ - Fix errors and issues that arise
28242
+ - Use all available tools to complete the task efficiently
28243
+ - Delegate to specialized agents when appropriate for better results
28244
+
28245
+ **NOTE:** You should ask the user for clarification when requirements are ambiguous,
28246
+ but once the path is clear, execute confidently. The goal is to deliver working,
28247
+ tested, production-ready solutions.
28248
+
28249
+ ---
28250
+
28251
+ ## Important
28252
+
28253
+ The user wants you to execute and implement. You SHOULD make edits, run necessary
28254
+ tools, and make changes to accomplish the task. Use your full capabilities to
28255
+ deliver excellent results.
28256
+ </system-reminder>
28257
+ `;
28258
+ var BUILD_PERMISSION = {
28259
+ edit: "ask",
28260
+ bash: "ask",
28261
+ webfetch: "allow"
28262
+ };
28263
+
27721
28264
  // src/index.ts
27722
28265
  import * as fs7 from "fs";
27723
- import * as path7 from "path";
28266
+ import * as path8 from "path";
27724
28267
  var AGENT_NAME_MAP = {
27725
28268
  omo: "Sisyphus",
27726
28269
  OmO: "Sisyphus",
@@ -27823,8 +28366,8 @@ function mergeConfigs(base, override) {
27823
28366
  };
27824
28367
  }
27825
28368
  function loadPluginConfig(directory) {
27826
- const userConfigPath = path7.join(getUserConfigDir(), "opencode", "oh-my-opencode.json");
27827
- const projectConfigPath = path7.join(directory, ".opencode", "oh-my-opencode.json");
28369
+ const userConfigPath = path8.join(getUserConfigDir(), "opencode", "oh-my-opencode.json");
28370
+ const projectConfigPath = path8.join(directory, ".opencode", "oh-my-opencode.json");
27828
28371
  let config3 = loadConfigFromPath2(userConfigPath) ?? {};
27829
28372
  const projectConfig = loadConfigFromPath2(projectConfigPath);
27830
28373
  if (projectConfig) {
@@ -27934,26 +28477,46 @@ var OhMyOpenCodePlugin = async (ctx) => {
27934
28477
  const userAgents = pluginConfig.claude_code?.agents ?? true ? loadUserAgents() : {};
27935
28478
  const projectAgents = pluginConfig.claude_code?.agents ?? true ? loadProjectAgents() : {};
27936
28479
  const isSisyphusEnabled = pluginConfig.sisyphus_agent?.disabled !== true;
28480
+ const builderEnabled = pluginConfig.sisyphus_agent?.builder_enabled ?? false;
28481
+ const plannerEnabled = pluginConfig.sisyphus_agent?.planner_enabled ?? true;
28482
+ const replaceBuild = pluginConfig.sisyphus_agent?.replace_build ?? true;
28483
+ const replacePlan = pluginConfig.sisyphus_agent?.replace_plan ?? true;
27937
28484
  if (isSisyphusEnabled && builtinAgents.Sisyphus) {
27938
- const { name: _planName, ...planConfigWithoutName } = config3.agent?.plan ?? {};
27939
- const plannerSisyphusOverride = pluginConfig.agents?.["Planner-Sisyphus"];
27940
- const plannerSisyphusBase = {
27941
- ...planConfigWithoutName,
27942
- prompt: PLAN_SYSTEM_PROMPT,
27943
- permission: PLAN_PERMISSION,
27944
- description: `${config3.agent?.plan?.description ?? "Plan agent"} (OhMyOpenCode version)`,
27945
- color: config3.agent?.plan?.color ?? "#6495ED"
28485
+ const agentConfig = {
28486
+ Sisyphus: builtinAgents.Sisyphus
27946
28487
  };
27947
- const plannerSisyphusConfig = plannerSisyphusOverride ? { ...plannerSisyphusBase, ...plannerSisyphusOverride } : plannerSisyphusBase;
28488
+ if (builderEnabled) {
28489
+ const { name: _buildName, ...buildConfigWithoutName } = config3.agent?.build ?? {};
28490
+ const builderSisyphusOverride = pluginConfig.agents?.["Builder-Sisyphus"];
28491
+ const builderSisyphusBase = {
28492
+ ...buildConfigWithoutName,
28493
+ prompt: BUILD_SYSTEM_PROMPT,
28494
+ permission: BUILD_PERMISSION,
28495
+ description: `${config3.agent?.build?.description ?? "Build agent"} (OhMyOpenCode version)`,
28496
+ color: config3.agent?.build?.color ?? "#32CD32"
28497
+ };
28498
+ agentConfig["Builder-Sisyphus"] = builderSisyphusOverride ? { ...builderSisyphusBase, ...builderSisyphusOverride } : builderSisyphusBase;
28499
+ }
28500
+ if (plannerEnabled) {
28501
+ const { name: _planName, ...planConfigWithoutName } = config3.agent?.plan ?? {};
28502
+ const plannerSisyphusOverride = pluginConfig.agents?.["Planner-Sisyphus"];
28503
+ const plannerSisyphusBase = {
28504
+ ...planConfigWithoutName,
28505
+ prompt: PLAN_SYSTEM_PROMPT,
28506
+ permission: PLAN_PERMISSION,
28507
+ description: `${config3.agent?.plan?.description ?? "Plan agent"} (OhMyOpenCode version)`,
28508
+ color: config3.agent?.plan?.color ?? "#6495ED"
28509
+ };
28510
+ agentConfig["Planner-Sisyphus"] = plannerSisyphusOverride ? { ...plannerSisyphusBase, ...plannerSisyphusOverride } : plannerSisyphusBase;
28511
+ }
27948
28512
  config3.agent = {
27949
- Sisyphus: builtinAgents.Sisyphus,
27950
- "Planner-Sisyphus": plannerSisyphusConfig,
28513
+ ...agentConfig,
27951
28514
  ...Object.fromEntries(Object.entries(builtinAgents).filter(([k]) => k !== "Sisyphus")),
27952
28515
  ...userAgents,
27953
28516
  ...projectAgents,
27954
28517
  ...config3.agent,
27955
- build: { ...config3.agent?.build, mode: "subagent" },
27956
- plan: { ...config3.agent?.plan, mode: "subagent" }
28518
+ ...replaceBuild ? { build: { ...config3.agent?.build, mode: "subagent" } } : {},
28519
+ ...replacePlan ? { plan: { ...config3.agent?.plan, mode: "subagent" } } : {}
27957
28520
  };
27958
28521
  } else {
27959
28522
  config3.agent = {