@skj1724/oh-my-opencode 3.19.5 → 3.19.7

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
@@ -4859,7 +4859,7 @@ var init_agent_tool_restrictions = __esm(() => {
4859
4859
  });
4860
4860
 
4861
4861
  // src/shared/model-requirements.ts
4862
- var AGENT_MODEL_REQUIREMENTS;
4862
+ var AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS;
4863
4863
  var init_model_requirements = __esm(() => {
4864
4864
  AGENT_MODEL_REQUIREMENTS = {
4865
4865
  sisyphus: {
@@ -4928,6 +4928,58 @@ var init_model_requirements = __esm(() => {
4928
4928
  ]
4929
4929
  }
4930
4930
  };
4931
+ CATEGORY_MODEL_REQUIREMENTS = {
4932
+ "visual-engineering": {
4933
+ fallbackChain: [
4934
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" },
4935
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4936
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" }
4937
+ ]
4938
+ },
4939
+ ultrabrain: {
4940
+ fallbackChain: [
4941
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
4942
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4943
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4944
+ ]
4945
+ },
4946
+ artistry: {
4947
+ fallbackChain: [
4948
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
4949
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4950
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4951
+ ]
4952
+ },
4953
+ quick: {
4954
+ fallbackChain: [
4955
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
4956
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4957
+ { providers: ["opencode"], model: "gpt-5-nano" }
4958
+ ]
4959
+ },
4960
+ "unspecified-low": {
4961
+ fallbackChain: [
4962
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4963
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
4964
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
4965
+ ]
4966
+ },
4967
+ "unspecified-high": {
4968
+ fallbackChain: [
4969
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4970
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4971
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4972
+ ]
4973
+ },
4974
+ writing: {
4975
+ fallbackChain: [
4976
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4977
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4978
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
4979
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4980
+ ]
4981
+ }
4982
+ };
4931
4983
  });
4932
4984
 
4933
4985
  // src/shared/model-availability.ts
@@ -5064,6 +5116,81 @@ var init_model_resolver = __esm(() => {
5064
5116
  init_model_availability();
5065
5117
  });
5066
5118
 
5119
+ // src/shared/runtime-fallback.ts
5120
+ function expandChain(chain) {
5121
+ const candidates = [];
5122
+ for (const entry of chain) {
5123
+ for (const provider of entry.providers) {
5124
+ candidates.push({
5125
+ providerID: provider,
5126
+ modelID: entry.model,
5127
+ variant: entry.variant
5128
+ });
5129
+ }
5130
+ }
5131
+ return candidates;
5132
+ }
5133
+ function modelKey(m) {
5134
+ return `${m.providerID}/${m.modelID}`;
5135
+ }
5136
+ function getChain(agent, category) {
5137
+ if (agent && AGENT_MODEL_REQUIREMENTS[agent]) {
5138
+ return AGENT_MODEL_REQUIREMENTS[agent].fallbackChain;
5139
+ }
5140
+ if (category && CATEGORY_MODEL_REQUIREMENTS[category]) {
5141
+ return CATEGORY_MODEL_REQUIREMENTS[category].fallbackChain;
5142
+ }
5143
+ throw new Error(`No fallback chain found for agent="${agent ?? ""}" category="${category ?? ""}"`);
5144
+ }
5145
+ function resolveNextFallbackModel(input) {
5146
+ const {
5147
+ agent,
5148
+ category,
5149
+ currentModel,
5150
+ attempts,
5151
+ availableModels,
5152
+ lastErrorClassification
5153
+ } = input;
5154
+ const chain = getChain(agent, category);
5155
+ const candidates = expandChain(chain);
5156
+ const skipKeys = new Set;
5157
+ skipKeys.add(modelKey(currentModel));
5158
+ for (const a of attempts) {
5159
+ skipKeys.add(modelKey(a.model));
5160
+ }
5161
+ const resultAttempts = [...attempts];
5162
+ const currentKey = modelKey(currentModel);
5163
+ const isInAttempts = attempts.some((a) => modelKey(a.model) === currentKey);
5164
+ if (!isInAttempts) {
5165
+ resultAttempts.push({ model: currentModel });
5166
+ }
5167
+ const hasAvailabilityFilter = availableModels != null && availableModels.size > 0;
5168
+ for (const candidate of candidates) {
5169
+ const key = modelKey(candidate);
5170
+ if (skipKeys.has(key))
5171
+ continue;
5172
+ if (hasAvailabilityFilter) {
5173
+ const match = fuzzyMatchModel(key, availableModels, [candidate.providerID]);
5174
+ if (!match)
5175
+ continue;
5176
+ }
5177
+ return {
5178
+ kind: "next",
5179
+ model: candidate,
5180
+ attempts: resultAttempts
5181
+ };
5182
+ }
5183
+ return {
5184
+ kind: "exhausted",
5185
+ attempts: resultAttempts,
5186
+ lastErrorClassification
5187
+ };
5188
+ }
5189
+ var init_runtime_fallback = __esm(() => {
5190
+ init_model_availability();
5191
+ init_model_requirements();
5192
+ });
5193
+
5067
5194
  // src/shared/perf-timer.ts
5068
5195
  class PerfTimer {
5069
5196
  marks = new Map;
@@ -5241,6 +5368,86 @@ class PerfTracer {
5241
5368
  }
5242
5369
  var init_perf_tracer = () => {};
5243
5370
 
5371
+ // src/shared/windows-reserved-names.ts
5372
+ import { existsSync as existsSync12, readdirSync as readdirSync5 } from "fs";
5373
+ import { join as join14 } from "path";
5374
+ function scanForReservedNames(directory, maxDepth = 2) {
5375
+ if (!existsSync12(directory))
5376
+ return [];
5377
+ const found = [];
5378
+ _scan(directory, 0, maxDepth, found);
5379
+ return found;
5380
+ }
5381
+ function _scan(dir, depth, maxDepth, found) {
5382
+ if (depth > maxDepth)
5383
+ return;
5384
+ let entries;
5385
+ try {
5386
+ entries = readdirSync5(dir);
5387
+ } catch {
5388
+ return;
5389
+ }
5390
+ for (const name of entries) {
5391
+ const upper = name.toUpperCase();
5392
+ const baseName = upper.split(".")[0] ?? "";
5393
+ if (WIN_RESERVED_NAMES.has(upper) || WIN_RESERVED_NAMES.has(baseName)) {
5394
+ found.push(join14(dir, name));
5395
+ }
5396
+ const fullPath = join14(dir, name);
5397
+ try {
5398
+ const stat = existsSync12(fullPath);
5399
+ if (stat && depth < maxDepth) {
5400
+ _scan(fullPath, depth + 1, maxDepth, found);
5401
+ }
5402
+ } catch {}
5403
+ }
5404
+ }
5405
+ function formatReservedNamesWarning(found) {
5406
+ const lines = [
5407
+ "",
5408
+ "\u26A0\uFE0F WINDOWS RESERVED DEVICE NAMES DETECTED",
5409
+ " The following paths match Windows reserved device names (NUL, CON, AUX, etc.):",
5410
+ "",
5411
+ ...found.map((p) => ` - ${p}`),
5412
+ "",
5413
+ " These will cause 'error: short read while indexing' git failures on Windows.",
5414
+ " This can make OpenCode's snapshot system extremely slow (30+ minutes).",
5415
+ "",
5416
+ " Fix: Rename these files/directories to avoid reserved names.",
5417
+ " e.g., rename 'nul' \u2192 'null-device', 'con' \u2192 'console-util'",
5418
+ ""
5419
+ ];
5420
+ return lines.join(`
5421
+ `);
5422
+ }
5423
+ var WIN_RESERVED_NAMES;
5424
+ var init_windows_reserved_names = __esm(() => {
5425
+ WIN_RESERVED_NAMES = new Set([
5426
+ "CON",
5427
+ "PRN",
5428
+ "AUX",
5429
+ "NUL",
5430
+ "COM1",
5431
+ "COM2",
5432
+ "COM3",
5433
+ "COM4",
5434
+ "COM5",
5435
+ "COM6",
5436
+ "COM7",
5437
+ "COM8",
5438
+ "COM9",
5439
+ "LPT1",
5440
+ "LPT2",
5441
+ "LPT3",
5442
+ "LPT4",
5443
+ "LPT5",
5444
+ "LPT6",
5445
+ "LPT7",
5446
+ "LPT8",
5447
+ "LPT9"
5448
+ ]);
5449
+ });
5450
+
5244
5451
  // src/shared/index.ts
5245
5452
  var init_shared = __esm(() => {
5246
5453
  init_frontmatter();
@@ -5268,8 +5475,10 @@ var init_shared = __esm(() => {
5268
5475
  init_model_requirements();
5269
5476
  init_model_resolver();
5270
5477
  init_model_availability();
5478
+ init_runtime_fallback();
5271
5479
  init_perf_tracer();
5272
5480
  init_fileio_monitor();
5481
+ init_windows_reserved_names();
5273
5482
  });
5274
5483
 
5275
5484
  // node_modules/picomatch/lib/constants.js
@@ -16159,20 +16368,20 @@ function createSessionRecoveryHook(ctx, options) {
16159
16368
  // src/hooks/comment-checker/cli.ts
16160
16369
  var {spawn: spawn5 } = globalThis.Bun;
16161
16370
  import { createRequire as createRequire2 } from "module";
16162
- import { dirname, join as join15 } from "path";
16163
- import { existsSync as existsSync13 } from "fs";
16371
+ import { dirname, join as join16 } from "path";
16372
+ import { existsSync as existsSync14 } from "fs";
16164
16373
  import * as fs5 from "fs";
16165
16374
  import { tmpdir as tmpdir4 } from "os";
16166
16375
 
16167
16376
  // src/hooks/comment-checker/downloader.ts
16168
16377
  init_shared();
16169
16378
  var {spawn: spawn4 } = globalThis.Bun;
16170
- import { existsSync as existsSync12, mkdirSync as mkdirSync4, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync3 } from "fs";
16171
- import { join as join14 } from "path";
16379
+ import { existsSync as existsSync13, mkdirSync as mkdirSync4, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync3 } from "fs";
16380
+ import { join as join15 } from "path";
16172
16381
  import { homedir as homedir7, tmpdir as tmpdir3 } from "os";
16173
16382
  import { createRequire } from "module";
16174
16383
  var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
16175
- var DEBUG_FILE = join14(tmpdir3(), "comment-checker-debug.log");
16384
+ var DEBUG_FILE = join15(tmpdir3(), "comment-checker-debug.log");
16176
16385
  function debugLog(...args) {
16177
16386
  if (DEBUG) {
16178
16387
  const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16191,19 +16400,19 @@ var PLATFORM_MAP = {
16191
16400
  function getCacheDir() {
16192
16401
  if (process.platform === "win32") {
16193
16402
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
16194
- const base2 = localAppData || join14(homedir7(), "AppData", "Local");
16195
- return join14(base2, "oh-my-opencode", "bin");
16403
+ const base2 = localAppData || join15(homedir7(), "AppData", "Local");
16404
+ return join15(base2, "oh-my-opencode", "bin");
16196
16405
  }
16197
16406
  const xdgCache = process.env.XDG_CACHE_HOME;
16198
- const base = xdgCache || join14(homedir7(), ".cache");
16199
- return join14(base, "oh-my-opencode", "bin");
16407
+ const base = xdgCache || join15(homedir7(), ".cache");
16408
+ return join15(base, "oh-my-opencode", "bin");
16200
16409
  }
16201
16410
  function getBinaryName() {
16202
16411
  return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
16203
16412
  }
16204
16413
  function getCachedBinaryPath() {
16205
- const binaryPath = join14(getCacheDir(), getBinaryName());
16206
- return existsSync12(binaryPath) ? binaryPath : null;
16414
+ const binaryPath = join15(getCacheDir(), getBinaryName());
16415
+ return existsSync13(binaryPath) ? binaryPath : null;
16207
16416
  }
16208
16417
  function getPackageVersion() {
16209
16418
  try {
@@ -16235,8 +16444,8 @@ async function downloadCommentChecker() {
16235
16444
  }
16236
16445
  const cacheDir = getCacheDir();
16237
16446
  const binaryName = getBinaryName();
16238
- const binaryPath = join14(cacheDir, binaryName);
16239
- if (existsSync12(binaryPath)) {
16447
+ const binaryPath = join15(cacheDir, binaryName);
16448
+ if (existsSync13(binaryPath)) {
16240
16449
  debugLog("Binary already cached at:", binaryPath);
16241
16450
  return binaryPath;
16242
16451
  }
@@ -16247,14 +16456,14 @@ async function downloadCommentChecker() {
16247
16456
  debugLog(`Downloading from: ${downloadUrl}`);
16248
16457
  console.log(`[oh-my-opencode] Downloading comment-checker binary...`);
16249
16458
  try {
16250
- if (!existsSync12(cacheDir)) {
16459
+ if (!existsSync13(cacheDir)) {
16251
16460
  mkdirSync4(cacheDir, { recursive: true });
16252
16461
  }
16253
16462
  const response = await fetch(downloadUrl, { redirect: "follow" });
16254
16463
  if (!response.ok) {
16255
16464
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
16256
16465
  }
16257
- const archivePath = join14(cacheDir, assetName);
16466
+ const archivePath = join15(cacheDir, assetName);
16258
16467
  const arrayBuffer = await response.arrayBuffer();
16259
16468
  await Bun.write(archivePath, arrayBuffer);
16260
16469
  debugLog(`Downloaded archive to: ${archivePath}`);
@@ -16263,10 +16472,10 @@ async function downloadCommentChecker() {
16263
16472
  } else {
16264
16473
  await extractZip(archivePath, cacheDir);
16265
16474
  }
16266
- if (existsSync12(archivePath)) {
16475
+ if (existsSync13(archivePath)) {
16267
16476
  unlinkSync2(archivePath);
16268
16477
  }
16269
- if (process.platform !== "win32" && existsSync12(binaryPath)) {
16478
+ if (process.platform !== "win32" && existsSync13(binaryPath)) {
16270
16479
  chmodSync(binaryPath, 493);
16271
16480
  }
16272
16481
  debugLog(`Successfully downloaded binary to: ${binaryPath}`);
@@ -16290,7 +16499,7 @@ async function ensureCommentCheckerBinary() {
16290
16499
 
16291
16500
  // src/hooks/comment-checker/cli.ts
16292
16501
  var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
16293
- var DEBUG_FILE2 = join15(tmpdir4(), "comment-checker-debug.log");
16502
+ var DEBUG_FILE2 = join16(tmpdir4(), "comment-checker-debug.log");
16294
16503
  function debugLog2(...args) {
16295
16504
  if (DEBUG2) {
16296
16505
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16316,8 +16525,8 @@ function findCommentCheckerPathSync() {
16316
16525
  const require2 = createRequire2(import.meta.url);
16317
16526
  const cliPkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
16318
16527
  const cliDir = dirname(cliPkgPath);
16319
- const binaryPath = join15(cliDir, "bin", binaryName);
16320
- if (existsSync13(binaryPath)) {
16528
+ const binaryPath = join16(cliDir, "bin", binaryName);
16529
+ if (existsSync14(binaryPath)) {
16321
16530
  debugLog2("found binary in main package:", binaryPath);
16322
16531
  return binaryPath;
16323
16532
  }
@@ -16338,7 +16547,7 @@ async function getCommentCheckerPath() {
16338
16547
  }
16339
16548
  initPromise = (async () => {
16340
16549
  const syncPath = findCommentCheckerPathSync();
16341
- if (syncPath && existsSync13(syncPath)) {
16550
+ if (syncPath && existsSync14(syncPath)) {
16342
16551
  resolvedCliPath = syncPath;
16343
16552
  debugLog2("using sync-resolved path:", syncPath);
16344
16553
  return syncPath;
@@ -16374,7 +16583,7 @@ async function runCommentChecker(input, cliPath, customPrompt) {
16374
16583
  debugLog2("comment-checker binary not found");
16375
16584
  return { hasComments: false, message: "" };
16376
16585
  }
16377
- if (!existsSync13(binaryPath)) {
16586
+ if (!existsSync14(binaryPath)) {
16378
16587
  debugLog2("comment-checker binary does not exist:", binaryPath);
16379
16588
  return { hasComments: false, message: "" };
16380
16589
  }
@@ -16412,11 +16621,11 @@ async function runCommentChecker(input, cliPath, customPrompt) {
16412
16621
 
16413
16622
  // src/hooks/comment-checker/index.ts
16414
16623
  import * as fs6 from "fs";
16415
- import { existsSync as existsSync14 } from "fs";
16624
+ import { existsSync as existsSync15 } from "fs";
16416
16625
  import { tmpdir as tmpdir5 } from "os";
16417
- import { join as join16 } from "path";
16626
+ import { join as join17 } from "path";
16418
16627
  var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
16419
- var DEBUG_FILE3 = join16(tmpdir5(), "comment-checker-debug.log");
16628
+ var DEBUG_FILE3 = join17(tmpdir5(), "comment-checker-debug.log");
16420
16629
  function debugLog3(...args) {
16421
16630
  if (DEBUG3) {
16422
16631
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16496,7 +16705,7 @@ function createCommentCheckerHooks(config) {
16496
16705
  }
16497
16706
  try {
16498
16707
  const cliPath = await cliPathPromise;
16499
- if (!cliPath || !existsSync14(cliPath)) {
16708
+ if (!cliPath || !existsSync15(cliPath)) {
16500
16709
  debugLog3("CLI not available, skipping comment check");
16501
16710
  return;
16502
16711
  }
@@ -16576,33 +16785,33 @@ function createToolOutputTruncatorHook(ctx, options) {
16576
16785
  };
16577
16786
  }
16578
16787
  // src/hooks/directory-agents-injector/index.ts
16579
- import { existsSync as existsSync16, readFileSync as readFileSync9 } from "fs";
16580
- import { dirname as dirname2, join as join19, resolve as resolve3 } from "path";
16788
+ import { existsSync as existsSync17, readFileSync as readFileSync9 } from "fs";
16789
+ import { dirname as dirname2, join as join20, resolve as resolve3 } from "path";
16581
16790
 
16582
16791
  // src/hooks/directory-agents-injector/storage.ts
16583
16792
  import {
16584
- existsSync as existsSync15,
16793
+ existsSync as existsSync16,
16585
16794
  mkdirSync as mkdirSync5,
16586
16795
  readFileSync as readFileSync8,
16587
16796
  writeFileSync as writeFileSync5,
16588
16797
  unlinkSync as unlinkSync3
16589
16798
  } from "fs";
16590
- import { join as join18 } from "path";
16799
+ import { join as join19 } from "path";
16591
16800
 
16592
16801
  // src/hooks/directory-agents-injector/constants.ts
16593
16802
  init_data_path();
16594
- import { join as join17 } from "path";
16803
+ import { join as join18 } from "path";
16595
16804
  var OPENCODE_STORAGE3 = getOpenCodeStorageDir();
16596
- var AGENTS_INJECTOR_STORAGE = join17(OPENCODE_STORAGE3, "directory-agents");
16805
+ var AGENTS_INJECTOR_STORAGE = join18(OPENCODE_STORAGE3, "directory-agents");
16597
16806
  var AGENTS_FILENAME = "AGENTS.md";
16598
16807
 
16599
16808
  // src/hooks/directory-agents-injector/storage.ts
16600
16809
  function getStoragePath(sessionID) {
16601
- return join18(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
16810
+ return join19(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
16602
16811
  }
16603
16812
  function loadInjectedPaths(sessionID) {
16604
16813
  const filePath = getStoragePath(sessionID);
16605
- if (!existsSync15(filePath))
16814
+ if (!existsSync16(filePath))
16606
16815
  return new Set;
16607
16816
  try {
16608
16817
  const content = readFileSync8(filePath, "utf-8");
@@ -16613,7 +16822,7 @@ function loadInjectedPaths(sessionID) {
16613
16822
  }
16614
16823
  }
16615
16824
  function saveInjectedPaths(sessionID, paths) {
16616
- if (!existsSync15(AGENTS_INJECTOR_STORAGE)) {
16825
+ if (!existsSync16(AGENTS_INJECTOR_STORAGE)) {
16617
16826
  mkdirSync5(AGENTS_INJECTOR_STORAGE, { recursive: true });
16618
16827
  }
16619
16828
  const data = {
@@ -16625,7 +16834,7 @@ function saveInjectedPaths(sessionID, paths) {
16625
16834
  }
16626
16835
  function clearInjectedPaths(sessionID) {
16627
16836
  const filePath = getStoragePath(sessionID);
16628
- if (existsSync15(filePath)) {
16837
+ if (existsSync16(filePath)) {
16629
16838
  unlinkSync3(filePath);
16630
16839
  }
16631
16840
  }
@@ -16655,8 +16864,8 @@ function createDirectoryAgentsInjectorHook(ctx) {
16655
16864
  while (true) {
16656
16865
  const isRootDir = current === ctx.directory;
16657
16866
  if (!isRootDir) {
16658
- const agentsPath = join19(current, AGENTS_FILENAME);
16659
- if (existsSync16(agentsPath)) {
16867
+ const agentsPath = join20(current, AGENTS_FILENAME);
16868
+ if (existsSync17(agentsPath)) {
16660
16869
  found.push(agentsPath);
16661
16870
  }
16662
16871
  }
@@ -16753,33 +16962,33 @@ ${result}${truncationNotice}`;
16753
16962
  };
16754
16963
  }
16755
16964
  // src/hooks/directory-readme-injector/index.ts
16756
- import { existsSync as existsSync18, readFileSync as readFileSync11 } from "fs";
16757
- import { dirname as dirname3, join as join22, resolve as resolve4 } from "path";
16965
+ import { existsSync as existsSync19, readFileSync as readFileSync11 } from "fs";
16966
+ import { dirname as dirname3, join as join23, resolve as resolve4 } from "path";
16758
16967
 
16759
16968
  // src/hooks/directory-readme-injector/storage.ts
16760
16969
  import {
16761
- existsSync as existsSync17,
16970
+ existsSync as existsSync18,
16762
16971
  mkdirSync as mkdirSync6,
16763
16972
  readFileSync as readFileSync10,
16764
16973
  writeFileSync as writeFileSync6,
16765
16974
  unlinkSync as unlinkSync4
16766
16975
  } from "fs";
16767
- import { join as join21 } from "path";
16976
+ import { join as join22 } from "path";
16768
16977
 
16769
16978
  // src/hooks/directory-readme-injector/constants.ts
16770
16979
  init_data_path();
16771
- import { join as join20 } from "path";
16980
+ import { join as join21 } from "path";
16772
16981
  var OPENCODE_STORAGE4 = getOpenCodeStorageDir();
16773
- var README_INJECTOR_STORAGE = join20(OPENCODE_STORAGE4, "directory-readme");
16982
+ var README_INJECTOR_STORAGE = join21(OPENCODE_STORAGE4, "directory-readme");
16774
16983
  var README_FILENAME = "README.md";
16775
16984
 
16776
16985
  // src/hooks/directory-readme-injector/storage.ts
16777
16986
  function getStoragePath2(sessionID) {
16778
- return join21(README_INJECTOR_STORAGE, `${sessionID}.json`);
16987
+ return join22(README_INJECTOR_STORAGE, `${sessionID}.json`);
16779
16988
  }
16780
16989
  function loadInjectedPaths2(sessionID) {
16781
16990
  const filePath = getStoragePath2(sessionID);
16782
- if (!existsSync17(filePath))
16991
+ if (!existsSync18(filePath))
16783
16992
  return new Set;
16784
16993
  try {
16785
16994
  const content = readFileSync10(filePath, "utf-8");
@@ -16790,7 +16999,7 @@ function loadInjectedPaths2(sessionID) {
16790
16999
  }
16791
17000
  }
16792
17001
  function saveInjectedPaths2(sessionID, paths) {
16793
- if (!existsSync17(README_INJECTOR_STORAGE)) {
17002
+ if (!existsSync18(README_INJECTOR_STORAGE)) {
16794
17003
  mkdirSync6(README_INJECTOR_STORAGE, { recursive: true });
16795
17004
  }
16796
17005
  const data = {
@@ -16802,7 +17011,7 @@ function saveInjectedPaths2(sessionID, paths) {
16802
17011
  }
16803
17012
  function clearInjectedPaths2(sessionID) {
16804
17013
  const filePath = getStoragePath2(sessionID);
16805
- if (existsSync17(filePath)) {
17014
+ if (existsSync18(filePath)) {
16806
17015
  unlinkSync4(filePath);
16807
17016
  }
16808
17017
  }
@@ -16830,8 +17039,8 @@ function createDirectoryReadmeInjectorHook(ctx) {
16830
17039
  const found = [];
16831
17040
  let current = startDir;
16832
17041
  while (true) {
16833
- const readmePath = join22(current, README_FILENAME);
16834
- if (existsSync18(readmePath)) {
17042
+ const readmePath = join23(current, README_FILENAME);
17043
+ if (existsSync19(readmePath)) {
16835
17044
  found.push(readmePath);
16836
17045
  }
16837
17046
  if (current === ctx.directory)
@@ -17141,22 +17350,22 @@ var TRUNCATE_CONFIG = {
17141
17350
 
17142
17351
  // src/hooks/anthropic-context-window-limit-recovery/storage.ts
17143
17352
  init_data_path();
17144
- import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
17145
- import { join as join23 } from "path";
17353
+ import { existsSync as existsSync20, readdirSync as readdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
17354
+ import { join as join24 } from "path";
17146
17355
  var OPENCODE_STORAGE5 = getOpenCodeStorageDir();
17147
- var MESSAGE_STORAGE3 = join23(OPENCODE_STORAGE5, "message");
17148
- var PART_STORAGE3 = join23(OPENCODE_STORAGE5, "part");
17356
+ var MESSAGE_STORAGE3 = join24(OPENCODE_STORAGE5, "message");
17357
+ var PART_STORAGE3 = join24(OPENCODE_STORAGE5, "part");
17149
17358
  var TRUNCATION_MESSAGE = "[TOOL RESULT TRUNCATED - Context limit exceeded. Original output was too large and has been truncated to recover the session. Please re-run this tool if you need the full output.]";
17150
17359
  function getMessageDir3(sessionID) {
17151
- if (!existsSync19(MESSAGE_STORAGE3))
17360
+ if (!existsSync20(MESSAGE_STORAGE3))
17152
17361
  return "";
17153
- const directPath = join23(MESSAGE_STORAGE3, sessionID);
17154
- if (existsSync19(directPath)) {
17362
+ const directPath = join24(MESSAGE_STORAGE3, sessionID);
17363
+ if (existsSync20(directPath)) {
17155
17364
  return directPath;
17156
17365
  }
17157
- for (const dir of readdirSync5(MESSAGE_STORAGE3)) {
17158
- const sessionPath = join23(MESSAGE_STORAGE3, dir, sessionID);
17159
- if (existsSync19(sessionPath)) {
17366
+ for (const dir of readdirSync6(MESSAGE_STORAGE3)) {
17367
+ const sessionPath = join24(MESSAGE_STORAGE3, dir, sessionID);
17368
+ if (existsSync20(sessionPath)) {
17160
17369
  return sessionPath;
17161
17370
  }
17162
17371
  }
@@ -17164,10 +17373,10 @@ function getMessageDir3(sessionID) {
17164
17373
  }
17165
17374
  function getMessageIds(sessionID) {
17166
17375
  const messageDir = getMessageDir3(sessionID);
17167
- if (!messageDir || !existsSync19(messageDir))
17376
+ if (!messageDir || !existsSync20(messageDir))
17168
17377
  return [];
17169
17378
  const messageIds = [];
17170
- for (const file of readdirSync5(messageDir)) {
17379
+ for (const file of readdirSync6(messageDir)) {
17171
17380
  if (!file.endsWith(".json"))
17172
17381
  continue;
17173
17382
  const messageId = file.replace(".json", "");
@@ -17179,14 +17388,14 @@ function findToolResultsBySize(sessionID) {
17179
17388
  const messageIds = getMessageIds(sessionID);
17180
17389
  const results = [];
17181
17390
  for (const messageID of messageIds) {
17182
- const partDir = join23(PART_STORAGE3, messageID);
17183
- if (!existsSync19(partDir))
17391
+ const partDir = join24(PART_STORAGE3, messageID);
17392
+ if (!existsSync20(partDir))
17184
17393
  continue;
17185
- for (const file of readdirSync5(partDir)) {
17394
+ for (const file of readdirSync6(partDir)) {
17186
17395
  if (!file.endsWith(".json"))
17187
17396
  continue;
17188
17397
  try {
17189
- const partPath = join23(partDir, file);
17398
+ const partPath = join24(partDir, file);
17190
17399
  const content = readFileSync12(partPath, "utf-8");
17191
17400
  const part = JSON.parse(content);
17192
17401
  if (part.type === "tool" && part.state?.output && !part.truncated) {
@@ -18033,8 +18242,8 @@ function createThinkModeHook() {
18033
18242
  }
18034
18243
  // src/hooks/claude-code-hooks/config.ts
18035
18244
  init_shared();
18036
- import { join as join24 } from "path";
18037
- import { existsSync as existsSync20 } from "fs";
18245
+ import { join as join25 } from "path";
18246
+ import { existsSync as existsSync21 } from "fs";
18038
18247
  function normalizeHookMatcher(raw) {
18039
18248
  return {
18040
18249
  matcher: raw.matcher ?? raw.pattern ?? "*",
@@ -18060,11 +18269,11 @@ function normalizeHooksConfig(raw) {
18060
18269
  function getClaudeSettingsPaths(customPath) {
18061
18270
  const claudeConfigDir = getClaudeConfigDir();
18062
18271
  const paths = [
18063
- join24(claudeConfigDir, "settings.json"),
18064
- join24(process.cwd(), ".claude", "settings.json"),
18065
- join24(process.cwd(), ".claude", "settings.local.json")
18272
+ join25(claudeConfigDir, "settings.json"),
18273
+ join25(process.cwd(), ".claude", "settings.json"),
18274
+ join25(process.cwd(), ".claude", "settings.local.json")
18066
18275
  ];
18067
- if (customPath && existsSync20(customPath)) {
18276
+ if (customPath && existsSync21(customPath)) {
18068
18277
  paths.unshift(customPath);
18069
18278
  }
18070
18279
  return paths;
@@ -18089,7 +18298,7 @@ async function loadClaudeHooksConfig(customSettingsPath) {
18089
18298
  const paths = getClaudeSettingsPaths(customSettingsPath);
18090
18299
  let mergedConfig = {};
18091
18300
  for (const settingsPath of paths) {
18092
- if (existsSync20(settingsPath)) {
18301
+ if (existsSync21(settingsPath)) {
18093
18302
  try {
18094
18303
  const content = await Bun.file(settingsPath).text();
18095
18304
  const settings = JSON.parse(content);
@@ -18108,14 +18317,14 @@ async function loadClaudeHooksConfig(customSettingsPath) {
18108
18317
  // src/hooks/claude-code-hooks/config-loader.ts
18109
18318
  init_logger();
18110
18319
  init_shared();
18111
- import { existsSync as existsSync21 } from "fs";
18112
- import { join as join25 } from "path";
18113
- var USER_CONFIG_PATH = join25(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json");
18320
+ import { existsSync as existsSync22 } from "fs";
18321
+ import { join as join26 } from "path";
18322
+ var USER_CONFIG_PATH = join26(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json");
18114
18323
  function getProjectConfigPath() {
18115
- return join25(process.cwd(), ".opencode", "opencode-cc-plugin.json");
18324
+ return join26(process.cwd(), ".opencode", "opencode-cc-plugin.json");
18116
18325
  }
18117
18326
  async function loadConfigFromPath(path4) {
18118
- if (!existsSync21(path4)) {
18327
+ if (!existsSync22(path4)) {
18119
18328
  return null;
18120
18329
  }
18121
18330
  try {
@@ -18303,16 +18512,16 @@ init_shared();
18303
18512
  // src/hooks/claude-code-hooks/transcript.ts
18304
18513
  init_tool_name();
18305
18514
  init_shared();
18306
- import { join as join26 } from "path";
18307
- import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync6, existsSync as existsSync22, writeFileSync as writeFileSync8, unlinkSync as unlinkSync5 } from "fs";
18515
+ import { join as join27 } from "path";
18516
+ import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync6, existsSync as existsSync23, writeFileSync as writeFileSync8, unlinkSync as unlinkSync5 } from "fs";
18308
18517
  import { tmpdir as tmpdir6 } from "os";
18309
18518
  import { randomUUID } from "crypto";
18310
- var TRANSCRIPT_DIR = join26(getClaudeConfigDir(), "transcripts");
18519
+ var TRANSCRIPT_DIR = join27(getClaudeConfigDir(), "transcripts");
18311
18520
  function getTranscriptPath(sessionId) {
18312
- return join26(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
18521
+ return join27(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
18313
18522
  }
18314
18523
  function ensureTranscriptDir() {
18315
- if (!existsSync22(TRANSCRIPT_DIR)) {
18524
+ if (!existsSync23(TRANSCRIPT_DIR)) {
18316
18525
  mkdirSync7(TRANSCRIPT_DIR, { recursive: true });
18317
18526
  }
18318
18527
  }
@@ -18399,7 +18608,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
18399
18608
  }
18400
18609
  };
18401
18610
  entries.push(JSON.stringify(currentEntry));
18402
- const tempPath = join26(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18611
+ const tempPath = join27(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18403
18612
  writeFileSync8(tempPath, entries.join(`
18404
18613
  `) + `
18405
18614
  `);
@@ -18419,7 +18628,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
18419
18628
  ]
18420
18629
  }
18421
18630
  };
18422
- const tempPath = join26(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18631
+ const tempPath = join27(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18423
18632
  writeFileSync8(tempPath, JSON.stringify(currentEntry) + `
18424
18633
  `);
18425
18634
  return tempPath;
@@ -18635,11 +18844,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
18635
18844
  init_shared();
18636
18845
 
18637
18846
  // src/hooks/claude-code-hooks/todo.ts
18638
- import { join as join27 } from "path";
18847
+ import { join as join28 } from "path";
18639
18848
  init_shared();
18640
- var TODO_DIR = join27(getClaudeConfigDir(), "todos");
18849
+ var TODO_DIR = join28(getClaudeConfigDir(), "todos");
18641
18850
  function getTodoPath(sessionId) {
18642
- return join27(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
18851
+ return join28(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
18643
18852
  }
18644
18853
 
18645
18854
  // src/hooks/claude-code-hooks/stop.ts
@@ -19087,18 +19296,18 @@ import { relative as relative4, resolve as resolve5 } from "path";
19087
19296
 
19088
19297
  // src/hooks/rules-injector/finder.ts
19089
19298
  import {
19090
- existsSync as existsSync23,
19091
- readdirSync as readdirSync6,
19299
+ existsSync as existsSync24,
19300
+ readdirSync as readdirSync7,
19092
19301
  realpathSync,
19093
19302
  statSync as statSync2
19094
19303
  } from "fs";
19095
- import { dirname as dirname4, join as join29, relative as relative2 } from "path";
19304
+ import { dirname as dirname4, join as join30, relative as relative2 } from "path";
19096
19305
 
19097
19306
  // src/hooks/rules-injector/constants.ts
19098
19307
  init_data_path();
19099
- import { join as join28 } from "path";
19308
+ import { join as join29 } from "path";
19100
19309
  var OPENCODE_STORAGE6 = getOpenCodeStorageDir();
19101
- var RULES_INJECTOR_STORAGE = join28(OPENCODE_STORAGE6, "rules-injector");
19310
+ var RULES_INJECTOR_STORAGE = join29(OPENCODE_STORAGE6, "rules-injector");
19102
19311
  var PROJECT_MARKERS = [
19103
19312
  ".git",
19104
19313
  "pyproject.toml",
@@ -19139,8 +19348,8 @@ function findProjectRoot(startPath) {
19139
19348
  }
19140
19349
  while (true) {
19141
19350
  for (const marker of PROJECT_MARKERS) {
19142
- const markerPath = join29(current, marker);
19143
- if (existsSync23(markerPath)) {
19351
+ const markerPath = join30(current, marker);
19352
+ if (existsSync24(markerPath)) {
19144
19353
  return current;
19145
19354
  }
19146
19355
  }
@@ -19152,12 +19361,12 @@ function findProjectRoot(startPath) {
19152
19361
  }
19153
19362
  }
19154
19363
  function findRuleFilesRecursive(dir, results) {
19155
- if (!existsSync23(dir))
19364
+ if (!existsSync24(dir))
19156
19365
  return;
19157
19366
  try {
19158
- const entries = readdirSync6(dir, { withFileTypes: true });
19367
+ const entries = readdirSync7(dir, { withFileTypes: true });
19159
19368
  for (const entry of entries) {
19160
- const fullPath = join29(dir, entry.name);
19369
+ const fullPath = join30(dir, entry.name);
19161
19370
  if (entry.isDirectory()) {
19162
19371
  findRuleFilesRecursive(fullPath, results);
19163
19372
  } else if (entry.isFile()) {
@@ -19182,7 +19391,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
19182
19391
  let distance = 0;
19183
19392
  while (true) {
19184
19393
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
19185
- const ruleDir = join29(currentDir, parent, subdir);
19394
+ const ruleDir = join30(currentDir, parent, subdir);
19186
19395
  const files = [];
19187
19396
  findRuleFilesRecursive(ruleDir, files);
19188
19397
  for (const filePath of files) {
@@ -19208,8 +19417,8 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
19208
19417
  }
19209
19418
  if (projectRoot) {
19210
19419
  for (const ruleFile of PROJECT_RULE_FILES) {
19211
- const filePath = join29(projectRoot, ruleFile);
19212
- if (existsSync23(filePath)) {
19420
+ const filePath = join30(projectRoot, ruleFile);
19421
+ if (existsSync24(filePath)) {
19213
19422
  try {
19214
19423
  const stat = statSync2(filePath);
19215
19424
  if (stat.isFile()) {
@@ -19229,7 +19438,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
19229
19438
  }
19230
19439
  }
19231
19440
  }
19232
- const userRuleDir = join29(homeDir, USER_RULE_DIR);
19441
+ const userRuleDir = join30(homeDir, USER_RULE_DIR);
19233
19442
  const userFiles = [];
19234
19443
  findRuleFilesRecursive(userRuleDir, userFiles);
19235
19444
  for (const filePath of userFiles) {
@@ -19418,19 +19627,19 @@ function mergeGlobs(existing, newValue) {
19418
19627
 
19419
19628
  // src/hooks/rules-injector/storage.ts
19420
19629
  import {
19421
- existsSync as existsSync24,
19630
+ existsSync as existsSync25,
19422
19631
  mkdirSync as mkdirSync8,
19423
19632
  readFileSync as readFileSync13,
19424
19633
  writeFileSync as writeFileSync9,
19425
19634
  unlinkSync as unlinkSync6
19426
19635
  } from "fs";
19427
- import { join as join30 } from "path";
19636
+ import { join as join31 } from "path";
19428
19637
  function getStoragePath3(sessionID) {
19429
- return join30(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
19638
+ return join31(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
19430
19639
  }
19431
19640
  function loadInjectedRules(sessionID) {
19432
19641
  const filePath = getStoragePath3(sessionID);
19433
- if (!existsSync24(filePath))
19642
+ if (!existsSync25(filePath))
19434
19643
  return { contentHashes: new Set, realPaths: new Set };
19435
19644
  try {
19436
19645
  const content = readFileSync13(filePath, "utf-8");
@@ -19444,7 +19653,7 @@ function loadInjectedRules(sessionID) {
19444
19653
  }
19445
19654
  }
19446
19655
  function saveInjectedRules(sessionID, data) {
19447
- if (!existsSync24(RULES_INJECTOR_STORAGE)) {
19656
+ if (!existsSync25(RULES_INJECTOR_STORAGE)) {
19448
19657
  mkdirSync8(RULES_INJECTOR_STORAGE, { recursive: true });
19449
19658
  }
19450
19659
  const storageData = {
@@ -19457,7 +19666,7 @@ function saveInjectedRules(sessionID, data) {
19457
19666
  }
19458
19667
  function clearInjectedRules(sessionID) {
19459
19668
  const filePath = getStoragePath3(sessionID);
19460
- if (existsSync24(filePath)) {
19669
+ if (existsSync25(filePath)) {
19461
19670
  unlinkSync6(filePath);
19462
19671
  }
19463
19672
  }
@@ -19613,19 +19822,19 @@ init_auto_update_checker();
19613
19822
 
19614
19823
  // src/hooks/agent-usage-reminder/storage.ts
19615
19824
  import {
19616
- existsSync as existsSync27,
19825
+ existsSync as existsSync28,
19617
19826
  mkdirSync as mkdirSync9,
19618
19827
  readFileSync as readFileSync17,
19619
19828
  writeFileSync as writeFileSync12,
19620
19829
  unlinkSync as unlinkSync7
19621
19830
  } from "fs";
19622
- import { join as join35 } from "path";
19831
+ import { join as join36 } from "path";
19623
19832
 
19624
19833
  // src/hooks/agent-usage-reminder/constants.ts
19625
19834
  init_data_path();
19626
- import { join as join34 } from "path";
19835
+ import { join as join35 } from "path";
19627
19836
  var OPENCODE_STORAGE7 = getOpenCodeStorageDir();
19628
- var AGENT_USAGE_REMINDER_STORAGE = join34(OPENCODE_STORAGE7, "agent-usage-reminder");
19837
+ var AGENT_USAGE_REMINDER_STORAGE = join35(OPENCODE_STORAGE7, "agent-usage-reminder");
19629
19838
  var TARGET_TOOLS = new Set([
19630
19839
  "grep",
19631
19840
  "safe_grep",
@@ -19671,11 +19880,11 @@ delegate_task(agent="librarian", prompt="\u67E5\u627E Z \u7684\u6587\u6863")
19671
19880
 
19672
19881
  // src/hooks/agent-usage-reminder/storage.ts
19673
19882
  function getStoragePath4(sessionID) {
19674
- return join35(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
19883
+ return join36(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
19675
19884
  }
19676
19885
  function loadAgentUsageState(sessionID) {
19677
19886
  const filePath = getStoragePath4(sessionID);
19678
- if (!existsSync27(filePath))
19887
+ if (!existsSync28(filePath))
19679
19888
  return null;
19680
19889
  try {
19681
19890
  const content = readFileSync17(filePath, "utf-8");
@@ -19685,7 +19894,7 @@ function loadAgentUsageState(sessionID) {
19685
19894
  }
19686
19895
  }
19687
19896
  function saveAgentUsageState(state2) {
19688
- if (!existsSync27(AGENT_USAGE_REMINDER_STORAGE)) {
19897
+ if (!existsSync28(AGENT_USAGE_REMINDER_STORAGE)) {
19689
19898
  mkdirSync9(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
19690
19899
  }
19691
19900
  const filePath = getStoragePath4(state2.sessionID);
@@ -19693,7 +19902,7 @@ function saveAgentUsageState(state2) {
19693
19902
  }
19694
19903
  function clearAgentUsageState(sessionID) {
19695
19904
  const filePath = getStoragePath4(sessionID);
19696
- if (existsSync27(filePath)) {
19905
+ if (existsSync28(filePath)) {
19697
19906
  unlinkSync7(filePath);
19698
19907
  }
19699
19908
  }
@@ -20276,19 +20485,19 @@ function createNonInteractiveEnvHook(_ctx) {
20276
20485
  }
20277
20486
  // src/hooks/interactive-bash-session/storage.ts
20278
20487
  import {
20279
- existsSync as existsSync28,
20488
+ existsSync as existsSync29,
20280
20489
  mkdirSync as mkdirSync10,
20281
20490
  readFileSync as readFileSync18,
20282
20491
  writeFileSync as writeFileSync13,
20283
20492
  unlinkSync as unlinkSync8
20284
20493
  } from "fs";
20285
- import { join as join37 } from "path";
20494
+ import { join as join38 } from "path";
20286
20495
 
20287
20496
  // src/hooks/interactive-bash-session/constants.ts
20288
20497
  init_data_path();
20289
- import { join as join36 } from "path";
20498
+ import { join as join37 } from "path";
20290
20499
  var OPENCODE_STORAGE8 = getOpenCodeStorageDir();
20291
- var INTERACTIVE_BASH_SESSION_STORAGE = join36(OPENCODE_STORAGE8, "interactive-bash-session");
20500
+ var INTERACTIVE_BASH_SESSION_STORAGE = join37(OPENCODE_STORAGE8, "interactive-bash-session");
20292
20501
  var OMO_SESSION_PREFIX = "omo-";
20293
20502
  function buildSessionReminderMessage(sessions) {
20294
20503
  if (sessions.length === 0)
@@ -20300,11 +20509,11 @@ function buildSessionReminderMessage(sessions) {
20300
20509
 
20301
20510
  // src/hooks/interactive-bash-session/storage.ts
20302
20511
  function getStoragePath5(sessionID) {
20303
- return join37(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
20512
+ return join38(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
20304
20513
  }
20305
20514
  function loadInteractiveBashSessionState(sessionID) {
20306
20515
  const filePath = getStoragePath5(sessionID);
20307
- if (!existsSync28(filePath))
20516
+ if (!existsSync29(filePath))
20308
20517
  return null;
20309
20518
  try {
20310
20519
  const content = readFileSync18(filePath, "utf-8");
@@ -20319,7 +20528,7 @@ function loadInteractiveBashSessionState(sessionID) {
20319
20528
  }
20320
20529
  }
20321
20530
  function saveInteractiveBashSessionState(state2) {
20322
- if (!existsSync28(INTERACTIVE_BASH_SESSION_STORAGE)) {
20531
+ if (!existsSync29(INTERACTIVE_BASH_SESSION_STORAGE)) {
20323
20532
  mkdirSync10(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
20324
20533
  }
20325
20534
  const filePath = getStoragePath5(state2.sessionID);
@@ -20332,7 +20541,7 @@ function saveInteractiveBashSessionState(state2) {
20332
20541
  }
20333
20542
  function clearInteractiveBashSessionState(sessionID) {
20334
20543
  const filePath = getStoragePath5(sessionID);
20335
- if (existsSync28(filePath)) {
20544
+ if (existsSync29(filePath)) {
20336
20545
  unlinkSync8(filePath);
20337
20546
  }
20338
20547
  }
@@ -20596,13 +20805,13 @@ function createThinkingBlockValidatorHook() {
20596
20805
  // src/hooks/ralph-loop/index.ts
20597
20806
  init_logger();
20598
20807
  init_system_directive();
20599
- import { existsSync as existsSync30, readFileSync as readFileSync20, readdirSync as readdirSync7 } from "fs";
20600
- import { join as join39 } from "path";
20808
+ import { existsSync as existsSync31, readFileSync as readFileSync20, readdirSync as readdirSync8 } from "fs";
20809
+ import { join as join40 } from "path";
20601
20810
 
20602
20811
  // src/hooks/ralph-loop/storage.ts
20603
20812
  init_frontmatter();
20604
- import { existsSync as existsSync29, readFileSync as readFileSync19, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, mkdirSync as mkdirSync11 } from "fs";
20605
- import { dirname as dirname6, join as join38 } from "path";
20813
+ import { existsSync as existsSync30, readFileSync as readFileSync19, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, mkdirSync as mkdirSync11 } from "fs";
20814
+ import { dirname as dirname6, join as join39 } from "path";
20606
20815
 
20607
20816
  // src/hooks/ralph-loop/constants.ts
20608
20817
  var HOOK_NAME3 = "ralph-loop";
@@ -20612,11 +20821,11 @@ var DEFAULT_COMPLETION_PROMISE = "DONE";
20612
20821
 
20613
20822
  // src/hooks/ralph-loop/storage.ts
20614
20823
  function getStateFilePath(directory, customPath) {
20615
- return customPath ? join38(directory, customPath) : join38(directory, DEFAULT_STATE_FILE);
20824
+ return customPath ? join39(directory, customPath) : join39(directory, DEFAULT_STATE_FILE);
20616
20825
  }
20617
20826
  function readState(directory, customPath) {
20618
20827
  const filePath = getStateFilePath(directory, customPath);
20619
- if (!existsSync29(filePath)) {
20828
+ if (!existsSync30(filePath)) {
20620
20829
  return null;
20621
20830
  }
20622
20831
  try {
@@ -20654,7 +20863,7 @@ function writeState(directory, state2, customPath) {
20654
20863
  const filePath = getStateFilePath(directory, customPath);
20655
20864
  try {
20656
20865
  const dir = dirname6(filePath);
20657
- if (!existsSync29(dir)) {
20866
+ if (!existsSync30(dir)) {
20658
20867
  mkdirSync11(dir, { recursive: true });
20659
20868
  }
20660
20869
  const sessionIdLine = state2.session_id ? `session_id: "${state2.session_id}"
@@ -20679,7 +20888,7 @@ ${state2.prompt}
20679
20888
  function clearState(directory, customPath) {
20680
20889
  const filePath = getStateFilePath(directory, customPath);
20681
20890
  try {
20682
- if (existsSync29(filePath)) {
20891
+ if (existsSync30(filePath)) {
20683
20892
  unlinkSync9(filePath);
20684
20893
  }
20685
20894
  return true;
@@ -20700,14 +20909,14 @@ function incrementIteration(directory, customPath) {
20700
20909
 
20701
20910
  // src/hooks/ralph-loop/index.ts
20702
20911
  function getMessageDir4(sessionID) {
20703
- if (!existsSync30(MESSAGE_STORAGE))
20912
+ if (!existsSync31(MESSAGE_STORAGE))
20704
20913
  return null;
20705
- const directPath = join39(MESSAGE_STORAGE, sessionID);
20706
- if (existsSync30(directPath))
20914
+ const directPath = join40(MESSAGE_STORAGE, sessionID);
20915
+ if (existsSync31(directPath))
20707
20916
  return directPath;
20708
- for (const dir of readdirSync7(MESSAGE_STORAGE)) {
20709
- const sessionPath = join39(MESSAGE_STORAGE, dir, sessionID);
20710
- if (existsSync30(sessionPath))
20917
+ for (const dir of readdirSync8(MESSAGE_STORAGE)) {
20918
+ const sessionPath = join40(MESSAGE_STORAGE, dir, sessionID);
20919
+ if (existsSync31(sessionPath))
20711
20920
  return sessionPath;
20712
20921
  }
20713
20922
  return null;
@@ -20744,7 +20953,7 @@ function createRalphLoopHook(ctx, options) {
20744
20953
  if (!transcriptPath)
20745
20954
  return false;
20746
20955
  try {
20747
- if (!existsSync30(transcriptPath))
20956
+ if (!existsSync31(transcriptPath))
20748
20957
  return false;
20749
20958
  const content = readFileSync20(transcriptPath, "utf-8");
20750
20959
  const pattern = new RegExp(`<promise>\\s*${escapeRegex(promise)}\\s*</promise>`, "is");
@@ -21060,8 +21269,8 @@ function extractPromptText3(parts) {
21060
21269
  // src/hooks/auto-slash-command/executor.ts
21061
21270
  init_shared();
21062
21271
  init_file_utils();
21063
- import { existsSync as existsSync32, readdirSync as readdirSync8, readFileSync as readFileSync23 } from "fs";
21064
- import { join as join41, basename as basename2, dirname as dirname8 } from "path";
21272
+ import { existsSync as existsSync33, readdirSync as readdirSync9, readFileSync as readFileSync23 } from "fs";
21273
+ import { join as join42, basename as basename2, dirname as dirname8 } from "path";
21065
21274
  // src/features/opencode-skill-loader/loader.ts
21066
21275
  init_js_yaml();
21067
21276
  init_frontmatter();
@@ -21069,7 +21278,7 @@ init_file_utils();
21069
21278
  init_shared();
21070
21279
  init_opencode_config_dir();
21071
21280
  import { promises as fs9 } from "fs";
21072
- import { join as join40, basename } from "path";
21281
+ import { join as join41, basename } from "path";
21073
21282
  function parseSkillMcpConfigFromFrontmatter(content) {
21074
21283
  const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
21075
21284
  if (!frontmatterMatch)
@@ -21085,7 +21294,7 @@ function parseSkillMcpConfigFromFrontmatter(content) {
21085
21294
  return;
21086
21295
  }
21087
21296
  async function loadMcpJsonFromDir(skillDir) {
21088
- const mcpJsonPath = join40(skillDir, "mcp.json");
21297
+ const mcpJsonPath = join41(skillDir, "mcp.json");
21089
21298
  try {
21090
21299
  const content = await fs9.readFile(mcpJsonPath, "utf-8");
21091
21300
  const parsed = JSON.parse(content);
@@ -21166,11 +21375,11 @@ async function loadSkillsFromDir(skillsDir, scope) {
21166
21375
  for (const entry of entries) {
21167
21376
  if (entry.name.startsWith("."))
21168
21377
  continue;
21169
- const entryPath = join40(skillsDir, entry.name);
21378
+ const entryPath = join41(skillsDir, entry.name);
21170
21379
  if (entry.isDirectory() || entry.isSymbolicLink()) {
21171
21380
  const resolvedPath = await resolveSymlinkAsync(entryPath);
21172
21381
  const dirName = entry.name;
21173
- const skillMdPath = join40(resolvedPath, "SKILL.md");
21382
+ const skillMdPath = join41(resolvedPath, "SKILL.md");
21174
21383
  try {
21175
21384
  await fs9.access(skillMdPath);
21176
21385
  const skill = await loadSkillFromPath(skillMdPath, resolvedPath, dirName, scope);
@@ -21178,7 +21387,7 @@ async function loadSkillsFromDir(skillsDir, scope) {
21178
21387
  skills.push(skill);
21179
21388
  continue;
21180
21389
  } catch {}
21181
- const namedSkillMdPath = join40(resolvedPath, `${dirName}.md`);
21390
+ const namedSkillMdPath = join41(resolvedPath, `${dirName}.md`);
21182
21391
  try {
21183
21392
  await fs9.access(namedSkillMdPath);
21184
21393
  const skill = await loadSkillFromPath(namedSkillMdPath, resolvedPath, dirName, scope);
@@ -21206,23 +21415,23 @@ function skillsToRecord(skills) {
21206
21415
  return result;
21207
21416
  }
21208
21417
  async function loadUserSkills() {
21209
- const userSkillsDir = join40(getClaudeConfigDir(), "skills");
21418
+ const userSkillsDir = join41(getClaudeConfigDir(), "skills");
21210
21419
  const skills = await loadSkillsFromDir(userSkillsDir, "user");
21211
21420
  return skillsToRecord(skills);
21212
21421
  }
21213
21422
  async function loadProjectSkills() {
21214
- const projectSkillsDir = join40(process.cwd(), ".claude", "skills");
21423
+ const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
21215
21424
  const skills = await loadSkillsFromDir(projectSkillsDir, "project");
21216
21425
  return skillsToRecord(skills);
21217
21426
  }
21218
21427
  async function loadOpencodeGlobalSkills() {
21219
21428
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
21220
- const opencodeSkillsDir = join40(configDir, "skills");
21429
+ const opencodeSkillsDir = join41(configDir, "skills");
21221
21430
  const skills = await loadSkillsFromDir(opencodeSkillsDir, "opencode");
21222
21431
  return skillsToRecord(skills);
21223
21432
  }
21224
21433
  async function loadOpencodeProjectSkills() {
21225
- const opencodeProjectDir = join40(process.cwd(), ".opencode", "skills");
21434
+ const opencodeProjectDir = join41(process.cwd(), ".opencode", "skills");
21226
21435
  const skills = await loadSkillsFromDir(opencodeProjectDir, "opencode-project");
21227
21436
  return skillsToRecord(skills);
21228
21437
  }
@@ -21251,28 +21460,29 @@ async function discoverSkills(options = {}) {
21251
21460
  return [...opencodeProjectSkills, ...projectSkills, ...opencodeGlobalSkills, ...userSkills];
21252
21461
  }
21253
21462
  async function discoverUserClaudeSkills() {
21254
- const userSkillsDir = join40(getClaudeConfigDir(), "skills");
21463
+ const userSkillsDir = join41(getClaudeConfigDir(), "skills");
21255
21464
  return loadSkillsFromDir(userSkillsDir, "user");
21256
21465
  }
21257
21466
  async function discoverProjectClaudeSkills() {
21258
- const projectSkillsDir = join40(process.cwd(), ".claude", "skills");
21467
+ const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
21259
21468
  return loadSkillsFromDir(projectSkillsDir, "project");
21260
21469
  }
21261
21470
  async function discoverOpencodeGlobalSkills() {
21262
21471
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
21263
- const opencodeSkillsDir = join40(configDir, "skills");
21472
+ const opencodeSkillsDir = join41(configDir, "skills");
21264
21473
  return loadSkillsFromDir(opencodeSkillsDir, "opencode");
21265
21474
  }
21266
21475
  async function discoverOpencodeProjectSkills() {
21267
- const opencodeProjectDir = join40(process.cwd(), ".opencode", "skills");
21476
+ const opencodeProjectDir = join41(process.cwd(), ".opencode", "skills");
21268
21477
  return loadSkillsFromDir(opencodeProjectDir, "opencode-project");
21269
21478
  }
21270
21479
  // src/features/opencode-skill-loader/merger.ts
21271
21480
  init_frontmatter();
21272
21481
  init_deep_merge();
21273
- import { readFileSync as readFileSync21, existsSync as existsSync31 } from "fs";
21482
+ import { readFileSync as readFileSync21, existsSync as existsSync32 } from "fs";
21274
21483
  import { dirname as dirname7, resolve as resolve6, isAbsolute as isAbsolute2 } from "path";
21275
21484
  import { homedir as homedir11 } from "os";
21485
+ import { createHash as createHash2 } from "crypto";
21276
21486
  var SCOPE_PRIORITY = {
21277
21487
  builtin: 1,
21278
21488
  config: 2,
@@ -21318,7 +21528,7 @@ function resolveFilePath2(from, configDir) {
21318
21528
  }
21319
21529
  function loadSkillFromFile(filePath) {
21320
21530
  try {
21321
- if (!existsSync31(filePath))
21531
+ if (!existsSync32(filePath))
21322
21532
  return null;
21323
21533
  const content = readFileSync21(filePath, "utf-8");
21324
21534
  const { data, body } = parseFrontmatter(content);
@@ -21407,13 +21617,28 @@ function mergeSkillDefinitions(base, patch) {
21407
21617
  allowedTools: mergedTools ? [...new Set(mergedTools)] : undefined
21408
21618
  };
21409
21619
  }
21620
+ function contentHash(content) {
21621
+ return createHash2("md5").update(content).digest("hex").slice(0, 8);
21622
+ }
21623
+ function emptyDedupStats() {
21624
+ return { totalScanned: 0, unique: 0, skippedByScope: 0, skippedByContent: 0, byScope: {} };
21625
+ }
21410
21626
  function mergeSkills(builtinSkills, config, userClaudeSkills, userOpencodeSkills, projectClaudeSkills, projectOpencodeSkills, options = {}) {
21411
21627
  const skillMap = new Map;
21628
+ const contentHashes = new Map;
21629
+ const stats = emptyDedupStats();
21412
21630
  for (const builtin of builtinSkills) {
21413
21631
  const loaded = builtinToLoaded(builtin);
21414
21632
  skillMap.set(loaded.name, loaded);
21633
+ stats.byScope["builtin"] = (stats.byScope["builtin"] ?? 0) + 1;
21634
+ stats.unique++;
21635
+ if (loaded.definition.template) {
21636
+ contentHashes.set(loaded.name, contentHash(loaded.definition.template));
21637
+ }
21415
21638
  }
21639
+ stats.totalScanned += builtinSkills.length;
21416
21640
  const normalizedConfig = normalizeConfig(config);
21641
+ let configLoaded = 0;
21417
21642
  for (const [name, entry] of Object.entries(normalizedConfig.entries)) {
21418
21643
  if (entry === false)
21419
21644
  continue;
@@ -21428,9 +21653,18 @@ function mergeSkills(builtinSkills, config, userClaudeSkills, userOpencodeSkills
21428
21653
  skillMap.set(name, mergeSkillDefinitions(existing, entry));
21429
21654
  } else {
21430
21655
  skillMap.set(name, loaded);
21656
+ configLoaded++;
21657
+ stats.unique++;
21658
+ if (loaded.definition.template) {
21659
+ contentHashes.set(name, contentHash(loaded.definition.template));
21660
+ }
21431
21661
  }
21432
21662
  }
21433
21663
  }
21664
+ if (configLoaded > 0) {
21665
+ stats.byScope["config"] = configLoaded;
21666
+ stats.totalScanned += configLoaded;
21667
+ }
21434
21668
  const fileSystemSkills = [
21435
21669
  ...userClaudeSkills,
21436
21670
  ...userOpencodeSkills,
@@ -21438,10 +21672,30 @@ function mergeSkills(builtinSkills, config, userClaudeSkills, userOpencodeSkills
21438
21672
  ...projectOpencodeSkills
21439
21673
  ];
21440
21674
  for (const skill of fileSystemSkills) {
21675
+ stats.totalScanned++;
21676
+ stats.byScope[skill.scope] = (stats.byScope[skill.scope] ?? 0) + 1;
21441
21677
  const existing = skillMap.get(skill.name);
21442
- if (!existing || SCOPE_PRIORITY[skill.scope] > SCOPE_PRIORITY[existing.scope]) {
21443
- skillMap.set(skill.name, skill);
21678
+ const hash = skill.definition.template ? contentHash(skill.definition.template) : undefined;
21679
+ if (existing) {
21680
+ const existingHash = contentHashes.get(skill.name);
21681
+ if (hash && existingHash && hash === existingHash) {
21682
+ stats.skippedByContent++;
21683
+ continue;
21684
+ }
21685
+ if (SCOPE_PRIORITY[skill.scope] <= SCOPE_PRIORITY[existing.scope]) {
21686
+ stats.skippedByScope++;
21687
+ continue;
21688
+ }
21689
+ }
21690
+ skillMap.set(skill.name, skill);
21691
+ if (hash) {
21692
+ contentHashes.set(skill.name, hash);
21444
21693
  }
21694
+ stats.unique++;
21695
+ }
21696
+ if (stats.skippedByContent > 0 || stats.skippedByScope > 1) {
21697
+ const scopeSummary = Object.entries(stats.byScope).map(([scope, count]) => `${scope}:${count}`).join(", ");
21698
+ console.debug(`[skill-loader] Scanned ${stats.totalScanned} skills (${scopeSummary}), ` + `${stats.unique} loaded, ` + `${stats.skippedByContent} skipped (identical content), ` + `${stats.skippedByScope} skipped (lower priority scope)`);
21445
21699
  }
21446
21700
  for (const [name, entry] of Object.entries(normalizedConfig.entries)) {
21447
21701
  if (entry === true)
@@ -22802,15 +23056,15 @@ async function resolveMultipleSkillsAsync(skillNames, options) {
22802
23056
  }
22803
23057
  // src/hooks/auto-slash-command/executor.ts
22804
23058
  function discoverCommandsFromDir(commandsDir, scope) {
22805
- if (!existsSync32(commandsDir)) {
23059
+ if (!existsSync33(commandsDir)) {
22806
23060
  return [];
22807
23061
  }
22808
- const entries = readdirSync8(commandsDir, { withFileTypes: true });
23062
+ const entries = readdirSync9(commandsDir, { withFileTypes: true });
22809
23063
  const commands = [];
22810
23064
  for (const entry of entries) {
22811
23065
  if (!isMarkdownFile(entry))
22812
23066
  continue;
22813
- const commandPath = join41(commandsDir, entry.name);
23067
+ const commandPath = join42(commandsDir, entry.name);
22814
23068
  const commandName = basename2(entry.name, ".md");
22815
23069
  try {
22816
23070
  const content = readFileSync23(commandPath, "utf-8");
@@ -22856,10 +23110,10 @@ function skillToCommandInfo(skill) {
22856
23110
  }
22857
23111
  async function discoverAllCommands(options) {
22858
23112
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
22859
- const userCommandsDir = join41(getClaudeConfigDir(), "commands");
22860
- const projectCommandsDir = join41(process.cwd(), ".claude", "commands");
22861
- const opencodeGlobalDir = join41(configDir, "command");
22862
- const opencodeProjectDir = join41(process.cwd(), ".opencode", "command");
23113
+ const userCommandsDir = join42(getClaudeConfigDir(), "commands");
23114
+ const projectCommandsDir = join42(process.cwd(), ".claude", "commands");
23115
+ const opencodeGlobalDir = join42(configDir, "command");
23116
+ const opencodeProjectDir = join42(process.cwd(), ".opencode", "command");
22863
23117
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
22864
23118
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
22865
23119
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -23029,8 +23283,8 @@ ${EDIT_ERROR_REMINDER}`;
23029
23283
  };
23030
23284
  }
23031
23285
  // src/hooks/prometheus-md-only/index.ts
23032
- import { existsSync as existsSync33, readdirSync as readdirSync9 } from "fs";
23033
- import { join as join42, resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3 } from "path";
23286
+ import { existsSync as existsSync34, readdirSync as readdirSync10 } from "fs";
23287
+ import { join as join43, resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3 } from "path";
23034
23288
 
23035
23289
  // src/hooks/prometheus-md-only/constants.ts
23036
23290
  init_system_directive();
@@ -23149,14 +23403,14 @@ function isAllowedFile(filePath, workspaceRoot) {
23149
23403
  return true;
23150
23404
  }
23151
23405
  function getMessageDir5(sessionID) {
23152
- if (!existsSync33(MESSAGE_STORAGE))
23406
+ if (!existsSync34(MESSAGE_STORAGE))
23153
23407
  return null;
23154
- const directPath = join42(MESSAGE_STORAGE, sessionID);
23155
- if (existsSync33(directPath))
23408
+ const directPath = join43(MESSAGE_STORAGE, sessionID);
23409
+ if (existsSync34(directPath))
23156
23410
  return directPath;
23157
- for (const dir of readdirSync9(MESSAGE_STORAGE)) {
23158
- const sessionPath = join42(MESSAGE_STORAGE, dir, sessionID);
23159
- if (existsSync33(sessionPath))
23411
+ for (const dir of readdirSync10(MESSAGE_STORAGE)) {
23412
+ const sessionPath = join43(MESSAGE_STORAGE, dir, sessionID);
23413
+ if (existsSync34(sessionPath))
23160
23414
  return sessionPath;
23161
23415
  }
23162
23416
  return null;
@@ -23270,14 +23524,14 @@ var NOTEPAD_DIR = "notepads";
23270
23524
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
23271
23525
  var PROMETHEUS_PLANS_DIR = ".sisyphus/plans";
23272
23526
  // src/features/boulder-state/storage.ts
23273
- import { existsSync as existsSync34, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync10 } from "fs";
23274
- import { dirname as dirname9, join as join43, basename as basename3 } from "path";
23527
+ import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync11 } from "fs";
23528
+ import { dirname as dirname9, join as join44, basename as basename3 } from "path";
23275
23529
  function getBoulderFilePath(directory) {
23276
- return join43(directory, BOULDER_DIR, BOULDER_FILE);
23530
+ return join44(directory, BOULDER_DIR, BOULDER_FILE);
23277
23531
  }
23278
23532
  function readBoulderState(directory) {
23279
23533
  const filePath = getBoulderFilePath(directory);
23280
- if (!existsSync34(filePath)) {
23534
+ if (!existsSync35(filePath)) {
23281
23535
  return null;
23282
23536
  }
23283
23537
  try {
@@ -23291,7 +23545,7 @@ function writeBoulderState(directory, state2) {
23291
23545
  const filePath = getBoulderFilePath(directory);
23292
23546
  try {
23293
23547
  const dir = dirname9(filePath);
23294
- if (!existsSync34(dir)) {
23548
+ if (!existsSync35(dir)) {
23295
23549
  mkdirSync12(dir, { recursive: true });
23296
23550
  }
23297
23551
  writeFileSync15(filePath, JSON.stringify(state2, null, 2), "utf-8");
@@ -23315,7 +23569,7 @@ function appendSessionId(directory, sessionId) {
23315
23569
  function clearBoulderState(directory) {
23316
23570
  const filePath = getBoulderFilePath(directory);
23317
23571
  try {
23318
- if (existsSync34(filePath)) {
23572
+ if (existsSync35(filePath)) {
23319
23573
  const { unlinkSync: unlinkSync10 } = __require("fs");
23320
23574
  unlinkSync10(filePath);
23321
23575
  }
@@ -23325,13 +23579,13 @@ function clearBoulderState(directory) {
23325
23579
  }
23326
23580
  }
23327
23581
  function findPrometheusPlans(directory) {
23328
- const plansDir = join43(directory, PROMETHEUS_PLANS_DIR);
23329
- if (!existsSync34(plansDir)) {
23582
+ const plansDir = join44(directory, PROMETHEUS_PLANS_DIR);
23583
+ if (!existsSync35(plansDir)) {
23330
23584
  return [];
23331
23585
  }
23332
23586
  try {
23333
- const files = readdirSync10(plansDir);
23334
- return files.filter((f) => f.endsWith(".md")).map((f) => join43(plansDir, f)).sort((a, b) => {
23587
+ const files = readdirSync11(plansDir);
23588
+ return files.filter((f) => f.endsWith(".md")).map((f) => join44(plansDir, f)).sort((a, b) => {
23335
23589
  const aStat = __require("fs").statSync(a);
23336
23590
  const bStat = __require("fs").statSync(b);
23337
23591
  return bStat.mtimeMs - aStat.mtimeMs;
@@ -23341,7 +23595,7 @@ function findPrometheusPlans(directory) {
23341
23595
  }
23342
23596
  }
23343
23597
  function getPlanProgress(planPath) {
23344
- if (!existsSync34(planPath)) {
23598
+ if (!existsSync35(planPath)) {
23345
23599
  return { total: 0, completed: 0, isComplete: true };
23346
23600
  }
23347
23601
  try {
@@ -23562,8 +23816,8 @@ ${contextInfo}`;
23562
23816
  }
23563
23817
  // src/hooks/atlas/index.ts
23564
23818
  import { execSync } from "child_process";
23565
- import { existsSync as existsSync35, readdirSync as readdirSync11 } from "fs";
23566
- import { join as join44 } from "path";
23819
+ import { existsSync as existsSync36, readdirSync as readdirSync12 } from "fs";
23820
+ import { join as join45 } from "path";
23567
23821
  init_logger();
23568
23822
  init_system_directive();
23569
23823
  var HOOK_NAME6 = "atlas";
@@ -23892,14 +24146,14 @@ function formatFileChanges(stats, notepadPath) {
23892
24146
  `);
23893
24147
  }
23894
24148
  function getMessageDir6(sessionID) {
23895
- if (!existsSync35(MESSAGE_STORAGE))
24149
+ if (!existsSync36(MESSAGE_STORAGE))
23896
24150
  return null;
23897
- const directPath = join44(MESSAGE_STORAGE, sessionID);
23898
- if (existsSync35(directPath))
24151
+ const directPath = join45(MESSAGE_STORAGE, sessionID);
24152
+ if (existsSync36(directPath))
23899
24153
  return directPath;
23900
- for (const dir of readdirSync11(MESSAGE_STORAGE)) {
23901
- const sessionPath = join44(MESSAGE_STORAGE, dir, sessionID);
23902
- if (existsSync35(sessionPath))
24154
+ for (const dir of readdirSync12(MESSAGE_STORAGE)) {
24155
+ const sessionPath = join45(MESSAGE_STORAGE, dir, sessionID);
24156
+ if (existsSync36(sessionPath))
23903
24157
  return sessionPath;
23904
24158
  }
23905
24159
  return null;
@@ -24253,7 +24507,7 @@ var DELEGATE_TASK_ERROR_PATTERNS = [
24253
24507
  }
24254
24508
  ];
24255
24509
  function detectDelegateTaskError(output) {
24256
- if (!output.includes("[ERROR]") && !output.includes("Invalid arguments"))
24510
+ if (!output.includes("[ERROR]") && !output.includes("Invalid arguments") && !output.includes("\u53C2\u6570\u9519\u8BEF\uFF1A"))
24257
24511
  return null;
24258
24512
  for (const errorPattern of DELEGATE_TASK_ERROR_PATTERNS) {
24259
24513
  if (output.includes(errorPattern.pattern)) {
@@ -24548,8 +24802,8 @@ function createFirstMessageVariantGate() {
24548
24802
  }
24549
24803
  // src/features/claude-code-mcp-loader/loader.ts
24550
24804
  init_shared();
24551
- import { existsSync as existsSync36, readFileSync as readFileSync25 } from "fs";
24552
- import { join as join45 } from "path";
24805
+ import { existsSync as existsSync37, readFileSync as readFileSync25 } from "fs";
24806
+ import { join as join46 } from "path";
24553
24807
 
24554
24808
  // src/features/claude-code-mcp-loader/env-expander.ts
24555
24809
  function expandEnvVars(value) {
@@ -24619,13 +24873,13 @@ function getMcpConfigPaths() {
24619
24873
  const claudeConfigDir = getClaudeConfigDir();
24620
24874
  const cwd2 = process.cwd();
24621
24875
  return [
24622
- { path: join45(claudeConfigDir, ".mcp.json"), scope: "user" },
24623
- { path: join45(cwd2, ".mcp.json"), scope: "project" },
24624
- { path: join45(cwd2, ".claude", ".mcp.json"), scope: "local" }
24876
+ { path: join46(claudeConfigDir, ".mcp.json"), scope: "user" },
24877
+ { path: join46(cwd2, ".mcp.json"), scope: "project" },
24878
+ { path: join46(cwd2, ".claude", ".mcp.json"), scope: "local" }
24625
24879
  ];
24626
24880
  }
24627
24881
  async function loadMcpConfigFile(filePath) {
24628
- if (!existsSync36(filePath)) {
24882
+ if (!existsSync37(filePath)) {
24629
24883
  return null;
24630
24884
  }
24631
24885
  try {
@@ -24640,7 +24894,7 @@ function getSystemMcpServerNames() {
24640
24894
  const names = new Set;
24641
24895
  const paths = getMcpConfigPaths();
24642
24896
  for (const { path: path7 } of paths) {
24643
- if (!existsSync36(path7))
24897
+ if (!existsSync37(path7))
24644
24898
  continue;
24645
24899
  try {
24646
24900
  const content = readFileSync25(path7, "utf-8");
@@ -25086,11 +25340,11 @@ var EXT_TO_LANG = {
25086
25340
  ".gql": "graphql"
25087
25341
  };
25088
25342
  // src/tools/lsp/config.ts
25089
- import { existsSync as existsSync37, readFileSync as readFileSync26 } from "fs";
25090
- import { join as join46 } from "path";
25343
+ import { existsSync as existsSync38, readFileSync as readFileSync26 } from "fs";
25344
+ import { join as join47 } from "path";
25091
25345
  init_shared();
25092
25346
  function loadJsonFile(path7) {
25093
- if (!existsSync37(path7))
25347
+ if (!existsSync38(path7))
25094
25348
  return null;
25095
25349
  try {
25096
25350
  return JSON.parse(readFileSync26(path7, "utf-8"));
@@ -25102,9 +25356,9 @@ function getConfigPaths3() {
25102
25356
  const cwd2 = process.cwd();
25103
25357
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
25104
25358
  return {
25105
- project: join46(cwd2, ".opencode", "oh-my-opencode.json"),
25106
- user: join46(configDir, "oh-my-opencode.json"),
25107
- opencode: join46(configDir, "opencode.json")
25359
+ project: join47(cwd2, ".opencode", "oh-my-opencode.json"),
25360
+ user: join47(configDir, "oh-my-opencode.json"),
25361
+ opencode: join47(configDir, "opencode.json")
25108
25362
  };
25109
25363
  }
25110
25364
  function loadAllConfigs() {
@@ -25217,7 +25471,7 @@ function isServerInstalled(command) {
25217
25471
  return false;
25218
25472
  const cmd = command[0];
25219
25473
  if (cmd.includes("/") || cmd.includes("\\")) {
25220
- if (existsSync37(cmd))
25474
+ if (existsSync38(cmd))
25221
25475
  return true;
25222
25476
  }
25223
25477
  const isWindows2 = process.platform === "win32";
@@ -25239,23 +25493,23 @@ function isServerInstalled(command) {
25239
25493
  const paths = pathEnv.split(pathSeparator);
25240
25494
  for (const p of paths) {
25241
25495
  for (const suffix of exts) {
25242
- if (existsSync37(join46(p, cmd + suffix))) {
25496
+ if (existsSync38(join47(p, cmd + suffix))) {
25243
25497
  return true;
25244
25498
  }
25245
25499
  }
25246
25500
  }
25247
25501
  const cwd2 = process.cwd();
25248
25502
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
25249
- const dataDir = join46(getDataDir(), "opencode");
25503
+ const dataDir = join47(getDataDir(), "opencode");
25250
25504
  const additionalBases = [
25251
- join46(cwd2, "node_modules", ".bin"),
25252
- join46(configDir, "bin"),
25253
- join46(configDir, "node_modules", ".bin"),
25254
- join46(dataDir, "bin")
25505
+ join47(cwd2, "node_modules", ".bin"),
25506
+ join47(configDir, "bin"),
25507
+ join47(configDir, "node_modules", ".bin"),
25508
+ join47(dataDir, "bin")
25255
25509
  ];
25256
25510
  for (const base of additionalBases) {
25257
25511
  for (const suffix of exts) {
25258
- if (existsSync37(join46(base, cmd + suffix))) {
25512
+ if (existsSync38(join47(base, cmd + suffix))) {
25259
25513
  return true;
25260
25514
  }
25261
25515
  }
@@ -25807,17 +26061,17 @@ ${msg}`);
25807
26061
  // src/tools/lsp/utils.ts
25808
26062
  import { extname as extname2, resolve as resolve9 } from "path";
25809
26063
  import { fileURLToPath as fileURLToPath2 } from "url";
25810
- import { existsSync as existsSync38, readFileSync as readFileSync28, writeFileSync as writeFileSync16 } from "fs";
26064
+ import { existsSync as existsSync39, readFileSync as readFileSync28, writeFileSync as writeFileSync16 } from "fs";
25811
26065
  function findWorkspaceRoot(filePath) {
25812
26066
  let dir = resolve9(filePath);
25813
- if (!existsSync38(dir) || !__require("fs").statSync(dir).isDirectory()) {
26067
+ if (!existsSync39(dir) || !__require("fs").statSync(dir).isDirectory()) {
25814
26068
  dir = __require("path").dirname(dir);
25815
26069
  }
25816
26070
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
25817
26071
  let prevDir = "";
25818
26072
  while (dir !== prevDir) {
25819
26073
  for (const marker of markers) {
25820
- if (existsSync38(__require("path").join(dir, marker))) {
26074
+ if (existsSync39(__require("path").join(dir, marker))) {
25821
26075
  return dir;
25822
26076
  }
25823
26077
  }
@@ -38618,13 +38872,13 @@ var lsp_rename = tool({
38618
38872
  });
38619
38873
  // src/tools/ast-grep/constants.ts
38620
38874
  import { createRequire as createRequire4 } from "module";
38621
- import { dirname as dirname10, join as join48 } from "path";
38622
- import { existsSync as existsSync40, statSync as statSync4 } from "fs";
38875
+ import { dirname as dirname10, join as join49 } from "path";
38876
+ import { existsSync as existsSync41, statSync as statSync4 } from "fs";
38623
38877
 
38624
38878
  // src/tools/ast-grep/downloader.ts
38625
38879
  init_shared();
38626
- import { existsSync as existsSync39, mkdirSync as mkdirSync13, chmodSync as chmodSync2, unlinkSync as unlinkSync10 } from "fs";
38627
- import { join as join47 } from "path";
38880
+ import { existsSync as existsSync40, mkdirSync as mkdirSync13, chmodSync as chmodSync2, unlinkSync as unlinkSync10 } from "fs";
38881
+ import { join as join48 } from "path";
38628
38882
  import { homedir as homedir12 } from "os";
38629
38883
  import { createRequire as createRequire3 } from "module";
38630
38884
  var REPO2 = "ast-grep/ast-grep";
@@ -38650,19 +38904,19 @@ var PLATFORM_MAP2 = {
38650
38904
  function getCacheDir3() {
38651
38905
  if (process.platform === "win32") {
38652
38906
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
38653
- const base2 = localAppData || join47(homedir12(), "AppData", "Local");
38654
- return join47(base2, "oh-my-opencode", "bin");
38907
+ const base2 = localAppData || join48(homedir12(), "AppData", "Local");
38908
+ return join48(base2, "oh-my-opencode", "bin");
38655
38909
  }
38656
38910
  const xdgCache = process.env.XDG_CACHE_HOME;
38657
- const base = xdgCache || join47(homedir12(), ".cache");
38658
- return join47(base, "oh-my-opencode", "bin");
38911
+ const base = xdgCache || join48(homedir12(), ".cache");
38912
+ return join48(base, "oh-my-opencode", "bin");
38659
38913
  }
38660
38914
  function getBinaryName3() {
38661
38915
  return process.platform === "win32" ? "sg.exe" : "sg";
38662
38916
  }
38663
38917
  function getCachedBinaryPath2() {
38664
- const binaryPath = join47(getCacheDir3(), getBinaryName3());
38665
- return existsSync39(binaryPath) ? binaryPath : null;
38918
+ const binaryPath = join48(getCacheDir3(), getBinaryName3());
38919
+ return existsSync40(binaryPath) ? binaryPath : null;
38666
38920
  }
38667
38921
  async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38668
38922
  const platformKey = `${process.platform}-${process.arch}`;
@@ -38673,8 +38927,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38673
38927
  }
38674
38928
  const cacheDir = getCacheDir3();
38675
38929
  const binaryName = getBinaryName3();
38676
- const binaryPath = join47(cacheDir, binaryName);
38677
- if (existsSync39(binaryPath)) {
38930
+ const binaryPath = join48(cacheDir, binaryName);
38931
+ if (existsSync40(binaryPath)) {
38678
38932
  return binaryPath;
38679
38933
  }
38680
38934
  const { arch, os: os6 } = platformInfo;
@@ -38682,21 +38936,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38682
38936
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
38683
38937
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
38684
38938
  try {
38685
- if (!existsSync39(cacheDir)) {
38939
+ if (!existsSync40(cacheDir)) {
38686
38940
  mkdirSync13(cacheDir, { recursive: true });
38687
38941
  }
38688
38942
  const response = await fetch(downloadUrl, { redirect: "follow" });
38689
38943
  if (!response.ok) {
38690
38944
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
38691
38945
  }
38692
- const archivePath = join47(cacheDir, assetName);
38946
+ const archivePath = join48(cacheDir, assetName);
38693
38947
  const arrayBuffer = await response.arrayBuffer();
38694
38948
  await Bun.write(archivePath, arrayBuffer);
38695
38949
  await extractZip(archivePath, cacheDir);
38696
- if (existsSync39(archivePath)) {
38950
+ if (existsSync40(archivePath)) {
38697
38951
  unlinkSync10(archivePath);
38698
38952
  }
38699
- if (process.platform !== "win32" && existsSync39(binaryPath)) {
38953
+ if (process.platform !== "win32" && existsSync40(binaryPath)) {
38700
38954
  chmodSync2(binaryPath, 493);
38701
38955
  }
38702
38956
  console.log(`[oh-my-opencode] ast-grep binary ready.`);
@@ -38747,8 +39001,8 @@ function findSgCliPathSync() {
38747
39001
  const require2 = createRequire4(import.meta.url);
38748
39002
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
38749
39003
  const cliDir = dirname10(cliPkgPath);
38750
- const sgPath = join48(cliDir, binaryName);
38751
- if (existsSync40(sgPath) && isValidBinary(sgPath)) {
39004
+ const sgPath = join49(cliDir, binaryName);
39005
+ if (existsSync41(sgPath) && isValidBinary(sgPath)) {
38752
39006
  return sgPath;
38753
39007
  }
38754
39008
  } catch {}
@@ -38759,8 +39013,8 @@ function findSgCliPathSync() {
38759
39013
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
38760
39014
  const pkgDir = dirname10(pkgPath);
38761
39015
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
38762
- const binaryPath = join48(pkgDir, astGrepName);
38763
- if (existsSync40(binaryPath) && isValidBinary(binaryPath)) {
39016
+ const binaryPath = join49(pkgDir, astGrepName);
39017
+ if (existsSync41(binaryPath) && isValidBinary(binaryPath)) {
38764
39018
  return binaryPath;
38765
39019
  }
38766
39020
  } catch {}
@@ -38768,7 +39022,7 @@ function findSgCliPathSync() {
38768
39022
  if (process.platform === "darwin") {
38769
39023
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
38770
39024
  for (const path7 of homebrewPaths) {
38771
- if (existsSync40(path7) && isValidBinary(path7)) {
39025
+ if (existsSync41(path7) && isValidBinary(path7)) {
38772
39026
  return path7;
38773
39027
  }
38774
39028
  }
@@ -38823,11 +39077,11 @@ var DEFAULT_MAX_MATCHES = 500;
38823
39077
 
38824
39078
  // src/tools/ast-grep/cli.ts
38825
39079
  var {spawn: spawn7 } = globalThis.Bun;
38826
- import { existsSync as existsSync41 } from "fs";
39080
+ import { existsSync as existsSync42 } from "fs";
38827
39081
  var resolvedCliPath3 = null;
38828
39082
  var initPromise2 = null;
38829
39083
  async function getAstGrepPath() {
38830
- if (resolvedCliPath3 !== null && existsSync41(resolvedCliPath3)) {
39084
+ if (resolvedCliPath3 !== null && existsSync42(resolvedCliPath3)) {
38831
39085
  return resolvedCliPath3;
38832
39086
  }
38833
39087
  if (initPromise2) {
@@ -38835,7 +39089,7 @@ async function getAstGrepPath() {
38835
39089
  }
38836
39090
  initPromise2 = (async () => {
38837
39091
  const syncPath = findSgCliPathSync();
38838
- if (syncPath && existsSync41(syncPath)) {
39092
+ if (syncPath && existsSync42(syncPath)) {
38839
39093
  resolvedCliPath3 = syncPath;
38840
39094
  setSgCliPath(syncPath);
38841
39095
  return syncPath;
@@ -38869,7 +39123,7 @@ async function runSg(options) {
38869
39123
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
38870
39124
  args.push(...paths);
38871
39125
  let cliPath = getSgCliPath();
38872
- if (!existsSync41(cliPath) && cliPath !== "sg") {
39126
+ if (!existsSync42(cliPath) && cliPath !== "sg") {
38873
39127
  const downloadedPath = await getAstGrepPath();
38874
39128
  if (downloadedPath) {
38875
39129
  cliPath = downloadedPath;
@@ -39133,21 +39387,21 @@ var ast_grep_replace = tool({
39133
39387
  var {spawn: spawn9 } = globalThis.Bun;
39134
39388
 
39135
39389
  // src/tools/grep/constants.ts
39136
- import { existsSync as existsSync43 } from "fs";
39137
- import { join as join50, dirname as dirname11 } from "path";
39390
+ import { existsSync as existsSync44 } from "fs";
39391
+ import { join as join51, dirname as dirname11 } from "path";
39138
39392
  import { spawnSync as spawnSync2 } from "child_process";
39139
39393
 
39140
39394
  // src/tools/grep/downloader.ts
39141
39395
  init_shared();
39142
- import { existsSync as existsSync42, mkdirSync as mkdirSync14, chmodSync as chmodSync3, unlinkSync as unlinkSync11, readdirSync as readdirSync12 } from "fs";
39143
- import { join as join49 } from "path";
39396
+ import { existsSync as existsSync43, mkdirSync as mkdirSync14, chmodSync as chmodSync3, unlinkSync as unlinkSync11, readdirSync as readdirSync13 } from "fs";
39397
+ import { join as join50 } from "path";
39144
39398
  var {spawn: spawn8 } = globalThis.Bun;
39145
39399
  function findFileRecursive(dir, filename) {
39146
39400
  try {
39147
- const entries = readdirSync12(dir, { withFileTypes: true, recursive: true });
39401
+ const entries = readdirSync13(dir, { withFileTypes: true, recursive: true });
39148
39402
  for (const entry of entries) {
39149
39403
  if (entry.isFile() && entry.name === filename) {
39150
- return join49(entry.parentPath ?? dir, entry.name);
39404
+ return join50(entry.parentPath ?? dir, entry.name);
39151
39405
  }
39152
39406
  }
39153
39407
  } catch {
@@ -39168,11 +39422,11 @@ function getPlatformKey() {
39168
39422
  }
39169
39423
  function getInstallDir() {
39170
39424
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
39171
- return join49(homeDir, ".cache", "oh-my-opencode", "bin");
39425
+ return join50(homeDir, ".cache", "oh-my-opencode", "bin");
39172
39426
  }
39173
39427
  function getRgPath() {
39174
39428
  const isWindows2 = process.platform === "win32";
39175
- return join49(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
39429
+ return join50(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
39176
39430
  }
39177
39431
  async function downloadFile(url2, destPath) {
39178
39432
  const response = await fetch(url2);
@@ -39206,7 +39460,7 @@ async function extractZip2(archivePath, destDir) {
39206
39460
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
39207
39461
  const foundPath = findFileRecursive(destDir, binaryName);
39208
39462
  if (foundPath) {
39209
- const destPath = join49(destDir, binaryName);
39463
+ const destPath = join50(destDir, binaryName);
39210
39464
  if (foundPath !== destPath) {
39211
39465
  const { renameSync } = await import("fs");
39212
39466
  renameSync(foundPath, destPath);
@@ -39221,13 +39475,13 @@ async function downloadAndInstallRipgrep() {
39221
39475
  }
39222
39476
  const installDir = getInstallDir();
39223
39477
  const rgPath = getRgPath();
39224
- if (existsSync42(rgPath)) {
39478
+ if (existsSync43(rgPath)) {
39225
39479
  return rgPath;
39226
39480
  }
39227
39481
  mkdirSync14(installDir, { recursive: true });
39228
39482
  const filename = `ripgrep-${RG_VERSION}-${config3.platform}.${config3.extension}`;
39229
39483
  const url2 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
39230
- const archivePath = join49(installDir, filename);
39484
+ const archivePath = join50(installDir, filename);
39231
39485
  try {
39232
39486
  await downloadFile(url2, archivePath);
39233
39487
  if (config3.extension === "tar.gz") {
@@ -39238,12 +39492,12 @@ async function downloadAndInstallRipgrep() {
39238
39492
  if (process.platform !== "win32") {
39239
39493
  chmodSync3(rgPath, 493);
39240
39494
  }
39241
- if (!existsSync42(rgPath)) {
39495
+ if (!existsSync43(rgPath)) {
39242
39496
  throw new Error("ripgrep binary not found after extraction");
39243
39497
  }
39244
39498
  return rgPath;
39245
39499
  } finally {
39246
- if (existsSync42(archivePath)) {
39500
+ if (existsSync43(archivePath)) {
39247
39501
  try {
39248
39502
  unlinkSync11(archivePath);
39249
39503
  } catch {}
@@ -39252,7 +39506,7 @@ async function downloadAndInstallRipgrep() {
39252
39506
  }
39253
39507
  function getInstalledRipgrepPath() {
39254
39508
  const rgPath = getRgPath();
39255
- return existsSync42(rgPath) ? rgPath : null;
39509
+ return existsSync43(rgPath) ? rgPath : null;
39256
39510
  }
39257
39511
 
39258
39512
  // src/tools/grep/constants.ts
@@ -39277,14 +39531,14 @@ function getOpenCodeBundledRg() {
39277
39531
  const isWindows2 = process.platform === "win32";
39278
39532
  const rgName = isWindows2 ? "rg.exe" : "rg";
39279
39533
  const candidates = [
39280
- join50(getDataDir(), "opencode", "bin", rgName),
39281
- join50(execDir, rgName),
39282
- join50(execDir, "bin", rgName),
39283
- join50(execDir, "..", "bin", rgName),
39284
- join50(execDir, "..", "libexec", rgName)
39534
+ join51(getDataDir(), "opencode", "bin", rgName),
39535
+ join51(execDir, rgName),
39536
+ join51(execDir, "bin", rgName),
39537
+ join51(execDir, "..", "bin", rgName),
39538
+ join51(execDir, "..", "libexec", rgName)
39285
39539
  ];
39286
39540
  for (const candidate of candidates) {
39287
- if (existsSync43(candidate)) {
39541
+ if (existsSync44(candidate)) {
39288
39542
  return candidate;
39289
39543
  }
39290
39544
  }
@@ -39746,8 +40000,8 @@ var glob = tool({
39746
40000
  init_shared();
39747
40001
  init_file_utils();
39748
40002
  init_shared();
39749
- import { existsSync as existsSync44, readdirSync as readdirSync13, readFileSync as readFileSync29 } from "fs";
39750
- import { join as join51, basename as basename4, dirname as dirname12 } from "path";
40003
+ import { existsSync as existsSync45, readdirSync as readdirSync14, readFileSync as readFileSync29 } from "fs";
40004
+ import { join as join52, basename as basename4, dirname as dirname12 } from "path";
39751
40005
  // src/features/builtin-commands/templates/init-deep.ts
39752
40006
  var INIT_DEEP_TEMPLATE = `# /init-deep
39753
40007
 
@@ -40863,15 +41117,15 @@ function loadBuiltinCommands(disabledCommands) {
40863
41117
  }
40864
41118
  // src/tools/slashcommand/tools.ts
40865
41119
  function discoverCommandsFromDir2(commandsDir, scope) {
40866
- if (!existsSync44(commandsDir)) {
41120
+ if (!existsSync45(commandsDir)) {
40867
41121
  return [];
40868
41122
  }
40869
- const entries = readdirSync13(commandsDir, { withFileTypes: true });
41123
+ const entries = readdirSync14(commandsDir, { withFileTypes: true });
40870
41124
  const commands2 = [];
40871
41125
  for (const entry of entries) {
40872
41126
  if (!isMarkdownFile(entry))
40873
41127
  continue;
40874
- const commandPath = join51(commandsDir, entry.name);
41128
+ const commandPath = join52(commandsDir, entry.name);
40875
41129
  const commandName = basename4(entry.name, ".md");
40876
41130
  try {
40877
41131
  const content = readFileSync29(commandPath, "utf-8");
@@ -40900,10 +41154,10 @@ function discoverCommandsFromDir2(commandsDir, scope) {
40900
41154
  }
40901
41155
  function discoverCommandsSync() {
40902
41156
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
40903
- const userCommandsDir = join51(getClaudeConfigDir(), "commands");
40904
- const projectCommandsDir = join51(process.cwd(), ".claude", "commands");
40905
- const opencodeGlobalDir = join51(configDir, "command");
40906
- const opencodeProjectDir = join51(process.cwd(), ".opencode", "command");
41157
+ const userCommandsDir = join52(getClaudeConfigDir(), "commands");
41158
+ const projectCommandsDir = join52(process.cwd(), ".claude", "commands");
41159
+ const opencodeGlobalDir = join52(configDir, "command");
41160
+ const opencodeProjectDir = join52(process.cwd(), ".opencode", "command");
40907
41161
  const userCommands = discoverCommandsFromDir2(userCommandsDir, "user");
40908
41162
  const opencodeGlobalCommands = discoverCommandsFromDir2(opencodeGlobalDir, "opencode");
40909
41163
  const projectCommands = discoverCommandsFromDir2(projectCommandsDir, "project");
@@ -41080,13 +41334,13 @@ var slashcommand = createSlashcommandTool();
41080
41334
  // src/tools/session-manager/constants.ts
41081
41335
  init_data_path();
41082
41336
  init_shared();
41083
- import { join as join52 } from "path";
41337
+ import { join as join53 } from "path";
41084
41338
  var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
41085
- var MESSAGE_STORAGE4 = join52(OPENCODE_STORAGE9, "message");
41086
- var PART_STORAGE4 = join52(OPENCODE_STORAGE9, "part");
41087
- var SESSION_STORAGE = join52(OPENCODE_STORAGE9, "session");
41088
- var TODO_DIR2 = join52(getClaudeConfigDir(), "todos");
41089
- var TRANSCRIPT_DIR2 = join52(getClaudeConfigDir(), "transcripts");
41339
+ var MESSAGE_STORAGE4 = join53(OPENCODE_STORAGE9, "message");
41340
+ var PART_STORAGE4 = join53(OPENCODE_STORAGE9, "part");
41341
+ var SESSION_STORAGE = join53(OPENCODE_STORAGE9, "session");
41342
+ var TODO_DIR2 = join53(getClaudeConfigDir(), "todos");
41343
+ var TRANSCRIPT_DIR2 = join53(getClaudeConfigDir(), "transcripts");
41090
41344
  var SESSION_LIST_DESCRIPTION = `\u5217\u51FA\u6240\u6709 OpenCode session\uFF0C\u652F\u6301\u53EF\u9009\u8FC7\u6EE4\u3002
41091
41345
 
41092
41346
  \u8FD4\u56DE\u53EF\u7528\u7684 session ID \u5217\u8868\uFF0C\u5305\u542B\u6D88\u606F\u6570\u91CF\u3001\u65E5\u671F\u8303\u56F4\u548C\u4F7F\u7528\u8FC7\u7684 agents \u7B49\u5143\u6570\u636E\u3002
@@ -41159,11 +41413,11 @@ Has Todos: Yes (12 items, 8 completed)
41159
41413
  Has Transcript: Yes (234 entries)`;
41160
41414
 
41161
41415
  // src/tools/session-manager/storage.ts
41162
- import { existsSync as existsSync45, readdirSync as readdirSync14 } from "fs";
41416
+ import { existsSync as existsSync46, readdirSync as readdirSync15 } from "fs";
41163
41417
  import { readdir, readFile } from "fs/promises";
41164
- import { join as join53 } from "path";
41418
+ import { join as join54 } from "path";
41165
41419
  async function getMainSessions(options) {
41166
- if (!existsSync45(SESSION_STORAGE))
41420
+ if (!existsSync46(SESSION_STORAGE))
41167
41421
  return [];
41168
41422
  const sessions = [];
41169
41423
  try {
@@ -41171,13 +41425,13 @@ async function getMainSessions(options) {
41171
41425
  for (const projectDir of projectDirs) {
41172
41426
  if (!projectDir.isDirectory())
41173
41427
  continue;
41174
- const projectPath = join53(SESSION_STORAGE, projectDir.name);
41428
+ const projectPath = join54(SESSION_STORAGE, projectDir.name);
41175
41429
  const sessionFiles = await readdir(projectPath);
41176
41430
  for (const file2 of sessionFiles) {
41177
41431
  if (!file2.endsWith(".json"))
41178
41432
  continue;
41179
41433
  try {
41180
- const content = await readFile(join53(projectPath, file2), "utf-8");
41434
+ const content = await readFile(join54(projectPath, file2), "utf-8");
41181
41435
  const meta = JSON.parse(content);
41182
41436
  if (meta.parentID)
41183
41437
  continue;
@@ -41195,7 +41449,7 @@ async function getMainSessions(options) {
41195
41449
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
41196
41450
  }
41197
41451
  async function getAllSessions() {
41198
- if (!existsSync45(MESSAGE_STORAGE4))
41452
+ if (!existsSync46(MESSAGE_STORAGE4))
41199
41453
  return [];
41200
41454
  const sessions = [];
41201
41455
  async function scanDirectory(dir) {
@@ -41203,7 +41457,7 @@ async function getAllSessions() {
41203
41457
  const entries = await readdir(dir, { withFileTypes: true });
41204
41458
  for (const entry of entries) {
41205
41459
  if (entry.isDirectory()) {
41206
- const sessionPath = join53(dir, entry.name);
41460
+ const sessionPath = join54(dir, entry.name);
41207
41461
  const files = await readdir(sessionPath);
41208
41462
  if (files.some((f) => f.endsWith(".json"))) {
41209
41463
  sessions.push(entry.name);
@@ -41220,16 +41474,16 @@ async function getAllSessions() {
41220
41474
  return [...new Set(sessions)];
41221
41475
  }
41222
41476
  function getMessageDir7(sessionID) {
41223
- if (!existsSync45(MESSAGE_STORAGE4))
41477
+ if (!existsSync46(MESSAGE_STORAGE4))
41224
41478
  return "";
41225
- const directPath = join53(MESSAGE_STORAGE4, sessionID);
41226
- if (existsSync45(directPath)) {
41479
+ const directPath = join54(MESSAGE_STORAGE4, sessionID);
41480
+ if (existsSync46(directPath)) {
41227
41481
  return directPath;
41228
41482
  }
41229
41483
  try {
41230
- for (const dir of readdirSync14(MESSAGE_STORAGE4)) {
41231
- const sessionPath = join53(MESSAGE_STORAGE4, dir, sessionID);
41232
- if (existsSync45(sessionPath)) {
41484
+ for (const dir of readdirSync15(MESSAGE_STORAGE4)) {
41485
+ const sessionPath = join54(MESSAGE_STORAGE4, dir, sessionID);
41486
+ if (existsSync46(sessionPath)) {
41233
41487
  return sessionPath;
41234
41488
  }
41235
41489
  }
@@ -41243,7 +41497,7 @@ function sessionExists(sessionID) {
41243
41497
  }
41244
41498
  async function readSessionMessages(sessionID) {
41245
41499
  const messageDir = getMessageDir7(sessionID);
41246
- if (!messageDir || !existsSync45(messageDir))
41500
+ if (!messageDir || !existsSync46(messageDir))
41247
41501
  return [];
41248
41502
  const messages = [];
41249
41503
  try {
@@ -41252,7 +41506,7 @@ async function readSessionMessages(sessionID) {
41252
41506
  if (!file2.endsWith(".json"))
41253
41507
  continue;
41254
41508
  try {
41255
- const content = await readFile(join53(messageDir, file2), "utf-8");
41509
+ const content = await readFile(join54(messageDir, file2), "utf-8");
41256
41510
  const meta = JSON.parse(content);
41257
41511
  const parts = await readParts2(meta.id);
41258
41512
  messages.push({
@@ -41278,8 +41532,8 @@ async function readSessionMessages(sessionID) {
41278
41532
  });
41279
41533
  }
41280
41534
  async function readParts2(messageID) {
41281
- const partDir = join53(PART_STORAGE4, messageID);
41282
- if (!existsSync45(partDir))
41535
+ const partDir = join54(PART_STORAGE4, messageID);
41536
+ if (!existsSync46(partDir))
41283
41537
  return [];
41284
41538
  const parts = [];
41285
41539
  try {
@@ -41288,7 +41542,7 @@ async function readParts2(messageID) {
41288
41542
  if (!file2.endsWith(".json"))
41289
41543
  continue;
41290
41544
  try {
41291
- const content = await readFile(join53(partDir, file2), "utf-8");
41545
+ const content = await readFile(join54(partDir, file2), "utf-8");
41292
41546
  parts.push(JSON.parse(content));
41293
41547
  } catch {
41294
41548
  continue;
@@ -41300,14 +41554,14 @@ async function readParts2(messageID) {
41300
41554
  return parts.sort((a, b) => a.id.localeCompare(b.id));
41301
41555
  }
41302
41556
  async function readSessionTodos(sessionID) {
41303
- if (!existsSync45(TODO_DIR2))
41557
+ if (!existsSync46(TODO_DIR2))
41304
41558
  return [];
41305
41559
  try {
41306
41560
  const allFiles = await readdir(TODO_DIR2);
41307
41561
  const todoFiles = allFiles.filter((f) => f.includes(sessionID) && f.endsWith(".json"));
41308
41562
  for (const file2 of todoFiles) {
41309
41563
  try {
41310
- const content = await readFile(join53(TODO_DIR2, file2), "utf-8");
41564
+ const content = await readFile(join54(TODO_DIR2, file2), "utf-8");
41311
41565
  const data = JSON.parse(content);
41312
41566
  if (Array.isArray(data)) {
41313
41567
  return data.map((item) => ({
@@ -41327,10 +41581,10 @@ async function readSessionTodos(sessionID) {
41327
41581
  return [];
41328
41582
  }
41329
41583
  async function readSessionTranscript(sessionID) {
41330
- if (!existsSync45(TRANSCRIPT_DIR2))
41584
+ if (!existsSync46(TRANSCRIPT_DIR2))
41331
41585
  return 0;
41332
- const transcriptFile = join53(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
41333
- if (!existsSync45(transcriptFile))
41586
+ const transcriptFile = join54(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
41587
+ if (!existsSync46(transcriptFile))
41334
41588
  return 0;
41335
41589
  try {
41336
41590
  const content = await readFile(transcriptFile, "utf-8");
@@ -42532,19 +42786,19 @@ var CALL_OMO_AGENT_DESCRIPTION = `\u542F\u52A8 explore/librarian agent\u3002run_
42532
42786
 
42533
42787
  \u4F20\u5165 \`session_id=<id>\` \u53EF\u7EE7\u7EED\u4E4B\u524D\u7684 agent\uFF0C\u4FDD\u7559\u5B8C\u6574\u4E0A\u4E0B\u6587\u3002Prompts \u5FC5\u987B\u4E3A\u4E2D\u6587\u3002\u4F7F\u7528 \`background_output\` \u83B7\u53D6\u5F02\u6B65\u7ED3\u679C\u3002`;
42534
42788
  // src/tools/call-omo-agent/tools.ts
42535
- import { existsSync as existsSync46, readdirSync as readdirSync15 } from "fs";
42536
- import { join as join54 } from "path";
42789
+ import { existsSync as existsSync47, readdirSync as readdirSync16 } from "fs";
42790
+ import { join as join55 } from "path";
42537
42791
  init_shared();
42538
42792
  init_session_cursor();
42539
42793
  function getMessageDir8(sessionID) {
42540
- if (!existsSync46(MESSAGE_STORAGE))
42794
+ if (!existsSync47(MESSAGE_STORAGE))
42541
42795
  return null;
42542
- const directPath = join54(MESSAGE_STORAGE, sessionID);
42543
- if (existsSync46(directPath))
42796
+ const directPath = join55(MESSAGE_STORAGE, sessionID);
42797
+ if (existsSync47(directPath))
42544
42798
  return directPath;
42545
- for (const dir of readdirSync15(MESSAGE_STORAGE)) {
42546
- const sessionPath = join54(MESSAGE_STORAGE, dir, sessionID);
42547
- if (existsSync46(sessionPath))
42799
+ for (const dir of readdirSync16(MESSAGE_STORAGE)) {
42800
+ const sessionPath = join55(MESSAGE_STORAGE, dir, sessionID);
42801
+ if (existsSync47(sessionPath))
42548
42802
  return sessionPath;
42549
42803
  }
42550
42804
  return null;
@@ -42953,14 +43207,17 @@ If the requested information is not found, clearly state what is missing.`;
42953
43207
  }
42954
43208
  // src/tools/delegate-task/tools.ts
42955
43209
  init_constants2();
42956
- import { existsSync as existsSync47, readdirSync as readdirSync16 } from "fs";
42957
- import { join as join55 } from "path";
43210
+ import { existsSync as existsSync48, readdirSync as readdirSync17 } from "fs";
43211
+ import { join as join56 } from "path";
42958
43212
 
42959
43213
  // src/features/task-toast-manager/manager.ts
42960
43214
  class TaskToastManager {
42961
43215
  tasks = new Map;
42962
43216
  client;
42963
43217
  concurrencyManager;
43218
+ completionBatch = [];
43219
+ completionDebounceTimer;
43220
+ static COMPLETION_DEBOUNCE_MS = 800;
42964
43221
  constructor(client2, concurrencyManager) {
42965
43222
  this.client = client2;
42966
43223
  this.concurrencyManager = concurrencyManager;
@@ -43072,13 +43329,36 @@ class TaskToastManager {
43072
43329
  }).catch(() => {});
43073
43330
  }
43074
43331
  showCompletionToast(task) {
43332
+ this.removeTask(task.id);
43333
+ this.completionBatch.push(task);
43334
+ if (this.completionDebounceTimer) {
43335
+ clearTimeout(this.completionDebounceTimer);
43336
+ }
43337
+ this.completionDebounceTimer = setTimeout(() => {
43338
+ this.flushCompletionBatch();
43339
+ }, TaskToastManager.COMPLETION_DEBOUNCE_MS);
43340
+ }
43341
+ flushCompletionBatch() {
43075
43342
  const tuiClient = this.client;
43076
- if (!tuiClient.tui?.showToast)
43343
+ if (!tuiClient.tui?.showToast) {
43344
+ this.completionBatch = [];
43345
+ return;
43346
+ }
43347
+ const batch = [...this.completionBatch];
43348
+ this.completionBatch = [];
43349
+ if (batch.length === 0)
43077
43350
  return;
43078
- this.removeTask(task.id);
43079
43351
  const remaining = this.getRunningTasks();
43080
43352
  const queued = this.getQueuedTasks();
43081
- let message = `"${task.description}" finished in ${task.duration}`;
43353
+ let message;
43354
+ if (batch.length === 1) {
43355
+ message = `"${batch[0].description}" finished in ${batch[0].duration}`;
43356
+ } else {
43357
+ const lines = batch.map((t) => ` \u2713 "${t.description}" (${t.duration})`);
43358
+ message = `${batch.length} tasks completed:
43359
+ ${lines.join(`
43360
+ `)}`;
43361
+ }
43082
43362
  if (remaining.length > 0 || queued.length > 0) {
43083
43363
  message += `
43084
43364
 
@@ -43086,12 +43366,13 @@ Still running: ${remaining.length} | Queued: ${queued.length}`;
43086
43366
  }
43087
43367
  tuiClient.tui.showToast({
43088
43368
  body: {
43089
- title: "Task Completed",
43369
+ title: batch.length === 1 ? "Task Completed" : `${batch.length} Tasks Completed`,
43090
43370
  message,
43091
43371
  variant: "success",
43092
- duration: 5000
43372
+ duration: batch.length > 1 ? 7000 : 5000
43093
43373
  }
43094
43374
  }).catch(() => {});
43375
+ this.completionDebounceTimer = undefined;
43095
43376
  }
43096
43377
  }
43097
43378
  var instance = null;
@@ -43104,6 +43385,256 @@ function initTaskToastManager(client2, concurrencyManager) {
43104
43385
  }
43105
43386
  // src/tools/delegate-task/tools.ts
43106
43387
  init_shared();
43388
+
43389
+ // src/shared/provider-error-classifier.ts
43390
+ function extractErrorInfo(error45) {
43391
+ if (typeof error45 === "string") {
43392
+ return { message: error45 };
43393
+ }
43394
+ if (error45 instanceof Error) {
43395
+ const anyErr = error45;
43396
+ return {
43397
+ statusCode: anyErr.status ?? anyErr.statusCode ?? anyErr.httpStatus,
43398
+ code: anyErr.code ?? anyErr.error?.code,
43399
+ type: anyErr.type ?? anyErr.error?.type,
43400
+ message: error45.message,
43401
+ status: anyErr.status ?? anyErr.error?.status,
43402
+ headers: anyErr.headers
43403
+ };
43404
+ }
43405
+ if (typeof error45 === "object" && error45 !== null) {
43406
+ const obj = error45;
43407
+ const inner = obj.error ?? {};
43408
+ return {
43409
+ statusCode: obj.status ?? obj.statusCode ?? inner.status,
43410
+ code: inner.code ?? obj.code,
43411
+ type: inner.type ?? obj.type,
43412
+ message: inner.message ?? obj.message ?? String(error45),
43413
+ status: inner.status ?? obj.status,
43414
+ headers: obj.headers
43415
+ };
43416
+ }
43417
+ return { message: String(error45) };
43418
+ }
43419
+ function parseRetryAfterMs(headers) {
43420
+ if (!headers)
43421
+ return;
43422
+ const retryAfter = headers["retry-after"] ?? headers["Retry-After"];
43423
+ if (retryAfter) {
43424
+ const seconds = Number(retryAfter);
43425
+ if (!isNaN(seconds) && seconds > 0) {
43426
+ return seconds * 1000;
43427
+ }
43428
+ }
43429
+ const reset = headers["x-ratelimit-reset"] ?? headers["X-Ratelimit-Reset"];
43430
+ if (reset) {
43431
+ const resetTimestamp = Number(reset);
43432
+ if (!isNaN(resetTimestamp)) {
43433
+ const resetMs = resetTimestamp > 1000000000000 ? resetTimestamp : resetTimestamp * 1000;
43434
+ const delayMs = resetMs - Date.now();
43435
+ return delayMs > 0 ? delayMs : 0;
43436
+ }
43437
+ }
43438
+ return;
43439
+ }
43440
+ function isContextOverflow(message, code) {
43441
+ const lowerMessage = message.toLowerCase();
43442
+ return lowerMessage.includes("context_length_exceeded") || lowerMessage.includes("prompt is too long") || lowerMessage.includes("maximum context length") || code === "context_length_exceeded";
43443
+ }
43444
+ function isZhipuQuotaCode(code) {
43445
+ if (typeof code !== "number")
43446
+ return false;
43447
+ return [1113, 1304, 1308, 1309].includes(code);
43448
+ }
43449
+ function isZhipuRateLimitCode(code) {
43450
+ if (typeof code !== "number")
43451
+ return false;
43452
+ return [1302, 1303].includes(code);
43453
+ }
43454
+ function isZhipuOverloadedCode(code) {
43455
+ if (typeof code !== "number")
43456
+ return false;
43457
+ return code === 1312;
43458
+ }
43459
+ function isGeminiQuotaDetails(details) {
43460
+ if (!Array.isArray(details))
43461
+ return false;
43462
+ return details.some((d) => d?.["@type"]?.includes("QuotaFailure") || d?.["@type"]?.includes("google.rpc.QuotaFailure"));
43463
+ }
43464
+ function isGeminiPerMinuteLimit(message, details) {
43465
+ const lowerMessage = message.toLowerCase();
43466
+ if (lowerMessage.includes("per_minute") || lowerMessage.includes("per minute")) {
43467
+ return true;
43468
+ }
43469
+ if (Array.isArray(details)) {
43470
+ return details.some((d) => d?.["@type"]?.includes("RetryInfo"));
43471
+ }
43472
+ return false;
43473
+ }
43474
+ function classifyProviderError(error45) {
43475
+ const info = extractErrorInfo(error45);
43476
+ const { statusCode, code, type: type2, message, status, headers } = info;
43477
+ if (isContextOverflow(message, code)) {
43478
+ return {
43479
+ category: "context_overflow",
43480
+ retryable: false,
43481
+ shouldFallback: false,
43482
+ statusCode,
43483
+ reason: "Context length exceeded, prompt too long for model"
43484
+ };
43485
+ }
43486
+ if (statusCode === 401 || statusCode === 403) {
43487
+ return {
43488
+ category: "auth",
43489
+ retryable: false,
43490
+ shouldFallback: false,
43491
+ statusCode,
43492
+ reason: statusCode === 401 ? "Invalid API key or authentication" : "Permission denied"
43493
+ };
43494
+ }
43495
+ if (statusCode === 400) {
43496
+ return {
43497
+ category: "bad_request",
43498
+ retryable: false,
43499
+ shouldFallback: false,
43500
+ statusCode,
43501
+ reason: "Invalid request parameters"
43502
+ };
43503
+ }
43504
+ if (statusCode === 429 && (code === "insufficient_quota" || type2 === "insufficient_quota")) {
43505
+ return {
43506
+ category: "quota",
43507
+ retryable: false,
43508
+ shouldFallback: true,
43509
+ statusCode,
43510
+ providerGuess: "openai",
43511
+ reason: "OpenAI quota exceeded, billing issue"
43512
+ };
43513
+ }
43514
+ if (statusCode === 402 && type2 === "billing_error") {
43515
+ return {
43516
+ category: "quota",
43517
+ retryable: false,
43518
+ shouldFallback: true,
43519
+ statusCode,
43520
+ providerGuess: "anthropic",
43521
+ reason: "Anthropic billing error, payment required"
43522
+ };
43523
+ }
43524
+ if (statusCode === 429 && status === "RESOURCE_EXHAUSTED" && isGeminiQuotaDetails(info.headers ? undefined : error45?.error?.details)) {
43525
+ return {
43526
+ category: "quota",
43527
+ retryable: false,
43528
+ shouldFallback: true,
43529
+ statusCode,
43530
+ providerGuess: "gemini",
43531
+ reason: "Gemini daily quota exceeded"
43532
+ };
43533
+ }
43534
+ if (statusCode === 429 && isZhipuQuotaCode(code)) {
43535
+ const quotaReasons = {
43536
+ 1113: "\u8D26\u6237\u6B20\u8D39",
43537
+ 1304: "\u8C03\u7528\u6B21\u6570\u8D85\u8FC7\u9650\u989D",
43538
+ 1308: "\u4F7F\u7528\u91CF\u8D85\u8FC7\u4E0A\u9650",
43539
+ 1309: "\u5957\u9910\u5DF2\u5230\u671F"
43540
+ };
43541
+ return {
43542
+ category: "quota",
43543
+ retryable: false,
43544
+ shouldFallback: true,
43545
+ statusCode,
43546
+ providerGuess: "zhipu",
43547
+ reason: `Zhipu/GLM: ${quotaReasons[code] ?? "quota exceeded"}`
43548
+ };
43549
+ }
43550
+ if (statusCode === 529 && type2 === "overloaded_error") {
43551
+ return {
43552
+ category: "overloaded",
43553
+ retryable: true,
43554
+ shouldFallback: false,
43555
+ statusCode,
43556
+ providerGuess: "anthropic",
43557
+ reason: "Anthropic API overloaded"
43558
+ };
43559
+ }
43560
+ if (statusCode === 429 && isZhipuOverloadedCode(code)) {
43561
+ return {
43562
+ category: "overloaded",
43563
+ retryable: true,
43564
+ shouldFallback: false,
43565
+ statusCode,
43566
+ providerGuess: "zhipu",
43567
+ reason: "Zhipu/GLM: \u5F53\u524D\u8D1F\u8F7D\u8FC7\u9AD8"
43568
+ };
43569
+ }
43570
+ if (statusCode === 429 && type2 === "rate_limit_error") {
43571
+ return {
43572
+ category: "rate_limit",
43573
+ retryable: true,
43574
+ shouldFallback: false,
43575
+ statusCode,
43576
+ providerGuess: "anthropic",
43577
+ retryAfterMs: parseRetryAfterMs(headers),
43578
+ reason: "Anthropic rate limit exceeded"
43579
+ };
43580
+ }
43581
+ if (statusCode === 429 && code === "rate_limit_exceeded") {
43582
+ return {
43583
+ category: "rate_limit",
43584
+ retryable: true,
43585
+ shouldFallback: false,
43586
+ statusCode,
43587
+ providerGuess: "openai",
43588
+ retryAfterMs: parseRetryAfterMs(headers),
43589
+ reason: "OpenAI rate limit exceeded"
43590
+ };
43591
+ }
43592
+ if (statusCode === 429 && status === "RESOURCE_EXHAUSTED" && isGeminiPerMinuteLimit(message, error45?.error?.details)) {
43593
+ return {
43594
+ category: "rate_limit",
43595
+ retryable: true,
43596
+ shouldFallback: false,
43597
+ statusCode,
43598
+ providerGuess: "gemini",
43599
+ retryAfterMs: parseRetryAfterMs(headers),
43600
+ reason: "Gemini per-minute rate limit exceeded"
43601
+ };
43602
+ }
43603
+ if (statusCode === 429 && isZhipuRateLimitCode(code)) {
43604
+ const rateLimitReasons = {
43605
+ 1302: "\u5E76\u53D1\u8BF7\u6C42\u8D85\u8FC7\u9650\u5236",
43606
+ 1303: "\u8BF7\u6C42\u9891\u7387\u8D85\u8FC7\u9650\u5236"
43607
+ };
43608
+ return {
43609
+ category: "rate_limit",
43610
+ retryable: true,
43611
+ shouldFallback: false,
43612
+ statusCode,
43613
+ providerGuess: "zhipu",
43614
+ retryAfterMs: parseRetryAfterMs(headers),
43615
+ reason: `Zhipu/GLM: ${rateLimitReasons[code] ?? "rate limit exceeded"}`
43616
+ };
43617
+ }
43618
+ if (statusCode === 429) {
43619
+ return {
43620
+ category: "rate_limit",
43621
+ retryable: true,
43622
+ shouldFallback: false,
43623
+ statusCode,
43624
+ retryAfterMs: parseRetryAfterMs(headers),
43625
+ reason: "Rate limit exceeded (generic 429)"
43626
+ };
43627
+ }
43628
+ return {
43629
+ category: "unknown",
43630
+ retryable: false,
43631
+ shouldFallback: false,
43632
+ statusCode,
43633
+ reason: `Unknown error: ${message.substring(0, 100)}`
43634
+ };
43635
+ }
43636
+
43637
+ // src/tools/delegate-task/tools.ts
43107
43638
  var SISYPHUS_JUNIOR_AGENT = "sisyphus-junior";
43108
43639
  function parseModelString(model) {
43109
43640
  const parts = model.split("/");
@@ -43113,14 +43644,14 @@ function parseModelString(model) {
43113
43644
  return;
43114
43645
  }
43115
43646
  function getMessageDir9(sessionID) {
43116
- if (!existsSync47(MESSAGE_STORAGE))
43647
+ if (!existsSync48(MESSAGE_STORAGE))
43117
43648
  return null;
43118
- const directPath = join55(MESSAGE_STORAGE, sessionID);
43119
- if (existsSync47(directPath))
43649
+ const directPath = join56(MESSAGE_STORAGE, sessionID);
43650
+ if (existsSync48(directPath))
43120
43651
  return directPath;
43121
- for (const dir of readdirSync16(MESSAGE_STORAGE)) {
43122
- const sessionPath = join55(MESSAGE_STORAGE, dir, sessionID);
43123
- if (existsSync47(sessionPath))
43652
+ for (const dir of readdirSync17(MESSAGE_STORAGE)) {
43653
+ const sessionPath = join56(MESSAGE_STORAGE, dir, sessionID);
43654
+ if (existsSync48(sessionPath))
43124
43655
  return sessionPath;
43125
43656
  }
43126
43657
  return null;
@@ -43715,7 +44246,12 @@ Session ID: ${sessionID}`;
43715
44246
  path: { id: sessionID }
43716
44247
  });
43717
44248
  if (messagesResult.error) {
43718
- return `Error fetching result: ${messagesResult.error}
44249
+ const classification = classifyProviderError(messagesResult.error);
44250
+ const diagnosis = classification.category !== "unknown" ? `
44251
+
44252
+ \uD83D\uDD0D **\u9519\u8BEF\u5206\u7C7B**: ${classification.reason}
44253
+ ${classification.shouldFallback ? "\uD83D\uDCA1 \u6B64\u9519\u8BEF\u53EF\u901A\u8FC7 runtime fallback \u81EA\u52A8\u5904\u7406\u3002" : classification.retryable ? "\u23F3 \u6B64\u9519\u8BEF\u53EF\u91CD\u8BD5\u3002" : ""}` : "";
44254
+ return `Error fetching result: ${messagesResult.error}${diagnosis}
43719
44255
 
43720
44256
  Session ID: ${sessionID}`;
43721
44257
  }
@@ -43753,13 +44289,14 @@ ${textContent || "(\u65E0\u6587\u672C\u8F93\u51FA)"}
43753
44289
  if (syncSessionID) {
43754
44290
  subagentSessions.delete(syncSessionID);
43755
44291
  }
43756
- return formatDetailedError(error45, {
43757
- operation: "\u6267\u884C\u4EFB\u52A1",
43758
- args,
43759
- sessionID: syncSessionID,
43760
- agent: agentToUse,
43761
- category: args.category
43762
- });
44292
+ const classification = classifyProviderError(error45);
44293
+ const diagnosis = classification.category !== "unknown" ? `
44294
+
44295
+ \uD83D\uDD0D **\u9519\u8BEF\u5206\u7C7B**: ${classification.reason}
44296
+ ${classification.shouldFallback ? "\uD83D\uDCA1 \u6B64\u9519\u8BEF\u53EF\u901A\u8FC7 runtime fallback \u81EA\u52A8\u5904\u7406\u3002" : classification.retryable ? "\u23F3 \u6B64\u9519\u8BEF\u53EF\u91CD\u8BD5\u3002" : ""}` : "";
44297
+ return `\u4EFB\u52A1\u6267\u884C\u5931\u8D25: ${error45 instanceof Error ? error45.message : String(error45)}${diagnosis}
44298
+
44299
+ Session ID: ${syncSessionID ?? "unknown"}`;
43763
44300
  }
43764
44301
  }
43765
44302
  });
@@ -43888,6 +44425,9 @@ class ConcurrencyManager {
43888
44425
  }
43889
44426
  }
43890
44427
 
44428
+ // src/features/background-agent/manager.ts
44429
+ init_runtime_fallback();
44430
+
43891
44431
  // src/features/background-agent/perf-aggregator.ts
43892
44432
  function percentile(sorted, p) {
43893
44433
  if (sorted.length === 0)
@@ -43948,12 +44488,14 @@ class PerformanceAggregator {
43948
44488
  }
43949
44489
 
43950
44490
  // src/features/background-agent/manager.ts
43951
- import { existsSync as existsSync48, readdirSync as readdirSync17 } from "fs";
43952
- import { join as join56 } from "path";
44491
+ import { existsSync as existsSync49, readdirSync as readdirSync18 } from "fs";
44492
+ import { join as join57 } from "path";
43953
44493
  var TASK_TTL_MS = 30 * 60 * 1000;
43954
44494
  var MIN_STABILITY_TIME_MS = 10 * 1000;
43955
- var DEFAULT_STALE_TIMEOUT_MS = 180000;
44495
+ var DEFAULT_STALE_TIMEOUT_MS = 120000;
43956
44496
  var MIN_RUNTIME_BEFORE_STALE_MS = 30000;
44497
+ var STEP_TIMEOUT_MS = 600000;
44498
+ var MIN_IDLE_TIME_MS = 15000;
43957
44499
 
43958
44500
  class BackgroundManager {
43959
44501
  static cleanupManagers = new Set;
@@ -44006,7 +44548,11 @@ class BackgroundManager {
44006
44548
  parentMessageID: input.parentMessageID,
44007
44549
  parentModel: input.parentModel,
44008
44550
  parentAgent: input.parentAgent,
44009
- model: input.model
44551
+ model: input.model,
44552
+ maxSteps: this.config?.maxSteps,
44553
+ maxRuntimeMs: this.config?.maxRuntimeMs,
44554
+ stepTimeoutMs: this.config?.stepTimeoutMs ?? STEP_TIMEOUT_MS,
44555
+ stepCount: 0
44010
44556
  };
44011
44557
  this.tasks.set(task.id, task);
44012
44558
  if (input.parentSessionID) {
@@ -44098,7 +44644,8 @@ class BackgroundManager {
44098
44644
  task.sessionID = sessionID;
44099
44645
  task.progress = {
44100
44646
  toolCalls: 0,
44101
- lastUpdate: new Date
44647
+ lastUpdate: new Date,
44648
+ stepStartedAt: Date.now()
44102
44649
  };
44103
44650
  task.concurrencyKey = concurrencyKey;
44104
44651
  task.concurrencyGroup = concurrencyKey;
@@ -44133,13 +44680,58 @@ class BackgroundManager {
44133
44680
  log("[background-agent] promptAsync error:", error45);
44134
44681
  const existingTask = this.findBySession(sessionID);
44135
44682
  if (existingTask) {
44136
- existingTask.status = "error";
44137
- const errorMessage = error45 instanceof Error ? error45.message : String(error45);
44138
- if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
44139
- existingTask.error = `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`;
44683
+ const classification = classifyProviderError(error45);
44684
+ if (classification.retryable || classification.shouldFallback) {
44685
+ const attempts = existingTask.attempts ?? [];
44686
+ const currentModel = input.model ?? { providerID: "", modelID: "" };
44687
+ const fallbackResult = resolveNextFallbackModel({
44688
+ agent: input.agent,
44689
+ currentModel,
44690
+ attempts,
44691
+ lastErrorClassification: classification
44692
+ });
44693
+ if (fallbackResult.kind === "next") {
44694
+ existingTask.attempts = [...attempts, {
44695
+ model: fallbackResult.model,
44696
+ error: classification
44697
+ }];
44698
+ log("[background-agent] Fallback to model:", fallbackResult.model);
44699
+ this.client.session.prompt({
44700
+ path: { id: sessionID },
44701
+ body: {
44702
+ agent: input.agent,
44703
+ model: fallbackResult.model,
44704
+ parts: [{ type: "text", text: input.prompt }]
44705
+ }
44706
+ }).catch((retryError) => {
44707
+ log("[background-agent] Fallback prompt error:", retryError);
44708
+ const task2 = this.findBySession(sessionID);
44709
+ if (task2) {
44710
+ task2.status = "error";
44711
+ task2.error = `Fallback failed: ${retryError instanceof Error ? retryError.message : String(retryError)}`;
44712
+ task2.completedAt = new Date;
44713
+ if (task2.concurrencyKey) {
44714
+ this.concurrencyManager.release(task2.concurrencyKey);
44715
+ task2.concurrencyKey = undefined;
44716
+ }
44717
+ this.markForNotification(task2);
44718
+ this.notifyParentSession(task2).catch((err) => {
44719
+ log("[background-agent] Failed to notify on fallback error:", err);
44720
+ });
44721
+ }
44722
+ });
44723
+ return;
44724
+ }
44725
+ existingTask.error = `All fallback models exhausted. Last error: ${classification.reason}`;
44140
44726
  } else {
44141
- existingTask.error = errorMessage;
44727
+ const errorMessage = error45 instanceof Error ? error45.message : String(error45);
44728
+ if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
44729
+ existingTask.error = `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`;
44730
+ } else {
44731
+ existingTask.error = errorMessage;
44732
+ }
44142
44733
  }
44734
+ existingTask.status = "error";
44143
44735
  existingTask.completedAt = new Date;
44144
44736
  if (existingTask.concurrencyKey) {
44145
44737
  this.concurrencyManager.release(existingTask.concurrencyKey);
@@ -44238,7 +44830,11 @@ class BackgroundManager {
44238
44830
  },
44239
44831
  parentAgent: input.parentAgent,
44240
44832
  concurrencyKey: input.concurrencyKey,
44241
- concurrencyGroup
44833
+ concurrencyGroup,
44834
+ maxSteps: this.config?.maxSteps,
44835
+ maxRuntimeMs: this.config?.maxRuntimeMs,
44836
+ stepTimeoutMs: this.config?.stepTimeoutMs ?? STEP_TIMEOUT_MS,
44837
+ stepCount: 0
44242
44838
  };
44243
44839
  this.tasks.set(task.id, task);
44244
44840
  subagentSessions.add(input.sessionID);
@@ -44278,12 +44874,14 @@ class BackgroundManager {
44278
44874
  existingTask.parentModel = input.parentModel;
44279
44875
  existingTask.parentAgent = input.parentAgent;
44280
44876
  existingTask.startedAt = new Date;
44877
+ existingTask.stepCount = 0;
44281
44878
  if (existingTask.progress) {
44282
44879
  existingTask.progress.phaseTiming = undefined;
44283
44880
  }
44284
44881
  existingTask.progress = {
44285
44882
  toolCalls: existingTask.progress?.toolCalls ?? 0,
44286
- lastUpdate: new Date
44883
+ lastUpdate: new Date,
44884
+ stepStartedAt: Date.now()
44287
44885
  };
44288
44886
  this.startPolling();
44289
44887
  if (existingTask.sessionID) {
@@ -44385,11 +44983,20 @@ class BackgroundManager {
44385
44983
  const task = this.findBySession(sessionID);
44386
44984
  if (!task || task.status !== "running")
44387
44985
  return;
44986
+ task.stepCount = (task.stepCount ?? 0) + 1;
44987
+ if (task.progress) {
44988
+ task.progress.stepStartedAt = Date.now();
44989
+ }
44990
+ if (this.isStepLimitExceeded(task)) {
44991
+ this.tryCompleteTask(task, `step limit (${task.maxSteps} steps)`).catch((err) => {
44992
+ log("[background-agent] Error completing task on step limit:", err);
44993
+ });
44994
+ return;
44995
+ }
44388
44996
  const startedAt = task.startedAt;
44389
44997
  if (!startedAt)
44390
44998
  return;
44391
44999
  const elapsedMs = Date.now() - startedAt.getTime();
44392
- const MIN_IDLE_TIME_MS = 5000;
44393
45000
  if (elapsedMs < MIN_IDLE_TIME_MS) {
44394
45001
  log("[background-agent] Ignoring early session.idle, elapsed:", { elapsedMs, taskId: task.id });
44395
45002
  return;
@@ -44776,6 +45383,41 @@ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Dat
44776
45383
  const runtime = now - startedAt.getTime();
44777
45384
  if (runtime < MIN_RUNTIME_BEFORE_STALE_MS)
44778
45385
  continue;
45386
+ if (this.isRuntimeLimitExceeded(task)) {
45387
+ task.status = "cancelled";
45388
+ task.error = `Runtime limit exceeded (${Math.round(runtime / 60000)}min)`;
45389
+ task.completedAt = new Date;
45390
+ if (task.concurrencyKey) {
45391
+ this.concurrencyManager.release(task.concurrencyKey);
45392
+ task.concurrencyKey = undefined;
45393
+ }
45394
+ this.client.session.abort({ path: { id: sessionID } }).catch(() => {});
45395
+ log(`[background-agent] Task ${task.id} interrupted: runtime limit`);
45396
+ try {
45397
+ await this.notifyParentSession(task);
45398
+ } catch (err) {
45399
+ log("[background-agent] Error in notifyParentSession for runtime-limit task:", { taskId: task.id, error: err });
45400
+ }
45401
+ continue;
45402
+ }
45403
+ if (this.isStepTimeoutExceeded(task)) {
45404
+ const stepTimeoutMs = task.stepTimeoutMs ?? STEP_TIMEOUT_MS;
45405
+ task.status = "cancelled";
45406
+ task.error = `Step timeout exceeded (single step > ${Math.round(stepTimeoutMs / 60000)}min)`;
45407
+ task.completedAt = new Date;
45408
+ if (task.concurrencyKey) {
45409
+ this.concurrencyManager.release(task.concurrencyKey);
45410
+ task.concurrencyKey = undefined;
45411
+ }
45412
+ this.client.session.abort({ path: { id: sessionID } }).catch(() => {});
45413
+ log(`[background-agent] Task ${task.id} interrupted: step timeout`);
45414
+ try {
45415
+ await this.notifyParentSession(task);
45416
+ } catch (err) {
45417
+ log("[background-agent] Error in notifyParentSession for step-timeout task:", { taskId: task.id, error: err });
45418
+ }
45419
+ continue;
45420
+ }
44779
45421
  const timeSinceLastUpdate = now - task.progress.lastUpdate.getTime();
44780
45422
  if (timeSinceLastUpdate <= staleTimeoutMs)
44781
45423
  continue;
@@ -44800,6 +45442,30 @@ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Dat
44800
45442
  }
44801
45443
  }
44802
45444
  }
45445
+ isStepLimitExceeded(task) {
45446
+ const maxSteps = task.maxSteps;
45447
+ if (!maxSteps || maxSteps <= 0)
45448
+ return false;
45449
+ return (task.stepCount ?? 0) >= maxSteps;
45450
+ }
45451
+ isRuntimeLimitExceeded(task) {
45452
+ const maxRuntimeMs = task.maxRuntimeMs;
45453
+ if (!maxRuntimeMs || maxRuntimeMs <= 0)
45454
+ return false;
45455
+ if (!task.startedAt)
45456
+ return false;
45457
+ const runtime = Date.now() - task.startedAt.getTime();
45458
+ return runtime >= maxRuntimeMs;
45459
+ }
45460
+ isStepTimeoutExceeded(task) {
45461
+ const stepTimeoutMs = task.stepTimeoutMs;
45462
+ if (!stepTimeoutMs || stepTimeoutMs <= 0)
45463
+ return false;
45464
+ if (!task.progress?.stepStartedAt)
45465
+ return false;
45466
+ const stepDuration = Date.now() - task.progress.stepStartedAt;
45467
+ return stepDuration >= stepTimeoutMs;
45468
+ }
44803
45469
  async pollRunningTasks() {
44804
45470
  const start = this.perfTracer?.isEnabled() ? performance.now() : undefined;
44805
45471
  try {
@@ -44828,6 +45494,10 @@ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Dat
44828
45494
  log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
44829
45495
  continue;
44830
45496
  }
45497
+ if (this.isStepLimitExceeded(task)) {
45498
+ await this.tryCompleteTask(task, `step limit via polling (${task.maxSteps} steps)`);
45499
+ continue;
45500
+ }
44831
45501
  await this.tryCompleteTask(task, "polling (idle status)");
44832
45502
  continue;
44833
45503
  }
@@ -44900,6 +45570,10 @@ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Dat
44900
45570
  }
44901
45571
  if (task.status !== "running")
44902
45572
  continue;
45573
+ if (this.isStepLimitExceeded(task)) {
45574
+ await this.tryCompleteTask(task, `step limit via stability (${task.maxSteps} steps)`);
45575
+ continue;
45576
+ }
44903
45577
  const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44904
45578
  if (!hasIncompleteTodos2) {
44905
45579
  await this.tryCompleteTask(task, "stability detection");
@@ -44964,14 +45638,14 @@ function registerProcessSignal(signal, handler, exitAfter) {
44964
45638
  return listener;
44965
45639
  }
44966
45640
  function getMessageDir10(sessionID) {
44967
- if (!existsSync48(MESSAGE_STORAGE))
45641
+ if (!existsSync49(MESSAGE_STORAGE))
44968
45642
  return null;
44969
- const directPath = join56(MESSAGE_STORAGE, sessionID);
44970
- if (existsSync48(directPath))
45643
+ const directPath = join57(MESSAGE_STORAGE, sessionID);
45644
+ if (existsSync49(directPath))
44971
45645
  return directPath;
44972
- for (const dir of readdirSync17(MESSAGE_STORAGE)) {
44973
- const sessionPath = join56(MESSAGE_STORAGE, dir, sessionID);
44974
- if (existsSync48(sessionPath))
45646
+ for (const dir of readdirSync18(MESSAGE_STORAGE)) {
45647
+ const sessionPath = join57(MESSAGE_STORAGE, dir, sessionID);
45648
+ if (existsSync49(sessionPath))
44975
45649
  return sessionPath;
44976
45650
  }
44977
45651
  return null;
@@ -62884,6 +63558,7 @@ var HookNameSchema = exports_external2.enum([
62884
63558
  "auto-slash-command",
62885
63559
  "edit-error-recovery",
62886
63560
  "delegate-task-retry",
63561
+ "runtime-fallback",
62887
63562
  "prometheus-md-only",
62888
63563
  "perf-profiler",
62889
63564
  "start-work",
@@ -63058,7 +63733,10 @@ var BackgroundTaskConfigSchema = exports_external2.object({
63058
63733
  defaultConcurrency: exports_external2.number().min(1).optional(),
63059
63734
  providerConcurrency: exports_external2.record(exports_external2.string(), exports_external2.number().min(0)).optional(),
63060
63735
  modelConcurrency: exports_external2.record(exports_external2.string(), exports_external2.number().min(0)).optional(),
63061
- staleTimeoutMs: exports_external2.number().min(60000).optional()
63736
+ staleTimeoutMs: exports_external2.number().min(60000).optional(),
63737
+ maxSteps: exports_external2.number().min(0).optional(),
63738
+ maxRuntimeMs: exports_external2.number().min(0).optional(),
63739
+ stepTimeoutMs: exports_external2.number().min(0).optional()
63062
63740
  });
63063
63741
  var NotificationConfigSchema = exports_external2.object({
63064
63742
  force_enable: exports_external2.boolean().optional()
@@ -63067,6 +63745,15 @@ var GitMasterConfigSchema = exports_external2.object({
63067
63745
  commit_footer: exports_external2.boolean().default(true),
63068
63746
  include_co_authored_by: exports_external2.boolean().default(true)
63069
63747
  });
63748
+ var RuntimeFallbackConfigSchema = exports_external2.object({
63749
+ enabled: exports_external2.boolean().default(true),
63750
+ max_attempts: exports_external2.number().min(0).default(3),
63751
+ initial_delay_ms: exports_external2.number().min(0).default(2000),
63752
+ backoff_factor: exports_external2.number().min(1).default(2),
63753
+ max_delay_ms: exports_external2.number().min(0).default(30000),
63754
+ respect_retry_after: exports_external2.boolean().default(true),
63755
+ jitter: exports_external2.boolean().default(true)
63756
+ });
63070
63757
  var OhMyOpenCodeConfigSchema = exports_external2.object({
63071
63758
  $schema: exports_external2.string().optional(),
63072
63759
  disabled_mcps: exports_external2.array(AnyMcpNameSchema).optional(),
@@ -63085,7 +63772,8 @@ var OhMyOpenCodeConfigSchema = exports_external2.object({
63085
63772
  ralph_loop: RalphLoopConfigSchema.optional(),
63086
63773
  background_task: BackgroundTaskConfigSchema.optional(),
63087
63774
  notification: NotificationConfigSchema.optional(),
63088
- git_master: GitMasterConfigSchema.optional()
63775
+ git_master: GitMasterConfigSchema.optional(),
63776
+ runtime_fallback: RuntimeFallbackConfigSchema.optional()
63089
63777
  });
63090
63778
  // src/plugin-config.ts
63091
63779
  init_shared();
@@ -65153,21 +65841,21 @@ TODO \u5217\u8868\uFF1A[\u8DEF\u5F84]
65153
65841
 
65154
65842
  **\u5BF9\u4E8E\u63A2\u7D22\uFF08explore/librarian\uFF09**\uFF1A\u59CB\u7EC8\u540E\u53F0\u8FD0\u884C
65155
65843
  \`\`\`typescript
65156
- delegate_task(subagent_type="explore", run_in_background=true, ...)
65157
- delegate_task(subagent_type="librarian", run_in_background=true, ...)
65844
+ delegate_task(subagent_type="explore", run_in_background=true, load_skills=[], ...)
65845
+ delegate_task(subagent_type="librarian", run_in_background=true, load_skills=[], ...)
65158
65846
  \`\`\`
65159
65847
 
65160
65848
  **\u5BF9\u4E8E\u4EFB\u52A1\u6267\u884C**\uFF1A\u7EDD\u4E0D\u7528\u540E\u53F0\u8FD0\u884C
65161
65849
  \`\`\`typescript
65162
- delegate_task(category="...", run_in_background=false, ...)
65850
+ delegate_task(category="...", run_in_background=false, load_skills=[], ...)
65163
65851
  \`\`\`
65164
65852
 
65165
65853
  **\u5E76\u884C\u4EFB\u52A1\u7EC4**\uFF1A\u5728\u4E00\u6761\u6D88\u606F\u4E2D\u591A\u6B21\u8C03\u7528
65166
65854
  \`\`\`typescript
65167
65855
  // \u4EFB\u52A12\u30013\u30014\u662F\u72EC\u7ACB\u7684\u2014\u2014\u4E00\u8D77\u8C03\u7528
65168
- delegate_task(category="quick", prompt="\u4EFB\u52A12...")
65169
- delegate_task(category="quick", prompt="\u4EFB\u52A13...")
65170
- delegate_task(category="quick", prompt="\u4EFB\u52A14...")
65856
+ delegate_task(category="quick", prompt="\u4EFB\u52A12...", load_skills=[])
65857
+ delegate_task(category="quick", prompt="\u4EFB\u52A13...", load_skills=[])
65858
+ delegate_task(category="quick", prompt="\u4EFB\u52A14...", load_skills=[])
65171
65859
  \`\`\`
65172
65860
 
65173
65861
  **\u540E\u53F0\u7BA1\u7406**\uFF1A
@@ -66042,7 +66730,7 @@ init_file_utils();
66042
66730
  init_shared();
66043
66731
  init_logger();
66044
66732
  import { promises as fs11 } from "fs";
66045
- import { join as join58, basename as basename6 } from "path";
66733
+ import { join as join59, basename as basename6 } from "path";
66046
66734
  async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
66047
66735
  try {
66048
66736
  await fs11.access(commandsDir);
@@ -66072,7 +66760,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
66072
66760
  if (entry.isDirectory()) {
66073
66761
  if (entry.name.startsWith("."))
66074
66762
  continue;
66075
- const subDirPath = join58(commandsDir, entry.name);
66763
+ const subDirPath = join59(commandsDir, entry.name);
66076
66764
  const subPrefix = prefix ? `${prefix}:${entry.name}` : entry.name;
66077
66765
  const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
66078
66766
  commands2.push(...subCommands);
@@ -66080,7 +66768,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
66080
66768
  }
66081
66769
  if (!isMarkdownFile(entry))
66082
66770
  continue;
66083
- const commandPath = join58(commandsDir, entry.name);
66771
+ const commandPath = join59(commandsDir, entry.name);
66084
66772
  const baseCommandName = basename6(entry.name, ".md");
66085
66773
  const commandName = prefix ? `${prefix}:${baseCommandName}` : baseCommandName;
66086
66774
  try {
@@ -66127,23 +66815,23 @@ function commandsToRecord(commands2) {
66127
66815
  return result;
66128
66816
  }
66129
66817
  async function loadUserCommands() {
66130
- const userCommandsDir = join58(getClaudeConfigDir(), "commands");
66818
+ const userCommandsDir = join59(getClaudeConfigDir(), "commands");
66131
66819
  const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
66132
66820
  return commandsToRecord(commands2);
66133
66821
  }
66134
66822
  async function loadProjectCommands() {
66135
- const projectCommandsDir = join58(process.cwd(), ".claude", "commands");
66823
+ const projectCommandsDir = join59(process.cwd(), ".claude", "commands");
66136
66824
  const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
66137
66825
  return commandsToRecord(commands2);
66138
66826
  }
66139
66827
  async function loadOpencodeGlobalCommands() {
66140
66828
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
66141
- const opencodeCommandsDir = join58(configDir, "command");
66829
+ const opencodeCommandsDir = join59(configDir, "command");
66142
66830
  const commands2 = await loadCommandsFromDir(opencodeCommandsDir, "opencode");
66143
66831
  return commandsToRecord(commands2);
66144
66832
  }
66145
66833
  async function loadOpencodeProjectCommands() {
66146
- const opencodeProjectDir = join58(process.cwd(), ".opencode", "command");
66834
+ const opencodeProjectDir = join59(process.cwd(), ".opencode", "command");
66147
66835
  const commands2 = await loadCommandsFromDir(opencodeProjectDir, "opencode-project");
66148
66836
  return commandsToRecord(commands2);
66149
66837
  }
@@ -66151,8 +66839,8 @@ async function loadOpencodeProjectCommands() {
66151
66839
  init_frontmatter();
66152
66840
  init_file_utils();
66153
66841
  init_shared();
66154
- import { existsSync as existsSync50, readdirSync as readdirSync18, readFileSync as readFileSync31 } from "fs";
66155
- import { join as join59, basename as basename7 } from "path";
66842
+ import { existsSync as existsSync51, readdirSync as readdirSync19, readFileSync as readFileSync31 } from "fs";
66843
+ import { join as join60, basename as basename7 } from "path";
66156
66844
  function parseToolsConfig(toolsStr) {
66157
66845
  if (!toolsStr)
66158
66846
  return;
@@ -66166,15 +66854,15 @@ function parseToolsConfig(toolsStr) {
66166
66854
  return result;
66167
66855
  }
66168
66856
  function loadAgentsFromDir(agentsDir, scope) {
66169
- if (!existsSync50(agentsDir)) {
66857
+ if (!existsSync51(agentsDir)) {
66170
66858
  return [];
66171
66859
  }
66172
- const entries = readdirSync18(agentsDir, { withFileTypes: true });
66860
+ const entries = readdirSync19(agentsDir, { withFileTypes: true });
66173
66861
  const agents = [];
66174
66862
  for (const entry of entries) {
66175
66863
  if (!isMarkdownFile(entry))
66176
66864
  continue;
66177
- const agentPath = join59(agentsDir, entry.name);
66865
+ const agentPath = join60(agentsDir, entry.name);
66178
66866
  const agentName = basename7(entry.name, ".md");
66179
66867
  try {
66180
66868
  const content = readFileSync31(agentPath, "utf-8");
@@ -66204,7 +66892,7 @@ function loadAgentsFromDir(agentsDir, scope) {
66204
66892
  return agents;
66205
66893
  }
66206
66894
  function loadUserAgents() {
66207
- const userAgentsDir = join59(getClaudeConfigDir(), "agents");
66895
+ const userAgentsDir = join60(getClaudeConfigDir(), "agents");
66208
66896
  const agents = loadAgentsFromDir(userAgentsDir, "user");
66209
66897
  const result = {};
66210
66898
  for (const agent of agents) {
@@ -66213,7 +66901,7 @@ function loadUserAgents() {
66213
66901
  return result;
66214
66902
  }
66215
66903
  function loadProjectAgents() {
66216
- const projectAgentsDir = join59(process.cwd(), ".claude", "agents");
66904
+ const projectAgentsDir = join60(process.cwd(), ".claude", "agents");
66217
66905
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
66218
66906
  const result = {};
66219
66907
  for (const agent of agents) {
@@ -66225,18 +66913,18 @@ function loadProjectAgents() {
66225
66913
  init_frontmatter();
66226
66914
  init_file_utils();
66227
66915
  init_logger();
66228
- import { existsSync as existsSync51, readdirSync as readdirSync19, readFileSync as readFileSync32 } from "fs";
66916
+ import { existsSync as existsSync52, readdirSync as readdirSync20, readFileSync as readFileSync32 } from "fs";
66229
66917
  import { homedir as homedir13 } from "os";
66230
- import { join as join60, basename as basename8 } from "path";
66918
+ import { join as join61, basename as basename8 } from "path";
66231
66919
  var CLAUDE_PLUGIN_ROOT_VAR = "${CLAUDE_PLUGIN_ROOT}";
66232
66920
  function getPluginsBaseDir() {
66233
66921
  if (process.env.CLAUDE_PLUGINS_HOME) {
66234
66922
  return process.env.CLAUDE_PLUGINS_HOME;
66235
66923
  }
66236
- return join60(homedir13(), ".claude", "plugins");
66924
+ return join61(homedir13(), ".claude", "plugins");
66237
66925
  }
66238
66926
  function getInstalledPluginsPath() {
66239
- return join60(getPluginsBaseDir(), "installed_plugins.json");
66927
+ return join61(getPluginsBaseDir(), "installed_plugins.json");
66240
66928
  }
66241
66929
  function resolvePluginPath(path8, pluginRoot) {
66242
66930
  return path8.replace(CLAUDE_PLUGIN_ROOT_VAR, pluginRoot);
@@ -66261,7 +66949,7 @@ function resolvePluginPaths(obj, pluginRoot) {
66261
66949
  }
66262
66950
  function loadInstalledPlugins() {
66263
66951
  const dbPath = getInstalledPluginsPath();
66264
- if (!existsSync51(dbPath)) {
66952
+ if (!existsSync52(dbPath)) {
66265
66953
  return null;
66266
66954
  }
66267
66955
  try {
@@ -66276,11 +66964,11 @@ function getClaudeSettingsPath() {
66276
66964
  if (process.env.CLAUDE_SETTINGS_PATH) {
66277
66965
  return process.env.CLAUDE_SETTINGS_PATH;
66278
66966
  }
66279
- return join60(homedir13(), ".claude", "settings.json");
66967
+ return join61(homedir13(), ".claude", "settings.json");
66280
66968
  }
66281
66969
  function loadClaudeSettings() {
66282
66970
  const settingsPath = getClaudeSettingsPath();
66283
- if (!existsSync51(settingsPath)) {
66971
+ if (!existsSync52(settingsPath)) {
66284
66972
  return null;
66285
66973
  }
66286
66974
  try {
@@ -66292,8 +66980,8 @@ function loadClaudeSettings() {
66292
66980
  }
66293
66981
  }
66294
66982
  function loadPluginManifest(installPath) {
66295
- const manifestPath = join60(installPath, ".claude-plugin", "plugin.json");
66296
- if (!existsSync51(manifestPath)) {
66983
+ const manifestPath = join61(installPath, ".claude-plugin", "plugin.json");
66984
+ if (!existsSync52(manifestPath)) {
66297
66985
  return null;
66298
66986
  }
66299
66987
  try {
@@ -66344,7 +67032,7 @@ function discoverInstalledPlugins(options) {
66344
67032
  continue;
66345
67033
  }
66346
67034
  const { installPath, scope, version: version3 } = installation;
66347
- if (!existsSync51(installPath)) {
67035
+ if (!existsSync52(installPath)) {
66348
67036
  errors5.push({
66349
67037
  pluginKey,
66350
67038
  installPath,
@@ -66362,21 +67050,21 @@ function discoverInstalledPlugins(options) {
66362
67050
  pluginKey,
66363
67051
  manifest: manifest ?? undefined
66364
67052
  };
66365
- if (existsSync51(join60(installPath, "commands"))) {
66366
- loadedPlugin.commandsDir = join60(installPath, "commands");
67053
+ if (existsSync52(join61(installPath, "commands"))) {
67054
+ loadedPlugin.commandsDir = join61(installPath, "commands");
66367
67055
  }
66368
- if (existsSync51(join60(installPath, "agents"))) {
66369
- loadedPlugin.agentsDir = join60(installPath, "agents");
67056
+ if (existsSync52(join61(installPath, "agents"))) {
67057
+ loadedPlugin.agentsDir = join61(installPath, "agents");
66370
67058
  }
66371
- if (existsSync51(join60(installPath, "skills"))) {
66372
- loadedPlugin.skillsDir = join60(installPath, "skills");
67059
+ if (existsSync52(join61(installPath, "skills"))) {
67060
+ loadedPlugin.skillsDir = join61(installPath, "skills");
66373
67061
  }
66374
- const hooksPath = join60(installPath, "hooks", "hooks.json");
66375
- if (existsSync51(hooksPath)) {
67062
+ const hooksPath = join61(installPath, "hooks", "hooks.json");
67063
+ if (existsSync52(hooksPath)) {
66376
67064
  loadedPlugin.hooksPath = hooksPath;
66377
67065
  }
66378
- const mcpPath = join60(installPath, ".mcp.json");
66379
- if (existsSync51(mcpPath)) {
67066
+ const mcpPath = join61(installPath, ".mcp.json");
67067
+ if (existsSync52(mcpPath)) {
66380
67068
  loadedPlugin.mcpPath = mcpPath;
66381
67069
  }
66382
67070
  plugins.push(loadedPlugin);
@@ -66387,13 +67075,13 @@ function discoverInstalledPlugins(options) {
66387
67075
  function loadPluginCommands(plugins) {
66388
67076
  const commands2 = {};
66389
67077
  for (const plugin of plugins) {
66390
- if (!plugin.commandsDir || !existsSync51(plugin.commandsDir))
67078
+ if (!plugin.commandsDir || !existsSync52(plugin.commandsDir))
66391
67079
  continue;
66392
- const entries = readdirSync19(plugin.commandsDir, { withFileTypes: true });
67080
+ const entries = readdirSync20(plugin.commandsDir, { withFileTypes: true });
66393
67081
  for (const entry of entries) {
66394
67082
  if (!isMarkdownFile(entry))
66395
67083
  continue;
66396
- const commandPath = join60(plugin.commandsDir, entry.name);
67084
+ const commandPath = join61(plugin.commandsDir, entry.name);
66397
67085
  const commandName = basename8(entry.name, ".md");
66398
67086
  const namespacedName = `${plugin.name}:${commandName}`;
66399
67087
  try {
@@ -66429,18 +67117,18 @@ $ARGUMENTS
66429
67117
  function loadPluginSkillsAsCommands(plugins) {
66430
67118
  const skills = {};
66431
67119
  for (const plugin of plugins) {
66432
- if (!plugin.skillsDir || !existsSync51(plugin.skillsDir))
67120
+ if (!plugin.skillsDir || !existsSync52(plugin.skillsDir))
66433
67121
  continue;
66434
- const entries = readdirSync19(plugin.skillsDir, { withFileTypes: true });
67122
+ const entries = readdirSync20(plugin.skillsDir, { withFileTypes: true });
66435
67123
  for (const entry of entries) {
66436
67124
  if (entry.name.startsWith("."))
66437
67125
  continue;
66438
- const skillPath = join60(plugin.skillsDir, entry.name);
67126
+ const skillPath = join61(plugin.skillsDir, entry.name);
66439
67127
  if (!entry.isDirectory() && !entry.isSymbolicLink())
66440
67128
  continue;
66441
67129
  const resolvedPath = resolveSymlink(skillPath);
66442
- const skillMdPath = join60(resolvedPath, "SKILL.md");
66443
- if (!existsSync51(skillMdPath))
67130
+ const skillMdPath = join61(resolvedPath, "SKILL.md");
67131
+ if (!existsSync52(skillMdPath))
66444
67132
  continue;
66445
67133
  try {
66446
67134
  const content = readFileSync32(skillMdPath, "utf-8");
@@ -66490,13 +67178,13 @@ function parseToolsConfig2(toolsStr) {
66490
67178
  function loadPluginAgents(plugins) {
66491
67179
  const agents = {};
66492
67180
  for (const plugin of plugins) {
66493
- if (!plugin.agentsDir || !existsSync51(plugin.agentsDir))
67181
+ if (!plugin.agentsDir || !existsSync52(plugin.agentsDir))
66494
67182
  continue;
66495
- const entries = readdirSync19(plugin.agentsDir, { withFileTypes: true });
67183
+ const entries = readdirSync20(plugin.agentsDir, { withFileTypes: true });
66496
67184
  for (const entry of entries) {
66497
67185
  if (!isMarkdownFile(entry))
66498
67186
  continue;
66499
- const agentPath = join60(plugin.agentsDir, entry.name);
67187
+ const agentPath = join61(plugin.agentsDir, entry.name);
66500
67188
  const agentName = basename8(entry.name, ".md");
66501
67189
  const namespacedName = `${plugin.name}:${agentName}`;
66502
67190
  try {
@@ -66526,7 +67214,7 @@ function loadPluginAgents(plugins) {
66526
67214
  async function loadPluginMcpServers(plugins) {
66527
67215
  const servers = {};
66528
67216
  for (const plugin of plugins) {
66529
- if (!plugin.mcpPath || !existsSync51(plugin.mcpPath))
67217
+ if (!plugin.mcpPath || !existsSync52(plugin.mcpPath))
66530
67218
  continue;
66531
67219
  try {
66532
67220
  const content = await Bun.file(plugin.mcpPath).text();
@@ -66558,7 +67246,7 @@ async function loadPluginMcpServers(plugins) {
66558
67246
  function loadPluginHooksConfigs(plugins) {
66559
67247
  const configs = [];
66560
67248
  for (const plugin of plugins) {
66561
- if (!plugin.hooksPath || !existsSync51(plugin.hooksPath))
67249
+ if (!plugin.hooksPath || !existsSync52(plugin.hooksPath))
66562
67250
  continue;
66563
67251
  try {
66564
67252
  const content = readFileSync32(plugin.hooksPath, "utf-8");
@@ -66947,8 +67635,8 @@ Prometheus\uFF1A"\u5FEB\u901F\u4FEE\u590D\u2014\u2014\u6211\u770B\u5230\u62FC\u5
66947
67635
 
66948
67636
  **\u5148\u505A\u7814\u7A76\uFF1A**
66949
67637
  \`\`\`typescript
66950
- delegate_task(subagent_type="explore", prompt="\u4F7F\u7528 lsp_find_references \u6A21\u5F0F\u67E5\u627E [\u76EE\u6807] \u7684\u6240\u6709\u4F7F\u7528\u4F4D\u7F6E...", run_in_background=true)
66951
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u53D7\u5F71\u54CD\u4EE3\u7801] \u7684\u6D4B\u8BD5\u8986\u76D6\u7387...", run_in_background=true)
67638
+ delegate_task(subagent_type="explore", prompt="\u4F7F\u7528 lsp_find_references \u6A21\u5F0F\u67E5\u627E [\u76EE\u6807] \u7684\u6240\u6709\u4F7F\u7528\u4F4D\u7F6E...", run_in_background=true, load_skills=[])
67639
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u53D7\u5F71\u54CD\u4EE3\u7801] \u7684\u6D4B\u8BD5\u8986\u76D6\u7387...", run_in_background=true, load_skills=[])
66952
67640
  \`\`\`
66953
67641
 
66954
67642
  **\u8BBF\u8C08\u91CD\u70B9\uFF1A**
@@ -66971,9 +67659,9 @@ delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u53D7\u5F71\u54CD\
66971
67659
  **\u8BBF\u8C08\u524D\u7814\u7A76\uFF08\u5F3A\u5236\u8981\u6C42\uFF09\uFF1A**
66972
67660
  \`\`\`typescript
66973
67661
  // \u5728\u5411\u7528\u6237\u63D0\u95EE\u4E4B\u524D\u542F\u52A8
66974
- delegate_task(subagent_type="explore", prompt="\u5728\u4EE3\u7801\u5E93\u4E2D\u67E5\u627E\u7C7B\u4F3C\u5B9E\u73B0...", run_in_background=true)
66975
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u529F\u80FD\u7C7B\u578B] \u7684\u9879\u76EE\u6A21\u5F0F...", run_in_background=true)
66976
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u6280\u672F] \u7684\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true)
67662
+ delegate_task(subagent_type="explore", prompt="\u5728\u4EE3\u7801\u5E93\u4E2D\u67E5\u627E\u7C7B\u4F3C\u5B9E\u73B0...", run_in_background=true, load_skills=[])
67663
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u529F\u80FD\u7C7B\u578B] \u7684\u9879\u76EE\u6A21\u5F0F...", run_in_background=true, load_skills=[])
67664
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u6280\u672F] \u7684\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true, load_skills=[])
66977
67665
  \`\`\`
66978
67666
 
66979
67667
  **\u8BBF\u8C08\u91CD\u70B9**\uFF08\u7814\u7A76\u4E4B\u540E\uFF09\uFF1A
@@ -67012,7 +67700,7 @@ Prometheus\uFF1A"\u6211\u53D1\u73B0\u4E86\u4E00\u4E9B\u60C5\u51B5\uFF1A
67012
67700
 
67013
67701
  \u8FD0\u884C\u6B64\u68C0\u67E5\uFF1A
67014
67702
  \`\`\`typescript
67015
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u6D4B\u8BD5\u57FA\u7840\u8BBE\u65BD\uFF1Apackage.json \u4E2D\u7684\u6D4B\u8BD5\u811A\u672C\u3001\u6D4B\u8BD5\u914D\u7F6E\u6587\u4EF6\uFF08jest.config\u3001vitest.config\u3001pytest.ini \u7B49\uFF09\u3001\u73B0\u6709\u6D4B\u8BD5\u6587\u4EF6\uFF08*.test.*\u3001*.spec.*\u3001test_*\uFF09\u3002\u62A5\u544A\uFF1A1\uFF09\u662F\u5426\u5B58\u5728\u6D4B\u8BD5\u57FA\u7840\u8BBE\u65BD\uFF1F2\uFF09\u4F7F\u7528\u4EC0\u4E48\u6846\u67B6\uFF1F3\uFF09\u793A\u4F8B\u6D4B\u8BD5\u6587\u4EF6\u6A21\u5F0F\u3002", run_in_background=true)
67703
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u6D4B\u8BD5\u57FA\u7840\u8BBE\u65BD\uFF1Apackage.json \u4E2D\u7684\u6D4B\u8BD5\u811A\u672C\u3001\u6D4B\u8BD5\u914D\u7F6E\u6587\u4EF6\uFF08jest.config\u3001vitest.config\u3001pytest.ini \u7B49\uFF09\u3001\u73B0\u6709\u6D4B\u8BD5\u6587\u4EF6\uFF08*.test.*\u3001*.spec.*\u3001test_*\uFF09\u3002\u62A5\u544A\uFF1A1\uFF09\u662F\u5426\u5B58\u5728\u6D4B\u8BD5\u57FA\u7840\u8BBE\u65BD\uFF1F2\uFF09\u4F7F\u7528\u4EC0\u4E48\u6846\u67B6\uFF1F3\uFF09\u793A\u4F8B\u6D4B\u8BD5\u6587\u4EF6\u6A21\u5F0F\u3002", run_in_background=true, load_skills=[])
67016
67704
  \`\`\`
67017
67705
 
67018
67706
  #### \u7B2C2\u6B65\uFF1A\u8BE2\u95EE\u6D4B\u8BD5\u95EE\u9898\uFF08\u5F3A\u5236\u8981\u6C42\uFF09
@@ -67101,13 +67789,13 @@ delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u6D4B\u8BD5\u57FA\u7
67101
67789
 
67102
67790
  **\u5148\u505A\u7814\u7A76\uFF1A**
67103
67791
  \`\`\`typescript
67104
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u5F53\u524D\u7CFB\u7EDF\u67B6\u6784\u548C\u6A21\u5F0F...", run_in_background=true)
67105
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u9886\u57DF] \u7684\u67B6\u6784\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true)
67792
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u5F53\u524D\u7CFB\u7EDF\u67B6\u6784\u548C\u6A21\u5F0F...", run_in_background=true, load_skills=[])
67793
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u9886\u57DF] \u7684\u67B6\u6784\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true, load_skills=[])
67106
67794
  \`\`\`
67107
67795
 
67108
67796
  **Oracle \u54A8\u8BE2**\uFF08\u5F53\u98CE\u9669\u8F83\u9AD8\u65F6\u63A8\u8350\uFF09\uFF1A
67109
67797
  \`\`\`typescript
67110
- delegate_task(subagent_type="oracle", prompt="\u9700\u8981\u67B6\u6784\u54A8\u8BE2\uFF1A[\u4E0A\u4E0B\u6587]...", run_in_background=false)
67798
+ delegate_task(subagent_type="oracle", prompt="\u9700\u8981\u67B6\u6784\u54A8\u8BE2\uFF1A[\u4E0A\u4E0B\u6587]...", run_in_background=false, load_skills=[])
67111
67799
  \`\`\`
67112
67800
 
67113
67801
  **\u8BBF\u8C08\u91CD\u70B9\uFF1A**
@@ -67124,9 +67812,9 @@ delegate_task(subagent_type="oracle", prompt="\u9700\u8981\u67B6\u6784\u54A8\u8B
67124
67812
 
67125
67813
  **\u5E76\u884C\u8C03\u7814\uFF1A**
67126
67814
  \`\`\`typescript
67127
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E X \u5F53\u524D\u662F\u5982\u4F55\u5904\u7406\u7684...", run_in_background=true)
67128
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Y \u7684\u5B98\u65B9\u6587\u6863...", run_in_background=true)
67129
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Z \u7684\u5F00\u6E90\u5B9E\u73B0...", run_in_background=true)
67815
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E X \u5F53\u524D\u662F\u5982\u4F55\u5904\u7406\u7684...", run_in_background=true, load_skills=[])
67816
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Y \u7684\u5B98\u65B9\u6587\u6863...", run_in_background=true, load_skills=[])
67817
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Z \u7684\u5F00\u6E90\u5B9E\u73B0...", run_in_background=true, load_skills=[])
67130
67818
  \`\`\`
67131
67819
 
67132
67820
  **\u8BBF\u8C08\u91CD\u70B9\uFF1A**
@@ -67152,17 +67840,17 @@ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Z \u7684\u5F00\u6E
67152
67840
 
67153
67841
  **\u7528\u4E8E\u7406\u89E3\u4EE3\u7801\u5E93\uFF1A**
67154
67842
  \`\`\`typescript
67155
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u4E0E [\u4E3B\u9898] \u76F8\u5173\u7684\u6240\u6709\u6587\u4EF6\u3002\u5C55\u793A\u6A21\u5F0F\u3001\u7EA6\u5B9A\u548C\u7ED3\u6784\u3002", run_in_background=true)
67843
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u4E0E [\u4E3B\u9898] \u76F8\u5173\u7684\u6240\u6709\u6587\u4EF6\u3002\u5C55\u793A\u6A21\u5F0F\u3001\u7EA6\u5B9A\u548C\u7ED3\u6784\u3002", run_in_background=true, load_skills=[])
67156
67844
  \`\`\`
67157
67845
 
67158
67846
  **\u7528\u4E8E\u5916\u90E8\u77E5\u8BC6\uFF1A**
67159
67847
  \`\`\`typescript
67160
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u5E93] \u7684\u5B98\u65B9\u6587\u6863\u3002\u91CD\u70B9\u5173\u6CE8 [\u7279\u5B9A\u529F\u80FD] \u548C\u6700\u4F73\u5B9E\u8DF5\u3002", run_in_background=true)
67848
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u5E93] \u7684\u5B98\u65B9\u6587\u6863\u3002\u91CD\u70B9\u5173\u6CE8 [\u7279\u5B9A\u529F\u80FD] \u548C\u6700\u4F73\u5B9E\u8DF5\u3002", run_in_background=true, load_skills=[])
67161
67849
  \`\`\`
67162
67850
 
67163
67851
  **\u7528\u4E8E\u5B9E\u73B0\u793A\u4F8B\uFF1A**
67164
67852
  \`\`\`typescript
67165
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u529F\u80FD] \u7684\u5F00\u6E90\u5B9E\u73B0\u3002\u5BFB\u627E\u751F\u4EA7\u8D28\u91CF\u7684\u793A\u4F8B\u3002", run_in_background=true)
67853
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u529F\u80FD] \u7684\u5F00\u6E90\u5B9E\u73B0\u3002\u5BFB\u627E\u751F\u4EA7\u8D28\u91CF\u7684\u793A\u4F8B\u3002", run_in_background=true, load_skills=[])
67166
67854
  \`\`\`
67167
67855
 
67168
67856
  ## \u8BBF\u8C08\u6A21\u5F0F\u53CD\u6A21\u5F0F
@@ -67260,6 +67948,7 @@ todoWrite([
67260
67948
  \`\`\`typescript
67261
67949
  delegate_task(
67262
67950
  subagent_type="metis",
67951
+ load_skills=[],
67263
67952
  prompt=\`\u5728\u6211\u751F\u6210\u5DE5\u4F5C\u8BA1\u5212\u4E4B\u524D\uFF0C\u5BA1\u67E5\u8FD9\u6B21\u89C4\u5212\u4F1A\u8BDD\uFF1A
67264
67953
 
67265
67954
  **\u7528\u6237\u76EE\u6807**\uFF1A{\u603B\u7ED3\u7528\u6237\u60F3\u8981\u4EC0\u4E48}
@@ -67427,7 +68116,7 @@ while (true) {
67427
68116
  const result = delegate_task(
67428
68117
  subagent_type="momus",
67429
68118
  prompt=".sisyphus/plans/{name}.md",
67430
- run_in_background=false
68119
+ run_in_background=false, load_skills=[]
67431
68120
  )
67432
68121
 
67433
68122
  if (result.verdict === "OKAY") {
@@ -68130,6 +68819,13 @@ var OhMyOpenCodePlugin = async (ctx) => {
68130
68819
  log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { directory: ctx.directory });
68131
68820
  startBackgroundCheck2();
68132
68821
  const pluginConfig = loadPluginConfig(ctx.directory, ctx);
68822
+ if (process.platform === "win32") {
68823
+ const reservedNames = scanForReservedNames(ctx.directory, 3);
68824
+ if (reservedNames.length > 0) {
68825
+ console.warn(formatReservedNamesWarning(reservedNames));
68826
+ log("[oh-my-opencode] Windows reserved device names detected:", reservedNames);
68827
+ }
68828
+ }
68133
68829
  const disabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
68134
68830
  const firstMessageVariantGate = createFirstMessageVariantGate();
68135
68831
  const isHookEnabled = (hookName) => !disabledHooks.has(hookName);