@skj1724/oh-my-opencode 3.18.26 → 3.18.27

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
@@ -2743,12 +2743,26 @@ function logPerf(source, elapsedMs) {
2743
2743
  return;
2744
2744
  logPerfImpl(source, elapsedMs);
2745
2745
  }
2746
+ function ensureMaxLogSize() {
2747
+ try {
2748
+ const stat = fs.statSync(logFile);
2749
+ if (stat.size > MAX_LOG_BYTES) {
2750
+ const content = fs.readFileSync(logFile, "utf-8");
2751
+ const keepBytes = Math.floor(MAX_LOG_BYTES * LOG_TRUNCATE_RATIO);
2752
+ const truncated = content.slice(-keepBytes);
2753
+ const head = `[${new Date().toISOString()}] [logger] Log truncated (was ${stat.size} bytes, kept ${keepBytes} bytes)
2754
+ `;
2755
+ fs.writeFileSync(logFile, head + truncated);
2756
+ }
2757
+ } catch {}
2758
+ }
2746
2759
  function flush() {
2747
2760
  if (buffer.length === 0)
2748
2761
  return;
2749
2762
  const data = buffer.join("");
2750
2763
  buffer = [];
2751
2764
  try {
2765
+ ensureMaxLogSize();
2752
2766
  fs.appendFileSync(logFile, data);
2753
2767
  } catch {}
2754
2768
  }
