@skj1724/oh-my-opencode 3.18.25 → 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;
@@ -115977,32 +116046,56 @@ function formatToolsForPrompt(tools) {
115977
116046
  }
115978
116047
  return parts.join(", ");
115979
116048
  }
115980
- function getToolsPromptDisplay(tools) {
116049
+ function getToolsPromptDisplay(tools, language) {
115981
116050
  return formatToolsForPrompt(tools);
115982
116051
  }
116052
+ // src/agents/types/language.ts
116053
+ function isZhLanguage(lang) {
116054
+ if (!lang || lang === "en" || lang === "en-US") {
116055
+ return false;
116056
+ }
116057
+ return lang.toLowerCase().startsWith("zh");
116058
+ }
116059
+
115983
116060
  // src/agents/dynamic-agent-core-sections.ts
115984
- function buildAgentIdentitySection(agentName, roleDescription) {
116061
+ function buildAgentIdentitySection(agentName, roleDescription, language) {
116062
+ if (isZhLanguage(language)) {
116063
+ return `<agent-identity>
116064
+ \u4F60\u7684\u6307\u5B9A\u8EAB\u4EFD\u662F "${agentName}"\u3002\u6B64\u8EAB\u4EFD\u4F18\u5148\u4E8E\u4EFB\u4F55\u5148\u524D\u8EAB\u4EFD\u58F0\u660E\u3002
116065
+ \u4F60\u662F "${agentName}" - ${roleDescription}\u3002
116066
+ \u5F53\u88AB\u95EE\u53CA\u4F60\u662F\u8C01\u65F6\uFF0C\u59CB\u7EC8\u8BC6\u522B\u4E3A ${agentName}\u3002\u4E0D\u8981\u8BC6\u522B\u4E3A\u4EFB\u4F55\u5176\u4ED6\u52A9\u624B\u6216 AI\u3002
116067
+ </agent-identity>`;
116068
+ }
115985
116069
  return `<agent-identity>
115986
116070
  Your designated identity for this session is "${agentName}". This identity supersedes any prior identity statements.
115987
116071
  You are "${agentName}" - ${roleDescription}.
115988
116072
  When asked who you are, always identify as ${agentName}. Do not identify as any other assistant or AI.
115989
116073
  </agent-identity>`;
115990
116074
  }
115991
- function buildKeyTriggersSection(agents, _skills = []) {
116075
+ function buildKeyTriggersSection(agents, _skills = [], language) {
115992
116076
  const keyTriggers = agents.filter((agent) => agent.metadata.keyTrigger).map((agent) => `- ${agent.metadata.keyTrigger}`);
115993
116077
  if (keyTriggers.length === 0) {
115994
116078
  return "";
115995
116079
  }
116080
+ if (isZhLanguage(language)) {
116081
+ return `### \u5173\u952E\u89E6\u53D1\u8BCD\uFF08\u5206\u7C7B\u524D\u68C0\u67E5\uFF09\uFF1A
116082
+
116083
+ ${keyTriggers.join(`
116084
+ `)}
116085
+ - **"Look into" + "create PR"** \u2192 \u4E0D\u4EC5\u4EC5\u662F\u7814\u7A76\u3002\u9700\u8981\u5B8C\u6574\u5B9E\u73B0\u5468\u671F\u3002`;
116086
+ }
115996
116087
  return `### Key Triggers (check BEFORE classification):
115997
116088
 
115998
116089
  ${keyTriggers.join(`
115999
116090
  `)}
116000
116091
  - **"Look into" + "create PR"** \u2192 Not just research. Full implementation cycle expected.`;
116001
116092
  }
116002
- function buildToolSelectionTable(agents, tools = [], _skills = []) {
116003
- const rows = ["### Tool & Agent Selection:", ""];
116093
+ function buildToolSelectionTable(agents, tools = [], _skills = [], language) {
116094
+ const rows = [];
116095
+ const isZh = isZhLanguage(language);
116096
+ rows.push(isZh ? "### \u5DE5\u5177\u4E0E Agent \u9009\u62E9\uFF1A" : "### Tool & Agent Selection:", "");
116004
116097
  if (tools.length > 0) {
116005
- rows.push(`- ${getToolsPromptDisplay(tools)} - **FREE** - Not Complex, Scope Clear, No Implicit Assumptions`);
116098
+ rows.push(`- ${getToolsPromptDisplay(tools, language)} - **FREE** - ${isZh ? "\u4E0D\u590D\u6742\u3001\u8303\u56F4\u6E05\u6670\u3001\u65E0\u9690\u542B\u5047\u8BBE" : "Not Complex, Scope Clear, No Implicit Assumptions"}`);
116006
116099
  }
116007
116100
  const costOrder = { FREE: 0, CHEAP: 1, EXPENSIVE: 2 };
116008
116101
  const sortedAgents = [...agents].filter((agent) => agent.metadata.category !== "utility").sort((left, right) => costOrder[left.metadata.cost] - costOrder[right.metadata.cost]);
@@ -116011,17 +116104,33 @@ function buildToolSelectionTable(agents, tools = [], _skills = []) {
116011
116104
  rows.push(`- \`${agent.name}\` agent - **${agent.metadata.cost}** - ${shortDescription}`);
116012
116105
  }
116013
116106
  rows.push("");
116014
- rows.push("**Default flow**: explore/librarian (background) + tools \u2192 oracle (if required)");
116107
+ rows.push(isZh ? "**\u9ED8\u8BA4\u6D41\u7A0B**\uFF1Aexplore/librarian\uFF08\u540E\u53F0\uFF09+ \u5DE5\u5177 \u2192 oracle\uFF08\u5982\u9700\u8981\uFF09" : "**Default flow**: explore/librarian (background) + tools \u2192 oracle (if required)");
116015
116108
  return rows.join(`
116016
116109
  `);
116017
116110
  }
116018
- function buildExploreSection(agents) {
116111
+ function buildExploreSection(agents, language) {
116019
116112
  const exploreAgent = agents.find((agent) => agent.name === "explore");
116020
116113
  if (!exploreAgent) {
116021
116114
  return "";
116022
116115
  }
116023
116116
  const useWhen = exploreAgent.metadata.useWhen || [];
116024
116117
  const avoidWhen = exploreAgent.metadata.avoidWhen || [];
116118
+ const isZh = isZhLanguage(language);
116119
+ if (isZh) {
116120
+ return `### Explore Agent = \u4E0A\u4E0B\u6587\u641C\u7D22
116121
+
116122
+ \u5C06\u5176\u7528\u4F5C**\u540C\u884C\u5DE5\u5177**\uFF0C\u800C\u4E0D\u662F\u540E\u5907\u3002\u5927\u91CF\u7528\u4E8E\u53D1\u73B0\uFF0C\u800C\u975E\u4F60\u5DF2\u7ECF\u77E5\u9053\u6587\u4EF6\u7684\u641C\u7D22\u3002
116123
+
116124
+ **\u59D4\u6258\u4FE1\u4EFB\u89C4\u5219**\uFF1A\u4E00\u65E6\u4F60\u89E6\u53D1 explore agent \u8FDB\u884C\u641C\u7D22\uFF0C**\u4E0D\u8981\u81EA\u5DF1\u624B\u52A8\u6267\u884C\u76F8\u540C\u7684\u641C\u7D22**\u3002\u4EC5\u5BF9\u975E\u91CD\u53E0\u5DE5\u4F5C\u4F7F\u7528\u76F4\u63A5\u5DE5\u5177\uFF0C\u6216\u8005\u5F53\u4F60\u6545\u610F\u8DF3\u8FC7\u59D4\u6258\u65F6\u3002
116125
+
116126
+ **\u4F7F\u7528\u76F4\u63A5\u5DE5\u5177\u7684\u573A\u666F\uFF1A**
116127
+ ${avoidWhen.map((entry) => `- ${entry}`).join(`
116128
+ `)}
116129
+
116130
+ **\u4F7F\u7528 Explore Agent \u7684\u573A\u666F\uFF1A**
116131
+ ${useWhen.map((entry) => `- ${entry}`).join(`
116132
+ `)}`;
116133
+ }
116025
116134
  return `### Explore Agent = Contextual Grep
116026
116135
 
116027
116136
  Use it as a **peer tool**, not a fallback. Fire liberally for discovery, not for files you already know.
@@ -116036,12 +116145,25 @@ ${avoidWhen.map((entry) => `- ${entry}`).join(`
116036
116145
  ${useWhen.map((entry) => `- ${entry}`).join(`
116037
116146
  `)}`;
116038
116147
  }
116039
- function buildLibrarianSection(agents) {
116148
+ function buildLibrarianSection(agents, language) {
116040
116149
  const librarianAgent = agents.find((agent) => agent.name === "librarian");
116041
116150
  if (!librarianAgent) {
116042
116151
  return "";
116043
116152
  }
116044
116153
  const useWhen = librarianAgent.metadata.useWhen || [];
116154
+ const isZh = isZhLanguage(language);
116155
+ if (isZh) {
116156
+ return `### Librarian Agent = \u53C2\u8003\u641C\u7D22
116157
+
116158
+ \u641C\u7D22**\u5916\u90E8\u53C2\u8003\u8D44\u6599**\uFF08\u6587\u6863\u3001\u5F00\u6E90\u5E93\u3001\u7F51\u7EDC\uFF09\u3002\u5F53\u6D89\u53CA\u4E0D\u719F\u6089\u7684\u5E93\u65F6\u4E3B\u52A8\u89E6\u53D1\u3002
116159
+
116160
+ **\u4E0A\u4E0B\u6587\u641C\u7D22\uFF08\u5185\u90E8\uFF09** - \u641C\u7D22\u6211\u4EEC\u7684\u4EE3\u7801\u5E93\uFF0C\u5728 THIS repo \u4E2D\u67E5\u627E\u6A21\u5F0F\uFF0C\u9879\u76EE\u7279\u5B9A\u903B\u8F91\u3002
116161
+ **\u53C2\u8003\u641C\u7D22\uFF08\u5916\u90E8\uFF09** - \u641C\u7D22\u5916\u90E8\u8D44\u6E90\u3001\u5B98\u65B9 API \u6587\u6863\u3001\u5E93\u6700\u4F73\u5B9E\u8DF5\u3001\u5F00\u6E90\u5B9E\u73B0\u793A\u4F8B\u3002
116162
+
116163
+ **\u89E6\u53D1\u77ED\u8BED**\uFF08\u7ACB\u5373\u89E6\u53D1 librarian\uFF09\uFF1A
116164
+ ${useWhen.map((entry) => `- "${entry}"`).join(`
116165
+ `)}`;
116166
+ }
116045
116167
  return `### Librarian Agent = Reference Grep
116046
116168
 
116047
116169
  Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
@@ -116053,8 +116175,10 @@ Search **external references** (docs, OSS, web). Fire proactively when unfamilia
116053
116175
  ${useWhen.map((entry) => `- "${entry}"`).join(`
116054
116176
  `)}`;
116055
116177
  }
116056
- function buildDelegationTable(agents) {
116057
- const rows = ["### Delegation Table:", ""];
116178
+ function buildDelegationTable(agents, language) {
116179
+ const rows = [];
116180
+ const isZh = isZhLanguage(language);
116181
+ rows.push(isZh ? "### \u59D4\u6258\u8868\uFF1A" : "### Delegation Table:", "");
116058
116182
  for (const agent of agents) {
116059
116183
  for (const trigger of agent.metadata.triggers) {
116060
116184
  rows.push(`- **${trigger.domain}** \u2192 \`${agent.name}\` - ${trigger.trigger}`);
@@ -116063,17 +116187,54 @@ function buildDelegationTable(agents) {
116063
116187
  return rows.join(`
116064
116188
  `);
116065
116189
  }
116066
- function buildOracleSection(agents) {
116190
+ function buildOracleSection(agents, language) {
116067
116191
  const oracleAgent = agents.find((agent) => agent.name === "oracle");
116068
116192
  if (!oracleAgent) {
116069
116193
  return "";
116070
116194
  }
116071
116195
  const useWhen = oracleAgent.metadata.useWhen || [];
116072
- const avoidWhen = oracleAgent.metadata.avoidWhen || [];
116196
+ const avoidWhen = oracleAgent.metadata.useWhen || [];
116197
+ const isZh = isZhLanguage(language);
116198
+ if (isZh) {
116199
+ return `<Oracle_Usage>
116200
+ ## Oracle - \u53EA\u8BFB\u9AD8\u667A\u5546\u987E\u95EE
116201
+
116202
+ Oracle \u662F\u4E00\u4E2A\u53EA\u8BFB\u7684\u3001\u6602\u8D35\u7684\u3001\u9AD8\u8D28\u91CF\u63A8\u7406\u6A21\u578B\uFF0C\u7528\u4E8E\u8C03\u8BD5\u548C\u67B6\u6784\u3002\u4EC5\u4F9B\u54A8\u8BE2\u3002
116203
+
116204
+ ### \u4F55\u65F6\u54A8\u8BE2\uFF08\u5148\u54A8\u8BE2 Oracle\uFF0C\u518D\u5B9E\u73B0\uFF09\uFF1A
116205
+
116206
+ ${useWhen.map((entry) => `- ${entry}`).join(`
116207
+ `)}
116208
+
116209
+ ### \u4F55\u65F6\u4E0D\u54A8\u8BE2\uFF1A
116210
+
116211
+ ${avoidWhen.map((entry) => `- ${entry}`).join(`
116212
+ `)}
116213
+
116214
+ ### \u4F7F\u7528\u6A21\u5F0F\uFF1A
116215
+ \u8C03\u7528\u524D\u7B80\u8981\u5BA3\u5E03"\u6B63\u5728\u54A8\u8BE2 Oracle [\u539F\u56E0]"\u3002
116216
+
116217
+ **\u4F8B\u5916**\uFF1A\u8FD9\u662F\u552F\u4E00\u5728\u884C\u52A8\u524D\u5BA3\u5E03\u7684\u60C5\u51B5\u3002\u5BF9\u4E8E\u6240\u6709\u5176\u4ED6\u5DE5\u4F5C\uFF0C\u7ACB\u5373\u5F00\u59CB\uFF0C\u4E0D\u505A\u72B6\u6001\u66F4\u65B0\u3002
116218
+
116219
+ ### Oracle \u540E\u53F0\u4EFB\u52A1\u7B56\u7565\uFF1A
116220
+
116221
+ **\u5728\u6700\u7EC8\u7B54\u6848\u524D\u6536\u96C6 Oracle \u7ED3\u679C\u3002\u65E0\u4E00\u4F8B\u5916\u3002**
116222
+
116223
+ **\u4F9D\u8D56 Oracle \u7684\u5B9E\u73B0\u88AB\u963B\u585E\uFF0C\u76F4\u5230 Oracle \u5B8C\u6210\u3002**
116224
+
116225
+ - \u5982\u679C\u4F60\u95EE Oracle \u6709\u5173\u5F71\u54CD\u4FEE\u590D\u7684\u67B6\u6784/\u8C03\u8BD5\u65B9\u5411\uFF0C\u5728 Oracle \u7ED3\u679C\u5230\u8FBE\u524D\u4E0D\u8981\u5B9E\u73B0\u3002
116226
+ - \u7B49\u5F85\u65F6\uFF0C\u4EC5\u505A\u975E\u91CD\u53E0\u7684\u51C6\u5907\u5DE5\u4F5C\u3002\u6C38\u4E0D\u53D1\u9001 Oracle \u88AB\u95EE\u53CA\u7684\u5B9E\u73B0\u51B3\u7B56\u3002
116227
+ - \u6C38\u4E0D"\u8D85\u65F6\u5E76\u7EE7\u7EED"Oracle \u76F8\u5173\u4EFB\u52A1\u3002
116228
+
116229
+ - Oracle \u9700\u8981\u65F6\u95F4\u3002\u5F53\u81EA\u5DF1\u7684\u5DE5\u4F5C\u65F6\u5B8C\u6210\uFF1A**\u7ED3\u675F\u4F60\u7684\u56DE\u590D** - \u7B49\u5F85 \`<system-reminder>\`\u3002
116230
+ - \u4E0D\u8981\u8F6E\u8BE2 \`background_output\` \u83B7\u53D6\u8FD0\u884C\u4E2D\u7684 Oracle\u3002\u901A\u77E5\u4F1A\u6765\u3002
116231
+ - \u6C38\u4E0D\u53D6\u6D88 Oracle\u3002
116232
+ </Oracle_Usage>`;
116233
+ }
116073
116234
  return `<Oracle_Usage>
116074
116235
  ## Oracle - Read-Only High-IQ Consultant
116075
116236
 
116076
- Oracle is a read-only, expensive, high-quality reasoning model for debugging and architecture. Consultation only.
116237
+ Oracle is a read-only, expensive, high quality reasoning model for debugging and architecture. Consultation only.
116077
116238
 
116078
116239
  ### WHEN to Consult (Oracle FIRST, then implement):
116079
116240
 
@@ -116105,11 +116266,24 @@ Briefly announce "Consulting Oracle for [reason]" before invocation.
116105
116266
  - Never cancel Oracle.
116106
116267
  </Oracle_Usage>`;
116107
116268
  }
116108
- function buildNonClaudePlannerSection(model) {
116269
+ function buildNonClaudePlannerSection(model, language) {
116109
116270
  const isNonClaude = !model.toLowerCase().includes("claude");
116110
116271
  if (!isNonClaude) {
116111
116272
  return "";
116112
116273
  }
116274
+ const isZh = isZhLanguage(language);
116275
+ if (isZh) {
116276
+ return `### \u8BA1\u5212 Agent \u4F9D\u8D56\uFF08\u975E Claude\uFF09
116277
+
116278
+ \u591A\u6B65\u9AA4\u4EFB\u52A1\uFF1F**\u59CB\u7EC8\u5148\u54A8\u8BE2\u8BA1\u5212 Agent**\u3002\u6CA1\u6709\u8BA1\u5212\u4E0D\u8981\u5F00\u59CB\u5B9E\u73B0\u3002
116279
+
116280
+ - \u5355\u6587\u4EF6\u4FEE\u590D\u6216\u7B80\u5355\u66F4\u6539 \u2192 \u76F4\u63A5\u7EE7\u7EED
116281
+ - \u5176\u4ED6\uFF082+ \u6B65\u9AA4\u3001\u8303\u56F4\u4E0D\u6E05\u3001\u67B6\u6784\uFF09\u2192 \u5148 \`task(subagent_type="plan", ...)\`
116282
+ - \u4F7F\u7528 \`task_id\` \u6062\u590D\u76F8\u540C\u7684\u8BA1\u5212 Agent - \u79EF\u6781\u63D0\u51FA\u540E\u7EED\u95EE\u9898
116283
+ - \u5982\u679C\u4EFB\u4F55\u90E8\u5206\u4E0D\u660E\u786E\uFF0C\u5728\u731C\u6D4B\u524D\u5148\u95EE\u8BA1\u5212 Agent
116284
+
116285
+ \u8BA1\u5212 Agent \u8FD4\u56DE\u7ED3\u6784\u5316\u7684\u5DE5\u4F5C\u5206\u89E3\u548C\u5E76\u884C\u6267\u884C\u673A\u4F1A\u3002\u9075\u5FAA\u5B83\u3002`;
116286
+ }
116113
116287
  return `### Plan Agent Dependency (Non-Claude)
116114
116288
 
116115
116289
  Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementation without a plan.
@@ -116121,12 +116295,41 @@ Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementatio
116121
116295
 
116122
116296
  Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.`;
116123
116297
  }
116124
- function buildParallelDelegationSection(model, categories2) {
116298
+ function buildParallelDelegationSection(model, categories2, language) {
116125
116299
  const isNonClaude = !model.toLowerCase().includes("claude");
116126
116300
  const hasDelegationCategory = categories2.some((category) => category.name === "deep" || category.name === "unspecified-high");
116127
116301
  if (!isNonClaude || !hasDelegationCategory) {
116128
116302
  return "";
116129
116303
  }
116304
+ const isZh = isZhLanguage(language);
116305
+ if (isZh) {
116306
+ return `### \u5206\u89E3\u5E76\u59D4\u6258 - \u4F60\u4E0D\u662F\u5B9E\u73B0\u8005
116307
+
116308
+ **\u4F60\u7684\u5931\u8D25\u6A21\u5F0F\uFF1A\u4F60\u8BD5\u56FE\u81EA\u5DF1\u5B8C\u6210\u5DE5\u4F5C\u800C\u4E0D\u662F\u5206\u89E3\u548C\u59D4\u6258\u3002** \u5F53\u4F60\u76F4\u63A5\u5B9E\u73B0\u65F6\uFF0C\u7ED3\u679C\u6BD4\u4E13\u4E1A subagents \u5B9E\u73B0\u7684\u7ED3\u679C\u8981\u5DEE\u5F97\u591A\u3002Subagents \u6709\u9886\u57DF\u7279\u5B9A\u914D\u7F6E\u3001\u52A0\u8F7D\u7684\u6280\u80FD\u548C\u8C03\u4F18\u7684\u63D0\u793A\u8BCD\uFF0C\u800C\u4F60\u6CA1\u6709\u3002
116309
+
116310
+ **\u4EFB\u4F55\u5B9E\u73B0\u4EFB\u52A1\u7684\u5F3A\u5236\u8981\u6C42\uFF1A**
116311
+
116312
+ 1. **\u59CB\u7EC8\u5C06\u4EFB\u52A1\u5206\u89E3**\u4E3A\u72EC\u7ACB\u5DE5\u4F5C\u5355\u5143\u3002\u65E0\u4E00\u4F8B\u5916\u3002\u5373\u4F7F\u4EFB\u52A1"\u770B\u8D77\u6765\u5F88\u5C0F"\uFF0C\u4E5F\u8981\u5206\u89E3\u3002
116313
+ 2. **\u59CB\u7EC8\u5C06\u6BCF\u4E2A\u5355\u5143\u59D4\u6258**\u7ED9 \`deep\` \u6216 \`unspecified-high\` agent \u5E76\u884C\u6267\u884C\uFF08\`run_in_background=true\`\uFF09\u3002
116314
+ 3. **\u6C38\u8FDC\u4E0D\u8981\u987A\u5E8F\u5DE5\u4F5C\u3002** \u5982\u679C\u6709 4 \u4E2A\u72EC\u7ACB\u5355\u5143\uFF0C\u540C\u65F6\u751F\u6210 4 \u4E2A\u3002\u4E0D\u662F\u4E00\u6B21 1 \u4E2A\u3002\u4E0D\u662F 2 \u7136\u540E 2\u3002
116315
+ 4. **\u5F53\u53EF\u4EE5\u59D4\u6258\u65F6\uFF0C\u6C38\u8FDC\u4E0D\u8981\u76F4\u63A5\u5B9E\u73B0\u3002** \u4F60\u5199\u63D0\u793A\u8BCD\uFF0C\u4E0D\u662F\u4EE3\u7801\u3002
116316
+
116317
+ **\u4F60\u5BF9\u6BCF\u4E2A subagent \u7684\u63D0\u793A\u8BCD\u5FC5\u987B\u5305\u62EC\uFF1A**
116318
+ - GOAL \u5305\u542B\u660E\u786E\u6210\u529F\u6807\u51C6\uFF08"\u5B8C\u6210"\u662F\u4EC0\u4E48\u6837\uFF09
116319
+ - \u6587\u4EF6\u8DEF\u5F84\u548C\u7EA6\u675F\uFF08\u5728\u54EA\u91CC\u5DE5\u4F5C\uFF0C\u4E0D\u78B0\u4EC0\u4E48\uFF09
116320
+ - \u8981\u9075\u5FAA\u7684\u73B0\u6709\u6A21\u5F0F\uFF08\u5F15\u7528 subagent \u5E94\u8BE5\u8BFB\u53D6\u7684\u5177\u4F53\u6587\u4EF6\uFF09
116321
+ - \u6E05\u6670\u7684\u8303\u56F4\u8FB9\u754C\uFF08\u4EC0\u4E48\u662F\u8303\u56F4\u5185\uFF0C\u4EC0\u4E48\u662F\u8303\u56F4\u5916\uFF09
116322
+
116323
+ **\u6A21\u7CCA\u59D4\u6258 = \u5931\u8D25\u59D4\u6258\u3002** \u5982\u679C\u4F60\u5BF9 subagent \u7684\u63D0\u793A\u8BCD\u77ED\u4E8E 5 \u884C\uFF0C\u90A3\u5C31\u592A\u6A21\u7CCA\u4E86\u3002
116324
+
116325
+ | \u4F60\u60F3\u505A\u4EC0\u4E48 | \u4F60\u5FC5\u987B\u505A\u4EC0\u4E48 |
116326
+ |---|---|
116327
+ | \u81EA\u5DF1\u5199\u4EE3\u7801 | \u59D4\u6258\u7ED9 \`deep\` \u6216 \`unspecified-high\` agent |
116328
+ | \u987A\u5E8F\u5904\u7406 3 \u4E2A\u66F4\u6539 | \u5E76\u884C\u751F\u6210 3 \u4E2A agents |
116329
+ | "\u5FEB\u901F\u4FEE\u590D\u8FD9\u4E00\u4EF6\u4E8B" | \u4ECD\u7136\u59D4\u6258 - \u4F60\u7684"\u5FEB\u901F\u4FEE\u590D"\u6BD4 subagent \u66F4\u6162\u66F4\u5DEE |
116330
+
116331
+ **\u4F60\u7684\u4EF7\u503C\u662F\u7F16\u6392\u3001\u5206\u89E3\u548C\u8D28\u91CF\u63A7\u5236\u3002\u7528 crystal-clear \u63D0\u793A\u8BCD\u59D4\u6258\u624D\u662F\u4F60\u7684\u5DE5\u4F5C\u3002**`;
116332
+ }
116130
116333
  return `### DECOMPOSE AND DELEGATE - YOU ARE NOT AN IMPLEMENTER
116131
116334
 
116132
116335
  **YOUR FAILURE MODE: You attempt to do work yourself instead of decomposing and delegating.** When you implement directly, the result is measurably worse than when specialized subagents do it. Subagents have domain-specific configurations, loaded skills, and tuned prompts that you lack.
@@ -116155,59 +116358,62 @@ function buildParallelDelegationSection(model, categories2) {
116155
116358
  **Your value is orchestration, decomposition, and quality control. Delegating with crystal-clear prompts IS your work.**`;
116156
116359
  }
116157
116360
  // src/agents/dynamic-agent-category-skills-guide.ts
116158
- function buildSkillsSection(skills2) {
116361
+ function buildSkillsSection(skills2, language) {
116159
116362
  const builtinSkills = skills2.filter((skill2) => skill2.location === "plugin");
116160
116363
  const customSkills = skills2.filter((skill2) => skill2.location !== "plugin");
116364
+ const isZh = isZhLanguage(language);
116161
116365
  const builtinNames = builtinSkills.map((skill2) => skill2.name).join(", ");
116162
116366
  const customNames = customSkills.map((skill2) => {
116163
116367
  const source = skill2.location === "project" ? "project" : "user";
116164
116368
  return `${skill2.name} (${source})`;
116165
116369
  }).join(", ");
116166
116370
  if (customSkills.length > 0 && builtinSkills.length > 0) {
116167
- return `#### Available Skills (via \`skill\` tool)
116371
+ return `#### ${isZh ? "\u53EF\u7528\u6280\u80FD\uFF08\u901A\u8FC7 `skill` \u5DE5\u5177\uFF09" : "Available Skills (via `skill` tool)"}
116168
116372
 
116169
116373
  **Built-in**: ${builtinNames}
116170
116374
  **\u26A1 YOUR SKILLS (PRIORITY)**: ${customNames}
116171
116375
 
116172
- > User-installed skills OVERRIDE built-in defaults. ALWAYS prefer YOUR SKILLS when domain matches.
116173
- > Full skill descriptions \u2192 use the \`skill\` tool to check before EVERY delegation.`;
116376
+ > User-installed skills OVERRIDE built-in defaults. ${isZh ? "\u5F53\u9886\u57DF\u5339\u914D\u65F6\uFF0C\u59CB\u7EC8\u4F18\u5148\u4F7F\u7528\u4F60\u7684\u6280\u80FD\u3002" : "ALWAYS prefer YOUR SKILLS when domain matches."}
116377
+ > ${isZh ? "\u5B8C\u6574\u6280\u80FD\u63CF\u8FF0 \u2192 \u4F7F\u7528 `skill` \u5DE5\u5177\u5728\u6BCF\u6B21\u59D4\u6258\u524D\u68C0\u67E5\u3002" : "Full skill descriptions \u2192 use the `skill` tool to check before EVERY delegation."}`;
116174
116378
  }
116175
116379
  if (customSkills.length > 0) {
116176
- return `#### Available Skills (via \`skill\` tool)
116380
+ return `#### ${isZh ? "\u53EF\u7528\u6280\u80FD\uFF08\u901A\u8FC7 `skill` \u5DE5\u5177\uFF09" : "Available Skills (via `skill` tool)"}
116177
116381
 
116178
116382
  **\u26A1 YOUR SKILLS (PRIORITY)**: ${customNames}
116179
116383
 
116180
- > User-installed skills OVERRIDE built-in defaults. ALWAYS prefer YOUR SKILLS when domain matches.
116181
- > Full skill descriptions \u2192 use the \`skill\` tool to check before EVERY delegation.`;
116384
+ > User-installed skills OVERRIDE built-in defaults. ${isZh ? "\u5F53\u9886\u57DF\u5339\u914D\u65F6\uFF0C\u59CB\u7EC8\u4F18\u5148\u4F7F\u7528\u4F60\u7684\u6280\u80FD\u3002" : "ALWAYS prefer YOUR SKILLS when domain matches."}
116385
+ > ${isZh ? "\u5B8C\u6574\u6280\u80FD\u63CF\u8FF0 \u2192 \u4F7F\u7528 `skill` \u5DE5\u5177\u5728\u6BCF\u6B21\u59D4\u6258\u524D\u68C0\u67E5\u3002" : "Full skill descriptions \u2192 use the `skill` tool to check before EVERY delegation."}`;
116182
116386
  }
116183
116387
  if (builtinSkills.length > 0) {
116184
- return `#### Available Skills (via \`skill\` tool)
116388
+ return `#### ${isZh ? "\u53EF\u7528\u6280\u80FD\uFF08\u901A\u8FC7 `skill` \u5DE5\u5177\uFF09" : "Available Skills (via `skill` tool)"}
116185
116389
 
116186
116390
  **Built-in**: ${builtinNames}
116187
116391
 
116188
- > Full skill descriptions \u2192 use the \`skill\` tool to check before EVERY delegation.`;
116392
+ > ${isZh ? "\u5B8C\u6574\u6280\u80FD\u63CF\u8FF0 \u2192 \u4F7F\u7528 `skill` \u5DE5\u5177\u5728\u6BCF\u6B21\u59D4\u6258\u524D\u68C0\u67E5\u3002" : "Full skill descriptions \u2192 use the `skill` tool to check before EVERY delegation."}`;
116189
116393
  }
116190
116394
  return "";
116191
116395
  }
116192
- function buildCategorySkillsDelegationGuide(categories2, skills2) {
116396
+ function buildCategorySkillsDelegationGuide(categories2, skills2, language) {
116193
116397
  if (categories2.length === 0 && skills2.length === 0) {
116194
116398
  return "";
116195
116399
  }
116400
+ const isZh = isZhLanguage(language);
116196
116401
  const categoryRows = categories2.map((category) => {
116197
116402
  const description = category.description || category.name;
116198
- return `- \`${category.name}\` - ${description}`;
116403
+ return `- \`${category.name}\`: ${description}`;
116199
116404
  });
116200
116405
  const customSkills = skills2.filter((skill2) => skill2.location !== "plugin");
116201
- const skillsSection = buildSkillsSection(skills2);
116202
- const customPriorityNote = customSkills.length > 0 ? `
116406
+ const skillsSection = buildSkillsSection(skills2, language);
116407
+ const customPriorityNote = customSkills.length > 0 ? isZh ? `
116408
+ > **\u7528\u6237\u5B89\u88C5\u6280\u80FD\u4F18\u5148\u3002** \u6709\u7591\u95EE\u65F6\uFF0C\u5305\u542B\u800C\u4E0D\u662F\u7701\u7565\u3002` : `
116203
116409
  > **User-installed skills get PRIORITY.** When in doubt, INCLUDE rather than omit.` : "";
116204
- return `### Category + Skills Delegation System
116410
+ return `### ${isZh ? "\u7C7B\u522B + \u6280\u80FD\u59D4\u6258\u7CFB\u7EDF" : "Category + Skills Delegation System"}
116205
116411
 
116206
- **task() combines categories and skills for optimal task execution.**
116412
+ ${isZh ? "**task() \u7ED3\u5408\u7C7B\u522B\u548C\u6280\u80FD\u4EE5\u5B9E\u73B0\u6700\u4F73\u4EFB\u52A1\u6267\u884C\u3002**" : "**task() combines categories and skills for optimal task execution."}
116207
116413
 
116208
- #### Available Categories (Domain-Optimized Models)
116414
+ #### ${isZh ? "\u53EF\u7528\u7C7B\u522B\uFF08\u9886\u57DF\u4F18\u5316\u6A21\u578B\uFF09" : "Available Categories (Domain-Optimized Models)"}
116209
116415
 
116210
- Each category is configured with a model optimized for that domain. Read the description to understand when to use it.
116416
+ ${isZh ? "\u6BCF\u4E2A\u7C7B\u522B\u914D\u7F6E\u4E86\u9488\u5BF9\u8BE5\u9886\u57DF\u4F18\u5316\u7684\u6A21\u578B\u3002\u9605\u8BFB\u63CF\u8FF0\u4EE5\u4E86\u89E3\u4F55\u65F6\u4F7F\u7528\u3002" : "Each category is configured with a model optimized for that domain. Read the description to understand when to use it."}
116211
116417
 
116212
116418
  ${categoryRows.join(`
116213
116419
  `)}
@@ -116216,66 +116422,76 @@ ${skillsSection}
116216
116422
 
116217
116423
  ---
116218
116424
 
116219
- ### MANDATORY: Category + Skill Selection Protocol
116425
+ ### ${isZh ? "\u5F3A\u5236\uFF1A\u7C7B\u522B + \u6280\u80FD\u9009\u62E9\u534F\u8BAE" : "MANDATORY: Category + Skill Selection Protocol"}
116220
116426
 
116221
- **STEP 1: Select Category**
116222
- - Read each category's description
116223
- - Match task requirements to category domain
116224
- - Select the category whose domain BEST fits the task
116427
+ **STEP 1: ${isZh ? "\u9009\u62E9\u7C7B\u522B" : "Select Category"}**
116428
+ - ${isZh ? "\u9605\u8BFB\u6BCF\u4E2A\u7C7B\u522B\u7684\u63CF\u8FF0" : "Read each category's description"}
116429
+ - ${isZh ? "\u5C06\u4EFB\u52A1\u9700\u6C42\u4E0E\u7C7B\u522B\u9886\u57DF\u5339\u914D" : "Match task requirements to category domain"}
116430
+ - ${isZh ? "\u9009\u62E9\u4E0E\u4EFB\u52A1\u9886\u57DF\u6700\u5339\u914D\u7684\u7C7B\u522B" : "Select the category whose domain BEST fits the task"}
116225
116431
 
116226
- **STEP 2: Evaluate ALL Skills**
116227
- Check the \`skill\` tool for available skills and their descriptions. For EVERY skill, ask:
116228
- > "Does this skill's expertise domain overlap with my task?"
116432
+ **STEP 2: ${isZh ? "\u8BC4\u4F30\u6240\u6709\u6280\u80FD" : "Evaluate ALL Skills"}**
116433
+ ${isZh ? "\u68C0\u67E5 `skill` \u5DE5\u5177\u7684\u53EF\u7528\u6280\u80FD\u53CA\u5176\u63CF\u8FF0\u3002\u5BF9\u4E8E\u6BCF\u4E2A\u6280\u80FD\uFF0C\u95EE\uFF1A" : "Check the `skill` tool for available skills and their descriptions. For EVERY skill, ask:"}
116434
+ > ${isZh ? "\u300C\u8FD9\u4E2A\u6280\u80FD\u7684\u4E13\u4E1A\u9886\u57DF\u4E0E\u6211\u7684\u4EFB\u52A1\u6709\u91CD\u53E0\u5417\uFF1F\u300D" : "\u300CDoes this skill's expertise domain overlap with my task?\u300D"}
116229
116435
 
116230
- - If YES \u2192 INCLUDE in \`load_skills=[...]\`
116231
- - If NO \u2192 OMIT (no justification needed)${customPriorityNote}
116436
+ - ${isZh ? "\u662F \u2192 \u5728 `load_skills=[...]` \u4E2D\u5305\u542B" : "If YES \u2192 INCLUDE in `load_skills=[...]`"}
116437
+ - ${isZh ? "\u5426 \u2192 \u7701\u7565\uFF08\u65E0\u9700\u89E3\u91CA\uFF09" : "If NO \u2192 OMIT (no justification needed)"}${customPriorityNote}
116232
116438
 
116233
116439
  ---
116234
116440
 
116235
- ### Delegation Pattern
116441
+ ### ${isZh ? "\u59D4\u6258\u6A21\u5F0F" : "Delegation Pattern"}
116236
116442
 
116237
116443
  \`\`\`typescript
116238
116444
  task(
116239
116445
  category="[selected-category]",
116240
- load_skills=["skill-1", "skill-2"], // Include ALL relevant skills - ESPECIALLY user-installed ones
116446
+ load_skills=["skill-1", "skill-2"], // ${isZh ? "\u5305\u542B\u6240\u6709\u76F8\u5173\u6280\u80FD\u2014\u2014\u5C24\u5176\u662F\u7528\u6237\u5B89\u88C5\u7684" : "Include ALL relevant skills - ESPECIALLY user-installed ones"}
116241
116447
  prompt="..."
116242
116448
  )
116243
116449
  \`\`\`
116244
116450
 
116245
- **ANTI-PATTERN (will produce poor results):**
116451
+ **${isZh ? "\u53CD\u6A21\u5F0F\uFF08\u4F1A\u4EA7\u751F\u8F83\u5DEE\u7ED3\u679C\uFF09\uFF1A" : "ANTI-PATTERN (will produce poor results):"}**
116246
116452
  \`\`\`typescript
116247
- task(category="...", load_skills=[], run_in_background=false, prompt="...") // Empty load_skills without justification
116453
+ task(category="...", load_skills=[], run_in_background=false, prompt="...") // ${isZh ? "\u7A7A load_skills \u4E14\u65E0\u89E3\u91CA" : "Empty load_skills without justification"}
116248
116454
  \`\`\`
116249
116455
 
116250
116456
  ---
116251
116457
 
116252
- ### Category Domain Matching (ZERO TOLERANCE)
116458
+ ### ${isZh ? "\u7C7B\u522B\u9886\u57DF\u5339\u914D\uFF08\u96F6\u5BB9\u5FCD\uFF09" : "Category Domain Matching (ZERO TOLERANCE)"}
116253
116459
 
116254
- Every delegation MUST use the category that matches the task's domain. Mismatched categories produce measurably worse output because each category runs on a model optimized for that specific domain.
116460
+ ${isZh ? "\u6BCF\u6B21\u59D4\u6258\u5FC5\u987B\u4F7F\u7528\u4E0E\u4EFB\u52A1\u9886\u57DF\u5339\u914D\u7684\u7C7B\u522B\u3002\u9519\u8BEF\u7684\u7C7B\u522B\u5339\u914D\u4F1A\u4EA7\u751F\u660E\u663E\u66F4\u5DEE\u7684\u8F93\u51FA\uFF0C\u56E0\u4E3A\u6BCF\u4E2A\u7C7B\u522B\u8FD0\u884C\u5728\u9488\u5BF9\u7279\u5B9A\u9886\u57DF\u4F18\u5316\u7684\u6A21\u578B\u4E0A\u3002" : "Every delegation MUST use the category that matches the task's domain. Mismatched categories produce measurably worse output because each category runs on a model optimized for that specific domain."}
116255
116461
 
116256
- **VISUAL WORK = ALWAYS \`visual-engineering\`. NO EXCEPTIONS.**
116462
+ **${isZh ? "\u89C6\u89C9\u5DE5\u4F5C = \u59CB\u7EC8\u4F7F\u7528 `visual-engineering`\u3002\u65E0\u4F8B\u5916\u3002" : "VISUAL WORK = ALWAYS `visual-engineering`. NO EXCEPTIONS."}**
116257
116463
 
116258
- Any task involving UI, UX, CSS, styling, layout, animation, design, or frontend components MUST go to \`visual-engineering\`. Never delegate visual work to \`quick\`, \`unspecified-*\`, or any other category.
116464
+ ${isZh ? "\u4EFB\u4F55\u6D89\u53CA UI\u3001UX\u3001CSS\u3001\u6837\u5F0F\u3001\u5E03\u5C40\u3001\u52A8\u753B\u3001\u8BBE\u8BA1\u6216\u524D\u7AEF\u7EC4\u4EF6\u7684\u4EFB\u52A1\u5FC5\u987B\u4F7F\u7528 `visual-engineering`\u3002\u6C38\u8FDC\u4E0D\u8981\u5C06\u89C6\u89C9\u5DE5\u4F5C\u59D4\u6258\u7ED9 `quick`\u3001`unspecified-*` \u6216\u5176\u4ED6\u7C7B\u522B\u3002" : "Any task involving UI, UX, CSS, styling, layout, animation, design, or frontend components MUST go to `visual-engineering`. Never delegate visual work to `quick`, `unspecified-*`, or any other category."}
116259
116465
 
116260
116466
  \`\`\`typescript
116261
- // CORRECT: Visual work \u2192 visual-engineering category
116467
+ // ${isZh ? "\u6B63\u786E\uFF1A\u89C6\u89C9\u5DE5\u4F5C \u2192 visual-engineering \u7C7B\u522B" : "CORRECT: Visual work \u2192 visual-engineering category"}
116262
116468
  task(category="visual-engineering", load_skills=["frontend-ui-ux"], prompt="Redesign the sidebar layout with new spacing...")
116263
116469
 
116264
- // WRONG: Visual work in wrong category - WILL PRODUCE INFERIOR RESULTS
116470
+ // ${isZh ? "\u9519\u8BEF\uFF1A\u89C6\u89C9\u5DE5\u4F5C\u4F7F\u7528\u9519\u8BEF\u7C7B\u522B\u2014\u2014\u4F1A\u4EA7\u751F\u8F83\u5DEE\u7ED3\u679C" : "WRONG: Visual work in wrong category - WILL PRODUCE INFERIOR RESULTS"}
116265
116471
  task(category="quick", load_skills=[], prompt="Redesign the sidebar layout with new spacing...")
116266
116472
  \`\`\`
116267
116473
 
116268
- | Task Domain | MUST Use Category |
116474
+ | ${isZh ? "\u4EFB\u52A1\u9886\u57DF" : "Task Domain"} | ${isZh ? "\u5FC5\u987B\u4F7F\u7528\u7C7B\u522B" : "MUST Use Category"} |
116269
116475
  |---|---|
116270
- | UI, styling, animations, layout, design | \`visual-engineering\` |
116271
- | Hard logic, architecture decisions, algorithms | \`ultrabrain\` |
116272
- | Autonomous research + end-to-end implementation | \`deep\` |
116273
- | Single-file typo, trivial config change | \`quick\` |
116476
+ | ${isZh ? "UI\u3001\u6837\u5F0F\u3001\u52A8\u753B\u3001\u5E03\u5C40\u3001\u8BBE\u8BA1" : "UI, styling, animations, layout, design"} | \`visual-engineering\` |
116477
+ | ${isZh ? "\u786C\u903B\u8F91\u3001\u67B6\u6784\u51B3\u7B56\u3001\u7B97\u6CD5" : "Hard logic, architecture decisions, algorithms"} | \`ultrabrain\` |
116478
+ | ${isZh ? "\u81EA\u4E3B\u7814\u7A76 + \u7AEF\u5230\u7AEF\u5B9E\u73B0" : "Autonomous research + end-to-end implementation"} | \`deep\` |
116479
+ | ${isZh ? "\u5355\u6587\u4EF6\u62FC\u5199\u9519\u8BEF\u3001\u7B80\u5355\u914D\u7F6E\u66F4\u6539" : "Single-file typo, trivial config change"} | \`quick\` |
116274
116480
 
116275
- **When in doubt about category, it is almost never \`quick\` or \`unspecified-*\`. Match the domain.**`;
116481
+ **${isZh ? "\u5F53\u5BF9\u7C7B\u522B\u6709\u7591\u95EE\u65F6\uFF0C\u5B83\u51E0\u4E4E\u6C38\u8FDC\u4E0D\u662F `quick` \u6216 `unspecified-*`\u3002\u5339\u914D\u9886\u57DF\u3002" : "When in doubt about category, it is almost never `quick` or `unspecified-*`. Match the domain."}**`;
116276
116482
  }
116277
116483
  // src/agents/dynamic-agent-policy-sections.ts
116278
- function buildHardBlocksSection() {
116484
+ function buildHardBlocksSection(language) {
116485
+ if (isZhLanguage(language)) {
116486
+ return `## \u786C\u6027\u7981\u6B62\uFF08\u6C38\u4E0D\u8FDD\u53CD\uFF09
116487
+
116488
+ - \u7981\u6B62\u7C7B\u578B\u9519\u8BEF\u538B\u5236\uFF08\`as any\`\u3001\`@ts-ignore\`\uFF09\u2014\u2014\u6C38\u4E0D
116489
+ - \u672A\u7ECF\u660E\u786E\u8981\u6C42\u7981\u6B62\u63D0\u4EA4\u2014\u2014\u6C38\u4E0D
116490
+ - \u7981\u6B62\u63A8\u6D4B\u672A\u8BFB\u4EE3\u7801\u2014\u2014\u6C38\u4E0D
116491
+ - \u5931\u8D25\u540E\u7981\u6B62\u7559\u4E0B\u635F\u574F\u4EE3\u7801\u2014\u2014\u6C38\u4E0D
116492
+ - \`background_cancel(all=true)\`\u2014\u2014\u6C38\u4E0D\u3002\u59CB\u7EC8\u6309 taskId \u5355\u72EC\u53D6\u6D88\u3002
116493
+ - \u6536\u96C6 Oracle \u7ED3\u679C\u524D\u7981\u6B62\u4EA4\u4ED8\u6700\u7EC8\u7B54\u6848\u2014\u2014\u6C38\u4E0D\u3002`;
116494
+ }
116279
116495
  const blocks = [
116280
116496
  "- Type error suppression (`as any`, `@ts-ignore`) - **Never**",
116281
116497
  "- Commit without explicit request - **Never**",
@@ -116289,7 +116505,19 @@ function buildHardBlocksSection() {
116289
116505
  ${blocks.join(`
116290
116506
  `)}`;
116291
116507
  }
116292
- function buildAntiPatternsSection() {
116508
+ function buildAntiPatternsSection(language) {
116509
+ if (isZhLanguage(language)) {
116510
+ return `## \u53CD\u6A21\u5F0F\uFF08\u963B\u585E\u6027\u8FDD\u89C4\uFF09
116511
+
116512
+ - **\u7C7B\u578B\u5B89\u5168**\uFF1A\`as any\`\u3001\`@ts-ignore\`\u3001\`@ts-expect-error\`
116513
+ - **\u9519\u8BEF\u5904\u7406**\uFF1A\u7A7A catch \u5757 \`catch(e) {}\`
116514
+ - **\u6D4B\u8BD5**\uFF1A\u5220\u9664\u5931\u8D25\u7684\u6D4B\u8BD5\u4EE5"\u901A\u8FC7"
116515
+ - **\u641C\u7D22**\uFF1A\u4E3A\u5355\u884C\u62FC\u5199\u9519\u8BEF\u6216\u660E\u663E\u8BED\u6CD5\u9519\u8BEF\u89E6\u53D1 agents
116516
+ - **\u8C03\u8BD5**\uFF1A\u9730\u5F39\u5F0F\u8C03\u8BD5\uFF0C\u968F\u673A\u66F4\u6539
116517
+ - **\u540E\u53F0\u4EFB\u52A1**\uFF1A\u8F6E\u8BE2\u8FD0\u884C\u4E2D\u4EFB\u52A1\u7684 \`background_output\`\u2014\u2014\u7ED3\u675F\u56DE\u590D\u5E76\u7B49\u5F85\u901A\u77E5
116518
+ - **\u59D4\u6258\u91CD\u590D**\uFF1A\u59D4\u6258 explore/librarian \u540E\u81EA\u5DF1\u624B\u52A8\u505A\u76F8\u540C\u641C\u7D22
116519
+ - **Oracle**\uFF1A\u4E0D\u6536\u96C6 Oracle \u7ED3\u679C\u5C31\u4EA4\u4ED8\u7B54\u6848`;
116520
+ }
116293
116521
  const patterns = [
116294
116522
  "- **Type Safety**: `as any`, `@ts-ignore`, `@ts-expect-error`",
116295
116523
  "- **Error Handling**: Empty catch blocks `catch(e) {}`",
@@ -116305,7 +116533,24 @@ function buildAntiPatternsSection() {
116305
116533
  ${patterns.join(`
116306
116534
  `)}`;
116307
116535
  }
116308
- function buildToolCallFormatSection() {
116536
+ function buildToolCallFormatSection(language) {
116537
+ if (isZhLanguage(language)) {
116538
+ return `## \u5DE5\u5177\u8C03\u7528\u683C\u5F0F\uFF08\u5173\u952E\uFF09
116539
+
116540
+ **\u59CB\u7EC8\u4F7F\u7528\u539F\u751F\u5DE5\u5177\u8C03\u7528\u673A\u5236\u3002\u6C38\u4E0D\u5C06\u5DE5\u5177\u8C03\u7528\u8F93\u51FA\u4E3A\u6587\u672C\u3002**
116541
+
116542
+ \u5F53\u9700\u8981\u8C03\u7528\u5DE5\u5177\u65F6\uFF1A
116543
+ 1. \u4F7F\u7528\u7CFB\u7EDF\u63D0\u4F9B\u7684\u5DE5\u5177\u8C03\u7528\u63A5\u53E3
116544
+ 2. \u4E0D\u8981\u5C06\u5DE5\u5177\u8C03\u7528\u5199\u6210\u7EAF\u6587\u672C\uFF0C\u5982 \`assistant to=functions.XXX\`
116545
+ 3. \u4E0D\u8981\u5728\u6587\u672C\u56DE\u590D\u4E2D\u76F4\u63A5\u8F93\u51FA JSON
116546
+ 4. \u7CFB\u7EDF\u81EA\u52A8\u5904\u7406\u5DE5\u5177\u8C03\u7528\u683C\u5F0F
116547
+
116548
+ **\u6B63\u786E**\uFF1A\u901A\u8FC7\u5DE5\u5177\u8C03\u7528\u63A5\u53E3\u8C03\u7528
116549
+ **\u9519\u8BEF**\uFF1A\u5C06 \`assistant to=functions.todowrite\` \u6216 \`json
116550
+ {...}\` \u4F5C\u4E3A\u6587\u672C\u5199\u5165
116551
+
116552
+ \u4F60\u7684\u5DE5\u5177\u8C03\u7528\u81EA\u52A8\u5904\u7406\u3002\u4EC5\u8C03\u7528\u5DE5\u5177\u2014\u2014\u4E0D\u8981\u81EA\u5DF1\u683C\u5F0F\u5316\u8C03\u7528\u3002`;
116553
+ }
116309
116554
  return `## Tool Call Format (CRITICAL)
116310
116555
 
116311
116556
  **ALWAYS use the native tool calling mechanism. NEVER output tool calls as text.**
@@ -116322,7 +116567,54 @@ When you need to call a tool:
116322
116567
 
116323
116568
  Your tool calls are processed automatically. Just invoke the tool - do not format the call yourself.`;
116324
116569
  }
116325
- function buildAntiDuplicationSection() {
116570
+ function buildAntiDuplicationSection(language) {
116571
+ if (isZhLanguage(language)) {
116572
+ return `<Anti_Duplication>
116573
+ ## \u9632\u91CD\u590D\u89C4\u5219\uFF08\u5173\u952E\uFF09
116574
+
116575
+ \u4E00\u65E6\u5C06\u63A2\u7D22\u59D4\u6258\u7ED9 explore/librarian agents\uFF0C**\u4E0D\u8981\u81EA\u5DF1\u6267\u884C\u76F8\u540C\u7684\u641C\u7D22**\u3002
116576
+
116577
+ ### \u542B\u4E49
116578
+
116579
+ **\u7981\u6B62\uFF1A**
116580
+ - \u89E6\u53D1 explore/librarian \u540E\uFF0C\u624B\u52A8 grep/\u641C\u7D22\u76F8\u540C\u4FE1\u606F
116581
+ - \u91CD\u505A agents \u521A\u88AB\u59D4\u6258\u7684\u7814\u7A76
116582
+ - "\u5FEB\u901F\u68C0\u67E5"\u540E\u53F0 agents \u6B63\u5728\u68C0\u67E5\u7684\u76F8\u540C\u6587\u4EF6
116583
+
116584
+ **\u5141\u8BB8\uFF1A**
116585
+ - \u7EE7\u7EED**\u975E\u91CD\u53E0\u5DE5\u4F5C**\u2014\u2014\u4E0D\u4F9D\u8D56\u4E8E\u59D4\u6258\u7814\u7A76\u7684\u5DE5\u4F5C
116586
+ - \u5728\u4EE3\u7801\u5E93\u65E0\u5173\u90E8\u5206\u5DE5\u4F5C
116587
+ - \u51C6\u5907\u5DE5\u4F5C\uFF08\u5982\u8BBE\u7F6E\u6587\u4EF6\u3001\u914D\u7F6E\uFF09
116588
+
116589
+ ### \u6B63\u786E\u7B49\u5F85\u7ED3\u679C\uFF1A
116590
+
116591
+ \u5F53\u9700\u8981\u59D4\u6258\u7ED3\u679C\u4F46\u8FD8\u6CA1\u51C6\u5907\u597D\u65F6\uFF1A
116592
+
116593
+ 1. **\u7ED3\u675F\u56DE\u590D**\u2014\u2014\u4E0D\u8981\u7EE7\u7EED\u4F9D\u8D56\u90A3\u4E9B\u7ED3\u679C\u7684\u5DE5\u4F5C
116594
+ 2. **\u7B49\u5F85\u5B8C\u6210\u901A\u77E5**\u2014\u2014\u7CFB\u7EDF\u4F1A\u5728\u4E0B\u4E00\u8F6E\u89E6\u53D1\u4F60
116595
+ 3. \u7136\u540E\u901A\u8FC7 \`background_output(task_id="...")\` \u6536\u96C6\u7ED3\u679C
116596
+ 4. **\u4E0D\u8981**\u4E0D\u8010\u70E6\u5730\u91CD\u65B0\u641C\u7D22\u76F8\u540C\u4E3B\u9898
116597
+
116598
+ ### \u4E3A\u4EC0\u4E48\u8FD9\u5F88\u91CD\u8981\uFF1A
116599
+
116600
+ - **\u6D6A\u8D39 token**\uFF1A\u91CD\u590D\u63A2\u7D22\u6D6A\u8D39\u4F60\u7684\u4E0A\u4E0B\u6587\u9884\u7B97
116601
+ - **\u6DF7\u6DC6**\uFF1A\u4F60\u53EF\u80FD\u4E0E agents \u7684\u53D1\u73B0\u77DB\u76FE
116602
+ - **\u6548\u7387**\uFF1A\u59D4\u6258\u7684\u8981\u70B9\u662F\u5E76\u884C\u541E\u5410\u91CF
116603
+
116604
+ ### \u793A\u4F8B\uFF1A
116605
+
116606
+ \`\`\`typescript
116607
+ // \u9519\u8BEF\uFF1A\u59D4\u6258\u540E\u91CD\u505A\u641C\u7D22
116608
+ task(subagent_type="explore", run_in_background=true, ...)
116609
+ // \u7136\u540E\u7ACB\u5373\u81EA\u5DF1 grep \u76F8\u540C\u5185\u5BB9\u2014\u2014\u7981\u6B62
116610
+
116611
+ // \u6B63\u786E\uFF1A\u7EE7\u7EED\u975E\u91CD\u53E0\u5DE5\u4F5C
116612
+ task(subagent_type="explore", run_in_background=true, ...)
116613
+ // \u5728 agents \u641C\u7D22\u65F6\u5904\u7406\u5176\u4ED6\u65E0\u5173\u5DE5\u4F5C
116614
+ // \u7ED3\u675F\u56DE\u590D\u5E76\u7B49\u5F85\u901A\u77E5
116615
+ \`\`\`
116616
+ </Anti_Duplication>`;
116617
+ }
116326
116618
  return `<Anti_Duplication>
116327
116619
  ## Anti-Duplication Rule (CRITICAL)
116328
116620
 
@@ -116743,7 +117035,8 @@ ${styleBlock}`;
116743
117035
  }
116744
117036
 
116745
117037
  // src/agents/sisyphus/default.ts
116746
- function buildTaskManagementSection(useTaskSystem) {
117038
+ function buildTaskManagementSection(useTaskSystem, language) {
117039
+ const isZh = language?.startsWith("zh");
116747
117040
  if (useTaskSystem) {
116748
117041
  return `<Task_Management>
116749
117042
  ## Task Management (CRITICAL)
@@ -116853,7 +117146,7 @@ Should I proceed with [recommendation], or would you prefer differently?
116853
117146
  }
116854
117147
 
116855
117148
  // src/agents/load-prompt-template.ts
116856
- import { existsSync as existsSync91, readFileSync as readFileSync64 } from "fs";
117149
+ import { existsSync as existsSync91, readFileSync as readFileSync65 } from "fs";
116857
117150
  import { join as join101 } from "path";
116858
117151
  import { fileURLToPath as fileURLToPath5 } from "url";
116859
117152
  function loadPromptTemplate(language, agentName) {
@@ -116867,7 +117160,7 @@ function loadPromptTemplate(language, agentName) {
116867
117160
  ];
116868
117161
  for (const candidate of candidates) {
116869
117162
  if (existsSync91(candidate)) {
116870
- return readFileSync64(candidate, "utf-8");
117163
+ return readFileSync65(candidate, "utf-8");
116871
117164
  }
116872
117165
  }
116873
117166
  console.warn(`[loadPromptTemplate] Chinese template not found: ${agentName}`);
@@ -116877,7 +117170,7 @@ function loadPromptTemplate(language, agentName) {
116877
117170
  // src/agents/sisyphus.ts
116878
117171
  var MODE = "primary";
116879
117172
  var _zhTemplateCache = null;
116880
- function buildDynamicSisyphusPromptZh(model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
117173
+ function buildDynamicSisyphusPromptZh(model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false, language = "zh-CN") {
116881
117174
  if (_zhTemplateCache === null) {
116882
117175
  _zhTemplateCache = loadPromptTemplate("zh", "sisyphus");
116883
117176
  }
@@ -116885,20 +117178,20 @@ function buildDynamicSisyphusPromptZh(model, availableAgents, availableTools = [
116885
117178
  if (!template) {
116886
117179
  return buildDynamicSisyphusPrompt(model, availableAgents, availableTools, availableSkills, availableCategories, useTaskSystem);
116887
117180
  }
116888
- const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
116889
- const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
116890
- const exploreSection = buildExploreSection(availableAgents);
116891
- const librarianSection = buildLibrarianSection(availableAgents);
116892
- const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
116893
- const delegationTable = buildDelegationTable(availableAgents);
116894
- const oracleSection = buildOracleSection(availableAgents);
116895
- const hardBlocks = buildHardBlocksSection();
116896
- const antiPatterns = buildAntiPatternsSection();
116897
- const parallelDelegationSection = buildParallelDelegationSection(model, availableCategories);
116898
- const nonClaudePlannerSection = buildNonClaudePlannerSection(model);
116899
- const taskManagementSection = buildTaskManagementSection(useTaskSystem);
117181
+ const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills, language);
117182
+ const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, language);
117183
+ const exploreSection = buildExploreSection(availableAgents, language);
117184
+ const librarianSection = buildLibrarianSection(availableAgents, language);
117185
+ const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills, language);
117186
+ const delegationTable = buildDelegationTable(availableAgents, language);
117187
+ const oracleSection = buildOracleSection(availableAgents, language);
117188
+ const hardBlocks = buildHardBlocksSection(language);
117189
+ const antiPatterns = buildAntiPatternsSection(language);
117190
+ const parallelDelegationSection = buildParallelDelegationSection(model, availableCategories, language);
117191
+ const nonClaudePlannerSection = buildNonClaudePlannerSection(model, language);
117192
+ const taskManagementSection = buildTaskManagementSection(useTaskSystem, language);
116900
117193
  const todoHookNote = useTaskSystem ? "YOUR TASK CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TASK CONTINUATION])" : "YOUR TODO CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TODO CONTINUATION])";
116901
- const agentIdentity = buildAgentIdentitySection("Sisyphus", "Powerful AI Agent with orchestration capabilities from OhMyOpenCode");
117194
+ const agentIdentity = buildAgentIdentitySection("Sisyphus", "Powerful AI Agent with orchestration capabilities from OhMyOpenCode", language);
116902
117195
  return template.replace(/\$\{agentIdentity\}/g, agentIdentity).replace(/\$\{todoHookNote\}/g, todoHookNote).replace(/\$\{keyTriggers\}/g, keyTriggers).replace(/\$\{toolSelection\}/g, toolSelection).replace(/\$\{exploreSection\}/g, exploreSection).replace(/\$\{librarianSection\}/g, librarianSection).replace(/\$\{buildAntiDuplicationSection\(\)\}/g, buildAntiDuplicationSection()).replace(/\$\{categorySkillsGuide\}/g, categorySkillsGuide).replace(/\$\{nonClaudePlannerSection\}/g, nonClaudePlannerSection).replace(/\$\{parallelDelegationSection\}/g, parallelDelegationSection).replace(/\$\{delegationTable\}/g, delegationTable).replace(/\$\{oracleSection\}/g, oracleSection).replace(/\$\{taskManagementSection\}/g, taskManagementSection).replace(/\$\{hardBlocks\}/g, hardBlocks).replace(/\$\{antiPatterns\}/g, antiPatterns);
116903
117196
  }
116904
117197
  function buildDynamicSisyphusPrompt(model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
@@ -119562,7 +119855,13 @@ function getAtlasPromptSource(model) {
119562
119855
  }
119563
119856
  return "default";
119564
119857
  }
119565
- function getAtlasPrompt(model) {
119858
+ function getAtlasPrompt(model, language) {
119859
+ const isZh = language?.startsWith("zh");
119860
+ if (isZh) {
119861
+ const zhPrompt = loadPromptTemplate("zh", "atlas");
119862
+ if (zhPrompt)
119863
+ return zhPrompt;
119864
+ }
119566
119865
  const source = getAtlasPromptSource(model);
119567
119866
  switch (source) {
119568
119867
  case "gpt":
@@ -119588,9 +119887,9 @@ function buildDynamicOrchestratorPrompt(ctx) {
119588
119887
  const agentSection = buildAgentSelectionSection(agents);
119589
119888
  const decisionMatrix = buildDecisionMatrix(agents, userCategories);
119590
119889
  const skillsSection = buildSkillsSection2(skills2);
119591
- const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, skills2);
119592
- const agentIdentity = buildAgentIdentitySection("Atlas", "Master Orchestrator agent from OhMyOpenCode that coordinates specialized agents to complete todo lists");
119593
- const basePrompt = getAtlasPrompt(model);
119890
+ const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, skills2, ctx?.language);
119891
+ const agentIdentity = buildAgentIdentitySection("Atlas", "Master Orchestrator agent from OhMyOpenCode that coordinates specialized agents to complete todo lists", ctx?.language);
119892
+ const basePrompt = getAtlasPrompt(model, ctx?.language);
119594
119893
  return agentIdentity + `
119595
119894
  ` + basePrompt.replace("{CATEGORY_SECTION}", categorySection).replace("{AGENT_SECTION}", agentSection).replace("{DECISION_MATRIX}", decisionMatrix).replace("{SKILLS_SECTION}", skillsSection).replace("{{CATEGORY_SKILLS_DELEGATION_GUIDE}}", categorySkillsGuide);
119596
119895
  }
@@ -121091,7 +121390,7 @@ function createHephaestusAgent2(model, availableAgents, availableToolNames, avai
121091
121390
  }
121092
121391
  createHephaestusAgent2.mode = MODE10;
121093
121392
  // src/agents/builtin-agents/resolve-file-uri.ts
121094
- import { existsSync as existsSync92, readFileSync as readFileSync65 } from "fs";
121393
+ import { existsSync as existsSync92, readFileSync as readFileSync66 } from "fs";
121095
121394
  import { homedir as homedir19 } from "os";
121096
121395
  import { isAbsolute as isAbsolute13, resolve as resolve21 } from "path";
121097
121396
  init_logger();
@@ -121120,7 +121419,7 @@ function resolvePromptAppend(promptAppend, configDir) {
121120
121419
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
121121
121420
  }
121122
121421
  try {
121123
- return readFileSync65(filePath, "utf8");
121422
+ return readFileSync66(filePath, "utf8");
121124
121423
  } catch {
121125
121424
  return `[WARNING: Could not read file: ${promptAppend}]`;
121126
121425
  }
@@ -121874,7 +122173,12 @@ function createSisyphusJuniorAgentWithOverrides(override, systemDefaultModel, us
121874
122173
  const model = overrideModel ?? systemDefaultModel ?? SISYPHUS_JUNIOR_DEFAULTS.model;
121875
122174
  const temperature = override?.temperature ?? SISYPHUS_JUNIOR_DEFAULTS.temperature;
121876
122175
  const promptAppend = override?.prompt_append;
121877
- 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
+ }
121878
122182
  const blockedTools = isGptModel(model) ? GPT_BLOCKED_TOOLS : BLOCKED_TOOLS3;
121879
122183
  const baseRestrictions = createAgentToolRestrictions(blockedTools);
121880
122184
  const userPermission = override?.permission ?? {};
@@ -122120,6 +122424,13 @@ function collectPendingBuiltinAgents(input) {
122120
122424
  if (resolvedVariant) {
122121
122425
  config2 = { ...config2, variant: resolvedVariant };
122122
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
+ }
122123
122434
  if (["librarian", "oracle", "momus", "explore", "metis", "multimodal-looker"].includes(agentName)) {
122124
122435
  config2 = applyEnvironmentContext(config2, directory, { disableOmoEnv, language: override?.language ?? language });
122125
122436
  }
@@ -122280,7 +122591,8 @@ function maybeCreateAtlasConfig(input) {
122280
122591
  model: atlasModel,
122281
122592
  availableAgents,
122282
122593
  availableSkills,
122283
- userCategories
122594
+ userCategories,
122595
+ language: orchestratorOverride?.language ?? language
122284
122596
  });
122285
122597
  if (atlasResolvedVariant) {
122286
122598
  orchestratorConfig = { ...orchestratorConfig, variant: atlasResolvedVariant };
@@ -124628,7 +124940,12 @@ function getPrometheusPromptSource(model) {
124628
124940
  }
124629
124941
  return "default";
124630
124942
  }
124631
- 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
+ }
124632
124949
  const source = getPrometheusPromptSource(model);
124633
124950
  const isQuestionDisabled = disabledTools?.includes("question") ?? false;
124634
124951
  let prompt;
@@ -124700,7 +125017,7 @@ async function buildPrometheusAgentConfig(params) {
124700
125017
  ...resolvedModel ? { model: resolvedModel } : {},
124701
125018
  ...variantToUse ? { variant: variantToUse } : {},
124702
125019
  mode: "primary",
124703
- prompt: getPrometheusPrompt(resolvedModel, params.disabledTools),
125020
+ prompt: getPrometheusPrompt(resolvedModel, params.disabledTools, params.language),
124704
125021
  permission: PROMETHEUS_PERMISSION,
124705
125022
  description: `${params.configAgentPlan?.description ?? "Plan agent"} (Prometheus - OhMyOpenCode)`,
124706
125023
  color: params.configAgentPlan?.color ?? "#FF5722",
@@ -126836,6 +127153,7 @@ function createEventHandler2(args) {
126836
127153
  await runEventHookSafely("writeExistingFileGuard", hooks2.writeExistingFileGuard?.event, input);
126837
127154
  await runEventHookSafely("atlasHook", hooks2.atlasHook?.handler, input);
126838
127155
  await runEventHookSafely("autoSlashCommand", hooks2.autoSlashCommand?.event, input);
127156
+ await runEventHookSafely("toolOutputTruncator", hooks2.toolOutputTruncator?.event, input);
126839
127157
  };
126840
127158
  const recentSyntheticIdles = new Map;
126841
127159
  const recentRealIdles = new Map;
@@ -127270,21 +127588,28 @@ function createToolExecuteAfterHandler3(args) {
127270
127588
  await hooks2.preemptiveCompaction?.["tool.execute.after"]?.(hookInput, output);
127271
127589
  await hooks2.contextWindowMonitor?.["tool.execute.after"]?.(hookInput, output);
127272
127590
  await hooks2.commentChecker?.["tool.execute.after"]?.(hookInput, output);
127273
- await hooks2.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output);
127274
- 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
+ }
127275
127610
  await hooks2.rulesInjector?.["tool.execute.after"]?.(hookInput, output);
127276
127611
  await hooks2.emptyTaskResponseDetector?.["tool.execute.after"]?.(hookInput, output);
127277
- await hooks2.agentUsageReminder?.["tool.execute.after"]?.(hookInput, output);
127278
- await hooks2.categorySkillReminder?.["tool.execute.after"]?.(hookInput, output);
127279
- await hooks2.interactiveBashSession?.["tool.execute.after"]?.(hookInput, output);
127280
- await hooks2.editErrorRecovery?.["tool.execute.after"]?.(hookInput, output);
127281
- await hooks2.delegateTaskRetry?.["tool.execute.after"]?.(hookInput, output);
127282
- await hooks2.atlasHook?.["tool.execute.after"]?.(hookInput, output);
127283
- await hooks2.taskResumeInfo?.["tool.execute.after"]?.(hookInput, output);
127284
- await hooks2.readImageResizer?.["tool.execute.after"]?.(hookInput, output);
127285
127612
  await hooks2.hashlineReadEnhancer?.["tool.execute.after"]?.(hookInput, output);
127286
- await hooks2.webfetchRedirectGuard?.["tool.execute.after"]?.(hookInput, output);
127287
- await hooks2.jsonErrorRecovery?.["tool.execute.after"]?.(hookInput, output);
127288
127613
  };
127289
127614
  if (input.tool === "extract" || input.tool === "discard") {
127290
127615
  const originalOutput = {
@@ -132237,7 +132562,7 @@ class PostHog extends PostHogBackendClient {
132237
132562
  // package.json
132238
132563
  var package_default = {
132239
132564
  name: "@skj1724/oh-my-opencode",
132240
- version: "3.18.25",
132565
+ version: "3.18.27",
132241
132566
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
132242
132567
  main: "./dist/index.js",
132243
132568
  types: "dist/index.d.ts",
@@ -132298,6 +132623,7 @@ var package_default = {
132298
132623
  diff: "^8.0.3",
132299
132624
  "js-yaml": "^4.1.1",
132300
132625
  "jsonc-parser": "^3.3.1",
132626
+ "memory-boat": "^0.0.1",
132301
132627
  picocolors: "^1.1.1",
132302
132628
  picomatch: "^4.0.4",
132303
132629
  "posthog-node": "5.28.11",
@@ -132338,7 +132664,7 @@ var package_default = {
132338
132664
  init_plugin_identity();
132339
132665
 
132340
132666
  // src/shared/posthog-activity-state.ts
132341
- 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";
132342
132668
  import { join as join105 } from "path";
132343
132669
  init_logger();
132344
132670
  init_plugin_identity();
@@ -132361,7 +132687,7 @@ function readPostHogActivityState() {
132361
132687
  return {};
132362
132688
  }
132363
132689
  try {
132364
- const content = readFileSync67(stateFilePath, "utf-8");
132690
+ const content = readFileSync68(stateFilePath, "utf-8");
132365
132691
  const parsed = JSON.parse(content);
132366
132692
  if (!isPostHogActivityState(parsed)) {
132367
132693
  return {};