@@ -2776,10 +2790,11 @@ function log(message, data) {
2776
2790
  function getLogFilePath() {
2777
2791
  return logFile;
2778
2792
  }
2779
- var logFile, OMO_DEBUG, perfLogFile, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50;
2793
+ var logFile, MAX_LOG_BYTES, LOG_TRUNCATE_RATIO = 0.5, OMO_DEBUG, perfLogFile, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50;
2780
2794
  var init_logger = __esm(() => {
2781
2795
  init_plugin_identity();
2782
2796
  logFile = path.join(os.tmpdir(), LOG_FILENAME);
2797
+ MAX_LOG_BYTES = parseInt(process.env.OMO_MAX_LOG_BYTES ?? "", 10) || 1024 * 1024;
2783
2798
  OMO_DEBUG = process.env.OMO_DEBUG === "1";
2784
2799
  perfLogFile = path.join(os.tmpdir(), "oh-my-opencode-perf.log");
2785
2800
  buffer = [];
@@ -4717,7 +4732,7 @@ __export(exports_storage, {
4717
4732
  getStateFilePath: () => getStateFilePath,
4718
4733
  clearState: () => clearState
4719
4734
  });
4720
- import { existsSync as existsSync56, readFileSync as readFileSync40, writeFileSync as writeFileSync17, unlinkSync as unlinkSync11, mkdirSync as mkdirSync15 } from "fs";
4735
+ import { existsSync as existsSync56, readFileSync as readFileSync41, writeFileSync as writeFileSync18, unlinkSync as unlinkSync11, mkdirSync as mkdirSync15 } from "fs";
4721
4736
  import { dirname as dirname17, join as join65 } from "path";
4722
4737
  function getStateFilePath(directory, customPath) {
4723
4738
  return customPath ? join65(directory, customPath) : join65(directory, DEFAULT_STATE_FILE);
@@ -4728,7 +4743,7 @@ function readState(directory, customPath) {
4728
4743
  return null;
4729
4744
  }
4730
4745
  try {
4731
- const content = readFileSync40(filePath, "utf-8");
4746
+ const content = readFileSync41(filePath, "utf-8");
4732
4747
  const { data, body } = parseFrontmatter(content);
4733
4748
  const active = data.active;
4734
4749
  const iteration = data.iteration;
@@ -4799,7 +4814,7 @@ ${initialCompletionPromiseLine}${verificationAttemptLine}${verificationSessionLi
4799
4814
  ${sessionIdLine}${ultraworkLine}${verificationPendingLine}${strategyLine}${messageCountAtStartLine}---
4800
4815
  ${state3.prompt}
4801
4816
  `;
4802
- writeFileSync17(filePath, content, "utf-8");
4817
+ writeFileSync18(filePath, content, "utf-8");
4803
4818
  return true;
4804
4819
  } catch {
4805
4820
  return false;
@@ -15894,7 +15909,7 @@ function isWithinProject(candidatePath, projectRoot) {
15894
15909
  return containsPath(projectRoot, candidatePath);
15895
15910
  }
15896
15911
  // src/shared/file-reference-resolver.ts
15897
- import { existsSync as existsSync3, readFileSync, statSync } from "fs";
15912
+ import { existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
15898
15913
  import { isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
15899
15914
  init_logger();
15900
15915
  var FILE_REFERENCE_PATTERN = /@([^\s@]+)/g;
@@ -15922,11 +15937,11 @@ function readFileContent(resolvedPath) {
15922
15937
  if (!existsSync3(resolvedPath)) {
15923
15938
  return `[file not found: ${resolvedPath}]`;
15924
15939
  }
15925
- const stat = statSync(resolvedPath);
15940
+ const stat = statSync2(resolvedPath);
15926
15941
  if (stat.isDirectory()) {
15927
15942
  return `[cannot read directory: ${resolvedPath}]`;
15928
15943
  }
15929
- const content = readFileSync(resolvedPath, "utf-8");
15944
+ const content = readFileSync2(resolvedPath, "utf-8");
15930
15945
  return content;
15931
15946
  }
15932
15947
  async function resolveFileReferencesInText(text, cwd = process.cwd(), depth = 0, maxDepth = 3) {
@@ -16176,56 +16191,44 @@ function estimateTokens(text) {
16176
16191
  return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
16177
16192
  }
16178
16193
  function truncateToTokenLimit(output, maxTokens, preserveHeaderLines = 3) {
16179
- if (typeof output !== "string") {
16194
+ if (typeof output !== "string")
16180
16195
  return { result: String(output ?? ""), truncated: false };
16181
- }
16182
16196
  const currentTokens = estimateTokens(output);
16183
- if (currentTokens <= maxTokens) {
16197
+ if (currentTokens <= maxTokens)
16184
16198
  return { result: output, truncated: false };
16185
- }
16186
16199
  const lines = output.split(`
16187
16200
  `);
16188
16201
  if (lines.length <= preserveHeaderLines) {
16189
16202
  const maxChars = maxTokens * CHARS_PER_TOKEN_ESTIMATE;
16190
- return {
16191
- result: output.slice(0, maxChars) + `
16203
+ return { result: output.slice(0, maxChars) + `
16192
16204
 
16193
- [Output truncated due to context window limit]`,
16194
- truncated: true
16195
- };
16205
+ [Output truncated due to context window limit]`, truncated: true };
16196
16206
  }
16197
16207
  const headerLines = lines.slice(0, preserveHeaderLines);
16198
16208
  const contentLines = lines.slice(preserveHeaderLines);
16199
16209
  const headerText = headerLines.join(`
16200
16210
  `);
16201
16211
  const headerTokens = estimateTokens(headerText);
16202
- const truncationMessageTokens = 50;
16203
- const availableTokens = maxTokens - headerTokens - truncationMessageTokens;
16212
+ const availableTokens = maxTokens - headerTokens - 50;
16204
16213
  if (availableTokens <= 0) {
16205
- return {
16206
- result: headerText + `
16214
+ return { result: headerText + `
16207
16215
 
16208
- [Content truncated due to context window limit]`,
16209
- truncated: true,
16210
- removedCount: contentLines.length
16211
- };
16216
+ [Content truncated due to context window limit]`, truncated: true, removedCount: contentLines.length };
16212
16217
  }
16213
16218
  const resultLines = [];
16214
16219
  let currentTokenCount = 0;
16215
16220
  for (const line of contentLines) {
16216
16221
  const lineTokens = estimateTokens(line + `
16217
16222
  `);
16218
- if (currentTokenCount + lineTokens > availableTokens) {
16223
+ if (currentTokenCount + lineTokens > availableTokens)
16219
16224
  break;
16220
- }
16221
16225
  resultLines.push(line);
16222
16226
  currentTokenCount += lineTokens;
16223
16227
  }
16224
- const truncatedContent = [...headerLines, ...resultLines].join(`
16225
- `);
16226
16228
  const removedCount = contentLines.length - resultLines.length;
16227
16229
  return {
16228
- result: truncatedContent + `
16230
+ result: [...headerLines, ...resultLines].join(`
16231
+ `) + `
16229
16232
 
16230
16233
  [${removedCount} more lines truncated due to context window limit]`,
16231
16234
  truncated: true,
@@ -16234,9 +16237,14 @@ function truncateToTokenLimit(output, maxTokens, preserveHeaderLines = 3) {
16234
16237
  }
16235
16238
  async function getContextWindowUsage(ctx, sessionID, modelCacheState) {
16236
16239
  try {
16237
- const response = await ctx.client.session.messages({
16238
- path: { id: sessionID }
16240
+ const TIMEOUT_MS = 5000;
16241
+ const timeoutPromise = new Promise((_, reject) => {
16242
+ setTimeout(() => reject(new Error(`getContextWindowUsage timeout after ${TIMEOUT_MS}ms`)), TIMEOUT_MS);
16239
16243
  });
16244
+ const response = await Promise.race([
16245
+ ctx.client.session.messages({ path: { id: sessionID } }),
16246
+ timeoutPromise
16247
+ ]);
16240
16248
  const messages = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true });
16241
16249
  const assistantMessages = messages.filter((m) => m.info.role === "assistant").map((m) => m.info);
16242
16250
  if (assistantMessages.length === 0)
@@ -16342,7 +16350,7 @@ function getClaudeConfigDir() {
16342
16350
  return join4(homedir3(), ".claude");
16343
16351
  }
16344
16352
  // src/shared/jsonc-parser.ts
16345
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
16353
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
16346
16354
  import { join as join5 } from "path";
16347
16355
 
16348
16356
  // node_modules/jsonc-parser/lib/esm/impl/scanner.js
@@ -17897,10 +17905,10 @@ init_logger();
17897
17905
  import * as fs4 from "fs";
17898
17906
 
17899
17907
  // src/shared/write-file-atomically.ts
17900
- import { closeSync, fsyncSync, openSync, renameSync, unlinkSync, writeFileSync } from "fs";
17908
+ import { closeSync, fsyncSync, openSync, renameSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
17901
17909
  function writeFileAtomically(filePath, content) {
17902
17910
  const tempPath = `${filePath}.tmp`;
17903
- writeFileSync(tempPath, content, "utf-8");
17911
+ writeFileSync2(tempPath, content, "utf-8");
17904
17912
  const tempFileDescriptor = openSync(tempPath, "r");
17905
17913
  try {
17906
17914
  fsyncSync(tempFileDescriptor);
@@ -19511,7 +19519,7 @@ init_logger();
19511
19519
 
19512
19520
  // src/shared/json-file-cache-store.ts
19513
19521
  init_logger();
19514
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
19522
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
19515
19523
  import { join as join10 } from "path";
19516
19524
  function toLogLabel(cacheLabel) {
19517
19525
  return cacheLabel.toLowerCase();
@@ -19538,7 +19546,7 @@ function createJsonFileCacheStore(options) {
19538
19546
  return null;
19539
19547
  }
19540
19548
  try {
19541
- const content = readFileSync6(cacheFile, "utf-8");
19549
+ const content = readFileSync7(cacheFile, "utf-8");
19542
19550
  const value = JSON.parse(content);
19543
19551
  memoryValue = value;
19544
19552
  log(`[${options.logPrefix}] Read ${toLogLabel(options.cacheLabel)}`, options.describe(value));
@@ -19558,7 +19566,7 @@ function createJsonFileCacheStore(options) {
19558
19566
  ensureCacheDir2();
19559
19567
  const cacheFile = getCacheFilePath();
19560
19568
  try {
19561
- writeFileSync2(cacheFile, options.serialize?.(value) ?? JSON.stringify(value, null, 2));
19569
+ writeFileSync3(cacheFile, options.serialize?.(value) ?? JSON.stringify(value, null, 2));
19562
19570
  memoryValue = value;
19563
19571
  log(`[${options.logPrefix}] ${options.cacheLabel} written`, options.describe(value));
19564
19572
  } catch (error) {
@@ -19715,7 +19723,7 @@ var {
19715
19723
 
19716
19724
  // src/shared/model-availability.ts
19717
19725
  init_logger();
19718
- import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
19726
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
19719
19727
  import { join as join11 } from "path";
19720
19728
  function normalizeModelName(name) {
19721
19729
  return name.toLowerCase().replace(/claude-(opus|sonnet|haiku)-(\d+)[.-](\d+)/g, "claude-$1-$2.$3");
@@ -19857,7 +19865,7 @@ async function fetchAvailableModels(client, options) {
19857
19865
  log("[fetchAvailableModels] models.json cache file not found, falling back to client");
19858
19866
  } else {
19859
19867
  try {
19860
- const content = readFileSync7(cacheFile, "utf-8");
19868
+ const content = readFileSync8(cacheFile, "utf-8");
19861
19869
  const data = JSON.parse(content);
19862
19870
  const providerIds = Object.keys(data);
19863
19871
  log("[fetchAvailableModels] providers found in models.json", { count: providerIds.length, providers: providerIds.slice(0, 10) });
@@ -64458,13 +64466,13 @@ function isAnyProviderConnected(providers, availableModels) {
64458
64466
  return false;
64459
64467
  }
64460
64468
  // src/features/hook-message-injector/injector.ts
64461
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync3 } from "fs";
64469
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync10, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
64462
64470
  import { randomBytes } from "crypto";
64463
64471
  import { join as join14 } from "path";
64464
64472
  init_logger();
64465
64473
 
64466
64474
  // src/shared/compaction-marker.ts
64467
- import { existsSync as existsSync12, readdirSync, readFileSync as readFileSync8 } from "fs";
64475
+ import { existsSync as existsSync12, readdirSync, readFileSync as readFileSync9 } from "fs";
64468
64476
  import { join as join13 } from "path";
64469
64477
 
64470
64478
  // src/shared/opencode-storage-paths.ts
@@ -64501,7 +64509,7 @@ function hasCompactionPartInStorage(messageID) {
64501
64509
  try {
64502
64510
  return readdirSync(partDir).filter((fileName) => fileName.endsWith(".json")).some((fileName) => {
64503
64511
  try {
64504
- const content = readFileSync8(join13(partDir, fileName), "utf-8");
64512
+ const content = readFileSync9(join13(partDir, fileName), "utf-8");
64505
64513
  return isCompactionPart(JSON.parse(content));
64506
64514
  } catch {
64507
64515
  return false;
@@ -64594,7 +64602,7 @@ function findNearestMessageWithFields(messageDir) {
64594
64602
  try {
64595
64603
  const messages = readdirSync2(messageDir).filter((f) => f.endsWith(".json")).map((fileName) => {
64596
64604
  try {
64597
- const content = readFileSync9(join14(messageDir, fileName), "utf-8");
64605
+ const content = readFileSync10(join14(messageDir, fileName), "utf-8");
64598
64606
  const msg = JSON.parse(content);
64599
64607
  return {
64600
64608
  fileName,
@@ -64634,7 +64642,7 @@ function findFirstMessageWithAgent(messageDir) {
64634
64642
  try {
64635
64643
  const messages = readdirSync2(messageDir).filter((f) => f.endsWith(".json")).map((fileName) => {
64636
64644
  try {
64637
- const content = readFileSync9(join14(messageDir, fileName), "utf-8");
64645
+ const content = readFileSync10(join14(messageDir, fileName), "utf-8");
64638
64646
  const msg = JSON.parse(content);
64639
64647
  return {
64640
64648
  fileName,
@@ -65575,7 +65583,7 @@ function injectServerAuthIntoClient(client) {
65575
65583
  }
65576
65584
  }
65577
65585
  // src/shared/opencode-provider-auth.ts
65578
- import { readFileSync as readFileSync10, statSync as statSync2 } from "fs";
65586
+ import { readFileSync as readFileSync11, statSync as statSync3 } from "fs";
65579
65587
  import * as path6 from "path";
65580
65588
  init_logger();
65581
65589
  var cached = null;
@@ -65589,7 +65597,7 @@ function loadAuthMap() {
65589
65597
  const filePath = getAuthFilePath();
65590
65598
  let mtimeMs;
65591
65599
  try {
65592
- mtimeMs = statSync2(filePath).mtimeMs;
65600
+ mtimeMs = statSync3(filePath).mtimeMs;
65593
65601
  } catch {
65594
65602
  cached = null;
65595
65603
  return new Map;
@@ -65598,7 +65606,7 @@ function loadAuthMap() {
65598
65606
  return cached.map;
65599
65607
  }
65600
65608
  try {
65601
- const raw = readFileSync10(filePath, "utf-8");
65609
+ const raw = readFileSync11(filePath, "utf-8");
65602
65610
  const parsed = JSON.parse(raw);
65603
65611
  const map2 = new Map;
65604
65612
  if (isRecord5(parsed)) {
@@ -65823,7 +65831,7 @@ function parseGitDiffNumstat(output, statusMap) {
65823
65831
  }
65824
65832
  // src/shared/git-worktree/collect-git-diff-stats.ts
65825
65833
  import { execFileSync } from "child_process";
65826
- import { readFileSync as readFileSync11 } from "fs";
65834
+ import { readFileSync as readFileSync12 } from "fs";
65827
65835
  import { join as join17 } from "path";
65828
65836
  function collectGitDiffStats(directory) {
65829
65837
  try {
@@ -65848,7 +65856,7 @@ function collectGitDiffStats(directory) {
65848
65856
  const untrackedNumstat = untrackedOutput ? untrackedOutput.split(`
65849
65857
  `).filter(Boolean).map((filePath) => {
65850
65858
  try {
65851
- const content = readFileSync11(join17(directory, filePath), "utf-8");
65859
+ const content = readFileSync12(join17(directory, filePath), "utf-8");
65852
65860
  const lineCount = content.split(`
65853
65861
  `).length - (content.endsWith(`
65854
65862
  `) ? 1 : 0);
@@ -66084,7 +66092,7 @@ init_logger();
66084
66092
 
66085
66093
  // src/features/claude-code-plugin-loader/discovery.ts
66086
66094
  init_logger();
66087
- import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
66095
+ import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
66088
66096
  import { homedir as homedir8 } from "os";
66089
66097
  import { basename as basename3, join as join21 } from "path";
66090
66098
  import { fileURLToPath } from "url";
@@ -66127,7 +66135,7 @@ function loadInstalledPlugins(pluginsBaseDir) {
66127
66135
  return null;
66128
66136
  }
66129
66137
  try {
66130
- const content = readFileSync12(dbPath, "utf-8");
66138
+ const content = readFileSync13(dbPath, "utf-8");
66131
66139
  return JSON.parse(content);
66132
66140
  } catch (error) {
66133
66141
  log("Failed to load installed plugins database", error);
@@ -66146,7 +66154,7 @@ function loadClaudeSettings() {
66146
66154
  return null;
66147
66155
  }
66148
66156
  try {
66149
- const content = readFileSync12(settingsPath, "utf-8");
66157
+ const content = readFileSync13(settingsPath, "utf-8");
66150
66158
  return JSON.parse(content);
66151
66159
  } catch (error) {
66152
66160
  log("Failed to load Claude settings", error);
@@ -66159,7 +66167,7 @@ function loadPluginManifest(installPath) {
66159
66167
  return null;
66160
66168
  }
66161
66169
  try {
66162
- const content = readFileSync12(manifestPath, "utf-8");
66170
+ const content = readFileSync13(manifestPath, "utf-8");
66163
66171
  return JSON.parse(content);
66164
66172
  } catch (error) {
66165
66173
  log(`Failed to load plugin manifest from ${manifestPath}`, error);
@@ -66300,7 +66308,7 @@ function discoverInstalledPlugins(options) {
66300
66308
 
66301
66309
  // src/features/claude-code-plugin-loader/command-loader.ts
66302
66310
  init_frontmatter();
66303
- import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "fs";
66311
+ import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync14 } from "fs";
66304
66312
  import { basename as basename4, join as join22 } from "path";
66305
66313
  init_logger();
66306
66314
  function loadPluginCommands(plugins) {
@@ -66316,7 +66324,7 @@ function loadPluginCommands(plugins) {
66316
66324
  const commandName = basename4(entry.name, ".md");
66317
66325
  const namespacedName = `${plugin.name}:${commandName}`;
66318
66326
  try {
66319
- const content = readFileSync13(commandPath, "utf-8");
66327
+ const content = readFileSync14(commandPath, "utf-8");
66320
66328
  const { data, body } = parseFrontmatter(content);
66321
66329
  const wrappedTemplate = `<command-instruction>
66322
66330
  ${body.trim()}
@@ -66348,7 +66356,7 @@ $ARGUMENTS
66348
66356
 
66349
66357
  // src/features/claude-code-plugin-loader/skill-loader.ts
66350
66358
  init_frontmatter();
66351
- import { existsSync as existsSync18, readdirSync as readdirSync5, readFileSync as readFileSync14 } from "fs";
66359
+ import { existsSync as existsSync18, readdirSync as readdirSync5, readFileSync as readFileSync15 } from "fs";
66352
66360
  import { join as join23 } from "path";
66353
66361
 
66354
66362
  // src/shared/skill-path-resolver.ts
@@ -66395,7 +66403,7 @@ function loadPluginSkillsAsCommands(plugins) {
66395
66403
  if (!existsSync18(skillMdPath))
66396
66404
  continue;
66397
66405
  try {
66398
- const content = readFileSync14(skillMdPath, "utf-8");
66406
+ const content = readFileSync15(skillMdPath, "utf-8");
66399
66407
  const { data, body } = parseFrontmatter(content);
66400
66408
  const skillName = data.name || entry.name;
66401
66409
  const namespacedName = `${plugin.name}:${skillName}`;
@@ -66431,7 +66439,7 @@ $ARGUMENTS
66431
66439
 
66432
66440
  // src/features/claude-code-plugin-loader/agent-loader.ts
66433
66441
  init_frontmatter();
66434
- import { existsSync as existsSync19, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "fs";
66442
+ import { existsSync as existsSync19, readdirSync as readdirSync6, readFileSync as readFileSync16 } from "fs";
66435
66443
  import { basename as basename5, join as join24 } from "path";
66436
66444
  init_logger();
66437
66445
 
@@ -66523,7 +66531,7 @@ function loadPluginAgents(plugins) {
66523
66531
  const agentName = basename5(entry.name, ".md");
66524
66532
  const namespacedName = `${plugin.name}:${agentName}`;
66525
66533
  try {
66526
- const content = readFileSync15(agentPath, "utf-8");
66534
+ const content = readFileSync16(agentPath, "utf-8");
66527
66535
  const { data, body } = parseFrontmatter(content);
66528
66536
  const originalDescription = data.description || "";
66529
66537
  const formattedDescription = `(plugin: ${plugin.name}) ${originalDescription}`;
@@ -66756,14 +66764,14 @@ async function loadPluginMcpServers(plugins) {
66756
66764
 
66757
66765
  // src/features/claude-code-plugin-loader/hook-loader.ts
66758
66766
  init_logger();
66759
- import { existsSync as existsSync21, readFileSync as readFileSync16 } from "fs";
66767
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "fs";
66760
66768
  function loadPluginHooksConfigs(plugins) {
66761
66769
  const configs = [];
66762
66770
  for (const plugin of plugins) {
66763
66771
  if (!plugin.hooksPath || !existsSync21(plugin.hooksPath))
66764
66772
  continue;
66765
66773
  try {
66766
- const content = readFileSync16(plugin.hooksPath, "utf-8");
66774
+ const content = readFileSync17(plugin.hooksPath, "utf-8");
66767
66775
  let config = JSON.parse(content);
66768
66776
  config = resolvePluginPaths(config, plugin.installPath);
66769
66777
  configs.push(config);
@@ -66881,7 +66889,7 @@ var SessionCategoryRegistry = {
66881
66889
  init_plugin_identity();
66882
66890
 
66883
66891
  // src/shared/legacy-plugin-warning.ts
66884
- import { existsSync as existsSync22, readFileSync as readFileSync17 } from "fs";
66892
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "fs";
66885
66893
  import { join as join25 } from "path";
66886
66894
  init_plugin_identity();
66887
66895
  function getOpenCodeConfigPath(overrideConfigDir) {
@@ -66913,7 +66921,7 @@ function checkForLegacyPluginEntry(overrideConfigDir) {
66913
66921
  return { hasLegacyEntry: false, hasCanonicalEntry: false, legacyEntries: [], configPath: null };
66914
66922
  }
66915
66923
  try {
66916
- const content = readFileSync17(configPath, "utf-8");
66924
+ const content = readFileSync18(configPath, "utf-8");
66917
66925
  const parseResult = parseJsoncSafe(content);
66918
66926
  if (!parseResult.data) {
66919
66927
  return { hasLegacyEntry: false, hasCanonicalEntry: false, legacyEntries: [], configPath };
@@ -66935,7 +66943,7 @@ function checkForLegacyPluginEntry(overrideConfigDir) {
66935
66943
  init_logger();
66936
66944
 
66937
66945
  // src/shared/migrate-legacy-plugin-entry.ts
66938
- import { closeSync as closeSync2, existsSync as existsSync23, fsyncSync as fsyncSync2, openSync as openSync2, readFileSync as readFileSync18, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
66946
+ import { closeSync as closeSync2, existsSync as existsSync23, fsyncSync as fsyncSync2, openSync as openSync2, readFileSync as readFileSync19, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "fs";
66939
66947
  init_logger();
66940
66948
  init_plugin_identity();
66941
66949
 
@@ -66983,7 +66991,7 @@ function migrateLegacyPluginEntry(configPath) {
66983
66991
  if (!existsSync23(configPath))
66984
66992
  return false;
66985
66993
  try {
66986
- const content = readFileSync18(configPath, "utf-8");
66994
+ const content = readFileSync19(configPath, "utf-8");
66987
66995
  if (!content.includes(LEGACY_PLUGIN_NAME))
66988
66996
  return false;
66989
66997
  const parseResult = parseJsoncSafe(content);
@@ -66996,7 +67004,7 @@ function migrateLegacyPluginEntry(configPath) {
66996
67004
  if (!updated || updated === content)
66997
67005
  return false;
66998
67006
  const tempPath = `${configPath}.tmp`;
66999
- writeFileSync4(tempPath, updated, "utf-8");
67007
+ writeFileSync5(tempPath, updated, "utf-8");
67000
67008
  const tempFileDescriptor = openSync2(tempPath, "r");
67001
67009
  try {
67002
67010
  fsyncSync2(tempFileDescriptor);
@@ -67159,7 +67167,7 @@ var FAILURE_RESET_WINDOW_MS = 5 * 60 * 1000;
67159
67167
  // src/features/run-continuation-state/constants.ts
67160
67168
  var CONTINUATION_MARKER_DIR = ".sisyphus/run-continuation";
67161
67169
  // src/features/run-continuation-state/storage.ts
67162
- import { existsSync as existsSync24, mkdirSync as mkdirSync6, readFileSync as readFileSync19, rmSync, writeFileSync as writeFileSync5 } from "fs";
67170
+ import { existsSync as existsSync24, mkdirSync as mkdirSync6, readFileSync as readFileSync20, rmSync, writeFileSync as writeFileSync6 } from "fs";
67163
67171
  import { join as join26 } from "path";
67164
67172
  function getMarkerPath(directory, sessionID) {
67165
67173
  return join26(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
@@ -67169,7 +67177,7 @@ function readContinuationMarker(directory, sessionID) {
67169
67177
  if (!existsSync24(markerPath))
67170
67178
  return null;
67171
67179
  try {
67172
- const raw = readFileSync19(markerPath, "utf-8");
67180
+ const raw = readFileSync20(markerPath, "utf-8");
67173
67181
  const parsed = JSON.parse(raw);
67174
67182
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
67175
67183
  return null;
@@ -67195,7 +67203,7 @@ function setContinuationMarkerSource(directory, sessionID, source, state, reason
67195
67203
  };
67196
67204
  const markerPath = getMarkerPath(directory, sessionID);
67197
67205
  mkdirSync6(join26(directory, CONTINUATION_MARKER_DIR), { recursive: true });
67198
- writeFileSync5(markerPath, JSON.stringify(next, null, 2), "utf-8");
67206
+ writeFileSync6(markerPath, JSON.stringify(next, null, 2), "utf-8");
67199
67207
  return next;
67200
67208
  }
67201
67209
  function clearContinuationMarker(directory, sessionID) {
@@ -69132,7 +69140,7 @@ function generatePartId() {
69132
69140
  return `prt_${timestamp2}${random}`;
69133
69141
  }
69134
69142
  // src/hooks/session-recovery/storage/messages-reader.ts
69135
- import { existsSync as existsSync25, readdirSync as readdirSync7, readFileSync as readFileSync20 } from "fs";
69143
+ import { existsSync as existsSync25, readdirSync as readdirSync7, readFileSync as readFileSync21 } from "fs";
69136
69144
  import { join as join27 } from "path";
69137
69145
  function readMessages(sessionID) {
69138
69146
  if (isSqliteBackend())
@@ -69145,7 +69153,7 @@ function readMessages(sessionID) {
69145
69153
  if (!file.endsWith(".json"))
69146
69154
  continue;
69147
69155
  try {
69148
- const content = readFileSync20(join27(messageDir, file), "utf-8");
69156
+ const content = readFileSync21(join27(messageDir, file), "utf-8");
69149
69157
  messages.push(JSON.parse(content));
69150
69158
  } catch {
69151
69159
  continue;
@@ -69160,7 +69168,7 @@ function readMessages(sessionID) {
69160
69168
  });
69161
69169
  }
69162
69170
  // src/hooks/session-recovery/storage/parts-reader.ts
69163
- import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync21 } from "fs";
69171
+ import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync22 } from "fs";
69164
69172
  import { join as join28 } from "path";
69165
69173
 
69166
69174
  // src/hooks/session-recovery/constants.ts
@@ -69180,7 +69188,7 @@ function readParts(messageID) {
69180
69188
  if (!file.endsWith(".json"))
69181
69189
  continue;
69182
69190
  try {
69183
- const content = readFileSync21(join28(partDir, file), "utf-8");
69191
+ const content = readFileSync22(join28(partDir, file), "utf-8");
69184
69192
  parts.push(JSON.parse(content));
69185
69193
  } catch {
69186
69194
  continue;
@@ -69211,7 +69219,7 @@ function messageHasContent(messageID) {
69211
69219
  return parts.some(hasContent);
69212
69220
  }
69213
69221
  // src/hooks/session-recovery/storage/text-part-injector.ts
69214
- import { existsSync as existsSync27, mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "fs";
69222
+ import { existsSync as existsSync27, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
69215
69223
  import { join as join29 } from "path";
69216
69224
  function injectTextPart(sessionID, messageID, text) {
69217
69225
  if (isSqliteBackend()) {
@@ -69232,7 +69240,7 @@ function injectTextPart(sessionID, messageID, text) {
69232
69240
  synthetic: true
69233
69241
  };
69234
69242
  try {
69235
- writeFileSync6(join29(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
69243
+ writeFileSync7(join29(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
69236
69244
  return true;
69237
69245
  } catch {
69238
69246
  return false;
@@ -69289,7 +69297,7 @@ function findEmptyMessageByIndex(sessionID, targetIndex) {
69289
69297
  return null;
69290
69298
  }
69291
69299
  // src/hooks/session-recovery/storage/empty-text.ts
69292
- import { existsSync as existsSync28, readdirSync as readdirSync9, readFileSync as readFileSync22, writeFileSync as writeFileSync7 } from "fs";
69300
+ import { existsSync as existsSync28, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync8 } from "fs";
69293
69301
  import { join as join30 } from "path";
69294
69302
  function replaceEmptyTextParts(messageID, replacementText) {
69295
69303
  if (isSqliteBackend()) {
@@ -69305,14 +69313,14 @@ function replaceEmptyTextParts(messageID, replacementText) {
69305
69313
  continue;
69306
69314
  try {
69307
69315
  const filePath = join30(partDir, file);
69308
- const content = readFileSync22(filePath, "utf-8");
69316
+ const content = readFileSync23(filePath, "utf-8");
69309
69317
  const part = JSON.parse(content);
69310
69318
  if (part.type === "text") {
69311
69319
  const textPart = part;
69312
69320
  if (!textPart.text?.trim()) {
69313
69321
  textPart.text = replacementText;
69314
69322
  textPart.synthetic = true;
69315
- writeFileSync7(filePath, JSON.stringify(textPart, null, 2));
69323
+ writeFileSync8(filePath, JSON.stringify(textPart, null, 2));
69316
69324
  anyReplaced = true;
69317
69325
  }
69318
69326
  }
@@ -69431,7 +69439,7 @@ function findMessageByIndexNeedingThinking(sessionID, targetIndex) {
69431
69439
  return firstIsThinking ? null : targetMessage.id;
69432
69440
  }
69433
69441
  // src/hooks/session-recovery/storage/thinking-prepend.ts
69434
- import { existsSync as existsSync29, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
69442
+ import { existsSync as existsSync29, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
69435
69443
  import { join as join31 } from "path";
69436
69444
  var thinkingPrependDeps = {
69437
69445
  isSqliteBackend,
@@ -69519,7 +69527,7 @@ function prependThinkingPart(sessionID, messageID, deps = thinkingPrependDeps) {
69519
69527
  mkdirSync8(partDir, { recursive: true });
69520
69528
  }
69521
69529
  try {
69522
- writeFileSync8(join31(partDir, `${previousThinkingPart.id}.json`), JSON.stringify(previousThinkingPart, null, 2));
69530
+ writeFileSync9(join31(partDir, `${previousThinkingPart.id}.json`), JSON.stringify(previousThinkingPart, null, 2));
69523
69531
  return true;
69524
69532
  } catch {
69525
69533
  return false;
@@ -69566,7 +69574,7 @@ async function prependThinkingPartAsync(client, sessionID, messageID, deps = thi
69566
69574
  }
69567
69575
  }
69568
69576
  // src/hooks/session-recovery/storage/thinking-strip.ts
69569
- import { existsSync as existsSync30, readdirSync as readdirSync10, readFileSync as readFileSync23, unlinkSync as unlinkSync3 } from "fs";
69577
+ import { existsSync as existsSync30, readdirSync as readdirSync10, readFileSync as readFileSync24, unlinkSync as unlinkSync3 } from "fs";
69570
69578
  import { join as join32 } from "path";
69571
69579
  function stripThinkingParts(messageID) {
69572
69580
  if (isSqliteBackend()) {
@@ -69582,7 +69590,7 @@ function stripThinkingParts(messageID) {
69582
69590
  continue;
69583
69591
  try {
69584
69592
  const filePath = join32(partDir, file);
69585
- const content = readFileSync23(filePath, "utf-8");
69593
+ const content = readFileSync24(filePath, "utf-8");
69586
69594
  const part = JSON.parse(content);
69587
69595
  if (THINKING_TYPES.has(part.type)) {
69588
69596
  unlinkSync3(filePath);
@@ -70615,6 +70623,8 @@ var TOOL_SPECIFIC_MAX_TOKENS = {
70615
70623
  function createToolOutputTruncatorHook(ctx, options) {
70616
70624
  const truncator = createDynamicTruncator(ctx, options?.modelCacheState);
70617
70625
  const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? false;
70626
+ const CACHE_TTL_MS = 5000;
70627
+ const usageCache = new Map;
70618
70628
  const toolExecuteAfter = async (input, output) => {
70619
70629
  if (!truncateAll && !TRUNCATABLE_TOOLS.includes(input.tool))
70620
70630
  return;
@@ -70622,14 +70632,43 @@ function createToolOutputTruncatorHook(ctx, options) {
70622
70632
  return;
70623
70633
  try {
70624
70634
  const targetMaxTokens = TOOL_SPECIFIC_MAX_TOKENS[input.tool] ?? DEFAULT_MAX_TOKENS;
70625
- const { result, truncated } = await truncator.truncate(input.sessionID, output.output, { targetMaxTokens });
70626
- if (truncated) {
70627
- output.output = result;
70635
+ const cached2 = usageCache.get(input.sessionID);
70636
+ const usagePromise = cached2 && Date.now() - cached2.timestamp < CACHE_TTL_MS ? cached2.promise : (() => {
70637
+ const newPromise = truncator.getUsage(input.sessionID).catch(() => null);
70638
+ usageCache.set(input.sessionID, { promise: newPromise, timestamp: Date.now() });
70639
+ return newPromise;
70640
+ })();
70641
+ const usage = await usagePromise;
70642
+ if (usage) {
70643
+ const maxOutputTokens = Math.min(usage.remainingTokens * 0.5, targetMaxTokens);
70644
+ if (maxOutputTokens > 0) {
70645
+ const { result, truncated } = truncator.truncateSync(output.output, maxOutputTokens);
70646
+ if (truncated)
70647
+ output.output = result;
70648
+ }
70649
+ } else {
70650
+ const { result, truncated } = await truncator.truncate(input.sessionID, output.output, { targetMaxTokens });
70651
+ if (truncated)
70652
+ output.output = result;
70628
70653
  }
70629
- } catch {}
70654
+ } catch (error) {
70655
+ if (error instanceof Error && error.message.includes("timeout")) {
70656
+ usageCache.delete(input.sessionID);
70657
+ }
70658
+ }
70659
+ };
70660
+ const eventHandler = async ({ event }) => {
70661
+ const props = event.properties;
70662
+ if (event.type === "session.deleted") {
70663
+ const sessionInfo = props?.info;
70664
+ if (sessionInfo?.id) {
70665
+ usageCache.delete(sessionInfo.id);
70666
+ }
70667
+ }
70630
70668
  };
70631
70669
  return {
70632
- "tool.execute.after": toolExecuteAfter
70670
+ "tool.execute.after": toolExecuteAfter,
70671
+ event: eventHandler
70633
70672
  };
70634
70673
  }
70635
70674
  // src/hooks/directory-agents-injector/injector.ts
@@ -70681,9 +70720,9 @@ async function findAgentsMdUp(input) {
70681
70720
  import {
70682
70721
  existsSync as existsSync34,
70683
70722
  mkdirSync as mkdirSync9,
70684
- readFileSync as readFileSync24,
70723
+ readFileSync as readFileSync25,
70685
70724
  unlinkSync as unlinkSync4,
70686
- writeFileSync as writeFileSync9
70725
+ writeFileSync as writeFileSync10
70687
70726
  } from "fs";
70688
70727
  import { join as join38 } from "path";
70689
70728
  function createInjectedPathsStorage(storageDir) {
@@ -70693,7 +70732,7 @@ function createInjectedPathsStorage(storageDir) {
70693
70732
  if (!existsSync34(filePath))
70694
70733
  return new Set;
70695
70734
  try {
70696
- const content = readFileSync24(filePath, "utf-8");
70735
+ const content = readFileSync25(filePath, "utf-8");
70697
70736
  const data = JSON.parse(content);
70698
70737
  return new Set(data.injectedPaths);
70699
70738
  } catch {
@@ -70709,7 +70748,7 @@ function createInjectedPathsStorage(storageDir) {
70709
70748
  injectedPaths: [...paths],
70710
70749
  updatedAt: Date.now()
70711
70750
  };
70712
- writeFileSync9(getStoragePath(sessionID), JSON.stringify(data, null, 2));
70751
+ writeFileSync10(getStoragePath(sessionID), JSON.stringify(data, null, 2));
70713
70752
  };
70714
70753
  const clearInjectedPaths = (sessionID) => {
70715
70754
  const filePath = getStoragePath(sessionID);
@@ -71210,7 +71249,7 @@ function incrementEmptyContentAttempt(autoCompactState, sessionID) {
71210
71249
  }
71211
71250
 
71212
71251
  // src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts
71213
- import { existsSync as existsSync36, readdirSync as readdirSync12, readFileSync as readFileSync25, writeFileSync as writeFileSync10 } from "fs";
71252
+ import { existsSync as existsSync36, readdirSync as readdirSync12, readFileSync as readFileSync26, writeFileSync as writeFileSync11 } from "fs";
71214
71253
  import { join as join41 } from "path";
71215
71254
 
71216
71255
  // src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts
@@ -71247,7 +71286,7 @@ function findToolResultsBySize(sessionID) {
71247
71286
  continue;
71248
71287
  try {
71249
71288
  const partPath = join41(partDir, file);
71250
- const content = readFileSync25(partPath, "utf-8");
71289
+ const content = readFileSync26(partPath, "utf-8");
71251
71290
  const part = JSON.parse(content);
71252
71291
  if (part.type === "tool" && part.state?.output && !part.truncated) {
71253
71292
  results.push({
@@ -71274,7 +71313,7 @@ function truncateToolResult(partPath) {
71274
71313
  return { success: false };
71275
71314
  }
71276
71315
  try {
71277
- const content = readFileSync25(partPath, "utf-8");
71316
+ const content = readFileSync26(partPath, "utf-8");
71278
71317
  const part = JSON.parse(content);
71279
71318
  if (!part.state?.output) {
71280
71319
  return { success: false };
@@ -71288,7 +71327,7 @@ function truncateToolResult(partPath) {
71288
71327
  part.state.time = { start: Date.now() };
71289
71328
  }
71290
71329
  part.state.time.compacted = Date.now();
71291
- writeFileSync10(partPath, JSON.stringify(part, null, 2));
71330
+ writeFileSync11(partPath, JSON.stringify(part, null, 2));
71292
71331
  return { success: true, toolName, originalSize };
71293
71332
  } catch {
71294
71333
  return { success: false };
@@ -72076,7 +72115,7 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
72076
72115
  }
72077
72116
 
72078
72117
  // src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts
72079
- import { readdirSync as readdirSync13, readFileSync as readFileSync26 } from "fs";
72118
+ import { readdirSync as readdirSync13, readFileSync as readFileSync27 } from "fs";
72080
72119
  import { join as join42 } from "path";
72081
72120
 
72082
72121
  // src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts
@@ -72113,7 +72152,7 @@ function readMessages2(sessionID) {
72113
72152
  try {
72114
72153
  const files = readdirSync13(messageDir).filter((f) => f.endsWith(".json"));
72115
72154
  for (const file of files) {
72116
- const content = readFileSync26(join42(messageDir, file), "utf-8");
72155
+ const content = readFileSync27(join42(messageDir, file), "utf-8");
72117
72156
  const data = JSON.parse(content);
72118
72157
  if (data.parts) {
72119
72158
  messages.push(data);
@@ -72218,7 +72257,7 @@ function findToolOutput(messages, callID) {
72218
72257
  }
72219
72258
 
72220
72259
  // src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts
72221
- import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync27 } from "fs";
72260
+ import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync28 } from "fs";
72222
72261
  import { join as join43 } from "path";
72223
72262
  init_logger();
72224
72263
  function getPartStorage() {
@@ -72255,7 +72294,7 @@ async function truncateToolOutputsByCallId(sessionID, callIds, client) {
72255
72294
  continue;
72256
72295
  const partPath = join43(partDir, file);
72257
72296
  try {
72258
- const content = readFileSync27(partPath, "utf-8");
72297
+ const content = readFileSync28(partPath, "utf-8");
72259
72298
  const part = JSON.parse(content);
72260
72299
  if (part.type !== "tool" || !part.callID)
72261
72300
  continue;
@@ -73500,7 +73539,7 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
73500
73539
 
73501
73540
  // src/hooks/claude-code-hooks/transcript.ts
73502
73541
  import { join as join46 } from "path";
73503
- import { mkdirSync as mkdirSync10, appendFileSync as appendFileSync5, existsSync as existsSync40, writeFileSync as writeFileSync11, unlinkSync as unlinkSync5 } from "fs";
73542
+ import { mkdirSync as mkdirSync10, appendFileSync as appendFileSync5, existsSync as existsSync40, writeFileSync as writeFileSync12, unlinkSync as unlinkSync5 } from "fs";
73504
73543
  import { tmpdir as tmpdir6 } from "os";
73505
73544
  import { randomUUID } from "crypto";
73506
73545
  var TRANSCRIPT_DIR = join46(getClaudeConfigDir(), "transcripts");
@@ -73627,7 +73666,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
73627
73666
  }
73628
73667
  }
73629
73668
  const tempPath = join46(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
73630
- writeFileSync11(tempPath, allEntries.join(`
73669
+ writeFileSync12(tempPath, allEntries.join(`
73631
73670
  `) + `
73632
73671
  `);
73633
73672
  const cacheEntry = transcriptCache.get(sessionId);
@@ -73641,7 +73680,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
73641
73680
  log("[transcript] failed to build transcript from session", { error });
73642
73681
  try {
73643
73682
  const tempPath = join46(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
73644
- writeFileSync11(tempPath, buildCurrentEntry(currentToolName, currentToolInput) + `
73683
+ writeFileSync12(tempPath, buildCurrentEntry(currentToolName, currentToolInput) + `
73645
73684
  `);
73646
73685
  return tempPath;
73647
73686
  } catch (fallbackError) {
@@ -74538,8 +74577,8 @@ function getRuleInjectionFilePath(output) {
74538
74577
  import {
74539
74578
  existsSync as existsSync41,
74540
74579
  mkdirSync as mkdirSync11,
74541
- readFileSync as readFileSync28,
74542
- writeFileSync as writeFileSync12,
74580
+ readFileSync as readFileSync29,
74581
+ writeFileSync as writeFileSync13,
74543
74582
  unlinkSync as unlinkSync6
74544
74583
  } from "fs";
74545
74584
  import { join as join49 } from "path";
@@ -74578,7 +74617,7 @@ function loadInjectedRules(sessionID) {
74578
74617
  if (!existsSync41(filePath))
74579
74618
  return { contentHashes: new Set, realPaths: new Set };
74580
74619
  try {
74581
- const content = readFileSync28(filePath, "utf-8");
74620
+ const content = readFileSync29(filePath, "utf-8");
74582
74621
  const data = JSON.parse(content);
74583
74622
  return {
74584
74623
  contentHashes: new Set(data.injectedHashes),
@@ -74598,7 +74637,7 @@ function saveInjectedRules(sessionID, data) {
74598
74637
  injectedRealPaths: [...data.realPaths],
74599
74638
  updatedAt: Date.now()
74600
74639
  };
74601
- writeFileSync12(getStoragePath(sessionID), JSON.stringify(storageData, null, 2));
74640
+ writeFileSync13(getStoragePath(sessionID), JSON.stringify(storageData, null, 2));
74602
74641
  }
74603
74642
  function clearInjectedRules(sessionID) {
74604
74643
  const filePath = getStoragePath(sessionID);
@@ -74658,12 +74697,12 @@ function createSessionRuleScanCacheStore() {
74658
74697
  }
74659
74698
 
74660
74699
  // src/hooks/rules-injector/injector.ts
74661
- import { readFileSync as readFileSync29, statSync as statSync5 } from "fs";
74700
+ import { readFileSync as readFileSync30, statSync as statSync6 } from "fs";
74662
74701
  import { homedir as homedir10 } from "os";
74663
74702
  import { relative as relative5, resolve as resolve10 } from "path";
74664
74703
 
74665
74704
  // src/hooks/rules-injector/project-root-finder.ts
74666
- import { existsSync as existsSync42, statSync as statSync3 } from "fs";
74705
+ import { existsSync as existsSync42, statSync as statSync4 } from "fs";
74667
74706
  import { dirname as dirname11, join as join50 } from "path";
74668
74707
  var projectRootCache = new Map;
74669
74708
  function clearProjectRootCache() {
@@ -74680,7 +74719,7 @@ function findProjectRoot(startPath) {
74680
74719
  function findProjectRootWithoutCache(startPath) {
74681
74720
  let current;
74682
74721
  try {
74683
- const stat = statSync3(startPath);
74722
+ const stat = statSync4(startPath);
74684
74723
  current = stat.isDirectory() ? startPath : dirname11(startPath);
74685
74724
  } catch {
74686
74725
  current = dirname11(startPath);
@@ -74700,7 +74739,7 @@ function findProjectRootWithoutCache(startPath) {
74700
74739
  }
74701
74740
  }
74702
74741
  // src/hooks/rules-injector/rule-file-finder.ts
74703
- import { existsSync as existsSync44, statSync as statSync4 } from "fs";
74742
+ import { existsSync as existsSync44, statSync as statSync5 } from "fs";
74704
74743
  import { dirname as dirname12, join as join52, sep as sep3 } from "path";
74705
74744
 
74706
74745
  // src/hooks/rules-injector/rule-file-scanner.ts
@@ -74832,7 +74871,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile, options, cache2) {
74832
74871
  if (!existsSync44(filePath))
74833
74872
  continue;
74834
74873
  try {
74835
- const stat = statSync4(filePath);
74874
+ const stat = statSync5(filePath);
74836
74875
  if (!stat.isFile())
74837
74876
  continue;
74838
74877
  const realPath = safeRealpathSync(filePath);
@@ -75050,8 +75089,8 @@ function createRuleInjectionProcessor(deps) {
75050
75089
  getSessionCache: getSessionCache3,
75051
75090
  getSessionRuleScanCache,
75052
75091
  ruleFinderOptions,
75053
- readFileSync: readRuleFileSync = readFileSync29,
75054
- statSync: statRuleSync = statSync5,
75092
+ readFileSync: readRuleFileSync = readFileSync30,
75093
+ statSync: statRuleSync = statSync6,
75055
75094
  homedir: getHomeDir = homedir10,
75056
75095
  shouldApplyRule: shouldApplyRuleImpl = shouldApplyRule,
75057
75096
  isDuplicateByRealPath: isDuplicateByRealPathImpl = isDuplicateByRealPath,
@@ -75570,7 +75609,7 @@ import { join as join60 } from "path";
75570
75609
  // src/shared/migrate-legacy-config-file.ts
75571
75610
  init_logger();
75572
75611
  init_plugin_identity();
75573
- import { existsSync as existsSync50, readFileSync as readFileSync36, renameSync as renameSync4, rmSync as rmSync2 } from "fs";
75612
+ import { existsSync as existsSync50, readFileSync as readFileSync37, renameSync as renameSync4, rmSync as rmSync2 } from "fs";
75574
75613
  import { join as join57, dirname as dirname16, basename as basename6 } from "path";
75575
75614
  function buildCanonicalPath(legacyPath) {
75576
75615
  const dir = dirname16(legacyPath);
@@ -75615,7 +75654,7 @@ function migrateLegacyConfigFile(legacyPath) {
75615
75654
  if (existsSync50(canonicalPath))
75616
75655
  return false;
75617
75656
  try {
75618
- const content = readFileSync36(legacyPath, "utf-8");
75657
+ const content = readFileSync37(legacyPath, "utf-8");
75619
75658
  writeFileAtomically(canonicalPath, content);
75620
75659
  const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath);
75621
75660
  log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
@@ -76242,8 +76281,8 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
76242
76281
  import {
76243
76282
  existsSync as existsSync54,
76244
76283
  mkdirSync as mkdirSync13,
76245
- readFileSync as readFileSync38,
76246
- writeFileSync as writeFileSync15,
76284
+ readFileSync as readFileSync39,
76285
+ writeFileSync as writeFileSync16,
76247
76286
  unlinkSync as unlinkSync9
76248
76287
  } from "fs";
76249
76288
  import { join as join62 } from "path";
@@ -76303,7 +76342,7 @@ function loadAgentUsageState(sessionID) {
76303
76342
  if (!existsSync54(filePath))
76304
76343
  return null;
76305
76344
  try {
76306
- const content = readFileSync38(filePath, "utf-8");
76345
+ const content = readFileSync39(filePath, "utf-8");
76307
76346
  return JSON.parse(content);
76308
76347
  } catch {
76309
76348
  return null;
@@ -76314,7 +76353,7 @@ function saveAgentUsageState(state3) {
76314
76353
  mkdirSync13(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
76315
76354
  }
76316
76355
  const filePath = getStoragePath2(state3.sessionID);
76317
- writeFileSync15(filePath, JSON.stringify(state3, null, 2));
76356
+ writeFileSync16(filePath, JSON.stringify(state3, null, 2));
76318
76357
  }
76319
76358
  function clearAgentUsageState(sessionID) {
76320
76359
  const filePath = getStoragePath2(sessionID);
@@ -77596,8 +77635,8 @@ function createNonInteractiveEnvHook(_ctx) {
77596
77635
  import {
77597
77636
  existsSync as existsSync55,
77598
77637
  mkdirSync as mkdirSync14,
77599
- readFileSync as readFileSync39,
77600
- writeFileSync as writeFileSync16,
77638
+ readFileSync as readFileSync40,
77639
+ writeFileSync as writeFileSync17,
77601
77640
  unlinkSync as unlinkSync10
77602
77641
  } from "fs";
77603
77642
  import { join as join64 } from "path";
@@ -77623,7 +77662,7 @@ function loadInteractiveBashSessionState(sessionID) {
77623
77662
  if (!existsSync55(filePath))
77624
77663
  return null;
77625
77664
  try {
77626
- const content = readFileSync39(filePath, "utf-8");
77665
+ const content = readFileSync40(filePath, "utf-8");
77627
77666
  const serialized = JSON.parse(content);
77628
77667
  return {
77629
77668
  sessionID: serialized.sessionID,
@@ -77644,7 +77683,7 @@ function saveInteractiveBashSessionState(state3) {
77644
77683
  tmuxSessions: Array.from(state3.tmuxSessions),
77645
77684
  updatedAt: state3.updatedAt
77646
77685
  };
77647
- writeFileSync16(filePath, JSON.stringify(serialized, null, 2));
77686
+ writeFileSync17(filePath, JSON.stringify(serialized, null, 2));
77648
77687
  }
77649
77688
  function clearInteractiveBashSessionState(sessionID) {
77650
77689
  const filePath = getStoragePath3(sessionID);
@@ -77928,7 +77967,6 @@ function createThinkingBlockValidatorHook() {
77928
77967
  }
77929
77968
  // src/hooks/tool-pair-validator/hook.ts
77930
77969
  init_logger();
77931
- init_logger();
77932
77970
  var DEFAULT_THINKING_WINDOW2 = parseInt(process.env.OMO_THINKING_WINDOW ?? "50", 10);
77933
77971
  var TOOL_RESULT_PLACEHOLDER = "Tool output unavailable (context compacted)";
77934
77972
  function getToolUseID(part) {
@@ -78038,20 +78076,12 @@ function repairMissingToolResults(messages, assistantIndex) {
78038
78076
  function createToolPairValidatorHook() {
78039
78077
  return {
78040
78078
  "experimental.chat.messages.transform": async (_input, output) => {
78041
- const start = performance.now();
78042
- const windowSize = DEFAULT_THINKING_WINDOW2;
78043
- if (output.messages.length > windowSize) {
78044
- output.messages.splice(0, output.messages.length - windowSize);
78045
- }
78046
78079
  for (let i2 = 0;i2 < output.messages.length; i2++) {
78047
78080
  if (output.messages[i2].info.role !== "assistant") {
78048
78081
  continue;
78049
78082
  }
78050
78083
  repairMissingToolResults(output.messages, i2);
78051
78084
  }
78052
- if (process.env.OMO_DEBUG === "1") {
78053
- logPerf("toolPairValidator", performance.now() - start);
78054
- }
78055
78085
  }
78056
78086
  };
78057
78087
  }
@@ -78508,7 +78538,7 @@ async function handleDetectedCompletion(ctx, input) {
78508
78538
  init_logger();
78509
78539
  init_constants();
78510
78540
  init_constants();
78511
- import { existsSync as existsSync57, readFileSync as readFileSync41 } from "fs";
78541
+ import { existsSync as existsSync57, readFileSync as readFileSync42 } from "fs";
78512
78542
 
78513
78543
  // src/features/tool-metadata-store/store.ts
78514
78544
  var pendingStore = new Map;
@@ -78778,7 +78808,7 @@ function detectCompletionInTranscript(transcriptPath, promise, startedAt) {
78778
78808
  try {
78779
78809
  if (!existsSync57(transcriptPath))
78780
78810
  return false;
78781
- const content = readFileSync41(transcriptPath, "utf-8");
78811
+ const content = readFileSync42(transcriptPath, "utf-8");
78782
78812
  const pattern = buildPromisePattern(promise);
78783
78813
  const lines = content.split(`
78784
78814
  `).filter((line) => line.trim());
@@ -79848,7 +79878,7 @@ function builtinToLoadedSkill(builtin) {
79848
79878
 
79849
79879
  // src/features/opencode-skill-loader/merger/config-skill-entry-loader.ts
79850
79880
  init_frontmatter();
79851
- import { existsSync as existsSync58, readFileSync as readFileSync42 } from "fs";
79881
+ import { existsSync as existsSync58, readFileSync as readFileSync43 } from "fs";
79852
79882
  import { dirname as dirname18, isAbsolute as isAbsolute8, resolve as resolve11 } from "path";
79853
79883
  import { homedir as homedir14 } from "os";
79854
79884
  init_logger();
@@ -79870,7 +79900,7 @@ function loadSkillFromFile(filePath) {
79870
79900
  try {
79871
79901
  if (!existsSync58(filePath))
79872
79902
  return null;
79873
- const content = readFileSync42(filePath, "utf-8");
79903
+ const content = readFileSync43(filePath, "utf-8");
79874
79904
  const { data, body } = parseFrontmatter(content);
79875
79905
  return { template: body, metadata: data };
79876
79906
  } catch {
@@ -82925,13 +82955,13 @@ async function getAllSkills(options) {
82925
82955
  }
82926
82956
  // src/features/opencode-skill-loader/loaded-skill-template-extractor.ts
82927
82957
  init_frontmatter();
82928
- import { readFileSync as readFileSync43 } from "fs";
82958
+ import { readFileSync as readFileSync44 } from "fs";
82929
82959
  function extractSkillTemplate(skill) {
82930
82960
  if (skill.scope === "config" && skill.definition.template) {
82931
82961
  return skill.definition.template;
82932
82962
  }
82933
82963
  if (skill.path) {
82934
- const content = readFileSync43(skill.path, "utf-8");
82964
+ const content = readFileSync44(skill.path, "utf-8");
82935
82965
  const { body } = parseFrontmatter(content);
82936
82966
  return body.trim();
82937
82967
  }
@@ -83769,7 +83799,7 @@ async function discoverConfigSourceSkills(options) {
83769
83799
  return deduplicateSkillsByName(loadedBySource.flat());
83770
83800
  }
83771
83801
  // src/tools/slashcommand/command-discovery.ts
83772
- import { existsSync as existsSync59, readdirSync as readdirSync16, readFileSync as readFileSync44, statSync as statSync7 } from "fs";
83802
+ import { existsSync as existsSync59, readdirSync as readdirSync16, readFileSync as readFileSync45, statSync as statSync8 } from "fs";
83773
83803
  import { basename as basename8, join as join70 } from "path";
83774
83804
  // src/features/builtin-commands/templates/init-deep.ts
83775
83805
  var INIT_DEEP_TEMPLATE = `# /init-deep
@@ -85380,7 +85410,7 @@ var NESTED_COMMAND_SEPARATOR = "/";
85380
85410
  function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
85381
85411
  if (!existsSync59(commandsDir))
85382
85412
  return [];
85383
- if (!statSync7(commandsDir).isDirectory()) {
85413
+ if (!statSync8(commandsDir).isDirectory()) {
85384
85414
  log(`[command-discovery] Skipping non-directory path: ${commandsDir}`);
85385
85415
  return [];
85386
85416
  }
@@ -85402,7 +85432,7 @@ function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
85402
85432
  const baseCommandName = basename8(entry.name, ".md");
85403
85433
  const commandName = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${baseCommandName}` : baseCommandName;
85404
85434
  try {
85405
- const content = readFileSync44(commandPath, "utf-8");
85435
+ const content = readFileSync45(commandPath, "utf-8");
85406
85436
  const { data, body } = parseFrontmatter(content);
85407
85437
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
85408
85438
  const metadata = {
@@ -85995,7 +86025,7 @@ var NOTEPAD_DIR = "notepads";
85995
86025
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
85996
86026
  var PROMETHEUS_PLANS_DIR = ".sisyphus/plans";
85997
86027
  // src/features/boulder-state/storage.ts
85998
- import { existsSync as existsSync60, readFileSync as readFileSync45, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16, readdirSync as readdirSync17 } from "fs";
86028
+ import { existsSync as existsSync60, readFileSync as readFileSync46, writeFileSync as writeFileSync19, mkdirSync as mkdirSync16, readdirSync as readdirSync17 } from "fs";
85999
86029
  import { dirname as dirname21, join as join71, basename as basename9 } from "path";
86000
86030
  var RESERVED_KEYS = new Set(["__proto__", "prototype", "constructor"]);
86001
86031
  function getBoulderFilePath(directory) {
@@ -86007,7 +86037,7 @@ function readBoulderState(directory) {
86007
86037
  return null;
86008
86038
  }
86009
86039
  try {
86010
- const content = readFileSync45(filePath, "utf-8");
86040
+ const content = readFileSync46(filePath, "utf-8");
86011
86041
  const parsed = JSON.parse(content);
86012
86042
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
86013
86043
  return null;
@@ -86039,7 +86069,7 @@ function writeBoulderState(directory, state3) {
86039
86069
  if (!existsSync60(dir)) {
86040
86070
  mkdirSync16(dir, { recursive: true });
86041
86071
  }
86042
- writeFileSync18(filePath, JSON.stringify(state3, null, 2), "utf-8");
86072
+ writeFileSync19(filePath, JSON.stringify(state3, null, 2), "utf-8");
86043
86073
  return true;
86044
86074
  } catch {
86045
86075
  return false;
@@ -86146,7 +86176,7 @@ function getPlanProgress(planPath) {
86146
86176
  return { total: 0, completed: 0, isComplete: true };
86147
86177
  }
86148
86178
  try {
86149
- const content = readFileSync45(planPath, "utf-8");
86179
+ const content = readFileSync46(planPath, "utf-8");
86150
86180
  const lines = content.split(/\r?\n/);
86151
86181
  const hasStructuredSections = lines.some((line) => TODO_HEADING_PATTERN.test(line) || FINAL_VERIFICATION_HEADING_PATTERN.test(line));
86152
86182
  if (hasStructuredSections) {
@@ -86222,7 +86252,7 @@ function createBoulderState(planPath, sessionId, agent, worktreePath) {
86222
86252
  };
86223
86253
  }
86224
86254
  // src/features/boulder-state/top-level-task.ts
86225
- import { existsSync as existsSync61, readFileSync as readFileSync46 } from "fs";
86255
+ import { existsSync as existsSync61, readFileSync as readFileSync47 } from "fs";
86226
86256
  var TODO_HEADING_PATTERN2 = /^##\s+TODOs\b/i;
86227
86257
  var FINAL_VERIFICATION_HEADING_PATTERN2 = /^##\s+Final Verification Wave\b/i;
86228
86258
  var SECOND_LEVEL_HEADING_PATTERN2 = /^##\s+/;
@@ -86249,7 +86279,7 @@ function readCurrentTopLevelTask(planPath) {
86249
86279
  return null;
86250
86280
  }
86251
86281
  try {
86252
- const content = readFileSync46(planPath, "utf-8");
86282
+ const content = readFileSync47(planPath, "utf-8");
86253
86283
  const lines = content.split(/\r?\n/);
86254
86284
  let section = "other";
86255
86285
  for (const line of lines) {
@@ -86514,7 +86544,7 @@ function parseUserRequest(promptText) {
86514
86544
  }
86515
86545
 
86516
86546
  // src/hooks/start-work/context-info-builder.ts
86517
- import { statSync as statSync8 } from "fs";
86547
+ import { statSync as statSync9 } from "fs";
86518
86548
  init_logger();
86519
86549
 
86520
86550
  // src/hooks/start-work/worktree-block.ts
@@ -86692,7 +86722,7 @@ function buildPlanDiscoveryContext(params) {
86692
86722
  }
86693
86723
  const planList = incompletePlans.map((p, i2) => {
86694
86724
  const progress = getPlanProgress(p);
86695
- const modified = new Date(statSync8(p).mtimeMs).toISOString();
86725
+ const modified = new Date(statSync9(p).mtimeMs).toISOString();
86696
86726
  return `${i2 + 1}. [${getPlanName(p)}] - Modified: ${modified} - Progress: ${progress.completed}/${progress.total}`;
86697
86727
  }).join(`
86698
86728
  `);
@@ -86845,7 +86875,7 @@ function isAbortError(error) {
86845
86875
  }
86846
86876
 
86847
86877
  // src/hooks/atlas/session-last-agent.ts
86848
- import { readFileSync as readFileSync47, readdirSync as readdirSync18 } from "fs";
86878
+ import { readFileSync as readFileSync48, readdirSync as readdirSync18 } from "fs";
86849
86879
  import { join as join72 } from "path";
86850
86880
  var defaultSessionLastAgentDeps = {
86851
86881
  getMessageDir,
@@ -86894,7 +86924,7 @@ async function getLastAgentFromSession(sessionID, client, deps = {}) {
86894
86924
  try {
86895
86925
  const messages = readdirSync18(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
86896
86926
  try {
86897
- const content = readFileSync47(join72(messageDir, fileName), "utf-8");
86927
+ const content = readFileSync48(join72(messageDir, fileName), "utf-8");
86898
86928
  const parsed = JSON.parse(content);
86899
86929
  return {
86900
86930
  fileName,
@@ -87870,7 +87900,7 @@ async function resolveFallbackTrackedSessionId(input) {
87870
87900
  }
87871
87901
 
87872
87902
  // src/hooks/atlas/final-wave-plan-state.ts
87873
- import { existsSync as existsSync62, readFileSync as readFileSync48 } from "fs";
87903
+ import { existsSync as existsSync62, readFileSync as readFileSync49 } from "fs";
87874
87904
  var TODO_HEADING_PATTERN3 = /^##\s+TODOs\b/i;
87875
87905
  var FINAL_VERIFICATION_HEADING_PATTERN3 = /^##\s+Final Verification Wave\b/i;
87876
87906
  var SECOND_LEVEL_HEADING_PATTERN3 = /^##\s+/;
@@ -87882,7 +87912,7 @@ function readFinalWavePlanState(planPath) {
87882
87912
  return null;
87883
87913
  }
87884
87914
  try {
87885
- const content = readFileSync48(planPath, "utf-8");
87915
+ const content = readFileSync49(planPath, "utf-8");
87886
87916
  const lines = content.split(/\r?\n/);
87887
87917
  let section = "other";
87888
87918
  let pendingImplementationTaskCount = 0;
@@ -92608,7 +92638,7 @@ init_logger();
92608
92638
  init_plugin_identity();
92609
92639
 
92610
92640
  // src/hooks/legacy-plugin-toast/auto-migrate.ts
92611
- import { existsSync as existsSync65, readFileSync as readFileSync49 } from "fs";
92641
+ import { existsSync as existsSync65, readFileSync as readFileSync50 } from "fs";
92612
92642
  import { join as join74 } from "path";
92613
92643
  init_plugin_identity();
92614
92644
  function detectOpenCodeConfigPath(overrideConfigDir) {
@@ -92633,7 +92663,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
92633
92663
  if (!configPath)
92634
92664
  return { migrated: false, from: null, to: null, configPath: null };
92635
92665
  try {
92636
- const content = readFileSync49(configPath, "utf-8");
92666
+ const content = readFileSync50(configPath, "utf-8");
92637
92667
  const parseResult = parseJsoncSafe(content);
92638
92668
  if (!parseResult.data?.plugin)
92639
92669
  return { migrated: false, from: null, to: null, configPath };
@@ -93046,13 +93076,13 @@ var DEFAULT_MAX_SYMBOLS = 200;
93046
93076
  var DEFAULT_MAX_DIAGNOSTICS = 200;
93047
93077
  var DEFAULT_MAX_DIRECTORY_FILES = 50;
93048
93078
  // src/tools/lsp/server-config-loader.ts
93049
- import { existsSync as existsSync66, readFileSync as readFileSync50 } from "fs";
93079
+ import { existsSync as existsSync66, readFileSync as readFileSync51 } from "fs";
93050
93080
  import { join as join75 } from "path";
93051
93081
  function loadJsonFile(path13) {
93052
93082
  if (!existsSync66(path13))
93053
93083
  return null;
93054
93084
  try {
93055
- return parseJsonc(readFileSync50(path13, "utf-8"));
93085
+ return parseJsonc(readFileSync51(path13, "utf-8"));
93056
93086
  } catch {
93057
93087
  return null;
93058
93088
  }
@@ -93241,7 +93271,7 @@ function getLanguageId(ext) {
93241
93271
  init_logger();
93242
93272
  var {spawn: bunSpawn2 } = globalThis.Bun;
93243
93273
  import { spawn as nodeSpawn2 } from "child_process";
93244
- import { existsSync as existsSync68, statSync as statSync9 } from "fs";
93274
+ import { existsSync as existsSync68, statSync as statSync10 } from "fs";
93245
93275
  function shouldUseNodeSpawn() {
93246
93276
  return process.platform === "win32";
93247
93277
  }
@@ -93250,7 +93280,7 @@ function validateCwd(cwd) {
93250
93280
  if (!existsSync68(cwd)) {
93251
93281
  return { valid: false, error: `Working directory does not exist: ${cwd}` };
93252
93282
  }
93253
- const stats = statSync9(cwd);
93283
+ const stats = statSync10(cwd);
93254
93284
  if (!stats.isDirectory()) {
93255
93285
  return { valid: false, error: `Path is not a directory: ${cwd}` };
93256
93286
  }
@@ -93379,7 +93409,7 @@ function spawnProcess(command, options) {
93379
93409
  return proc;
93380
93410
  }
93381
93411
  // src/tools/lsp/lsp-client.ts
93382
- import { readFileSync as readFileSync51 } from "fs";
93412
+ import { readFileSync as readFileSync52 } from "fs";
93383
93413
  import { extname as extname3, resolve as resolve14 } from "path";
93384
93414
  import { pathToFileURL as pathToFileURL2 } from "url";
93385
93415
 
@@ -93651,7 +93681,7 @@ class LSPClient extends LSPClientConnection {
93651
93681
  async openFile(filePath) {
93652
93682
  const absPath = resolve14(filePath);
93653
93683
  const uri = pathToFileURL2(absPath).href;
93654
- const text = readFileSync51(absPath, "utf-8");
93684
+ const text = readFileSync52(absPath, "utf-8");
93655
93685
  if (!this.openedFiles.has(absPath)) {
93656
93686
  const ext = extname3(absPath);
93657
93687
  const languageId = getLanguageId(ext);
@@ -94009,13 +94039,13 @@ var lspManager = LSPServerManager.getInstance();
94009
94039
  // src/tools/lsp/lsp-client-wrapper.ts
94010
94040
  import { extname as extname4, resolve as resolve15 } from "path";
94011
94041
  import { fileURLToPath as fileURLToPath4 } from "url";
94012
- import { existsSync as existsSync69, statSync as statSync10 } from "fs";
94042
+ import { existsSync as existsSync69, statSync as statSync11 } from "fs";
94013
94043
  init_plugin_identity();
94014
94044
  function isDirectoryPath(filePath) {
94015
94045
  if (!existsSync69(filePath)) {
94016
94046
  return false;
94017
94047
  }
94018
- return statSync10(filePath).isDirectory();
94048
+ return statSync11(filePath).isDirectory();
94019
94049
  }
94020
94050
  function uriToPath(uri) {
94021
94051
  return fileURLToPath4(uri);
@@ -94204,10 +94234,10 @@ function formatApplyResult(result) {
94204
94234
  `);
94205
94235
  }
94206
94236
  // src/tools/lsp/workspace-edit.ts
94207
- import { readFileSync as readFileSync52, writeFileSync as writeFileSync19 } from "fs";
94237
+ import { readFileSync as readFileSync53, writeFileSync as writeFileSync20 } from "fs";
94208
94238
  function applyTextEditsToFile(filePath, edits) {
94209
94239
  try {
94210
- let content = readFileSync52(filePath, "utf-8");
94240
+ let content = readFileSync53(filePath, "utf-8");
94211
94241
  const lines = content.split(`
94212
94242
  `);
94213
94243
  const sortedEdits = [...edits].sort((a, b) => {
@@ -94232,7 +94262,7 @@ function applyTextEditsToFile(filePath, edits) {
94232
94262
  `));
94233
94263
  }
94234
94264
  }
94235
- writeFileSync19(filePath, lines.join(`
94265
+ writeFileSync20(filePath, lines.join(`
94236
94266
  `), "utf-8");
94237
94267
  return { success: true, editCount: edits.length };
94238
94268
  } catch (err) {
@@ -94263,7 +94293,7 @@ function applyWorkspaceEdit(edit) {
94263
94293
  if (change.kind === "create") {
94264
94294
  try {
94265
94295
  const filePath = uriToPath(change.uri);
94266
- writeFileSync19(filePath, "", "utf-8");
94296
+ writeFileSync20(filePath, "", "utf-8");
94267
94297
  result.filesModified.push(filePath);
94268
94298
  } catch (err) {
94269
94299
  result.success = false;
@@ -94273,8 +94303,8 @@ function applyWorkspaceEdit(edit) {
94273
94303
  try {
94274
94304
  const oldPath = uriToPath(change.oldUri);
94275
94305
  const newPath = uriToPath(change.newUri);
94276
- const content = readFileSync52(oldPath, "utf-8");
94277
- writeFileSync19(newPath, content, "utf-8");
94306
+ const content = readFileSync53(oldPath, "utf-8");
94307
+ writeFileSync20(newPath, content, "utf-8");
94278
94308
  __require("fs").unlinkSync(oldPath);
94279
94309
  result.filesModified.push(newPath);
94280
94310
  } catch (err) {
@@ -94746,7 +94776,7 @@ var DEFAULT_MAX_MATCHES = 500;
94746
94776
  // src/tools/ast-grep/sg-cli-path.ts
94747
94777
  import { createRequire as createRequire4 } from "module";
94748
94778
  import { dirname as dirname23, join as join81 } from "path";
94749
- import { existsSync as existsSync72, statSync as statSync11 } from "fs";
94779
+ import { existsSync as existsSync72, statSync as statSync12 } from "fs";
94750
94780
 
94751
94781
  // src/tools/ast-grep/downloader.ts
94752
94782
  import { existsSync as existsSync71 } from "fs";
@@ -94834,7 +94864,7 @@ async function ensureAstGrepBinary() {
94834
94864
  // src/tools/ast-grep/sg-cli-path.ts
94835
94865
  function isValidBinary(filePath) {
94836
94866
  try {
94837
- return statSync11(filePath).size > 1e4;
94867
+ return statSync12(filePath).size > 1e4;
94838
94868
  } catch {
94839
94869
  return false;
94840
94870
  }
@@ -97407,30 +97437,31 @@ function tokenizeCommand2(cmd) {
97407
97437
  tokens.push(current);
97408
97438
  return tokens;
97409
97439
  }
97410
- var interactive_bash = tool({
97411
- description: INTERACTIVE_BASH_DESCRIPTION,
97412
- args: {
97413
- tmux_command: tool.schema.string().describe("The tmux command to execute (without 'tmux' prefix)")
97414
- },
97415
- execute: async (args) => {
97416
- try {
97417
- const tmuxPath2 = getCachedTmuxPath() ?? "tmux";
97418
- const parts = tokenizeCommand2(args.tmux_command);
97419
- if (parts.length === 0) {
97420
- return "Error: Empty tmux command";
97421
- }
97422
- const subcommand = parts[0].toLowerCase();
97423
- if (BLOCKED_TMUX_SUBCOMMANDS.includes(subcommand)) {
97424
- const sessionIdx = parts.findIndex((p) => p === "-t" || p.startsWith("-t"));
97425
- let sessionName = "omo-session";
97426
- if (sessionIdx !== -1) {
97427
- if (parts[sessionIdx] === "-t" && parts[sessionIdx + 1]) {
97428
- sessionName = parts[sessionIdx + 1];
97429
- } else if (parts[sessionIdx].startsWith("-t")) {
97430
- sessionName = parts[sessionIdx].slice(2);
97440
+ function createInteractiveBashTool(timeoutMs = DEFAULT_TIMEOUT_MS5) {
97441
+ return tool({
97442
+ description: INTERACTIVE_BASH_DESCRIPTION,
97443
+ args: {
97444
+ tmux_command: tool.schema.string().describe("The tmux command to execute (without 'tmux' prefix)")
97445
+ },
97446
+ execute: async (args) => {
97447
+ try {
97448
+ const tmuxPath2 = getCachedTmuxPath() ?? "tmux";
97449
+ const parts = tokenizeCommand2(args.tmux_command);
97450
+ if (parts.length === 0) {
97451
+ return "Error: Empty tmux command";
97452
+ }
97453
+ const subcommand = parts[0].toLowerCase();
97454
+ if (BLOCKED_TMUX_SUBCOMMANDS.includes(subcommand)) {
97455
+ const sessionIdx = parts.findIndex((p) => p === "-t" || p.startsWith("-t"));
97456
+ let sessionName = "omo-session";
97457
+ if (sessionIdx !== -1) {
97458
+ if (parts[sessionIdx] === "-t" && parts[sessionIdx + 1]) {
97459
+ sessionName = parts[sessionIdx + 1];
97460
+ } else if (parts[sessionIdx].startsWith("-t")) {
97461
+ sessionName = parts[sessionIdx].slice(2);
97462
+ }
97431
97463
  }
97432
- }
97433
- return `Error: '${parts[0]}' is blocked in interactive_bash.
97464
+ return `Error: '${parts[0]}' is blocked in interactive_bash.
97434
97465
 
97435
97466
  **USE BASH TOOL INSTEAD:**
97436
97467
 
@@ -97443,40 +97474,42 @@ tmux capture-pane -p -t ${sessionName} -S -1000
97443
97474
  \`\`\`
97444
97475
 
97445
97476
  The Bash tool can execute these commands directly. Do NOT retry with interactive_bash.`;
97477
+ }
97478
+ const proc = spawnWithWindowsHide([tmuxPath2, ...parts], {
97479
+ stdout: "pipe",
97480
+ stderr: "pipe"
97481
+ });
97482
+ const timeoutPromise = new Promise((_, reject) => {
97483
+ const id = setTimeout(() => {
97484
+ const timeoutError = new Error(`Timeout after ${timeoutMs}ms`);
97485
+ try {
97486
+ proc.kill();
97487
+ proc.exited.catch(() => {});
97488
+ } catch {}
97489
+ reject(timeoutError);
97490
+ }, timeoutMs);
97491
+ proc.exited.then(() => clearTimeout(id)).catch(() => clearTimeout(id));
97492
+ });
97493
+ const [stdout, stderr, exitCode] = await Promise.race([
97494
+ Promise.all([
97495
+ new Response(proc.stdout).text(),
97496
+ new Response(proc.stderr).text(),
97497
+ proc.exited
97498
+ ]),
97499
+ timeoutPromise
97500
+ ]);
97501
+ if (exitCode !== 0) {
97502
+ const errorMsg = stderr.trim() || `Command failed with exit code ${exitCode}`;
97503
+ return `Error: ${errorMsg}`;
97504
+ }
97505
+ return stdout || "(no output)";
97506
+ } catch (e) {
97507
+ return `Error: ${e instanceof Error ? e.message : String(e)}`;
97446
97508
  }
97447
- const proc = spawnWithWindowsHide([tmuxPath2, ...parts], {
97448
- stdout: "pipe",
97449
- stderr: "pipe"
97450
- });
97451
- const timeoutPromise = new Promise((_, reject) => {
97452
- const id = setTimeout(() => {
97453
- const timeoutError = new Error(`Timeout after ${DEFAULT_TIMEOUT_MS5}ms`);
97454
- try {
97455
- proc.kill();
97456
- proc.exited.catch(() => {});
97457
- } catch {}
97458
- reject(timeoutError);
97459
- }, DEFAULT_TIMEOUT_MS5);
97460
- proc.exited.then(() => clearTimeout(id)).catch(() => clearTimeout(id));
97461
- });
97462
- const [stdout, stderr, exitCode] = await Promise.race([
97463
- Promise.all([
97464
- new Response(proc.stdout).text(),
97465
- new Response(proc.stderr).text(),
97466
- proc.exited
97467
- ]),
97468
- timeoutPromise
97469
- ]);
97470
- if (exitCode !== 0) {
97471
- const errorMsg = stderr.trim() || `Command failed with exit code ${exitCode}`;
97472
- return `Error: ${errorMsg}`;
97473
- }
97474
- return stdout || "(no output)";
97475
- } catch (e) {
97476
- return `Error: ${e instanceof Error ? e.message : String(e)}`;
97477
97509
  }
97478
- }
97479
- });
97510
+ });
97511
+ }
97512
+ var interactive_bash = createInteractiveBashTool();
97480
97513
 
97481
97514
  // src/tools/interactive-bash/index.ts
97482
97515
  init_tmux_path_resolver();
@@ -98897,7 +98930,7 @@ import { pathToFileURL as pathToFileURL3 } from "url";
98897
98930
 
98898
98931
  // src/tools/look-at/image-converter.ts
98899
98932
  import * as childProcess from "child_process";
98900
- import { existsSync as existsSync78, mkdtempSync, readFileSync as readFileSync53, rmSync as rmSync4, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
98933
+ import { existsSync as existsSync78, mkdtempSync, readFileSync as readFileSync54, rmSync as rmSync4, unlinkSync as unlinkSync12, writeFileSync as writeFileSync21 } from "fs";
98901
98934
  import { tmpdir as tmpdir7 } from "os";
98902
98935
  import { dirname as dirname27, join as join86 } from "path";
98903
98936
  var SUPPORTED_FORMATS = new Set([
@@ -99013,11 +99046,11 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
99013
99046
  try {
99014
99047
  const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
99015
99048
  const buffer2 = Buffer.from(cleanBase64, "base64");
99016
- writeFileSync20(inputPath, buffer2);
99049
+ writeFileSync21(inputPath, buffer2);
99017
99050
  log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
99018
99051
  const outputPath = convertImageToJpeg(inputPath, mimeType);
99019
99052
  tempFiles.push(outputPath);
99020
- const convertedBuffer = readFileSync53(outputPath);
99053
+ const convertedBuffer = readFileSync54(outputPath);
99021
99054
  const convertedBase64 = convertedBuffer.toString("base64");
99022
99055
  log(`[image-converter] Base64 conversion successful`);
99023
99056
  return { base64: convertedBase64, tempFiles };
@@ -101465,17 +101498,17 @@ import { join as join87 } from "path";
101465
101498
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
101466
101499
  init_frontmatter();
101467
101500
  init_logger();
101468
- import { existsSync as existsSync80, readFileSync as readFileSync55 } from "fs";
101501
+ import { existsSync as existsSync80, readFileSync as readFileSync56 } from "fs";
101469
101502
  import { basename as basename12, extname as extname7 } from "path";
101470
101503
 
101471
101504
  // src/features/claude-code-agent-loader/json-agent-loader.ts
101472
- import { existsSync as existsSync79, readFileSync as readFileSync54 } from "fs";
101505
+ import { existsSync as existsSync79, readFileSync as readFileSync55 } from "fs";
101473
101506
  function parseJsonAgentFile(filePath, scope) {
101474
101507
  try {
101475
101508
  if (!existsSync79(filePath)) {
101476
101509
  return null;
101477
101510
  }
101478
- const content = readFileSync54(filePath, "utf-8");
101511
+ const content = readFileSync55(filePath, "utf-8");
101479
101512
  const { data } = parseJsoncSafe(content);
101480
101513
  if (!data) {
101481
101514
  return null;
@@ -101514,7 +101547,7 @@ function parseMarkdownAgentFile(filePath, scope) {
101514
101547
  if (!existsSync80(filePath)) {
101515
101548
  return null;
101516
101549
  }
101517
- const content = readFileSync55(filePath, "utf-8");
101550
+ const content = readFileSync56(filePath, "utf-8");
101518
101551
  const { data, body } = parseFrontmatter(content);
101519
101552
  const fileName = basename12(filePath);
101520
101553
  const agentName = fileName.replace(/\.md$/i, "");
@@ -102222,7 +102255,7 @@ var TaskDeleteInputSchema = z34.object({
102222
102255
 
102223
102256
  // src/features/claude-tasks/storage.ts
102224
102257
  import { join as join89, dirname as dirname29, basename as basename13, isAbsolute as isAbsolute12 } from "path";
102225
- import { existsSync as existsSync83, mkdirSync as mkdirSync17, readFileSync as readFileSync57, writeFileSync as writeFileSync21, renameSync as renameSync5, unlinkSync as unlinkSync13, readdirSync as readdirSync23 } from "fs";
102258
+ import { existsSync as existsSync83, mkdirSync as mkdirSync17, readFileSync as readFileSync58, writeFileSync as writeFileSync22, renameSync as renameSync5, unlinkSync as unlinkSync13, readdirSync as readdirSync23 } from "fs";
102226
102259
  import { randomUUID as randomUUID3 } from "crypto";
102227
102260
  function getTaskDir(config2 = {}) {
102228
102261
  const tasksConfig = config2.sisyphus?.tasks;
@@ -102259,7 +102292,7 @@ function readJsonSafe(filePath, schema2) {
102259
102292
  if (!existsSync83(filePath)) {
102260
102293
  return null;
102261
102294
  }
102262
- const content = readFileSync57(filePath, "utf-8");
102295
+ const content = readFileSync58(filePath, "utf-8");
102263
102296
  const parsed = JSON.parse(content);
102264
102297
  const result = schema2.safeParse(parsed);
102265
102298
  if (!result.success) {
@@ -102275,7 +102308,7 @@ function writeJsonAtomic(filePath, data) {
102275
102308
  ensureDir(dir);
102276
102309
  const tempPath = `${filePath}.tmp.${Date.now()}`;
102277
102310
  try {
102278
- writeFileSync21(tempPath, JSON.stringify(data, null, 2), "utf-8");
102311
+ writeFileSync22(tempPath, JSON.stringify(data, null, 2), "utf-8");
102279
102312
  renameSync5(tempPath, filePath);
102280
102313
  } catch (error) {
102281
102314
  try {
@@ -102294,14 +102327,14 @@ function acquireLock(dirPath) {
102294
102327
  const lockPath = join89(dirPath, ".lock");
102295
102328
  const lockId = randomUUID3();
102296
102329
  const createLock = (timestamp2) => {
102297
- writeFileSync21(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
102330
+ writeFileSync22(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
102298
102331
  encoding: "utf-8",
102299
102332
  flag: "wx"
102300
102333
  });
102301
102334
  };
102302
102335
  const isStale = () => {
102303
102336
  try {
102304
- const lockContent = readFileSync57(lockPath, "utf-8");
102337
+ const lockContent = readFileSync58(lockPath, "utf-8");
102305
102338
  const lockData = JSON.parse(lockContent);
102306
102339
  const lockAge = Date.now() - lockData.timestamp;
102307
102340
  return lockAge > STALE_LOCK_THRESHOLD_MS;
@@ -102341,7 +102374,7 @@ function acquireLock(dirPath) {
102341
102374
  try {
102342
102375
  if (!existsSync83(lockPath))
102343
102376
  return;
102344
- const lockContent = readFileSync57(lockPath, "utf-8");
102377
+ const lockContent = readFileSync58(lockPath, "utf-8");
102345
102378
  const lockData = JSON.parse(lockContent);
102346
102379
  if (lockData.id !== lockId)
102347
102380
  return;
@@ -104965,6 +104998,8 @@ class TaskHistory {
104965
104998
  }
104966
104999
 
104967
105000
  // src/features/background-agent/concurrency.ts
105001
+ var DEFAULT_ACQUIRE_TIMEOUT_MS = 30000;
105002
+
104968
105003
  class ConcurrencyManager {
104969
105004
  config;
104970
105005
  counts = new Map;
@@ -104988,7 +105023,7 @@ class ConcurrencyManager {
104988
105023
  }
104989
105024
  return 5;
104990
105025
  }
104991
- async acquire(model) {
105026
+ async acquire(model, timeoutMs) {
104992
105027
  const limit = this.getConcurrencyLimit(model);
104993
105028
  if (limit === Infinity) {
104994
105029
  return;
@@ -104998,6 +105033,7 @@ class ConcurrencyManager {
104998
105033
  this.counts.set(model, current + 1);
104999
105034
  return;
105000
105035
  }
105036
+ const timeout = timeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS;
105001
105037
  return new Promise((resolve21, reject) => {
105002
105038
  const queue = this.queues.get(model) ?? [];
105003
105039
  const entry = {
@@ -105012,6 +105048,39 @@ class ConcurrencyManager {
105012
105048
  };
105013
105049
  queue.push(entry);
105014
105050
  this.queues.set(model, queue);
105051
+ const timer = setTimeout(() => {
105052
+ if (entry.settled)
105053
+ return;
105054
+ entry.settled = true;
105055
+ const queue2 = this.queues.get(model);
105056
+ if (queue2) {
105057
+ const idx = queue2.indexOf(entry);
105058
+ if (idx !== -1) {
105059
+ queue2.splice(idx, 1);
105060
+ }
105061
+ if (queue2.length === 0) {
105062
+ this.queues.delete(model);
105063
+ }
105064
+ }
105065
+ reject(new Error(`ConcurrencyManager.acquire() timed out after ${timeout}ms for model: ${model}`));
105066
+ }, timeout);
105067
+ entry.resolve = () => {
105068
+ clearTimeout(timer);
105069
+ if (entry.settled)
105070
+ return;
105071
+ entry.settled = true;
105072
+ const queue2 = this.queues.get(model);
105073
+ if (queue2) {
105074
+ const idx = queue2.indexOf(entry);
105075
+ if (idx !== -1) {
105076
+ queue2.splice(idx, 1);
105077
+ }
105078
+ if (queue2.length === 0) {
105079
+ this.queues.delete(model);
105080
+ }
105081
+ }
105082
+ resolve21();
105083
+ };
105015
105084
  });
105016
105085
  }
105017
105086
  release(model) {
@@ -105430,7 +105499,7 @@ function unregisterManagerForCleanup(manager) {
105430
105499
  }
105431
105500
 
105432
105501
  // src/features/background-agent/compaction-aware-message-resolver.ts
105433
- import { readdirSync as readdirSync25, readFileSync as readFileSync58 } from "fs";
105502
+ import { readdirSync as readdirSync25, readFileSync as readFileSync59 } from "fs";
105434
105503
  import { join as join94 } from "path";
105435
105504
  function hasFullAgentAndModel(message) {
105436
105505
  return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
@@ -105510,7 +105579,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
105510
105579
  const messages = [];
105511
105580
  for (const file of files) {
105512
105581
  try {
105513
- const content = readFileSync58(join94(messageDir, file), "utf-8");
105582
+ const content = readFileSync59(join94(messageDir, file), "utf-8");
105514
105583
  const parsed = JSON.parse(content);
105515
105584
  if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
105516
105585
  continue;
@@ -107590,7 +107659,7 @@ ${originalText}`;
107590
107659
  }
107591
107660
  }
107592
107661
  // src/features/mcp-oauth/storage.ts
107593
- import { chmodSync as chmodSync2, existsSync as existsSync85, mkdirSync as mkdirSync18, readFileSync as readFileSync59, renameSync as renameSync6, unlinkSync as unlinkSync14, writeFileSync as writeFileSync22 } from "fs";
107662
+ import { chmodSync as chmodSync2, existsSync as existsSync85, mkdirSync as mkdirSync18, readFileSync as readFileSync60, renameSync as renameSync6, unlinkSync as unlinkSync14, writeFileSync as writeFileSync23 } from "fs";
107594
107663
  import { dirname as dirname30, join as join96 } from "path";
107595
107664
  var STORAGE_FILE_NAME = "mcp-oauth.json";
107596
107665
  function getMcpOauthStoragePath() {
@@ -107635,7 +107704,7 @@ function readStore() {
107635
107704
  return null;
107636
107705
  }
107637
107706
  try {
107638
- const content = readFileSync59(filePath, "utf-8");
107707
+ const content = readFileSync60(filePath, "utf-8");
107639
107708
  return JSON.parse(content);
107640
107709
  } catch {
107641
107710
  return null;
@@ -107649,7 +107718,7 @@ function writeStore(store2) {
107649
107718
  mkdirSync18(dir, { recursive: true });
107650
107719
  }
107651
107720
  const tempPath = `${filePath}.tmp.${Date.now()}`;
107652
- writeFileSync22(tempPath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
107721
+ writeFileSync23(tempPath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
107653
107722
  chmodSync2(tempPath, 384);
107654
107723
  renameSync6(tempPath, filePath);
107655
107724
  return true;
@@ -114670,13 +114739,13 @@ import { dirname as dirname32, join as join99 } from "path";
114670
114739
  import {
114671
114740
  existsSync as existsSync86,
114672
114741
  mkdirSync as mkdirSync19,
114673
- readFileSync as readFileSync60,
114674
- writeFileSync as writeFileSync23,
114742
+ readFileSync as readFileSync61,
114743
+ writeFileSync as writeFileSync24,
114675
114744
  openSync as openSync3,
114676
114745
  closeSync as closeSync3,
114677
114746
  writeSync,
114678
114747
  unlinkSync as unlinkSync15,
114679
- statSync as statSync12,
114748
+ statSync as statSync13,
114680
114749
  constants as constants21
114681
114750
  } from "fs";
114682
114751
  import { join as join97, dirname as dirname31 } from "path";
@@ -114713,7 +114782,7 @@ function readLockSnapshot() {
114713
114782
  try {
114714
114783
  if (!existsSync86(REGISTRY_LOCK_PATH))
114715
114784
  return null;
114716
- const raw = readFileSync60(REGISTRY_LOCK_PATH, "utf-8");
114785
+ const raw = readFileSync61(REGISTRY_LOCK_PATH, "utf-8");
114717
114786
  const trimmed = raw.trim();
114718
114787
  if (!trimmed)
114719
114788
  return { raw, pid: null, token: null };
@@ -114739,7 +114808,7 @@ function removeLockIfUnchanged(snapshot) {
114739
114808
  try {
114740
114809
  if (!existsSync86(REGISTRY_LOCK_PATH))
114741
114810
  return false;
114742
- const currentRaw = readFileSync60(REGISTRY_LOCK_PATH, "utf-8");
114811
+ const currentRaw = readFileSync61(REGISTRY_LOCK_PATH, "utf-8");
114743
114812
  if (currentRaw !== snapshot.raw)
114744
114813
  return false;
114745
114814
  unlinkSync15(REGISTRY_LOCK_PATH);
@@ -114777,7 +114846,7 @@ function acquireRegistryLock() {
114777
114846
  if (err.code !== "EEXIST")
114778
114847
  throw error;
114779
114848
  try {
114780
- const stats = statSync12(REGISTRY_LOCK_PATH);
114849
+ const stats = statSync13(REGISTRY_LOCK_PATH);
114781
114850
  const lockAgeMs = Date.now() - stats.mtimeMs;
114782
114851
  if (lockAgeMs > LOCK_STALE_MS) {
114783
114852
  const snapshot = readLockSnapshot();
@@ -114846,7 +114915,7 @@ function readAllMappingsUnsafe() {
114846
114915
  if (!existsSync86(REGISTRY_PATH))
114847
114916
  return [];
114848
114917
  try {
114849
- const content = readFileSync60(REGISTRY_PATH, "utf-8");
114918
+ const content = readFileSync61(REGISTRY_PATH, "utf-8");
114850
114919
  return content.split(`
114851
114920
  `).filter((line) => line.trim()).map((line) => {
114852
114921
  try {
@@ -114862,13 +114931,13 @@ function readAllMappingsUnsafe() {
114862
114931
  function rewriteRegistryUnsafe(mappings) {
114863
114932
  ensureRegistryDir();
114864
114933
  if (mappings.length === 0) {
114865
- writeFileSync23(REGISTRY_PATH, "", { mode: SECURE_FILE_MODE });
114934
+ writeFileSync24(REGISTRY_PATH, "", { mode: SECURE_FILE_MODE });
114866
114935
  return;
114867
114936
  }
114868
114937
  const content = mappings.map((m) => JSON.stringify(m)).join(`
114869
114938
  `) + `
114870
114939
  `;
114871
- writeFileSync23(REGISTRY_PATH, content, { mode: SECURE_FILE_MODE });
114940
+ writeFileSync24(REGISTRY_PATH, content, { mode: SECURE_FILE_MODE });
114872
114941
  }
114873
114942
  function registerMessage(mapping) {
114874
114943
  return withRegistryLockOrWait(() => {
@@ -114903,9 +114972,9 @@ import {
114903
114972
  chmodSync as chmodSync3,
114904
114973
  existsSync as existsSync88,
114905
114974
  renameSync as renameSync7,
114906
- statSync as statSync13,
114975
+ statSync as statSync14,
114907
114976
  unlinkSync as unlinkSync16,
114908
- writeFileSync as writeFileSync24
114977
+ writeFileSync as writeFileSync25
114909
114978
  } from "fs";
114910
114979
 
114911
114980
  // src/openclaw/reply-listener-paths.ts
@@ -114942,7 +115011,7 @@ function ensureReplyListenerStateDir() {
114942
115011
  var MAX_REPLY_LISTENER_LOG_SIZE_BYTES = 1024 * 1024;
114943
115012
  function writeSecureReplyListenerFile(filePath, content) {
114944
115013
  ensureReplyListenerStateDir();
114945
- writeFileSync24(filePath, content, { mode: REPLY_LISTENER_SECURE_FILE_MODE });
115014
+ writeFileSync25(filePath, content, { mode: REPLY_LISTENER_SECURE_FILE_MODE });
114946
115015
  try {
114947
115016
  chmodSync3(filePath, REPLY_LISTENER_SECURE_FILE_MODE);
114948
115017
  } catch {}
@@ -114951,7 +115020,7 @@ function rotateReplyListenerLogIfNeeded(logPath) {
114951
115020
  try {
114952
115021
  if (!existsSync88(logPath))
114953
115022
  return;
114954
- const stats = statSync13(logPath);
115023
+ const stats = statSync14(logPath);
114955
115024
  if (stats.size <= MAX_REPLY_LISTENER_LOG_SIZE_BYTES)
114956
115025
  return;
114957
115026
  const backupPath = `${logPath}.old`;
@@ -114996,7 +115065,7 @@ class ReplyListenerRateLimiter {
114996
115065
  }
114997
115066
 
114998
115067
  // src/openclaw/reply-listener-state.ts
114999
- import { existsSync as existsSync89, readFileSync as readFileSync61, unlinkSync as unlinkSync17 } from "fs";
115068
+ import { existsSync as existsSync89, readFileSync as readFileSync62, unlinkSync as unlinkSync17 } from "fs";
115000
115069
  var REPLY_LISTENER_STARTUP_TOKEN_ENV = "OMO_OPENCLAW_REPLY_LISTENER_STARTUP_TOKEN";
115001
115070
  function createDefaultReplyListenerState() {
115002
115071
  return {
@@ -115060,7 +115129,7 @@ function readReplyListenerDaemonState() {
115060
115129
  const stateFilePath = getReplyListenerStateFilePath();
115061
115130
  if (!existsSync89(stateFilePath))
115062
115131
  return null;
115063
- return normalizeReplyListenerState(JSON.parse(readFileSync61(stateFilePath, "utf-8")));
115132
+ return normalizeReplyListenerState(JSON.parse(readFileSync62(stateFilePath, "utf-8")));
115064
115133
  } catch {
115065
115134
  return null;
115066
115135
  }
@@ -115077,7 +115146,7 @@ function readReplyListenerDaemonConfig() {
115077
115146
  const configFilePath = getReplyListenerConfigFilePath();
115078
115147
  if (!existsSync89(configFilePath))
115079
115148
  return null;
115080
- return JSON.parse(readFileSync61(configFilePath, "utf-8"));
115149
+ return JSON.parse(readFileSync62(configFilePath, "utf-8"));
115081
115150
  } catch {
115082
115151
  return null;
115083
115152
  }
@@ -115090,7 +115159,7 @@ function readReplyListenerPid() {
115090
115159
  const pidFilePath = getReplyListenerPidFilePath();
115091
115160
  if (!existsSync89(pidFilePath))
115092
115161
  return null;
115093
- const pid = Number.parseInt(readFileSync61(pidFilePath, "utf-8").trim(), 10);
115162
+ const pid = Number.parseInt(readFileSync62(pidFilePath, "utf-8").trim(), 10);
115094
115163
  return Number.isNaN(pid) ? null : pid;
115095
115164
  } catch {
115096
115165
  return null;
@@ -115117,7 +115186,7 @@ function markReplyListenerStopped(state3, error) {
115117
115186
  }
115118
115187
 
115119
115188
  // src/openclaw/reply-listener-process.ts
115120
- import { readFileSync as readFileSync62 } from "fs";
115189
+ import { readFileSync as readFileSync63 } from "fs";
115121
115190
  var {spawn: spawn25 } = globalThis.Bun;
115122
115191
  var REPLY_LISTENER_DAEMON_IDENTITY_MARKER = "--openclaw-reply-listener-daemon";
115123
115192
  var REPLY_LISTENER_DAEMON_ENV_ALLOWLIST = [
@@ -115173,7 +115242,7 @@ function isReplyListenerProcessRunning(pid) {
115173
115242
  async function isReplyListenerDaemonProcess(pid) {
115174
115243
  try {
115175
115244
  if (process.platform === "linux") {
115176
- const cmdline = readFileSync62(`/proc/${pid}/cmdline`, "utf-8");
115245
+ const cmdline = readFileSync63(`/proc/${pid}/cmdline`, "utf-8");
115177
115246
  return cmdline.includes(REPLY_LISTENER_DAEMON_IDENTITY_MARKER);
115178
115247
  }
115179
115248
  const processInfo = spawn25(["ps", "-p", String(pid), "-o", "args="], {
@@ -115606,7 +115675,7 @@ async function dispatchOpenClawEvent(params) {
115606
115675
  return result;
115607
115676
  }
115608
115677
  // src/features/claude-code-mcp-loader/loader.ts
115609
- import { existsSync as existsSync90, readFileSync as readFileSync63 } from "fs";
115678
+ import { existsSync as existsSync90, readFileSync as readFileSync64 } from "fs";
115610
115679
  import { join as join100 } from "path";
115611
115680
  import { homedir as homedir18 } from "os";
115612
115681
  init_logger();
@@ -115640,7 +115709,7 @@ function getSystemMcpServerNames() {
115640
115709
  if (!existsSync90(path15))
115641
115710
  continue;
115642
115711
  try {
115643
- const content = readFileSync63(path15, "utf-8");
115712
+ const content = readFileSync64(path15, "utf-8");
115644
115713
  const config2 = JSON.parse(content);
115645
115714
  if (!config2?.mcpServers)
115646
115715
  continue;
@@ -117077,7 +117146,7 @@ Should I proceed with [recommendation], or would you prefer differently?
117077
117146
  }
117078
117147
 
117079
117148
  // src/agents/load-prompt-template.ts
117080
- import { existsSync as existsSync91, readFileSync as readFileSync64 } from "fs";
117149
+ import { existsSync as existsSync91, readFileSync as readFileSync65 } from "fs";
117081
117150
  import { join as join101 } from "path";
117082
117151
  import { fileURLToPath as fileURLToPath5 } from "url";
117083
117152
  function loadPromptTemplate(language, agentName) {
@@ -117091,7 +117160,7 @@ function loadPromptTemplate(language, agentName) {
117091
117160
  ];
117092
117161
  for (const candidate of candidates) {
117093
117162
  if (existsSync91(candidate)) {
117094
- return readFileSync64(candidate, "utf-8");
117163
+ return readFileSync65(candidate, "utf-8");
117095
117164
  }
117096
117165
  }
117097
117166
  console.warn(`[loadPromptTemplate] Chinese template not found: ${agentName}`);
@@ -121321,7 +121390,7 @@ function createHephaestusAgent2(model, availableAgents, availableToolNames, avai
121321
121390
  }
121322
121391
  createHephaestusAgent2.mode = MODE10;
121323
121392
  // src/agents/builtin-agents/resolve-file-uri.ts
121324
- import { existsSync as existsSync92, readFileSync as readFileSync65 } from "fs";
121393
+ import { existsSync as existsSync92, readFileSync as readFileSync66 } from "fs";
121325
121394
  import { homedir as homedir19 } from "os";
121326
121395
  import { isAbsolute as isAbsolute13, resolve as resolve21 } from "path";
121327
121396
  init_logger();
@@ -121350,7 +121419,7 @@ function resolvePromptAppend(promptAppend, configDir) {
121350
121419
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
121351
121420
  }
121352
121421
  try {
121353
- return readFileSync65(filePath, "utf8");
121422
+ return readFileSync66(filePath, "utf8");
121354
121423
  } catch {
121355
121424
  return `[WARNING: Could not read file: ${promptAppend}]`;
121356
121425
  }
@@ -122104,7 +122173,12 @@ function createSisyphusJuniorAgentWithOverrides(override, systemDefaultModel, us
122104
122173
  const model = overrideModel ?? systemDefaultModel ?? SISYPHUS_JUNIOR_DEFAULTS.model;
122105
122174
  const temperature = override?.temperature ?? SISYPHUS_JUNIOR_DEFAULTS.temperature;
122106
122175
  const promptAppend = override?.prompt_append;
122107
- const prompt = buildSisyphusJuniorPrompt(model, useTaskSystem, promptAppend);
122176
+ const isZh = language?.startsWith("zh");
122177
+ let prompt = buildSisyphusJuniorPrompt(model, useTaskSystem, promptAppend);
122178
+ if (isZh) {
122179
+ const zhPrompt = loadPromptTemplate("zh", "sisyphus-junior");
122180
+ prompt = zhPrompt ?? prompt;
122181
+ }
122108
122182
  const blockedTools = isGptModel(model) ? GPT_BLOCKED_TOOLS : BLOCKED_TOOLS3;
122109
122183
  const baseRestrictions = createAgentToolRestrictions(blockedTools);
122110
122184
  const userPermission = override?.permission ?? {};
@@ -122350,6 +122424,13 @@ function collectPendingBuiltinAgents(input) {
122350
122424
  if (resolvedVariant) {
122351
122425
  config2 = { ...config2, variant: resolvedVariant };
122352
122426
  }
122427
+ const isZh = language?.startsWith("zh");
122428
+ if (isZh) {
122429
+ const zhPrompt = loadPromptTemplate("zh", agentName);
122430
+ if (zhPrompt) {
122431
+ config2 = { ...config2, prompt: zhPrompt };
122432
+ }
122433
+ }
122353
122434
  if (["librarian", "oracle", "momus", "explore", "metis", "multimodal-looker"].includes(agentName)) {
122354
122435
  config2 = applyEnvironmentContext(config2, directory, { disableOmoEnv, language: override?.language ?? language });
122355
122436
  }
@@ -124859,7 +124940,12 @@ function getPrometheusPromptSource(model) {
124859
124940
  }
124860
124941
  return "default";
124861
124942
  }
124862
- function getPrometheusPrompt(model, disabledTools) {
124943
+ function getPrometheusPrompt(model, disabledTools, language) {
124944
+ if (language?.startsWith("zh")) {
124945
+ const zhPrompt = loadPromptTemplate("zh", "prometheus");
124946
+ if (zhPrompt)
124947
+ return zhPrompt;
124948
+ }
124863
124949
  const source = getPrometheusPromptSource(model);
124864
124950
  const isQuestionDisabled = disabledTools?.includes("question") ?? false;
124865
124951
  let prompt;
@@ -124931,7 +125017,7 @@ async function buildPrometheusAgentConfig(params) {
124931
125017
  ...resolvedModel ? { model: resolvedModel } : {},
124932
125018
  ...variantToUse ? { variant: variantToUse } : {},
124933
125019
  mode: "primary",
124934
- prompt: getPrometheusPrompt(resolvedModel, params.disabledTools),
125020
+ prompt: getPrometheusPrompt(resolvedModel, params.disabledTools, params.language),
124935
125021
  permission: PROMETHEUS_PERMISSION,
124936
125022
  description: `${params.configAgentPlan?.description ?? "Plan agent"} (Prometheus - OhMyOpenCode)`,
124937
125023
  color: params.configAgentPlan?.color ?? "#FF5722",
@@ -127067,6 +127153,7 @@ function createEventHandler2(args) {
127067
127153
  await runEventHookSafely("writeExistingFileGuard", hooks2.writeExistingFileGuard?.event, input);
127068
127154
  await runEventHookSafely("atlasHook", hooks2.atlasHook?.handler, input);
127069
127155
  await runEventHookSafely("autoSlashCommand", hooks2.autoSlashCommand?.event, input);
127156
+ await runEventHookSafely("toolOutputTruncator", hooks2.toolOutputTruncator?.event, input);
127070
127157
  };
127071
127158
  const recentSyntheticIdles = new Map;
127072
127159
  const recentRealIdles = new Map;
@@ -127501,21 +127588,28 @@ function createToolExecuteAfterHandler3(args) {
127501
127588
  await hooks2.preemptiveCompaction?.["tool.execute.after"]?.(hookInput, output);
127502
127589
  await hooks2.contextWindowMonitor?.["tool.execute.after"]?.(hookInput, output);
127503
127590
  await hooks2.commentChecker?.["tool.execute.after"]?.(hookInput, output);
127504
- await hooks2.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output);
127505
- await hooks2.directoryReadmeInjector?.["tool.execute.after"]?.(hookInput, output);
127591
+ const phase2Results = await Promise.allSettled([
127592
+ hooks2.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output),
127593
+ hooks2.directoryReadmeInjector?.["tool.execute.after"]?.(hookInput, output),
127594
+ hooks2.agentUsageReminder?.["tool.execute.after"]?.(hookInput, output),
127595
+ hooks2.categorySkillReminder?.["tool.execute.after"]?.(hookInput, output),
127596
+ hooks2.interactiveBashSession?.["tool.execute.after"]?.(hookInput, output),
127597
+ hooks2.editErrorRecovery?.["tool.execute.after"]?.(hookInput, output),
127598
+ hooks2.delegateTaskRetry?.["tool.execute.after"]?.(hookInput, output),
127599
+ hooks2.atlasHook?.["tool.execute.after"]?.(hookInput, output),
127600
+ hooks2.taskResumeInfo?.["tool.execute.after"]?.(hookInput, output),
127601
+ hooks2.readImageResizer?.["tool.execute.after"]?.(hookInput, output),
127602
+ hooks2.webfetchRedirectGuard?.["tool.execute.after"]?.(hookInput, output),
127603
+ hooks2.jsonErrorRecovery?.["tool.execute.after"]?.(hookInput, output)
127604
+ ]);
127605
+ for (const result of phase2Results) {
127606
+ if (result.status === "rejected") {
127607
+ log("[tool-execute-after] Parallel hook failed", { error: result.reason });
127608
+ }
127609
+ }
127506
127610
  await hooks2.rulesInjector?.["tool.execute.after"]?.(hookInput, output);
127507
127611
  await hooks2.emptyTaskResponseDetector?.["tool.execute.after"]?.(hookInput, output);
127508
- await hooks2.agentUsageReminder?.["tool.execute.after"]?.(hookInput, output);
127509
- await hooks2.categorySkillReminder?.["tool.execute.after"]?.(hookInput, output);
127510
- await hooks2.interactiveBashSession?.["tool.execute.after"]?.(hookInput, output);
127511
- await hooks2.editErrorRecovery?.["tool.execute.after"]?.(hookInput, output);
127512
- await hooks2.delegateTaskRetry?.["tool.execute.after"]?.(hookInput, output);
127513
- await hooks2.atlasHook?.["tool.execute.after"]?.(hookInput, output);
127514
- await hooks2.taskResumeInfo?.["tool.execute.after"]?.(hookInput, output);
127515
- await hooks2.readImageResizer?.["tool.execute.after"]?.(hookInput, output);
127516
127612
  await hooks2.hashlineReadEnhancer?.["tool.execute.after"]?.(hookInput, output);
127517
- await hooks2.webfetchRedirectGuard?.["tool.execute.after"]?.(hookInput, output);
127518
- await hooks2.jsonErrorRecovery?.["tool.execute.after"]?.(hookInput, output);
127519
127613
  };
127520
127614
  if (input.tool === "extract" || input.tool === "discard") {
127521
127615
  const originalOutput = {
@@ -132468,7 +132562,7 @@ class PostHog extends PostHogBackendClient {
132468
132562
  // package.json
132469
132563
  var package_default = {
132470
132564
  name: "@skj1724/oh-my-opencode",
132471
- version: "3.18.26",
132565
+ version: "3.18.27",
132472
132566
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
132473
132567
  main: "./dist/index.js",
132474
132568
  types: "dist/index.d.ts",
@@ -132529,6 +132623,7 @@ var package_default = {
132529
132623
  diff: "^8.0.3",
132530
132624
  "js-yaml": "^4.1.1",
132531
132625
  "jsonc-parser": "^3.3.1",
132626
+ "memory-boat": "^0.0.1",
132532
132627
  picocolors: "^1.1.1",
132533
132628
  picomatch: "^4.0.4",
132534
132629
  "posthog-node": "5.28.11",
@@ -132569,7 +132664,7 @@ var package_default = {
132569
132664
  init_plugin_identity();
132570
132665
 
132571
132666
  // src/shared/posthog-activity-state.ts
132572
- import { existsSync as existsSync95, mkdirSync as mkdirSync21, readFileSync as readFileSync67 } from "fs";
132667
+ import { existsSync as existsSync95, mkdirSync as mkdirSync21, readFileSync as readFileSync68 } from "fs";
132573
132668
  import { join as join105 } from "path";
132574
132669
  init_logger();
132575
132670
  init_plugin_identity();
@@ -132592,7 +132687,7 @@ function readPostHogActivityState() {
132592
132687
  return {};
132593
132688
  }
132594
132689
  try {
132595
- const content = readFileSync67(stateFilePath, "utf-8");
132690
+ const content = readFileSync68(stateFilePath, "utf-8");
132596
132691
  const parsed = JSON.parse(content);
132597
132692
  if (!isPostHogActivityState(parsed)) {
132598
132693
  return {};