@skj1724/oh-my-opencode 3.19.4 → 3.19.6

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
@@ -46,6 +46,84 @@ var __export = (target, all) => {
46
46
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
47
  var __require = import.meta.require;
48
48
 
49
+ // src/shared/fileio-monitor.ts
50
+ import { readdirSync, readFileSync, writeFileSync, existsSync } from "fs";
51
+ import { relative } from "path";
52
+ import { cwd } from "process";
53
+ function summarize(path) {
54
+ let result;
55
+ try {
56
+ result = relative(cwd(), path);
57
+ } catch {
58
+ result = path;
59
+ }
60
+ if (result.length > MAX_PATH_LENGTH) {
61
+ return result.slice(0, MAX_PATH_LENGTH - 3) + "...";
62
+ }
63
+ return result;
64
+ }
65
+ function setFileIOMonitor(monitor) {
66
+ globalMonitor = monitor;
67
+ }
68
+ function getFileIOMonitor() {
69
+ return globalMonitor;
70
+ }
71
+ function createFileIOMonitor(tracer) {
72
+ return {
73
+ readdirSync(path) {
74
+ if (!tracer.isEnabled()) {
75
+ return readdirSync(path);
76
+ }
77
+ const start = performance.now();
78
+ try {
79
+ return readdirSync(path);
80
+ } finally {
81
+ const durationMs = performance.now() - start;
82
+ tracer.recordFileIO("readdirSync", summarize(path), durationMs);
83
+ }
84
+ },
85
+ readFileSync(path, options) {
86
+ if (!tracer.isEnabled()) {
87
+ return readFileSync(path, options);
88
+ }
89
+ const start = performance.now();
90
+ try {
91
+ return readFileSync(path, options);
92
+ } finally {
93
+ const durationMs = performance.now() - start;
94
+ tracer.recordFileIO("readFileSync", summarize(path), durationMs);
95
+ }
96
+ },
97
+ writeFileSync(path, data, options) {
98
+ if (!tracer.isEnabled()) {
99
+ writeFileSync(path, data, options);
100
+ return;
101
+ }
102
+ const start = performance.now();
103
+ try {
104
+ writeFileSync(path, data, options);
105
+ } finally {
106
+ const durationMs = performance.now() - start;
107
+ tracer.recordFileIO("writeFileSync", summarize(path), durationMs);
108
+ }
109
+ },
110
+ existsSync(path) {
111
+ if (!tracer.isEnabled()) {
112
+ return existsSync(path);
113
+ }
114
+ const start = performance.now();
115
+ try {
116
+ return existsSync(path);
117
+ } finally {
118
+ const durationMs = performance.now() - start;
119
+ tracer.recordFileIO("existsSync", summarize(path), durationMs);
120
+ }
121
+ }
122
+ };
123
+ }
124
+ var MAX_PATH_LENGTH = 120, globalMonitor = null;
125
+ var init_fileio_monitor = () => {};
126
+
49
127
  // src/shared/data-path.ts
50
128
  import * as path from "path";
51
129
  import * as os from "os";
@@ -2767,17 +2845,17 @@ var init_frontmatter = __esm(() => {
2767
2845
  import { spawn as spawn2 } from "child_process";
2768
2846
  import { exec } from "child_process";
2769
2847
  import { promisify } from "util";
2770
- import { existsSync as existsSync4 } from "fs";
2848
+ import { existsSync as existsSync5 } from "fs";
2771
2849
  import { homedir as homedir2 } from "os";
2772
2850
  function getHomeDir() {
2773
2851
  return process.env.HOME || process.env.USERPROFILE || homedir2();
2774
2852
  }
2775
2853
  function findShellPath(defaultPaths, customPath) {
2776
- if (customPath && existsSync4(customPath)) {
2854
+ if (customPath && existsSync5(customPath)) {
2777
2855
  return customPath;
2778
2856
  }
2779
2857
  for (const path3 of defaultPaths) {
2780
- if (existsSync4(path3)) {
2858
+ if (existsSync5(path3)) {
2781
2859
  return path3;
2782
2860
  }
2783
2861
  }
@@ -2789,9 +2867,9 @@ function findZshPath(customZshPath) {
2789
2867
  function findBashPath() {
2790
2868
  return findShellPath(DEFAULT_BASH_PATHS);
2791
2869
  }
2792
- async function executeHookCommand(command, stdin, cwd, options) {
2870
+ async function executeHookCommand(command, stdin, cwd2, options) {
2793
2871
  const home = getHomeDir();
2794
- let expandedCommand = command.replace(/^~(?=\/|$)/g, home).replace(/\s~(?=\/)/g, ` ${home}`).replace(/\$CLAUDE_PROJECT_DIR/g, cwd).replace(/\$\{CLAUDE_PROJECT_DIR\}/g, cwd);
2872
+ let expandedCommand = command.replace(/^~(?=\/|$)/g, home).replace(/\s~(?=\/)/g, ` ${home}`).replace(/\$CLAUDE_PROJECT_DIR/g, cwd2).replace(/\$\{CLAUDE_PROJECT_DIR\}/g, cwd2);
2795
2873
  let finalCommand = expandedCommand;
2796
2874
  if (options?.forceZsh) {
2797
2875
  const zshPath = findZshPath(options.zshPath);
@@ -2807,9 +2885,9 @@ async function executeHookCommand(command, stdin, cwd, options) {
2807
2885
  }
2808
2886
  return new Promise((resolve) => {
2809
2887
  const proc = spawn2(finalCommand, {
2810
- cwd,
2888
+ cwd: cwd2,
2811
2889
  shell: true,
2812
- env: { ...process.env, HOME: home, CLAUDE_PROJECT_DIR: cwd }
2890
+ env: { ...process.env, HOME: home, CLAUDE_PROJECT_DIR: cwd2 }
2813
2891
  });
2814
2892
  let stdout = "";
2815
2893
  let stderr = "";
@@ -2912,7 +2990,7 @@ var init_command_executor = __esm(() => {
2912
2990
  });
2913
2991
 
2914
2992
  // src/shared/file-reference-resolver.ts
2915
- import { existsSync as existsSync5, readFileSync as readFileSync3, statSync } from "fs";
2993
+ import { existsSync as existsSync6, readFileSync as readFileSync4, statSync } from "fs";
2916
2994
  import { join as join8, isAbsolute } from "path";
2917
2995
  function findFileReferences(text) {
2918
2996
  const matches = [];
@@ -2928,24 +3006,24 @@ function findFileReferences(text) {
2928
3006
  }
2929
3007
  return matches;
2930
3008
  }
2931
- function resolveFilePath(filePath, cwd) {
3009
+ function resolveFilePath(filePath, cwd2) {
2932
3010
  if (isAbsolute(filePath)) {
2933
3011
  return filePath;
2934
3012
  }
2935
- return join8(cwd, filePath);
3013
+ return join8(cwd2, filePath);
2936
3014
  }
2937
3015
  function readFileContent(resolvedPath) {
2938
- if (!existsSync5(resolvedPath)) {
3016
+ if (!existsSync6(resolvedPath)) {
2939
3017
  return `[file not found: ${resolvedPath}]`;
2940
3018
  }
2941
3019
  const stat = statSync(resolvedPath);
2942
3020
  if (stat.isDirectory()) {
2943
3021
  return `[cannot read directory: ${resolvedPath}]`;
2944
3022
  }
2945
- const content = readFileSync3(resolvedPath, "utf-8");
3023
+ const content = readFileSync4(resolvedPath, "utf-8");
2946
3024
  return content;
2947
3025
  }
2948
- async function resolveFileReferencesInText(text, cwd = process.cwd(), depth = 0, maxDepth = 3) {
3026
+ async function resolveFileReferencesInText(text, cwd2 = process.cwd(), depth = 0, maxDepth = 3) {
2949
3027
  if (depth >= maxDepth) {
2950
3028
  return text;
2951
3029
  }
@@ -2955,7 +3033,7 @@ async function resolveFileReferencesInText(text, cwd = process.cwd(), depth = 0,
2955
3033
  }
2956
3034
  const replacements = new Map;
2957
3035
  for (const match of matches) {
2958
- const resolvedPath = resolveFilePath(match.filePath, cwd);
3036
+ const resolvedPath = resolveFilePath(match.filePath, cwd2);
2959
3037
  const content = readFileContent(resolvedPath);
2960
3038
  replacements.set(match.fullMatch, content);
2961
3039
  }
@@ -2964,7 +3042,7 @@ async function resolveFileReferencesInText(text, cwd = process.cwd(), depth = 0,
2964
3042
  resolved = resolved.split(pattern).join(replacement);
2965
3043
  }
2966
3044
  if (findFileReferences(resolved).length > 0 && depth + 1 < maxDepth) {
2967
- return resolveFileReferencesInText(resolved, cwd, depth + 1, maxDepth);
3045
+ return resolveFileReferencesInText(resolved, cwd2, depth + 1, maxDepth);
2968
3046
  }
2969
3047
  return resolved;
2970
3048
  }
@@ -4138,7 +4216,7 @@ var init_main = __esm(() => {
4138
4216
  });
4139
4217
 
4140
4218
  // src/shared/jsonc-parser.ts
4141
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
4219
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
4142
4220
  function parseJsonc(content) {
4143
4221
  const errors = [];
4144
4222
  const result = parse2(content, errors, {
@@ -4169,10 +4247,10 @@ function parseJsoncSafe(content) {
4169
4247
  function detectConfigFile(basePath) {
4170
4248
  const jsoncPath = `${basePath}.jsonc`;
4171
4249
  const jsonPath = `${basePath}.json`;
4172
- if (existsSync6(jsoncPath)) {
4250
+ if (existsSync7(jsoncPath)) {
4173
4251
  return { format: "jsonc", path: jsoncPath };
4174
4252
  }
4175
- if (existsSync6(jsonPath)) {
4253
+ if (existsSync7(jsonPath)) {
4176
4254
  return { format: "json", path: jsonPath };
4177
4255
  }
4178
4256
  return { format: "none", path: jsonPath };
@@ -4318,7 +4396,7 @@ var init_migration = __esm(() => {
4318
4396
  });
4319
4397
 
4320
4398
  // src/shared/opencode-config-dir.ts
4321
- import { existsSync as existsSync7 } from "fs";
4399
+ import { existsSync as existsSync8 } from "fs";
4322
4400
  import { homedir as homedir4 } from "os";
4323
4401
  import { join as join10, resolve as resolve2 } from "path";
4324
4402
  function isDevBuild(version) {
@@ -4350,13 +4428,13 @@ function getCliConfigDir() {
4350
4428
  if (process.platform === "win32") {
4351
4429
  const crossPlatformDir = join10(homedir4(), ".config", "opencode");
4352
4430
  const crossPlatformConfig = join10(crossPlatformDir, "opencode.json");
4353
- if (existsSync7(crossPlatformConfig)) {
4431
+ if (existsSync8(crossPlatformConfig)) {
4354
4432
  return crossPlatformDir;
4355
4433
  }
4356
4434
  const appData = process.env.APPDATA || join10(homedir4(), "AppData", "Roaming");
4357
4435
  const appdataDir = join10(appData, "opencode");
4358
4436
  const appdataConfig = join10(appdataDir, "opencode.json");
4359
- if (existsSync7(appdataConfig)) {
4437
+ if (existsSync8(appdataConfig)) {
4360
4438
  return appdataDir;
4361
4439
  }
4362
4440
  return crossPlatformDir;
@@ -4375,7 +4453,7 @@ function getOpenCodeConfigDir(options) {
4375
4453
  const legacyDir = getCliConfigDir();
4376
4454
  const legacyConfig = join10(legacyDir, "opencode.json");
4377
4455
  const legacyConfigC = join10(legacyDir, "opencode.jsonc");
4378
- if (existsSync7(legacyConfig) || existsSync7(legacyConfigC)) {
4456
+ if (existsSync8(legacyConfig) || existsSync8(legacyConfigC)) {
4379
4457
  return legacyDir;
4380
4458
  }
4381
4459
  }
@@ -4853,7 +4931,7 @@ var init_model_requirements = __esm(() => {
4853
4931
  });
4854
4932
 
4855
4933
  // src/shared/model-availability.ts
4856
- import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
4934
+ import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
4857
4935
  import { homedir as homedir6 } from "os";
4858
4936
  import { join as join12 } from "path";
4859
4937
  function normalizeModelName(name) {
@@ -4908,12 +4986,12 @@ async function fetchAvailableModels(_client) {
4908
4986
  const modelSet = new Set;
4909
4987
  const cacheFile = join12(getOpenCodeCacheDir(), "models.json");
4910
4988
  log("[fetchAvailableModels] reading cache file", { cacheFile });
4911
- if (!existsSync9(cacheFile)) {
4989
+ if (!existsSync10(cacheFile)) {
4912
4990
  log("[fetchAvailableModels] cache file not found, returning empty set");
4913
4991
  return modelSet;
4914
4992
  }
4915
4993
  try {
4916
- const content = readFileSync6(cacheFile, "utf-8");
4994
+ const content = readFileSync7(cacheFile, "utf-8");
4917
4995
  const data = JSON.parse(content);
4918
4996
  const providerIds = Object.keys(data);
4919
4997
  log("[fetchAvailableModels] providers found", { count: providerIds.length, providers: providerIds.slice(0, 10) });
@@ -4936,7 +5014,7 @@ async function fetchAvailableModels(_client) {
4936
5014
  }
4937
5015
  function isModelCacheAvailable() {
4938
5016
  const cacheFile = join12(getOpenCodeCacheDir(), "models.json");
4939
- return existsSync9(cacheFile);
5017
+ return existsSync10(cacheFile);
4940
5018
  }
4941
5019
  var cachedModels = null;
4942
5020
  var init_model_availability = __esm(() => {
@@ -5033,6 +5111,216 @@ class PerfTimer {
5033
5111
  }
5034
5112
  }
5035
5113
 
5114
+ // src/shared/perf-tracer.ts
5115
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync11 } from "fs";
5116
+ import { tmpdir as tmpdir2 } from "os";
5117
+ import { join as join13 } from "path";
5118
+
5119
+ class PerfTracer {
5120
+ buffer = [];
5121
+ enabled;
5122
+ outputDir;
5123
+ slowThreshold;
5124
+ eventCount = 0;
5125
+ memorySnapshotInterval;
5126
+ constructor(config) {
5127
+ this.enabled = config.enabled;
5128
+ this.outputDir = config.outputDir ?? join13(tmpdir2(), "oh-my-opencode-perf");
5129
+ this.slowThreshold = config.slowThreshold ?? 100;
5130
+ this.memorySnapshotInterval = config.memorySnapshotInterval ?? 5;
5131
+ }
5132
+ isEnabled() {
5133
+ return this.enabled;
5134
+ }
5135
+ isSlowHook(durationMs) {
5136
+ return durationMs > this.slowThreshold;
5137
+ }
5138
+ recordHook(pipeline, hook, durationMs, sessionID, tool, error) {
5139
+ if (!this.enabled)
5140
+ return;
5141
+ const span = {
5142
+ t: new Date().toISOString(),
5143
+ type: "hook",
5144
+ pipeline,
5145
+ hook,
5146
+ durationMs,
5147
+ sessionID
5148
+ };
5149
+ if (tool !== undefined)
5150
+ span.tool = tool;
5151
+ if (error !== undefined)
5152
+ span.error = error;
5153
+ this.buffer.push(span);
5154
+ }
5155
+ recordPipeline(name, totalDurationMs, hookCount, sessionID) {
5156
+ if (!this.enabled)
5157
+ return;
5158
+ this.buffer.push({
5159
+ t: new Date().toISOString(),
5160
+ type: "pipeline",
5161
+ name,
5162
+ totalDurationMs,
5163
+ hookCount,
5164
+ sessionID
5165
+ });
5166
+ }
5167
+ recordApiCall(method, durationMs, sessionID, messageCount, error) {
5168
+ if (!this.enabled)
5169
+ return;
5170
+ const span = {
5171
+ t: new Date().toISOString(),
5172
+ type: "api",
5173
+ method,
5174
+ durationMs,
5175
+ sessionID
5176
+ };
5177
+ if (messageCount !== undefined)
5178
+ span.messageCount = messageCount;
5179
+ if (error !== undefined)
5180
+ span.error = error;
5181
+ this.buffer.push(span);
5182
+ }
5183
+ recordFileIO(operation, path4, durationMs, fileCount) {
5184
+ if (!this.enabled)
5185
+ return;
5186
+ const span = {
5187
+ t: new Date().toISOString(),
5188
+ type: "fileio",
5189
+ operation,
5190
+ path: path4,
5191
+ durationMs
5192
+ };
5193
+ if (fileCount !== undefined)
5194
+ span.fileCount = fileCount;
5195
+ this.buffer.push(span);
5196
+ }
5197
+ recordPolling(durationMs, taskCount, sessionCount) {
5198
+ if (!this.enabled)
5199
+ return;
5200
+ this.buffer.push({
5201
+ t: new Date().toISOString(),
5202
+ type: "polling",
5203
+ durationMs,
5204
+ taskCount,
5205
+ sessionCount
5206
+ });
5207
+ }
5208
+ snapshotMemory(trigger, mapSizes) {
5209
+ if (!this.enabled)
5210
+ return;
5211
+ this.eventCount++;
5212
+ if (this.eventCount % this.memorySnapshotInterval !== 0)
5213
+ return;
5214
+ this.buffer.push({
5215
+ t: new Date().toISOString(),
5216
+ type: "memory",
5217
+ trigger,
5218
+ mapSizes
5219
+ });
5220
+ }
5221
+ flush() {
5222
+ if (this.buffer.length === 0)
5223
+ return;
5224
+ if (!existsSync11(this.outputDir)) {
5225
+ mkdirSync3(this.outputDir, { recursive: true });
5226
+ }
5227
+ const date = new Date().toISOString().slice(0, 10);
5228
+ const filePath = join13(this.outputDir, `${date}.jsonl`);
5229
+ let output = "";
5230
+ for (const span of this.buffer) {
5231
+ output += JSON.stringify(span) + `
5232
+ `;
5233
+ }
5234
+ appendFileSync2(filePath, output);
5235
+ this.buffer = [];
5236
+ }
5237
+ reset() {
5238
+ this.buffer = [];
5239
+ this.eventCount = 0;
5240
+ }
5241
+ }
5242
+ var init_perf_tracer = () => {};
5243
+
5244
+ // src/shared/windows-reserved-names.ts
5245
+ import { existsSync as existsSync12, readdirSync as readdirSync5 } from "fs";
5246
+ import { join as join14 } from "path";
5247
+ function scanForReservedNames(directory, maxDepth = 2) {
5248
+ if (!existsSync12(directory))
5249
+ return [];
5250
+ const found = [];
5251
+ _scan(directory, 0, maxDepth, found);
5252
+ return found;
5253
+ }
5254
+ function _scan(dir, depth, maxDepth, found) {
5255
+ if (depth > maxDepth)
5256
+ return;
5257
+ let entries;
5258
+ try {
5259
+ entries = readdirSync5(dir);
5260
+ } catch {
5261
+ return;
5262
+ }
5263
+ for (const name of entries) {
5264
+ const upper = name.toUpperCase();
5265
+ const baseName = upper.split(".")[0] ?? "";
5266
+ if (WIN_RESERVED_NAMES.has(upper) || WIN_RESERVED_NAMES.has(baseName)) {
5267
+ found.push(join14(dir, name));
5268
+ }
5269
+ const fullPath = join14(dir, name);
5270
+ try {
5271
+ const stat = existsSync12(fullPath);
5272
+ if (stat && depth < maxDepth) {
5273
+ _scan(fullPath, depth + 1, maxDepth, found);
5274
+ }
5275
+ } catch {}
5276
+ }
5277
+ }
5278
+ function formatReservedNamesWarning(found) {
5279
+ const lines = [
5280
+ "",
5281
+ "\u26A0\uFE0F WINDOWS RESERVED DEVICE NAMES DETECTED",
5282
+ " The following paths match Windows reserved device names (NUL, CON, AUX, etc.):",
5283
+ "",
5284
+ ...found.map((p) => ` - ${p}`),
5285
+ "",
5286
+ " These will cause 'error: short read while indexing' git failures on Windows.",
5287
+ " This can make OpenCode's snapshot system extremely slow (30+ minutes).",
5288
+ "",
5289
+ " Fix: Rename these files/directories to avoid reserved names.",
5290
+ " e.g., rename 'nul' \u2192 'null-device', 'con' \u2192 'console-util'",
5291
+ ""
5292
+ ];
5293
+ return lines.join(`
5294
+ `);
5295
+ }
5296
+ var WIN_RESERVED_NAMES;
5297
+ var init_windows_reserved_names = __esm(() => {
5298
+ WIN_RESERVED_NAMES = new Set([
5299
+ "CON",
5300
+ "PRN",
5301
+ "AUX",
5302
+ "NUL",
5303
+ "COM1",
5304
+ "COM2",
5305
+ "COM3",
5306
+ "COM4",
5307
+ "COM5",
5308
+ "COM6",
5309
+ "COM7",
5310
+ "COM8",
5311
+ "COM9",
5312
+ "LPT1",
5313
+ "LPT2",
5314
+ "LPT3",
5315
+ "LPT4",
5316
+ "LPT5",
5317
+ "LPT6",
5318
+ "LPT7",
5319
+ "LPT8",
5320
+ "LPT9"
5321
+ ]);
5322
+ });
5323
+
5036
5324
  // src/shared/index.ts
5037
5325
  var init_shared = __esm(() => {
5038
5326
  init_frontmatter();
@@ -5060,6 +5348,9 @@ var init_shared = __esm(() => {
5060
5348
  init_model_requirements();
5061
5349
  init_model_resolver();
5062
5350
  init_model_availability();
5351
+ init_perf_tracer();
5352
+ init_fileio_monitor();
5353
+ init_windows_reserved_names();
5063
5354
  });
5064
5355
 
5065
5356
  // node_modules/picomatch/lib/constants.js
@@ -10944,49 +11235,49 @@ var require_fast_uri = __commonJS((exports, module) => {
10944
11235
  schemelessOptions.skipEscape = true;
10945
11236
  return serialize(resolved, schemelessOptions);
10946
11237
  }
10947
- function resolveComponent(base, relative5, options, skipNormalization) {
11238
+ function resolveComponent(base, relative6, options, skipNormalization) {
10948
11239
  const target = {};
10949
11240
  if (!skipNormalization) {
10950
11241
  base = parse11(serialize(base, options), options);
10951
- relative5 = parse11(serialize(relative5, options), options);
11242
+ relative6 = parse11(serialize(relative6, options), options);
10952
11243
  }
10953
11244
  options = options || {};
10954
- if (!options.tolerant && relative5.scheme) {
10955
- target.scheme = relative5.scheme;
10956
- target.userinfo = relative5.userinfo;
10957
- target.host = relative5.host;
10958
- target.port = relative5.port;
10959
- target.path = removeDotSegments(relative5.path || "");
10960
- target.query = relative5.query;
11245
+ if (!options.tolerant && relative6.scheme) {
11246
+ target.scheme = relative6.scheme;
11247
+ target.userinfo = relative6.userinfo;
11248
+ target.host = relative6.host;
11249
+ target.port = relative6.port;
11250
+ target.path = removeDotSegments(relative6.path || "");
11251
+ target.query = relative6.query;
10961
11252
  } else {
10962
- if (relative5.userinfo !== undefined || relative5.host !== undefined || relative5.port !== undefined) {
10963
- target.userinfo = relative5.userinfo;
10964
- target.host = relative5.host;
10965
- target.port = relative5.port;
10966
- target.path = removeDotSegments(relative5.path || "");
10967
- target.query = relative5.query;
11253
+ if (relative6.userinfo !== undefined || relative6.host !== undefined || relative6.port !== undefined) {
11254
+ target.userinfo = relative6.userinfo;
11255
+ target.host = relative6.host;
11256
+ target.port = relative6.port;
11257
+ target.path = removeDotSegments(relative6.path || "");
11258
+ target.query = relative6.query;
10968
11259
  } else {
10969
- if (!relative5.path) {
11260
+ if (!relative6.path) {
10970
11261
  target.path = base.path;
10971
- if (relative5.query !== undefined) {
10972
- target.query = relative5.query;
11262
+ if (relative6.query !== undefined) {
11263
+ target.query = relative6.query;
10973
11264
  } else {
10974
11265
  target.query = base.query;
10975
11266
  }
10976
11267
  } else {
10977
- if (relative5.path[0] === "/") {
10978
- target.path = removeDotSegments(relative5.path);
11268
+ if (relative6.path[0] === "/") {
11269
+ target.path = removeDotSegments(relative6.path);
10979
11270
  } else {
10980
11271
  if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
10981
- target.path = "/" + relative5.path;
11272
+ target.path = "/" + relative6.path;
10982
11273
  } else if (!base.path) {
10983
- target.path = relative5.path;
11274
+ target.path = relative6.path;
10984
11275
  } else {
10985
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative5.path;
11276
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative6.path;
10986
11277
  }
10987
11278
  target.path = removeDotSegments(target.path);
10988
11279
  }
10989
- target.query = relative5.query;
11280
+ target.query = relative6.query;
10990
11281
  }
10991
11282
  target.userinfo = base.userinfo;
10992
11283
  target.host = base.host;
@@ -10994,7 +11285,7 @@ var require_fast_uri = __commonJS((exports, module) => {
10994
11285
  }
10995
11286
  target.scheme = base.scheme;
10996
11287
  }
10997
- target.fragment = relative5.fragment;
11288
+ target.fragment = relative6.fragment;
10998
11289
  return target;
10999
11290
  }
11000
11291
  function equal(uriA, uriB, options) {
@@ -14201,7 +14492,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
14201
14492
  var getPathKey = require_path_key();
14202
14493
  function resolveCommandAttempt(parsed, withoutPathExt) {
14203
14494
  const env = parsed.options.env || process.env;
14204
- const cwd = process.cwd();
14495
+ const cwd2 = process.cwd();
14205
14496
  const hasCustomCwd = parsed.options.cwd != null;
14206
14497
  const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled;
14207
14498
  if (shouldSwitchCwd) {
@@ -14217,7 +14508,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
14217
14508
  });
14218
14509
  } catch (e) {} finally {
14219
14510
  if (shouldSwitchCwd) {
14220
- process.chdir(cwd);
14511
+ process.chdir(cwd2);
14221
14512
  }
14222
14513
  }
14223
14514
  if (resolved) {
@@ -14424,7 +14715,7 @@ var require_cross_spawn = __commonJS((exports, module) => {
14424
14715
  });
14425
14716
 
14426
14717
  // src/hooks/todo-continuation-enforcer.ts
14427
- import { existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
14718
+ import { existsSync as existsSync3, readdirSync as readdirSync3 } from "fs";
14428
14719
  import { join as join5 } from "path";
14429
14720
 
14430
14721
  // src/features/claude-code-session-state/state.ts
@@ -14452,7 +14743,8 @@ function clearSessionAgent(sessionID) {
14452
14743
  sessionAgentMap.delete(sessionID);
14453
14744
  }
14454
14745
  // src/features/hook-message-injector/injector.ts
14455
- import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
14746
+ init_fileio_monitor();
14747
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
14456
14748
  import { join as join3 } from "path";
14457
14749
 
14458
14750
  // src/features/hook-message-injector/constants.ts
@@ -14464,11 +14756,12 @@ var PART_STORAGE = join2(OPENCODE_STORAGE, "part");
14464
14756
 
14465
14757
  // src/features/hook-message-injector/injector.ts
14466
14758
  function findNearestMessageWithFields(messageDir) {
14759
+ const monitor = getFileIOMonitor();
14467
14760
  try {
14468
- const files = readdirSync(messageDir).filter((f) => f.endsWith(".json")).sort().reverse();
14761
+ const files = (monitor?.readdirSync(messageDir) ?? readdirSync2(messageDir)).filter((f) => f.endsWith(".json")).sort().reverse();
14469
14762
  for (const file of files) {
14470
14763
  try {
14471
- const content = readFileSync(join3(messageDir, file), "utf-8");
14764
+ const content = monitor?.readFileSync(join3(messageDir, file), "utf-8") ?? readFileSync2(join3(messageDir, file), "utf-8");
14472
14765
  const msg = JSON.parse(content);
14473
14766
  if (msg.agent && msg.model?.providerID && msg.model?.modelID) {
14474
14767
  return msg;
@@ -14479,7 +14772,7 @@ function findNearestMessageWithFields(messageDir) {
14479
14772
  }
14480
14773
  for (const file of files) {
14481
14774
  try {
14482
- const content = readFileSync(join3(messageDir, file), "utf-8");
14775
+ const content = monitor?.readFileSync(join3(messageDir, file), "utf-8") ?? readFileSync2(join3(messageDir, file), "utf-8");
14483
14776
  const msg = JSON.parse(content);
14484
14777
  if (msg.agent || msg.model?.providerID && msg.model?.modelID) {
14485
14778
  return msg;
@@ -14494,11 +14787,12 @@ function findNearestMessageWithFields(messageDir) {
14494
14787
  return null;
14495
14788
  }
14496
14789
  function findFirstMessageWithAgent(messageDir) {
14790
+ const monitor = getFileIOMonitor();
14497
14791
  try {
14498
- const files = readdirSync(messageDir).filter((f) => f.endsWith(".json")).sort();
14792
+ const files = (monitor?.readdirSync(messageDir) ?? readdirSync2(messageDir)).filter((f) => f.endsWith(".json")).sort();
14499
14793
  for (const file of files) {
14500
14794
  try {
14501
- const content = readFileSync(join3(messageDir, file), "utf-8");
14795
+ const content = monitor?.readFileSync(join3(messageDir, file), "utf-8") ?? readFileSync2(join3(messageDir, file), "utf-8");
14502
14796
  const msg = JSON.parse(content);
14503
14797
  if (msg.agent) {
14504
14798
  return msg.agent;
@@ -14523,20 +14817,24 @@ function generatePartId() {
14523
14817
  return `prt_${timestamp}${random}`;
14524
14818
  }
14525
14819
  function getOrCreateMessageDir(sessionID) {
14526
- if (!existsSync(MESSAGE_STORAGE)) {
14527
- mkdirSync(MESSAGE_STORAGE, { recursive: true });
14820
+ const monitor = getFileIOMonitor();
14821
+ const _exists = (p) => monitor?.existsSync(p) ?? existsSync2(p);
14822
+ const _mkdir = (p, opts) => monitor ? undefined : mkdirSync(p, opts);
14823
+ const _readdir = (p) => monitor?.readdirSync(p) ?? readdirSync2(p);
14824
+ if (!_exists(MESSAGE_STORAGE)) {
14825
+ _mkdir(MESSAGE_STORAGE, { recursive: true });
14528
14826
  }
14529
14827
  const directPath = join3(MESSAGE_STORAGE, sessionID);
14530
- if (existsSync(directPath)) {
14828
+ if (_exists(directPath)) {
14531
14829
  return directPath;
14532
14830
  }
14533
- for (const dir of readdirSync(MESSAGE_STORAGE)) {
14831
+ for (const dir of _readdir(MESSAGE_STORAGE)) {
14534
14832
  const sessionPath = join3(MESSAGE_STORAGE, dir, sessionID);
14535
- if (existsSync(sessionPath)) {
14833
+ if (_exists(sessionPath)) {
14536
14834
  return sessionPath;
14537
14835
  }
14538
14836
  }
14539
- mkdirSync(directPath, { recursive: true });
14837
+ _mkdir(directPath, { recursive: true });
14540
14838
  return directPath;
14541
14839
  }
14542
14840
  function injectHookMessage(sessionID, hookContent, originalMessage) {
@@ -14585,12 +14883,22 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
14585
14883
  sessionID
14586
14884
  };
14587
14885
  try {
14588
- writeFileSync(join3(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
14886
+ const monitor = getFileIOMonitor();
14887
+ if (monitor) {
14888
+ monitor.writeFileSync(join3(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
14889
+ } else {
14890
+ writeFileSync2(join3(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
14891
+ }
14589
14892
  const partDir = join3(PART_STORAGE, messageID);
14590
- if (!existsSync(partDir)) {
14893
+ const _exists = (p) => monitor?.existsSync(p) ?? existsSync2(p);
14894
+ if (!_exists(partDir)) {
14591
14895
  mkdirSync(partDir, { recursive: true });
14592
14896
  }
14593
- writeFileSync(join3(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
14897
+ if (monitor) {
14898
+ monitor.writeFileSync(join3(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
14899
+ } else {
14900
+ writeFileSync2(join3(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
14901
+ }
14594
14902
  return true;
14595
14903
  } catch {
14596
14904
  return false;
@@ -14612,14 +14920,14 @@ var COUNTDOWN_SECONDS = 2;
14612
14920
  var TOAST_DURATION_MS = 900;
14613
14921
  var COUNTDOWN_GRACE_PERIOD_MS = 500;
14614
14922
  function getMessageDir(sessionID) {
14615
- if (!existsSync2(MESSAGE_STORAGE))
14923
+ if (!existsSync3(MESSAGE_STORAGE))
14616
14924
  return null;
14617
14925
  const directPath = join5(MESSAGE_STORAGE, sessionID);
14618
- if (existsSync2(directPath))
14926
+ if (existsSync3(directPath))
14619
14927
  return directPath;
14620
- for (const dir of readdirSync2(MESSAGE_STORAGE)) {
14928
+ for (const dir of readdirSync3(MESSAGE_STORAGE)) {
14621
14929
  const sessionPath = join5(MESSAGE_STORAGE, dir, sessionID);
14622
- if (existsSync2(sessionPath))
14930
+ if (existsSync3(sessionPath))
14623
14931
  return sessionPath;
14624
14932
  }
14625
14933
  return null;
@@ -15397,7 +15705,7 @@ function createSessionNotification(ctx, config = {}) {
15397
15705
  };
15398
15706
  }
15399
15707
  // src/hooks/session-recovery/storage.ts
15400
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
15708
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync4, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
15401
15709
  import { join as join7 } from "path";
15402
15710
 
15403
15711
  // src/hooks/session-recovery/constants.ts
@@ -15418,15 +15726,15 @@ function generatePartId2() {
15418
15726
  return `prt_${timestamp}${random}`;
15419
15727
  }
15420
15728
  function getMessageDir2(sessionID) {
15421
- if (!existsSync3(MESSAGE_STORAGE2))
15729
+ if (!existsSync4(MESSAGE_STORAGE2))
15422
15730
  return "";
15423
15731
  const directPath = join7(MESSAGE_STORAGE2, sessionID);
15424
- if (existsSync3(directPath)) {
15732
+ if (existsSync4(directPath)) {
15425
15733
  return directPath;
15426
15734
  }
15427
- for (const dir of readdirSync3(MESSAGE_STORAGE2)) {
15735
+ for (const dir of readdirSync4(MESSAGE_STORAGE2)) {
15428
15736
  const sessionPath = join7(MESSAGE_STORAGE2, dir, sessionID);
15429
- if (existsSync3(sessionPath)) {
15737
+ if (existsSync4(sessionPath)) {
15430
15738
  return sessionPath;
15431
15739
  }
15432
15740
  }
@@ -15434,14 +15742,14 @@ function getMessageDir2(sessionID) {
15434
15742
  }
15435
15743
  function readMessages(sessionID) {
15436
15744
  const messageDir = getMessageDir2(sessionID);
15437
- if (!messageDir || !existsSync3(messageDir))
15745
+ if (!messageDir || !existsSync4(messageDir))
15438
15746
  return [];
15439
15747
  const messages = [];
15440
- for (const file of readdirSync3(messageDir)) {
15748
+ for (const file of readdirSync4(messageDir)) {
15441
15749
  if (!file.endsWith(".json"))
15442
15750
  continue;
15443
15751
  try {
15444
- const content = readFileSync2(join7(messageDir, file), "utf-8");
15752
+ const content = readFileSync3(join7(messageDir, file), "utf-8");
15445
15753
  messages.push(JSON.parse(content));
15446
15754
  } catch {
15447
15755
  continue;
@@ -15457,14 +15765,14 @@ function readMessages(sessionID) {
15457
15765
  }
15458
15766
  function readParts(messageID) {
15459
15767
  const partDir = join7(PART_STORAGE2, messageID);
15460
- if (!existsSync3(partDir))
15768
+ if (!existsSync4(partDir))
15461
15769
  return [];
15462
15770
  const parts = [];
15463
- for (const file of readdirSync3(partDir)) {
15771
+ for (const file of readdirSync4(partDir)) {
15464
15772
  if (!file.endsWith(".json"))
15465
15773
  continue;
15466
15774
  try {
15467
- const content = readFileSync2(join7(partDir, file), "utf-8");
15775
+ const content = readFileSync3(join7(partDir, file), "utf-8");
15468
15776
  parts.push(JSON.parse(content));
15469
15777
  } catch {
15470
15778
  continue;
@@ -15495,7 +15803,7 @@ function messageHasContent(messageID) {
15495
15803
  }
15496
15804
  function injectTextPart(sessionID, messageID, text) {
15497
15805
  const partDir = join7(PART_STORAGE2, messageID);
15498
- if (!existsSync3(partDir)) {
15806
+ if (!existsSync4(partDir)) {
15499
15807
  mkdirSync2(partDir, { recursive: true });
15500
15808
  }
15501
15809
  const partId = generatePartId2();
@@ -15508,7 +15816,7 @@ function injectTextPart(sessionID, messageID, text) {
15508
15816
  synthetic: true
15509
15817
  };
15510
15818
  try {
15511
- writeFileSync2(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15819
+ writeFileSync3(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15512
15820
  return true;
15513
15821
  } catch {
15514
15822
  return false;
@@ -15604,7 +15912,7 @@ function findLastThinkingContent(sessionID, beforeMessageID) {
15604
15912
  }
15605
15913
  function prependThinkingPart(sessionID, messageID) {
15606
15914
  const partDir = join7(PART_STORAGE2, messageID);
15607
- if (!existsSync3(partDir)) {
15915
+ if (!existsSync4(partDir)) {
15608
15916
  mkdirSync2(partDir, { recursive: true });
15609
15917
  }
15610
15918
  const previousThinking = findLastThinkingContent(sessionID, messageID);
@@ -15614,11 +15922,11 @@ function prependThinkingPart(sessionID, messageID) {
15614
15922
  sessionID,
15615
15923
  messageID,
15616
15924
  type: "thinking",
15617
- thinking: previousThinking || "[Continuing from previous reasoning]",
15925
+ thinking: previousThinking || "[\u63A5\u7EED\u4E4B\u524D\u7684\u63A8\u7406]",
15618
15926
  synthetic: true
15619
15927
  };
15620
15928
  try {
15621
- writeFileSync2(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15929
+ writeFileSync3(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15622
15930
  return true;
15623
15931
  } catch {
15624
15932
  return false;
@@ -15626,15 +15934,15 @@ function prependThinkingPart(sessionID, messageID) {
15626
15934
  }
15627
15935
  function stripThinkingParts(messageID) {
15628
15936
  const partDir = join7(PART_STORAGE2, messageID);
15629
- if (!existsSync3(partDir))
15937
+ if (!existsSync4(partDir))
15630
15938
  return false;
15631
15939
  let anyRemoved = false;
15632
- for (const file of readdirSync3(partDir)) {
15940
+ for (const file of readdirSync4(partDir)) {
15633
15941
  if (!file.endsWith(".json"))
15634
15942
  continue;
15635
15943
  try {
15636
15944
  const filePath = join7(partDir, file);
15637
- const content = readFileSync2(filePath, "utf-8");
15945
+ const content = readFileSync3(filePath, "utf-8");
15638
15946
  const part = JSON.parse(content);
15639
15947
  if (THINKING_TYPES.has(part.type)) {
15640
15948
  unlinkSync(filePath);
@@ -15648,22 +15956,22 @@ function stripThinkingParts(messageID) {
15648
15956
  }
15649
15957
  function replaceEmptyTextParts(messageID, replacementText) {
15650
15958
  const partDir = join7(PART_STORAGE2, messageID);
15651
- if (!existsSync3(partDir))
15959
+ if (!existsSync4(partDir))
15652
15960
  return false;
15653
15961
  let anyReplaced = false;
15654
- for (const file of readdirSync3(partDir)) {
15962
+ for (const file of readdirSync4(partDir)) {
15655
15963
  if (!file.endsWith(".json"))
15656
15964
  continue;
15657
15965
  try {
15658
15966
  const filePath = join7(partDir, file);
15659
- const content = readFileSync2(filePath, "utf-8");
15967
+ const content = readFileSync3(filePath, "utf-8");
15660
15968
  const part = JSON.parse(content);
15661
15969
  if (part.type === "text") {
15662
15970
  const textPart = part;
15663
15971
  if (!textPart.text?.trim()) {
15664
15972
  textPart.text = replacementText;
15665
15973
  textPart.synthetic = true;
15666
- writeFileSync2(filePath, JSON.stringify(textPart, null, 2));
15974
+ writeFileSync3(filePath, JSON.stringify(textPart, null, 2));
15667
15975
  anyReplaced = true;
15668
15976
  }
15669
15977
  }
@@ -15932,25 +16240,25 @@ function createSessionRecoveryHook(ctx, options) {
15932
16240
  // src/hooks/comment-checker/cli.ts
15933
16241
  var {spawn: spawn5 } = globalThis.Bun;
15934
16242
  import { createRequire as createRequire2 } from "module";
15935
- import { dirname, join as join14 } from "path";
15936
- import { existsSync as existsSync11 } from "fs";
16243
+ import { dirname, join as join16 } from "path";
16244
+ import { existsSync as existsSync14 } from "fs";
15937
16245
  import * as fs5 from "fs";
15938
- import { tmpdir as tmpdir3 } from "os";
16246
+ import { tmpdir as tmpdir4 } from "os";
15939
16247
 
15940
16248
  // src/hooks/comment-checker/downloader.ts
15941
16249
  init_shared();
15942
16250
  var {spawn: spawn4 } = globalThis.Bun;
15943
- import { existsSync as existsSync10, mkdirSync as mkdirSync3, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync2 } from "fs";
15944
- import { join as join13 } from "path";
15945
- import { homedir as homedir7, tmpdir as tmpdir2 } from "os";
16251
+ import { existsSync as existsSync13, mkdirSync as mkdirSync4, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync3 } from "fs";
16252
+ import { join as join15 } from "path";
16253
+ import { homedir as homedir7, tmpdir as tmpdir3 } from "os";
15946
16254
  import { createRequire } from "module";
15947
16255
  var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
15948
- var DEBUG_FILE = join13(tmpdir2(), "comment-checker-debug.log");
16256
+ var DEBUG_FILE = join15(tmpdir3(), "comment-checker-debug.log");
15949
16257
  function debugLog(...args) {
15950
16258
  if (DEBUG) {
15951
16259
  const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
15952
16260
  `;
15953
- appendFileSync2(DEBUG_FILE, msg);
16261
+ appendFileSync3(DEBUG_FILE, msg);
15954
16262
  }
15955
16263
  }
15956
16264
  var REPO = "code-yeongyu/go-claude-code-comment-checker";
@@ -15964,19 +16272,19 @@ var PLATFORM_MAP = {
15964
16272
  function getCacheDir() {
15965
16273
  if (process.platform === "win32") {
15966
16274
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
15967
- const base2 = localAppData || join13(homedir7(), "AppData", "Local");
15968
- return join13(base2, "oh-my-opencode", "bin");
16275
+ const base2 = localAppData || join15(homedir7(), "AppData", "Local");
16276
+ return join15(base2, "oh-my-opencode", "bin");
15969
16277
  }
15970
16278
  const xdgCache = process.env.XDG_CACHE_HOME;
15971
- const base = xdgCache || join13(homedir7(), ".cache");
15972
- return join13(base, "oh-my-opencode", "bin");
16279
+ const base = xdgCache || join15(homedir7(), ".cache");
16280
+ return join15(base, "oh-my-opencode", "bin");
15973
16281
  }
15974
16282
  function getBinaryName() {
15975
16283
  return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
15976
16284
  }
15977
16285
  function getCachedBinaryPath() {
15978
- const binaryPath = join13(getCacheDir(), getBinaryName());
15979
- return existsSync10(binaryPath) ? binaryPath : null;
16286
+ const binaryPath = join15(getCacheDir(), getBinaryName());
16287
+ return existsSync13(binaryPath) ? binaryPath : null;
15980
16288
  }
15981
16289
  function getPackageVersion() {
15982
16290
  try {
@@ -16008,8 +16316,8 @@ async function downloadCommentChecker() {
16008
16316
  }
16009
16317
  const cacheDir = getCacheDir();
16010
16318
  const binaryName = getBinaryName();
16011
- const binaryPath = join13(cacheDir, binaryName);
16012
- if (existsSync10(binaryPath)) {
16319
+ const binaryPath = join15(cacheDir, binaryName);
16320
+ if (existsSync13(binaryPath)) {
16013
16321
  debugLog("Binary already cached at:", binaryPath);
16014
16322
  return binaryPath;
16015
16323
  }
@@ -16020,14 +16328,14 @@ async function downloadCommentChecker() {
16020
16328
  debugLog(`Downloading from: ${downloadUrl}`);
16021
16329
  console.log(`[oh-my-opencode] Downloading comment-checker binary...`);
16022
16330
  try {
16023
- if (!existsSync10(cacheDir)) {
16024
- mkdirSync3(cacheDir, { recursive: true });
16331
+ if (!existsSync13(cacheDir)) {
16332
+ mkdirSync4(cacheDir, { recursive: true });
16025
16333
  }
16026
16334
  const response = await fetch(downloadUrl, { redirect: "follow" });
16027
16335
  if (!response.ok) {
16028
16336
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
16029
16337
  }
16030
- const archivePath = join13(cacheDir, assetName);
16338
+ const archivePath = join15(cacheDir, assetName);
16031
16339
  const arrayBuffer = await response.arrayBuffer();
16032
16340
  await Bun.write(archivePath, arrayBuffer);
16033
16341
  debugLog(`Downloaded archive to: ${archivePath}`);
@@ -16036,10 +16344,10 @@ async function downloadCommentChecker() {
16036
16344
  } else {
16037
16345
  await extractZip(archivePath, cacheDir);
16038
16346
  }
16039
- if (existsSync10(archivePath)) {
16347
+ if (existsSync13(archivePath)) {
16040
16348
  unlinkSync2(archivePath);
16041
16349
  }
16042
- if (process.platform !== "win32" && existsSync10(binaryPath)) {
16350
+ if (process.platform !== "win32" && existsSync13(binaryPath)) {
16043
16351
  chmodSync(binaryPath, 493);
16044
16352
  }
16045
16353
  debugLog(`Successfully downloaded binary to: ${binaryPath}`);
@@ -16063,7 +16371,7 @@ async function ensureCommentCheckerBinary() {
16063
16371
 
16064
16372
  // src/hooks/comment-checker/cli.ts
16065
16373
  var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
16066
- var DEBUG_FILE2 = join14(tmpdir3(), "comment-checker-debug.log");
16374
+ var DEBUG_FILE2 = join16(tmpdir4(), "comment-checker-debug.log");
16067
16375
  function debugLog2(...args) {
16068
16376
  if (DEBUG2) {
16069
16377
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16089,8 +16397,8 @@ function findCommentCheckerPathSync() {
16089
16397
  const require2 = createRequire2(import.meta.url);
16090
16398
  const cliPkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
16091
16399
  const cliDir = dirname(cliPkgPath);
16092
- const binaryPath = join14(cliDir, "bin", binaryName);
16093
- if (existsSync11(binaryPath)) {
16400
+ const binaryPath = join16(cliDir, "bin", binaryName);
16401
+ if (existsSync14(binaryPath)) {
16094
16402
  debugLog2("found binary in main package:", binaryPath);
16095
16403
  return binaryPath;
16096
16404
  }
@@ -16111,7 +16419,7 @@ async function getCommentCheckerPath() {
16111
16419
  }
16112
16420
  initPromise = (async () => {
16113
16421
  const syncPath = findCommentCheckerPathSync();
16114
- if (syncPath && existsSync11(syncPath)) {
16422
+ if (syncPath && existsSync14(syncPath)) {
16115
16423
  resolvedCliPath = syncPath;
16116
16424
  debugLog2("using sync-resolved path:", syncPath);
16117
16425
  return syncPath;
@@ -16147,7 +16455,7 @@ async function runCommentChecker(input, cliPath, customPrompt) {
16147
16455
  debugLog2("comment-checker binary not found");
16148
16456
  return { hasComments: false, message: "" };
16149
16457
  }
16150
- if (!existsSync11(binaryPath)) {
16458
+ if (!existsSync14(binaryPath)) {
16151
16459
  debugLog2("comment-checker binary does not exist:", binaryPath);
16152
16460
  return { hasComments: false, message: "" };
16153
16461
  }
@@ -16185,11 +16493,11 @@ async function runCommentChecker(input, cliPath, customPrompt) {
16185
16493
 
16186
16494
  // src/hooks/comment-checker/index.ts
16187
16495
  import * as fs6 from "fs";
16188
- import { existsSync as existsSync12 } from "fs";
16189
- import { tmpdir as tmpdir4 } from "os";
16190
- import { join as join15 } from "path";
16496
+ import { existsSync as existsSync15 } from "fs";
16497
+ import { tmpdir as tmpdir5 } from "os";
16498
+ import { join as join17 } from "path";
16191
16499
  var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
16192
- var DEBUG_FILE3 = join15(tmpdir4(), "comment-checker-debug.log");
16500
+ var DEBUG_FILE3 = join17(tmpdir5(), "comment-checker-debug.log");
16193
16501
  function debugLog3(...args) {
16194
16502
  if (DEBUG3) {
16195
16503
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16269,7 +16577,7 @@ function createCommentCheckerHooks(config) {
16269
16577
  }
16270
16578
  try {
16271
16579
  const cliPath = await cliPathPromise;
16272
- if (!cliPath || !existsSync12(cliPath)) {
16580
+ if (!cliPath || !existsSync15(cliPath)) {
16273
16581
  debugLog3("CLI not available, skipping comment check");
16274
16582
  return;
16275
16583
  }
@@ -16349,36 +16657,36 @@ function createToolOutputTruncatorHook(ctx, options) {
16349
16657
  };
16350
16658
  }
16351
16659
  // src/hooks/directory-agents-injector/index.ts
16352
- import { existsSync as existsSync14, readFileSync as readFileSync8 } from "fs";
16353
- import { dirname as dirname2, join as join18, resolve as resolve3 } from "path";
16660
+ import { existsSync as existsSync17, readFileSync as readFileSync9 } from "fs";
16661
+ import { dirname as dirname2, join as join20, resolve as resolve3 } from "path";
16354
16662
 
16355
16663
  // src/hooks/directory-agents-injector/storage.ts
16356
16664
  import {
16357
- existsSync as existsSync13,
16358
- mkdirSync as mkdirSync4,
16359
- readFileSync as readFileSync7,
16360
- writeFileSync as writeFileSync4,
16665
+ existsSync as existsSync16,
16666
+ mkdirSync as mkdirSync5,
16667
+ readFileSync as readFileSync8,
16668
+ writeFileSync as writeFileSync5,
16361
16669
  unlinkSync as unlinkSync3
16362
16670
  } from "fs";
16363
- import { join as join17 } from "path";
16671
+ import { join as join19 } from "path";
16364
16672
 
16365
16673
  // src/hooks/directory-agents-injector/constants.ts
16366
16674
  init_data_path();
16367
- import { join as join16 } from "path";
16675
+ import { join as join18 } from "path";
16368
16676
  var OPENCODE_STORAGE3 = getOpenCodeStorageDir();
16369
- var AGENTS_INJECTOR_STORAGE = join16(OPENCODE_STORAGE3, "directory-agents");
16677
+ var AGENTS_INJECTOR_STORAGE = join18(OPENCODE_STORAGE3, "directory-agents");
16370
16678
  var AGENTS_FILENAME = "AGENTS.md";
16371
16679
 
16372
16680
  // src/hooks/directory-agents-injector/storage.ts
16373
16681
  function getStoragePath(sessionID) {
16374
- return join17(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
16682
+ return join19(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
16375
16683
  }
16376
16684
  function loadInjectedPaths(sessionID) {
16377
16685
  const filePath = getStoragePath(sessionID);
16378
- if (!existsSync13(filePath))
16686
+ if (!existsSync16(filePath))
16379
16687
  return new Set;
16380
16688
  try {
16381
- const content = readFileSync7(filePath, "utf-8");
16689
+ const content = readFileSync8(filePath, "utf-8");
16382
16690
  const data = JSON.parse(content);
16383
16691
  return new Set(data.injectedPaths);
16384
16692
  } catch {
@@ -16386,19 +16694,19 @@ function loadInjectedPaths(sessionID) {
16386
16694
  }
16387
16695
  }
16388
16696
  function saveInjectedPaths(sessionID, paths) {
16389
- if (!existsSync13(AGENTS_INJECTOR_STORAGE)) {
16390
- mkdirSync4(AGENTS_INJECTOR_STORAGE, { recursive: true });
16697
+ if (!existsSync16(AGENTS_INJECTOR_STORAGE)) {
16698
+ mkdirSync5(AGENTS_INJECTOR_STORAGE, { recursive: true });
16391
16699
  }
16392
16700
  const data = {
16393
16701
  sessionID,
16394
16702
  injectedPaths: [...paths],
16395
16703
  updatedAt: Date.now()
16396
16704
  };
16397
- writeFileSync4(getStoragePath(sessionID), JSON.stringify(data, null, 2));
16705
+ writeFileSync5(getStoragePath(sessionID), JSON.stringify(data, null, 2));
16398
16706
  }
16399
16707
  function clearInjectedPaths(sessionID) {
16400
16708
  const filePath = getStoragePath(sessionID);
16401
- if (existsSync13(filePath)) {
16709
+ if (existsSync16(filePath)) {
16402
16710
  unlinkSync3(filePath);
16403
16711
  }
16404
16712
  }
@@ -16428,8 +16736,8 @@ function createDirectoryAgentsInjectorHook(ctx) {
16428
16736
  while (true) {
16429
16737
  const isRootDir = current === ctx.directory;
16430
16738
  if (!isRootDir) {
16431
- const agentsPath = join18(current, AGENTS_FILENAME);
16432
- if (existsSync14(agentsPath)) {
16739
+ const agentsPath = join20(current, AGENTS_FILENAME);
16740
+ if (existsSync17(agentsPath)) {
16433
16741
  found.push(agentsPath);
16434
16742
  }
16435
16743
  }
@@ -16456,7 +16764,7 @@ function createDirectoryAgentsInjectorHook(ctx) {
16456
16764
  if (cache.has(agentsDir))
16457
16765
  continue;
16458
16766
  try {
16459
- const content = readFileSync8(agentsPath, "utf-8");
16767
+ const content = readFileSync9(agentsPath, "utf-8");
16460
16768
  const { result, truncated } = await truncator.truncate(sessionID, content);
16461
16769
  const truncationNotice = truncated ? `
16462
16770
 
@@ -16526,36 +16834,36 @@ ${result}${truncationNotice}`;
16526
16834
  };
16527
16835
  }
16528
16836
  // src/hooks/directory-readme-injector/index.ts
16529
- import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
16530
- import { dirname as dirname3, join as join21, resolve as resolve4 } from "path";
16837
+ import { existsSync as existsSync19, readFileSync as readFileSync11 } from "fs";
16838
+ import { dirname as dirname3, join as join23, resolve as resolve4 } from "path";
16531
16839
 
16532
16840
  // src/hooks/directory-readme-injector/storage.ts
16533
16841
  import {
16534
- existsSync as existsSync15,
16535
- mkdirSync as mkdirSync5,
16536
- readFileSync as readFileSync9,
16537
- writeFileSync as writeFileSync5,
16842
+ existsSync as existsSync18,
16843
+ mkdirSync as mkdirSync6,
16844
+ readFileSync as readFileSync10,
16845
+ writeFileSync as writeFileSync6,
16538
16846
  unlinkSync as unlinkSync4
16539
16847
  } from "fs";
16540
- import { join as join20 } from "path";
16848
+ import { join as join22 } from "path";
16541
16849
 
16542
16850
  // src/hooks/directory-readme-injector/constants.ts
16543
16851
  init_data_path();
16544
- import { join as join19 } from "path";
16852
+ import { join as join21 } from "path";
16545
16853
  var OPENCODE_STORAGE4 = getOpenCodeStorageDir();
16546
- var README_INJECTOR_STORAGE = join19(OPENCODE_STORAGE4, "directory-readme");
16854
+ var README_INJECTOR_STORAGE = join21(OPENCODE_STORAGE4, "directory-readme");
16547
16855
  var README_FILENAME = "README.md";
16548
16856
 
16549
16857
  // src/hooks/directory-readme-injector/storage.ts
16550
16858
  function getStoragePath2(sessionID) {
16551
- return join20(README_INJECTOR_STORAGE, `${sessionID}.json`);
16859
+ return join22(README_INJECTOR_STORAGE, `${sessionID}.json`);
16552
16860
  }
16553
16861
  function loadInjectedPaths2(sessionID) {
16554
16862
  const filePath = getStoragePath2(sessionID);
16555
- if (!existsSync15(filePath))
16863
+ if (!existsSync18(filePath))
16556
16864
  return new Set;
16557
16865
  try {
16558
- const content = readFileSync9(filePath, "utf-8");
16866
+ const content = readFileSync10(filePath, "utf-8");
16559
16867
  const data = JSON.parse(content);
16560
16868
  return new Set(data.injectedPaths);
16561
16869
  } catch {
@@ -16563,19 +16871,19 @@ function loadInjectedPaths2(sessionID) {
16563
16871
  }
16564
16872
  }
16565
16873
  function saveInjectedPaths2(sessionID, paths) {
16566
- if (!existsSync15(README_INJECTOR_STORAGE)) {
16567
- mkdirSync5(README_INJECTOR_STORAGE, { recursive: true });
16874
+ if (!existsSync18(README_INJECTOR_STORAGE)) {
16875
+ mkdirSync6(README_INJECTOR_STORAGE, { recursive: true });
16568
16876
  }
16569
16877
  const data = {
16570
16878
  sessionID,
16571
16879
  injectedPaths: [...paths],
16572
16880
  updatedAt: Date.now()
16573
16881
  };
16574
- writeFileSync5(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
16882
+ writeFileSync6(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
16575
16883
  }
16576
16884
  function clearInjectedPaths2(sessionID) {
16577
16885
  const filePath = getStoragePath2(sessionID);
16578
- if (existsSync15(filePath)) {
16886
+ if (existsSync18(filePath)) {
16579
16887
  unlinkSync4(filePath);
16580
16888
  }
16581
16889
  }
@@ -16603,8 +16911,8 @@ function createDirectoryReadmeInjectorHook(ctx) {
16603
16911
  const found = [];
16604
16912
  let current = startDir;
16605
16913
  while (true) {
16606
- const readmePath = join21(current, README_FILENAME);
16607
- if (existsSync16(readmePath)) {
16914
+ const readmePath = join23(current, README_FILENAME);
16915
+ if (existsSync19(readmePath)) {
16608
16916
  found.push(readmePath);
16609
16917
  }
16610
16918
  if (current === ctx.directory)
@@ -16630,7 +16938,7 @@ function createDirectoryReadmeInjectorHook(ctx) {
16630
16938
  if (cache.has(readmeDir))
16631
16939
  continue;
16632
16940
  try {
16633
- const content = readFileSync10(readmePath, "utf-8");
16941
+ const content = readFileSync11(readmePath, "utf-8");
16634
16942
  const { result, truncated } = await truncator.truncate(sessionID, content);
16635
16943
  const truncationNotice = truncated ? `
16636
16944
 
@@ -16914,22 +17222,22 @@ var TRUNCATE_CONFIG = {
16914
17222
 
16915
17223
  // src/hooks/anthropic-context-window-limit-recovery/storage.ts
16916
17224
  init_data_path();
16917
- import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
16918
- import { join as join22 } from "path";
17225
+ import { existsSync as existsSync20, readdirSync as readdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
17226
+ import { join as join24 } from "path";
16919
17227
  var OPENCODE_STORAGE5 = getOpenCodeStorageDir();
16920
- var MESSAGE_STORAGE3 = join22(OPENCODE_STORAGE5, "message");
16921
- var PART_STORAGE3 = join22(OPENCODE_STORAGE5, "part");
17228
+ var MESSAGE_STORAGE3 = join24(OPENCODE_STORAGE5, "message");
17229
+ var PART_STORAGE3 = join24(OPENCODE_STORAGE5, "part");
16922
17230
  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.]";
16923
17231
  function getMessageDir3(sessionID) {
16924
- if (!existsSync17(MESSAGE_STORAGE3))
17232
+ if (!existsSync20(MESSAGE_STORAGE3))
16925
17233
  return "";
16926
- const directPath = join22(MESSAGE_STORAGE3, sessionID);
16927
- if (existsSync17(directPath)) {
17234
+ const directPath = join24(MESSAGE_STORAGE3, sessionID);
17235
+ if (existsSync20(directPath)) {
16928
17236
  return directPath;
16929
17237
  }
16930
- for (const dir of readdirSync4(MESSAGE_STORAGE3)) {
16931
- const sessionPath = join22(MESSAGE_STORAGE3, dir, sessionID);
16932
- if (existsSync17(sessionPath)) {
17238
+ for (const dir of readdirSync6(MESSAGE_STORAGE3)) {
17239
+ const sessionPath = join24(MESSAGE_STORAGE3, dir, sessionID);
17240
+ if (existsSync20(sessionPath)) {
16933
17241
  return sessionPath;
16934
17242
  }
16935
17243
  }
@@ -16937,10 +17245,10 @@ function getMessageDir3(sessionID) {
16937
17245
  }
16938
17246
  function getMessageIds(sessionID) {
16939
17247
  const messageDir = getMessageDir3(sessionID);
16940
- if (!messageDir || !existsSync17(messageDir))
17248
+ if (!messageDir || !existsSync20(messageDir))
16941
17249
  return [];
16942
17250
  const messageIds = [];
16943
- for (const file of readdirSync4(messageDir)) {
17251
+ for (const file of readdirSync6(messageDir)) {
16944
17252
  if (!file.endsWith(".json"))
16945
17253
  continue;
16946
17254
  const messageId = file.replace(".json", "");
@@ -16952,15 +17260,15 @@ function findToolResultsBySize(sessionID) {
16952
17260
  const messageIds = getMessageIds(sessionID);
16953
17261
  const results = [];
16954
17262
  for (const messageID of messageIds) {
16955
- const partDir = join22(PART_STORAGE3, messageID);
16956
- if (!existsSync17(partDir))
17263
+ const partDir = join24(PART_STORAGE3, messageID);
17264
+ if (!existsSync20(partDir))
16957
17265
  continue;
16958
- for (const file of readdirSync4(partDir)) {
17266
+ for (const file of readdirSync6(partDir)) {
16959
17267
  if (!file.endsWith(".json"))
16960
17268
  continue;
16961
17269
  try {
16962
- const partPath = join22(partDir, file);
16963
- const content = readFileSync11(partPath, "utf-8");
17270
+ const partPath = join24(partDir, file);
17271
+ const content = readFileSync12(partPath, "utf-8");
16964
17272
  const part = JSON.parse(content);
16965
17273
  if (part.type === "tool" && part.state?.output && !part.truncated) {
16966
17274
  results.push({
@@ -16980,7 +17288,7 @@ function findToolResultsBySize(sessionID) {
16980
17288
  }
16981
17289
  function truncateToolResult(partPath) {
16982
17290
  try {
16983
- const content = readFileSync11(partPath, "utf-8");
17291
+ const content = readFileSync12(partPath, "utf-8");
16984
17292
  const part = JSON.parse(content);
16985
17293
  if (!part.state?.output) {
16986
17294
  return { success: false };
@@ -16994,7 +17302,7 @@ function truncateToolResult(partPath) {
16994
17302
  part.state.time = { start: Date.now() };
16995
17303
  }
16996
17304
  part.state.time.compacted = Date.now();
16997
- writeFileSync6(partPath, JSON.stringify(part, null, 2));
17305
+ writeFileSync7(partPath, JSON.stringify(part, null, 2));
16998
17306
  return { success: true, toolName, originalSize };
16999
17307
  } catch {
17000
17308
  return { success: false };
@@ -17494,15 +17802,29 @@ function createCompactionContextInjector() {
17494
17802
  }
17495
17803
  // src/hooks/think-mode/detector.ts
17496
17804
  var ENGLISH_PATTERNS = [/\bultrathink\b/i, /\bthink\b/i];
17497
- var MULTILINGUAL_KEYWORDS = [
17805
+ var CHINESE_KEYWORDS = [
17806
+ "\u601D\u8003",
17807
+ "\u8003\u8651",
17808
+ "\u8003\u616E",
17809
+ "\u6DF1\u5165\u601D\u8003",
17810
+ "\u4ED4\u7EC6\u60F3\u60F3",
17811
+ "\u4ED4\u7EC6\u601D\u8003",
17812
+ "\u8BA4\u771F\u601D\u8003",
17813
+ "\u597D\u597D\u60F3\u60F3",
17814
+ "\u597D\u597D\u8003\u8651",
17815
+ "\u7422\u78E8",
17816
+ "\u5206\u6790\u4E00\u4E0B",
17817
+ "\u53CD\u601D",
17818
+ "\u63A8\u6572",
17819
+ "\u659F\u914C",
17820
+ "\u6DF1\u601D\u719F\u8651",
17821
+ "\u60F3\u4E00\u60F3"
17822
+ ];
17823
+ var OTHER_MULTILINGUAL_KEYWORDS = [
17498
17824
  "\uC0DD\uAC01",
17499
17825
  "\uACE0\uBBFC",
17500
17826
  "\uAC80\uD1A0",
17501
17827
  "\uC81C\uB300\uB85C",
17502
- "\u601D\u8003",
17503
- "\u8003\u8651",
17504
- "\u8003\u616E",
17505
- "\u601D\u8003",
17506
17828
  "\u8003\u3048",
17507
17829
  "\u719F\u8003",
17508
17830
  "\u0938\u094B\u091A",
@@ -17580,8 +17902,9 @@ var MULTILINGUAL_KEYWORDS = [
17580
17902
  "fikir",
17581
17903
  "berfikir"
17582
17904
  ];
17583
- var MULTILINGUAL_PATTERNS = MULTILINGUAL_KEYWORDS.map((kw) => new RegExp(kw, "i"));
17584
- var THINK_PATTERNS = [...ENGLISH_PATTERNS, ...MULTILINGUAL_PATTERNS];
17905
+ var CHINESE_PATTERNS = CHINESE_KEYWORDS.map((kw) => new RegExp(kw, "i"));
17906
+ var MULTILINGUAL_PATTERNS = OTHER_MULTILINGUAL_KEYWORDS.map((kw) => new RegExp(kw, "i"));
17907
+ var THINK_PATTERNS = [...ENGLISH_PATTERNS, ...CHINESE_PATTERNS, ...MULTILINGUAL_PATTERNS];
17585
17908
  var CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
17586
17909
  var INLINE_CODE_PATTERN = /`[^`]+`/g;
17587
17910
  function removeCodeBlocks(text) {
@@ -17729,53 +18052,55 @@ init_shared();
17729
18052
  var thinkModeState = new Map;
17730
18053
  function createThinkModeHook() {
17731
18054
  return {
17732
- "chat.params": async (output, sessionID) => {
17733
- const promptText = extractPromptText(output.parts);
18055
+ "chat.params": async (input, output) => {
18056
+ const promptText = extractPromptText(input.message.parts ?? []);
17734
18057
  const state2 = {
17735
18058
  requested: false,
17736
18059
  modelSwitched: false,
17737
18060
  thinkingConfigInjected: false
17738
18061
  };
17739
18062
  if (!detectThinkKeyword(promptText)) {
17740
- thinkModeState.set(sessionID, state2);
18063
+ thinkModeState.set(input.sessionID, state2);
17741
18064
  return;
17742
18065
  }
17743
18066
  state2.requested = true;
17744
- const currentModel = output.message.model;
17745
- if (!currentModel) {
17746
- thinkModeState.set(sessionID, state2);
18067
+ const modelID = input.model.id;
18068
+ const providerID = input.model.providerID;
18069
+ if (!modelID) {
18070
+ thinkModeState.set(input.sessionID, state2);
17747
18071
  return;
17748
18072
  }
17749
- state2.providerID = currentModel.providerID;
17750
- state2.modelID = currentModel.modelID;
17751
- if (isAlreadyHighVariant(currentModel.modelID)) {
17752
- thinkModeState.set(sessionID, state2);
18073
+ state2.providerID = providerID;
18074
+ state2.modelID = modelID;
18075
+ if (isAlreadyHighVariant(modelID)) {
18076
+ thinkModeState.set(input.sessionID, state2);
17753
18077
  return;
17754
18078
  }
17755
- const highVariant = getHighVariant(currentModel.modelID);
17756
- const thinkingConfig = getThinkingConfig(currentModel.providerID, currentModel.modelID);
18079
+ const highVariant = getHighVariant(modelID);
18080
+ const thinkingConfig = getThinkingConfig(providerID, modelID);
17757
18081
  if (highVariant) {
17758
- output.message.model = {
17759
- providerID: currentModel.providerID,
17760
- modelID: highVariant
17761
- };
18082
+ input.model.id = highVariant;
17762
18083
  state2.modelSwitched = true;
17763
18084
  log("Think mode: model switched to high variant", {
17764
- sessionID,
17765
- from: currentModel.modelID,
18085
+ sessionID: input.sessionID,
18086
+ from: modelID,
17766
18087
  to: highVariant
17767
18088
  });
17768
18089
  }
17769
18090
  if (thinkingConfig) {
17770
- Object.assign(output.message, thinkingConfig);
18091
+ const { maxTokens, ...thinkingOptions } = thinkingConfig;
18092
+ if (typeof maxTokens === "number") {
18093
+ output.maxOutputTokens = maxTokens;
18094
+ }
18095
+ Object.assign(output.options, thinkingOptions);
17771
18096
  state2.thinkingConfigInjected = true;
17772
18097
  log("Think mode: thinking config injected", {
17773
- sessionID,
17774
- provider: currentModel.providerID,
18098
+ sessionID: input.sessionID,
18099
+ provider: providerID,
17775
18100
  config: thinkingConfig
17776
18101
  });
17777
18102
  }
17778
- thinkModeState.set(sessionID, state2);
18103
+ thinkModeState.set(input.sessionID, state2);
17779
18104
  },
17780
18105
  event: async ({ event }) => {
17781
18106
  if (event.type === "session.deleted") {
@@ -17789,8 +18114,8 @@ function createThinkModeHook() {
17789
18114
  }
17790
18115
  // src/hooks/claude-code-hooks/config.ts
17791
18116
  init_shared();
17792
- import { join as join23 } from "path";
17793
- import { existsSync as existsSync18 } from "fs";
18117
+ import { join as join25 } from "path";
18118
+ import { existsSync as existsSync21 } from "fs";
17794
18119
  function normalizeHookMatcher(raw) {
17795
18120
  return {
17796
18121
  matcher: raw.matcher ?? raw.pattern ?? "*",
@@ -17816,11 +18141,11 @@ function normalizeHooksConfig(raw) {
17816
18141
  function getClaudeSettingsPaths(customPath) {
17817
18142
  const claudeConfigDir = getClaudeConfigDir();
17818
18143
  const paths = [
17819
- join23(claudeConfigDir, "settings.json"),
17820
- join23(process.cwd(), ".claude", "settings.json"),
17821
- join23(process.cwd(), ".claude", "settings.local.json")
18144
+ join25(claudeConfigDir, "settings.json"),
18145
+ join25(process.cwd(), ".claude", "settings.json"),
18146
+ join25(process.cwd(), ".claude", "settings.local.json")
17822
18147
  ];
17823
- if (customPath && existsSync18(customPath)) {
18148
+ if (customPath && existsSync21(customPath)) {
17824
18149
  paths.unshift(customPath);
17825
18150
  }
17826
18151
  return paths;
@@ -17845,7 +18170,7 @@ async function loadClaudeHooksConfig(customSettingsPath) {
17845
18170
  const paths = getClaudeSettingsPaths(customSettingsPath);
17846
18171
  let mergedConfig = {};
17847
18172
  for (const settingsPath of paths) {
17848
- if (existsSync18(settingsPath)) {
18173
+ if (existsSync21(settingsPath)) {
17849
18174
  try {
17850
18175
  const content = await Bun.file(settingsPath).text();
17851
18176
  const settings = JSON.parse(content);
@@ -17864,14 +18189,14 @@ async function loadClaudeHooksConfig(customSettingsPath) {
17864
18189
  // src/hooks/claude-code-hooks/config-loader.ts
17865
18190
  init_logger();
17866
18191
  init_shared();
17867
- import { existsSync as existsSync19 } from "fs";
17868
- import { join as join24 } from "path";
17869
- var USER_CONFIG_PATH = join24(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json");
18192
+ import { existsSync as existsSync22 } from "fs";
18193
+ import { join as join26 } from "path";
18194
+ var USER_CONFIG_PATH = join26(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json");
17870
18195
  function getProjectConfigPath() {
17871
- return join24(process.cwd(), ".opencode", "opencode-cc-plugin.json");
18196
+ return join26(process.cwd(), ".opencode", "opencode-cc-plugin.json");
17872
18197
  }
17873
18198
  async function loadConfigFromPath(path4) {
17874
- if (!existsSync19(path4)) {
18199
+ if (!existsSync22(path4)) {
17875
18200
  return null;
17876
18201
  }
17877
18202
  try {
@@ -18059,17 +18384,17 @@ init_shared();
18059
18384
  // src/hooks/claude-code-hooks/transcript.ts
18060
18385
  init_tool_name();
18061
18386
  init_shared();
18062
- import { join as join25 } from "path";
18063
- import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync20, writeFileSync as writeFileSync7, unlinkSync as unlinkSync5 } from "fs";
18064
- import { tmpdir as tmpdir5 } from "os";
18387
+ import { join as join27 } from "path";
18388
+ import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync6, existsSync as existsSync23, writeFileSync as writeFileSync8, unlinkSync as unlinkSync5 } from "fs";
18389
+ import { tmpdir as tmpdir6 } from "os";
18065
18390
  import { randomUUID } from "crypto";
18066
- var TRANSCRIPT_DIR = join25(getClaudeConfigDir(), "transcripts");
18391
+ var TRANSCRIPT_DIR = join27(getClaudeConfigDir(), "transcripts");
18067
18392
  function getTranscriptPath(sessionId) {
18068
- return join25(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
18393
+ return join27(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
18069
18394
  }
18070
18395
  function ensureTranscriptDir() {
18071
- if (!existsSync20(TRANSCRIPT_DIR)) {
18072
- mkdirSync6(TRANSCRIPT_DIR, { recursive: true });
18396
+ if (!existsSync23(TRANSCRIPT_DIR)) {
18397
+ mkdirSync7(TRANSCRIPT_DIR, { recursive: true });
18073
18398
  }
18074
18399
  }
18075
18400
  function appendTranscriptEntry(sessionId, entry) {
@@ -18077,7 +18402,7 @@ function appendTranscriptEntry(sessionId, entry) {
18077
18402
  const path4 = getTranscriptPath(sessionId);
18078
18403
  const line = JSON.stringify(entry) + `
18079
18404
  `;
18080
- appendFileSync5(path4, line);
18405
+ appendFileSync6(path4, line);
18081
18406
  }
18082
18407
  function recordToolUse(sessionId, toolName, toolInput) {
18083
18408
  appendTranscriptEntry(sessionId, {
@@ -18155,8 +18480,8 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
18155
18480
  }
18156
18481
  };
18157
18482
  entries.push(JSON.stringify(currentEntry));
18158
- const tempPath = join25(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18159
- writeFileSync7(tempPath, entries.join(`
18483
+ const tempPath = join27(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18484
+ writeFileSync8(tempPath, entries.join(`
18160
18485
  `) + `
18161
18486
  `);
18162
18487
  return tempPath;
@@ -18175,8 +18500,8 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
18175
18500
  ]
18176
18501
  }
18177
18502
  };
18178
- const tempPath = join25(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18179
- writeFileSync7(tempPath, JSON.stringify(currentEntry) + `
18503
+ const tempPath = join27(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18504
+ writeFileSync8(tempPath, JSON.stringify(currentEntry) + `
18180
18505
  `);
18181
18506
  return tempPath;
18182
18507
  } catch {
@@ -18391,11 +18716,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
18391
18716
  init_shared();
18392
18717
 
18393
18718
  // src/hooks/claude-code-hooks/todo.ts
18394
- import { join as join26 } from "path";
18719
+ import { join as join28 } from "path";
18395
18720
  init_shared();
18396
- var TODO_DIR = join26(getClaudeConfigDir(), "todos");
18721
+ var TODO_DIR = join28(getClaudeConfigDir(), "todos");
18397
18722
  function getTodoPath(sessionId) {
18398
- return join26(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
18723
+ return join28(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
18399
18724
  }
18400
18725
 
18401
18726
  // src/hooks/claude-code-hooks/stop.ts
@@ -18837,24 +19162,24 @@ ${result.message}`;
18837
19162
  };
18838
19163
  }
18839
19164
  // src/hooks/rules-injector/index.ts
18840
- import { readFileSync as readFileSync13 } from "fs";
19165
+ import { readFileSync as readFileSync14 } from "fs";
18841
19166
  import { homedir as homedir8 } from "os";
18842
- import { relative as relative3, resolve as resolve5 } from "path";
19167
+ import { relative as relative4, resolve as resolve5 } from "path";
18843
19168
 
18844
19169
  // src/hooks/rules-injector/finder.ts
18845
19170
  import {
18846
- existsSync as existsSync21,
18847
- readdirSync as readdirSync5,
19171
+ existsSync as existsSync24,
19172
+ readdirSync as readdirSync7,
18848
19173
  realpathSync,
18849
19174
  statSync as statSync2
18850
19175
  } from "fs";
18851
- import { dirname as dirname4, join as join28, relative } from "path";
19176
+ import { dirname as dirname4, join as join30, relative as relative2 } from "path";
18852
19177
 
18853
19178
  // src/hooks/rules-injector/constants.ts
18854
19179
  init_data_path();
18855
- import { join as join27 } from "path";
19180
+ import { join as join29 } from "path";
18856
19181
  var OPENCODE_STORAGE6 = getOpenCodeStorageDir();
18857
- var RULES_INJECTOR_STORAGE = join27(OPENCODE_STORAGE6, "rules-injector");
19182
+ var RULES_INJECTOR_STORAGE = join29(OPENCODE_STORAGE6, "rules-injector");
18858
19183
  var PROJECT_MARKERS = [
18859
19184
  ".git",
18860
19185
  "pyproject.toml",
@@ -18895,8 +19220,8 @@ function findProjectRoot(startPath) {
18895
19220
  }
18896
19221
  while (true) {
18897
19222
  for (const marker of PROJECT_MARKERS) {
18898
- const markerPath = join28(current, marker);
18899
- if (existsSync21(markerPath)) {
19223
+ const markerPath = join30(current, marker);
19224
+ if (existsSync24(markerPath)) {
18900
19225
  return current;
18901
19226
  }
18902
19227
  }
@@ -18908,12 +19233,12 @@ function findProjectRoot(startPath) {
18908
19233
  }
18909
19234
  }
18910
19235
  function findRuleFilesRecursive(dir, results) {
18911
- if (!existsSync21(dir))
19236
+ if (!existsSync24(dir))
18912
19237
  return;
18913
19238
  try {
18914
- const entries = readdirSync5(dir, { withFileTypes: true });
19239
+ const entries = readdirSync7(dir, { withFileTypes: true });
18915
19240
  for (const entry of entries) {
18916
- const fullPath = join28(dir, entry.name);
19241
+ const fullPath = join30(dir, entry.name);
18917
19242
  if (entry.isDirectory()) {
18918
19243
  findRuleFilesRecursive(fullPath, results);
18919
19244
  } else if (entry.isFile()) {
@@ -18938,7 +19263,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
18938
19263
  let distance = 0;
18939
19264
  while (true) {
18940
19265
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
18941
- const ruleDir = join28(currentDir, parent, subdir);
19266
+ const ruleDir = join30(currentDir, parent, subdir);
18942
19267
  const files = [];
18943
19268
  findRuleFilesRecursive(ruleDir, files);
18944
19269
  for (const filePath of files) {
@@ -18964,8 +19289,8 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
18964
19289
  }
18965
19290
  if (projectRoot) {
18966
19291
  for (const ruleFile of PROJECT_RULE_FILES) {
18967
- const filePath = join28(projectRoot, ruleFile);
18968
- if (existsSync21(filePath)) {
19292
+ const filePath = join30(projectRoot, ruleFile);
19293
+ if (existsSync24(filePath)) {
18969
19294
  try {
18970
19295
  const stat = statSync2(filePath);
18971
19296
  if (stat.isFile()) {
@@ -18985,7 +19310,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
18985
19310
  }
18986
19311
  }
18987
19312
  }
18988
- const userRuleDir = join28(homeDir, USER_RULE_DIR);
19313
+ const userRuleDir = join30(homeDir, USER_RULE_DIR);
18989
19314
  const userFiles = [];
18990
19315
  findRuleFilesRecursive(userRuleDir, userFiles);
18991
19316
  for (const filePath of userFiles) {
@@ -19012,7 +19337,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
19012
19337
  // src/hooks/rules-injector/matcher.ts
19013
19338
  var import_picomatch = __toESM(require_picomatch2(), 1);
19014
19339
  import { createHash } from "crypto";
19015
- import { relative as relative2 } from "path";
19340
+ import { relative as relative3 } from "path";
19016
19341
  function shouldApplyRule(metadata, currentFilePath, projectRoot) {
19017
19342
  if (metadata.alwaysApply === true) {
19018
19343
  return { applies: true, reason: "alwaysApply" };
@@ -19025,7 +19350,7 @@ function shouldApplyRule(metadata, currentFilePath, projectRoot) {
19025
19350
  if (patterns.length === 0) {
19026
19351
  return { applies: false };
19027
19352
  }
19028
- const relativePath = projectRoot ? relative2(projectRoot, currentFilePath) : currentFilePath;
19353
+ const relativePath = projectRoot ? relative3(projectRoot, currentFilePath) : currentFilePath;
19029
19354
  for (const pattern of patterns) {
19030
19355
  if (import_picomatch.default.isMatch(relativePath, pattern, { dot: true, bash: true })) {
19031
19356
  return { applies: true, reason: `glob: ${pattern}` };
@@ -19174,22 +19499,22 @@ function mergeGlobs(existing, newValue) {
19174
19499
 
19175
19500
  // src/hooks/rules-injector/storage.ts
19176
19501
  import {
19177
- existsSync as existsSync22,
19178
- mkdirSync as mkdirSync7,
19179
- readFileSync as readFileSync12,
19180
- writeFileSync as writeFileSync8,
19502
+ existsSync as existsSync25,
19503
+ mkdirSync as mkdirSync8,
19504
+ readFileSync as readFileSync13,
19505
+ writeFileSync as writeFileSync9,
19181
19506
  unlinkSync as unlinkSync6
19182
19507
  } from "fs";
19183
- import { join as join29 } from "path";
19508
+ import { join as join31 } from "path";
19184
19509
  function getStoragePath3(sessionID) {
19185
- return join29(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
19510
+ return join31(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
19186
19511
  }
19187
19512
  function loadInjectedRules(sessionID) {
19188
19513
  const filePath = getStoragePath3(sessionID);
19189
- if (!existsSync22(filePath))
19514
+ if (!existsSync25(filePath))
19190
19515
  return { contentHashes: new Set, realPaths: new Set };
19191
19516
  try {
19192
- const content = readFileSync12(filePath, "utf-8");
19517
+ const content = readFileSync13(filePath, "utf-8");
19193
19518
  const data = JSON.parse(content);
19194
19519
  return {
19195
19520
  contentHashes: new Set(data.injectedHashes),
@@ -19200,8 +19525,8 @@ function loadInjectedRules(sessionID) {
19200
19525
  }
19201
19526
  }
19202
19527
  function saveInjectedRules(sessionID, data) {
19203
- if (!existsSync22(RULES_INJECTOR_STORAGE)) {
19204
- mkdirSync7(RULES_INJECTOR_STORAGE, { recursive: true });
19528
+ if (!existsSync25(RULES_INJECTOR_STORAGE)) {
19529
+ mkdirSync8(RULES_INJECTOR_STORAGE, { recursive: true });
19205
19530
  }
19206
19531
  const storageData = {
19207
19532
  sessionID,
@@ -19209,11 +19534,11 @@ function saveInjectedRules(sessionID, data) {
19209
19534
  injectedRealPaths: [...data.realPaths],
19210
19535
  updatedAt: Date.now()
19211
19536
  };
19212
- writeFileSync8(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
19537
+ writeFileSync9(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
19213
19538
  }
19214
19539
  function clearInjectedRules(sessionID) {
19215
19540
  const filePath = getStoragePath3(sessionID);
19216
- if (existsSync22(filePath)) {
19541
+ if (existsSync25(filePath)) {
19217
19542
  unlinkSync6(filePath);
19218
19543
  }
19219
19544
  }
@@ -19251,7 +19576,7 @@ function createRulesInjectorHook(ctx) {
19251
19576
  if (isDuplicateByRealPath(candidate.realPath, cache2.realPaths))
19252
19577
  continue;
19253
19578
  try {
19254
- const rawContent = readFileSync13(candidate.path, "utf-8");
19579
+ const rawContent = readFileSync14(candidate.path, "utf-8");
19255
19580
  const { metadata, body } = parseRuleFrontmatter(rawContent);
19256
19581
  let matchReason;
19257
19582
  if (candidate.isSingleFile) {
@@ -19265,7 +19590,7 @@ function createRulesInjectorHook(ctx) {
19265
19590
  const contentHash = createContentHash(body);
19266
19591
  if (isDuplicateByContentHash(contentHash, cache2.contentHashes))
19267
19592
  continue;
19268
- const relativePath = projectRoot ? relative3(projectRoot, candidate.path) : candidate.path;
19593
+ const relativePath = projectRoot ? relative4(projectRoot, candidate.path) : candidate.path;
19269
19594
  toInject.push({
19270
19595
  relativePath,
19271
19596
  matchReason,
@@ -19369,19 +19694,19 @@ init_auto_update_checker();
19369
19694
 
19370
19695
  // src/hooks/agent-usage-reminder/storage.ts
19371
19696
  import {
19372
- existsSync as existsSync25,
19373
- mkdirSync as mkdirSync8,
19374
- readFileSync as readFileSync16,
19375
- writeFileSync as writeFileSync11,
19697
+ existsSync as existsSync28,
19698
+ mkdirSync as mkdirSync9,
19699
+ readFileSync as readFileSync17,
19700
+ writeFileSync as writeFileSync12,
19376
19701
  unlinkSync as unlinkSync7
19377
19702
  } from "fs";
19378
- import { join as join34 } from "path";
19703
+ import { join as join36 } from "path";
19379
19704
 
19380
19705
  // src/hooks/agent-usage-reminder/constants.ts
19381
19706
  init_data_path();
19382
- import { join as join33 } from "path";
19707
+ import { join as join35 } from "path";
19383
19708
  var OPENCODE_STORAGE7 = getOpenCodeStorageDir();
19384
- var AGENT_USAGE_REMINDER_STORAGE = join33(OPENCODE_STORAGE7, "agent-usage-reminder");
19709
+ var AGENT_USAGE_REMINDER_STORAGE = join35(OPENCODE_STORAGE7, "agent-usage-reminder");
19385
19710
  var TARGET_TOOLS = new Set([
19386
19711
  "grep",
19387
19712
  "safe_grep",
@@ -19427,29 +19752,29 @@ delegate_task(agent="librarian", prompt="\u67E5\u627E Z \u7684\u6587\u6863")
19427
19752
 
19428
19753
  // src/hooks/agent-usage-reminder/storage.ts
19429
19754
  function getStoragePath4(sessionID) {
19430
- return join34(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
19755
+ return join36(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
19431
19756
  }
19432
19757
  function loadAgentUsageState(sessionID) {
19433
19758
  const filePath = getStoragePath4(sessionID);
19434
- if (!existsSync25(filePath))
19759
+ if (!existsSync28(filePath))
19435
19760
  return null;
19436
19761
  try {
19437
- const content = readFileSync16(filePath, "utf-8");
19762
+ const content = readFileSync17(filePath, "utf-8");
19438
19763
  return JSON.parse(content);
19439
19764
  } catch {
19440
19765
  return null;
19441
19766
  }
19442
19767
  }
19443
19768
  function saveAgentUsageState(state2) {
19444
- if (!existsSync25(AGENT_USAGE_REMINDER_STORAGE)) {
19445
- mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
19769
+ if (!existsSync28(AGENT_USAGE_REMINDER_STORAGE)) {
19770
+ mkdirSync9(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
19446
19771
  }
19447
19772
  const filePath = getStoragePath4(state2.sessionID);
19448
- writeFileSync11(filePath, JSON.stringify(state2, null, 2));
19773
+ writeFileSync12(filePath, JSON.stringify(state2, null, 2));
19449
19774
  }
19450
19775
  function clearAgentUsageState(sessionID) {
19451
19776
  const filePath = getStoragePath4(sessionID);
19452
- if (existsSync25(filePath)) {
19777
+ if (existsSync28(filePath)) {
19453
19778
  unlinkSync7(filePath);
19454
19779
  }
19455
19780
  }
@@ -20032,19 +20357,19 @@ function createNonInteractiveEnvHook(_ctx) {
20032
20357
  }
20033
20358
  // src/hooks/interactive-bash-session/storage.ts
20034
20359
  import {
20035
- existsSync as existsSync26,
20036
- mkdirSync as mkdirSync9,
20037
- readFileSync as readFileSync17,
20038
- writeFileSync as writeFileSync12,
20360
+ existsSync as existsSync29,
20361
+ mkdirSync as mkdirSync10,
20362
+ readFileSync as readFileSync18,
20363
+ writeFileSync as writeFileSync13,
20039
20364
  unlinkSync as unlinkSync8
20040
20365
  } from "fs";
20041
- import { join as join36 } from "path";
20366
+ import { join as join38 } from "path";
20042
20367
 
20043
20368
  // src/hooks/interactive-bash-session/constants.ts
20044
20369
  init_data_path();
20045
- import { join as join35 } from "path";
20370
+ import { join as join37 } from "path";
20046
20371
  var OPENCODE_STORAGE8 = getOpenCodeStorageDir();
20047
- var INTERACTIVE_BASH_SESSION_STORAGE = join35(OPENCODE_STORAGE8, "interactive-bash-session");
20372
+ var INTERACTIVE_BASH_SESSION_STORAGE = join37(OPENCODE_STORAGE8, "interactive-bash-session");
20048
20373
  var OMO_SESSION_PREFIX = "omo-";
20049
20374
  function buildSessionReminderMessage(sessions) {
20050
20375
  if (sessions.length === 0)
@@ -20056,14 +20381,14 @@ function buildSessionReminderMessage(sessions) {
20056
20381
 
20057
20382
  // src/hooks/interactive-bash-session/storage.ts
20058
20383
  function getStoragePath5(sessionID) {
20059
- return join36(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
20384
+ return join38(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
20060
20385
  }
20061
20386
  function loadInteractiveBashSessionState(sessionID) {
20062
20387
  const filePath = getStoragePath5(sessionID);
20063
- if (!existsSync26(filePath))
20388
+ if (!existsSync29(filePath))
20064
20389
  return null;
20065
20390
  try {
20066
- const content = readFileSync17(filePath, "utf-8");
20391
+ const content = readFileSync18(filePath, "utf-8");
20067
20392
  const serialized = JSON.parse(content);
20068
20393
  return {
20069
20394
  sessionID: serialized.sessionID,
@@ -20075,8 +20400,8 @@ function loadInteractiveBashSessionState(sessionID) {
20075
20400
  }
20076
20401
  }
20077
20402
  function saveInteractiveBashSessionState(state2) {
20078
- if (!existsSync26(INTERACTIVE_BASH_SESSION_STORAGE)) {
20079
- mkdirSync9(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
20403
+ if (!existsSync29(INTERACTIVE_BASH_SESSION_STORAGE)) {
20404
+ mkdirSync10(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
20080
20405
  }
20081
20406
  const filePath = getStoragePath5(state2.sessionID);
20082
20407
  const serialized = {
@@ -20084,11 +20409,11 @@ function saveInteractiveBashSessionState(state2) {
20084
20409
  tmuxSessions: Array.from(state2.tmuxSessions),
20085
20410
  updatedAt: state2.updatedAt
20086
20411
  };
20087
- writeFileSync12(filePath, JSON.stringify(serialized, null, 2));
20412
+ writeFileSync13(filePath, JSON.stringify(serialized, null, 2));
20088
20413
  }
20089
20414
  function clearInteractiveBashSessionState(sessionID) {
20090
20415
  const filePath = getStoragePath5(sessionID);
20091
- if (existsSync26(filePath)) {
20416
+ if (existsSync29(filePath)) {
20092
20417
  unlinkSync8(filePath);
20093
20418
  }
20094
20419
  }
@@ -20342,7 +20667,7 @@ function createThinkingBlockValidatorHook() {
20342
20667
  continue;
20343
20668
  if (hasContentParts(msg.parts) && !startsWithThinkingBlock(msg.parts)) {
20344
20669
  const previousThinking = findPreviousThinkingContent(messages, i2);
20345
- const thinkingContent = previousThinking || "[Continuing from previous reasoning]";
20670
+ const thinkingContent = previousThinking || "[\u63A5\u7EED\u4E4B\u524D\u7684\u63A8\u7406]";
20346
20671
  prependThinkingBlock(msg, thinkingContent);
20347
20672
  }
20348
20673
  }
@@ -20352,13 +20677,13 @@ function createThinkingBlockValidatorHook() {
20352
20677
  // src/hooks/ralph-loop/index.ts
20353
20678
  init_logger();
20354
20679
  init_system_directive();
20355
- import { existsSync as existsSync28, readFileSync as readFileSync19, readdirSync as readdirSync6 } from "fs";
20356
- import { join as join38 } from "path";
20680
+ import { existsSync as existsSync31, readFileSync as readFileSync20, readdirSync as readdirSync8 } from "fs";
20681
+ import { join as join40 } from "path";
20357
20682
 
20358
20683
  // src/hooks/ralph-loop/storage.ts
20359
20684
  init_frontmatter();
20360
- import { existsSync as existsSync27, readFileSync as readFileSync18, writeFileSync as writeFileSync13, unlinkSync as unlinkSync9, mkdirSync as mkdirSync10 } from "fs";
20361
- import { dirname as dirname6, join as join37 } from "path";
20685
+ import { existsSync as existsSync30, readFileSync as readFileSync19, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, mkdirSync as mkdirSync11 } from "fs";
20686
+ import { dirname as dirname6, join as join39 } from "path";
20362
20687
 
20363
20688
  // src/hooks/ralph-loop/constants.ts
20364
20689
  var HOOK_NAME3 = "ralph-loop";
@@ -20368,15 +20693,15 @@ var DEFAULT_COMPLETION_PROMISE = "DONE";
20368
20693
 
20369
20694
  // src/hooks/ralph-loop/storage.ts
20370
20695
  function getStateFilePath(directory, customPath) {
20371
- return customPath ? join37(directory, customPath) : join37(directory, DEFAULT_STATE_FILE);
20696
+ return customPath ? join39(directory, customPath) : join39(directory, DEFAULT_STATE_FILE);
20372
20697
  }
20373
20698
  function readState(directory, customPath) {
20374
20699
  const filePath = getStateFilePath(directory, customPath);
20375
- if (!existsSync27(filePath)) {
20700
+ if (!existsSync30(filePath)) {
20376
20701
  return null;
20377
20702
  }
20378
20703
  try {
20379
- const content = readFileSync18(filePath, "utf-8");
20704
+ const content = readFileSync19(filePath, "utf-8");
20380
20705
  const { data, body } = parseFrontmatter(content);
20381
20706
  const active = data.active;
20382
20707
  const iteration = data.iteration;
@@ -20410,8 +20735,8 @@ function writeState(directory, state2, customPath) {
20410
20735
  const filePath = getStateFilePath(directory, customPath);
20411
20736
  try {
20412
20737
  const dir = dirname6(filePath);
20413
- if (!existsSync27(dir)) {
20414
- mkdirSync10(dir, { recursive: true });
20738
+ if (!existsSync30(dir)) {
20739
+ mkdirSync11(dir, { recursive: true });
20415
20740
  }
20416
20741
  const sessionIdLine = state2.session_id ? `session_id: "${state2.session_id}"
20417
20742
  ` : "";
@@ -20426,7 +20751,7 @@ started_at: "${state2.started_at}"
20426
20751
  ${sessionIdLine}${ultraworkLine}---
20427
20752
  ${state2.prompt}
20428
20753
  `;
20429
- writeFileSync13(filePath, content, "utf-8");
20754
+ writeFileSync14(filePath, content, "utf-8");
20430
20755
  return true;
20431
20756
  } catch {
20432
20757
  return false;
@@ -20435,7 +20760,7 @@ ${state2.prompt}
20435
20760
  function clearState(directory, customPath) {
20436
20761
  const filePath = getStateFilePath(directory, customPath);
20437
20762
  try {
20438
- if (existsSync27(filePath)) {
20763
+ if (existsSync30(filePath)) {
20439
20764
  unlinkSync9(filePath);
20440
20765
  }
20441
20766
  return true;
@@ -20456,14 +20781,14 @@ function incrementIteration(directory, customPath) {
20456
20781
 
20457
20782
  // src/hooks/ralph-loop/index.ts
20458
20783
  function getMessageDir4(sessionID) {
20459
- if (!existsSync28(MESSAGE_STORAGE))
20784
+ if (!existsSync31(MESSAGE_STORAGE))
20460
20785
  return null;
20461
- const directPath = join38(MESSAGE_STORAGE, sessionID);
20462
- if (existsSync28(directPath))
20786
+ const directPath = join40(MESSAGE_STORAGE, sessionID);
20787
+ if (existsSync31(directPath))
20463
20788
  return directPath;
20464
- for (const dir of readdirSync6(MESSAGE_STORAGE)) {
20465
- const sessionPath = join38(MESSAGE_STORAGE, dir, sessionID);
20466
- if (existsSync28(sessionPath))
20789
+ for (const dir of readdirSync8(MESSAGE_STORAGE)) {
20790
+ const sessionPath = join40(MESSAGE_STORAGE, dir, sessionID);
20791
+ if (existsSync31(sessionPath))
20467
20792
  return sessionPath;
20468
20793
  }
20469
20794
  return null;
@@ -20500,9 +20825,9 @@ function createRalphLoopHook(ctx, options) {
20500
20825
  if (!transcriptPath)
20501
20826
  return false;
20502
20827
  try {
20503
- if (!existsSync28(transcriptPath))
20828
+ if (!existsSync31(transcriptPath))
20504
20829
  return false;
20505
- const content = readFileSync19(transcriptPath, "utf-8");
20830
+ const content = readFileSync20(transcriptPath, "utf-8");
20506
20831
  const pattern = new RegExp(`<promise>\\s*${escapeRegex(promise)}\\s*</promise>`, "is");
20507
20832
  const lines = content.split(`
20508
20833
  `).filter((l) => l.trim());
@@ -20816,8 +21141,8 @@ function extractPromptText3(parts) {
20816
21141
  // src/hooks/auto-slash-command/executor.ts
20817
21142
  init_shared();
20818
21143
  init_file_utils();
20819
- import { existsSync as existsSync30, readdirSync as readdirSync7, readFileSync as readFileSync22 } from "fs";
20820
- import { join as join40, basename as basename2, dirname as dirname8 } from "path";
21144
+ import { existsSync as existsSync33, readdirSync as readdirSync9, readFileSync as readFileSync23 } from "fs";
21145
+ import { join as join42, basename as basename2, dirname as dirname8 } from "path";
20821
21146
  // src/features/opencode-skill-loader/loader.ts
20822
21147
  init_js_yaml();
20823
21148
  init_frontmatter();
@@ -20825,7 +21150,7 @@ init_file_utils();
20825
21150
  init_shared();
20826
21151
  init_opencode_config_dir();
20827
21152
  import { promises as fs9 } from "fs";
20828
- import { join as join39, basename } from "path";
21153
+ import { join as join41, basename } from "path";
20829
21154
  function parseSkillMcpConfigFromFrontmatter(content) {
20830
21155
  const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
20831
21156
  if (!frontmatterMatch)
@@ -20841,7 +21166,7 @@ function parseSkillMcpConfigFromFrontmatter(content) {
20841
21166
  return;
20842
21167
  }
20843
21168
  async function loadMcpJsonFromDir(skillDir) {
20844
- const mcpJsonPath = join39(skillDir, "mcp.json");
21169
+ const mcpJsonPath = join41(skillDir, "mcp.json");
20845
21170
  try {
20846
21171
  const content = await fs9.readFile(mcpJsonPath, "utf-8");
20847
21172
  const parsed = JSON.parse(content);
@@ -20922,11 +21247,11 @@ async function loadSkillsFromDir(skillsDir, scope) {
20922
21247
  for (const entry of entries) {
20923
21248
  if (entry.name.startsWith("."))
20924
21249
  continue;
20925
- const entryPath = join39(skillsDir, entry.name);
21250
+ const entryPath = join41(skillsDir, entry.name);
20926
21251
  if (entry.isDirectory() || entry.isSymbolicLink()) {
20927
21252
  const resolvedPath = await resolveSymlinkAsync(entryPath);
20928
21253
  const dirName = entry.name;
20929
- const skillMdPath = join39(resolvedPath, "SKILL.md");
21254
+ const skillMdPath = join41(resolvedPath, "SKILL.md");
20930
21255
  try {
20931
21256
  await fs9.access(skillMdPath);
20932
21257
  const skill = await loadSkillFromPath(skillMdPath, resolvedPath, dirName, scope);
@@ -20934,7 +21259,7 @@ async function loadSkillsFromDir(skillsDir, scope) {
20934
21259
  skills.push(skill);
20935
21260
  continue;
20936
21261
  } catch {}
20937
- const namedSkillMdPath = join39(resolvedPath, `${dirName}.md`);
21262
+ const namedSkillMdPath = join41(resolvedPath, `${dirName}.md`);
20938
21263
  try {
20939
21264
  await fs9.access(namedSkillMdPath);
20940
21265
  const skill = await loadSkillFromPath(namedSkillMdPath, resolvedPath, dirName, scope);
@@ -20962,23 +21287,23 @@ function skillsToRecord(skills) {
20962
21287
  return result;
20963
21288
  }
20964
21289
  async function loadUserSkills() {
20965
- const userSkillsDir = join39(getClaudeConfigDir(), "skills");
21290
+ const userSkillsDir = join41(getClaudeConfigDir(), "skills");
20966
21291
  const skills = await loadSkillsFromDir(userSkillsDir, "user");
20967
21292
  return skillsToRecord(skills);
20968
21293
  }
20969
21294
  async function loadProjectSkills() {
20970
- const projectSkillsDir = join39(process.cwd(), ".claude", "skills");
21295
+ const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
20971
21296
  const skills = await loadSkillsFromDir(projectSkillsDir, "project");
20972
21297
  return skillsToRecord(skills);
20973
21298
  }
20974
21299
  async function loadOpencodeGlobalSkills() {
20975
21300
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
20976
- const opencodeSkillsDir = join39(configDir, "skills");
21301
+ const opencodeSkillsDir = join41(configDir, "skills");
20977
21302
  const skills = await loadSkillsFromDir(opencodeSkillsDir, "opencode");
20978
21303
  return skillsToRecord(skills);
20979
21304
  }
20980
21305
  async function loadOpencodeProjectSkills() {
20981
- const opencodeProjectDir = join39(process.cwd(), ".opencode", "skills");
21306
+ const opencodeProjectDir = join41(process.cwd(), ".opencode", "skills");
20982
21307
  const skills = await loadSkillsFromDir(opencodeProjectDir, "opencode-project");
20983
21308
  return skillsToRecord(skills);
20984
21309
  }
@@ -21007,28 +21332,29 @@ async function discoverSkills(options = {}) {
21007
21332
  return [...opencodeProjectSkills, ...projectSkills, ...opencodeGlobalSkills, ...userSkills];
21008
21333
  }
21009
21334
  async function discoverUserClaudeSkills() {
21010
- const userSkillsDir = join39(getClaudeConfigDir(), "skills");
21335
+ const userSkillsDir = join41(getClaudeConfigDir(), "skills");
21011
21336
  return loadSkillsFromDir(userSkillsDir, "user");
21012
21337
  }
21013
21338
  async function discoverProjectClaudeSkills() {
21014
- const projectSkillsDir = join39(process.cwd(), ".claude", "skills");
21339
+ const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
21015
21340
  return loadSkillsFromDir(projectSkillsDir, "project");
21016
21341
  }
21017
21342
  async function discoverOpencodeGlobalSkills() {
21018
21343
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
21019
- const opencodeSkillsDir = join39(configDir, "skills");
21344
+ const opencodeSkillsDir = join41(configDir, "skills");
21020
21345
  return loadSkillsFromDir(opencodeSkillsDir, "opencode");
21021
21346
  }
21022
21347
  async function discoverOpencodeProjectSkills() {
21023
- const opencodeProjectDir = join39(process.cwd(), ".opencode", "skills");
21348
+ const opencodeProjectDir = join41(process.cwd(), ".opencode", "skills");
21024
21349
  return loadSkillsFromDir(opencodeProjectDir, "opencode-project");
21025
21350
  }
21026
21351
  // src/features/opencode-skill-loader/merger.ts
21027
21352
  init_frontmatter();
21028
21353
  init_deep_merge();
21029
- import { readFileSync as readFileSync20, existsSync as existsSync29 } from "fs";
21354
+ import { readFileSync as readFileSync21, existsSync as existsSync32 } from "fs";
21030
21355
  import { dirname as dirname7, resolve as resolve6, isAbsolute as isAbsolute2 } from "path";
21031
21356
  import { homedir as homedir11 } from "os";
21357
+ import { createHash as createHash2 } from "crypto";
21032
21358
  var SCOPE_PRIORITY = {
21033
21359
  builtin: 1,
21034
21360
  config: 2,
@@ -21074,9 +21400,9 @@ function resolveFilePath2(from, configDir) {
21074
21400
  }
21075
21401
  function loadSkillFromFile(filePath) {
21076
21402
  try {
21077
- if (!existsSync29(filePath))
21403
+ if (!existsSync32(filePath))
21078
21404
  return null;
21079
- const content = readFileSync20(filePath, "utf-8");
21405
+ const content = readFileSync21(filePath, "utf-8");
21080
21406
  const { data, body } = parseFrontmatter(content);
21081
21407
  return { template: body, metadata: data };
21082
21408
  } catch {
@@ -21163,13 +21489,28 @@ function mergeSkillDefinitions(base, patch) {
21163
21489
  allowedTools: mergedTools ? [...new Set(mergedTools)] : undefined
21164
21490
  };
21165
21491
  }
21492
+ function contentHash(content) {
21493
+ return createHash2("md5").update(content).digest("hex").slice(0, 8);
21494
+ }
21495
+ function emptyDedupStats() {
21496
+ return { totalScanned: 0, unique: 0, skippedByScope: 0, skippedByContent: 0, byScope: {} };
21497
+ }
21166
21498
  function mergeSkills(builtinSkills, config, userClaudeSkills, userOpencodeSkills, projectClaudeSkills, projectOpencodeSkills, options = {}) {
21167
21499
  const skillMap = new Map;
21500
+ const contentHashes = new Map;
21501
+ const stats = emptyDedupStats();
21168
21502
  for (const builtin of builtinSkills) {
21169
21503
  const loaded = builtinToLoaded(builtin);
21170
21504
  skillMap.set(loaded.name, loaded);
21505
+ stats.byScope["builtin"] = (stats.byScope["builtin"] ?? 0) + 1;
21506
+ stats.unique++;
21507
+ if (loaded.definition.template) {
21508
+ contentHashes.set(loaded.name, contentHash(loaded.definition.template));
21509
+ }
21171
21510
  }
21511
+ stats.totalScanned += builtinSkills.length;
21172
21512
  const normalizedConfig = normalizeConfig(config);
21513
+ let configLoaded = 0;
21173
21514
  for (const [name, entry] of Object.entries(normalizedConfig.entries)) {
21174
21515
  if (entry === false)
21175
21516
  continue;
@@ -21184,9 +21525,18 @@ function mergeSkills(builtinSkills, config, userClaudeSkills, userOpencodeSkills
21184
21525
  skillMap.set(name, mergeSkillDefinitions(existing, entry));
21185
21526
  } else {
21186
21527
  skillMap.set(name, loaded);
21528
+ configLoaded++;
21529
+ stats.unique++;
21530
+ if (loaded.definition.template) {
21531
+ contentHashes.set(name, contentHash(loaded.definition.template));
21532
+ }
21187
21533
  }
21188
21534
  }
21189
21535
  }
21536
+ if (configLoaded > 0) {
21537
+ stats.byScope["config"] = configLoaded;
21538
+ stats.totalScanned += configLoaded;
21539
+ }
21190
21540
  const fileSystemSkills = [
21191
21541
  ...userClaudeSkills,
21192
21542
  ...userOpencodeSkills,
@@ -21194,10 +21544,30 @@ function mergeSkills(builtinSkills, config, userClaudeSkills, userOpencodeSkills
21194
21544
  ...projectOpencodeSkills
21195
21545
  ];
21196
21546
  for (const skill of fileSystemSkills) {
21547
+ stats.totalScanned++;
21548
+ stats.byScope[skill.scope] = (stats.byScope[skill.scope] ?? 0) + 1;
21197
21549
  const existing = skillMap.get(skill.name);
21198
- if (!existing || SCOPE_PRIORITY[skill.scope] > SCOPE_PRIORITY[existing.scope]) {
21199
- skillMap.set(skill.name, skill);
21550
+ const hash = skill.definition.template ? contentHash(skill.definition.template) : undefined;
21551
+ if (existing) {
21552
+ const existingHash = contentHashes.get(skill.name);
21553
+ if (hash && existingHash && hash === existingHash) {
21554
+ stats.skippedByContent++;
21555
+ continue;
21556
+ }
21557
+ if (SCOPE_PRIORITY[skill.scope] <= SCOPE_PRIORITY[existing.scope]) {
21558
+ stats.skippedByScope++;
21559
+ continue;
21560
+ }
21200
21561
  }
21562
+ skillMap.set(skill.name, skill);
21563
+ if (hash) {
21564
+ contentHashes.set(skill.name, hash);
21565
+ }
21566
+ stats.unique++;
21567
+ }
21568
+ if (stats.skippedByContent > 0 || stats.skippedByScope > 1) {
21569
+ const scopeSummary = Object.entries(stats.byScope).map(([scope, count]) => `${scope}:${count}`).join(", ");
21570
+ console.debug(`[skill-loader] Scanned ${stats.totalScanned} skills (${scopeSummary}), ` + `${stats.unique} loaded, ` + `${stats.skippedByContent} skipped (identical content), ` + `${stats.skippedByScope} skipped (lower priority scope)`);
21201
21571
  }
21202
21572
  for (const [name, entry] of Object.entries(normalizedConfig.entries)) {
21203
21573
  if (entry === true)
@@ -22423,7 +22793,7 @@ function createBuiltinSkills() {
22423
22793
 
22424
22794
  // src/features/opencode-skill-loader/skill-content.ts
22425
22795
  init_frontmatter();
22426
- import { readFileSync as readFileSync21 } from "fs";
22796
+ import { readFileSync as readFileSync22 } from "fs";
22427
22797
  var cachedSkills = null;
22428
22798
  async function getAllSkills() {
22429
22799
  if (cachedSkills)
@@ -22456,7 +22826,7 @@ async function getAllSkills() {
22456
22826
  }
22457
22827
  async function extractSkillTemplate(skill) {
22458
22828
  if (skill.path) {
22459
- const content = readFileSync21(skill.path, "utf-8");
22829
+ const content = readFileSync22(skill.path, "utf-8");
22460
22830
  const { body } = parseFrontmatter(content);
22461
22831
  return body.trim();
22462
22832
  }
@@ -22558,18 +22928,18 @@ async function resolveMultipleSkillsAsync(skillNames, options) {
22558
22928
  }
22559
22929
  // src/hooks/auto-slash-command/executor.ts
22560
22930
  function discoverCommandsFromDir(commandsDir, scope) {
22561
- if (!existsSync30(commandsDir)) {
22931
+ if (!existsSync33(commandsDir)) {
22562
22932
  return [];
22563
22933
  }
22564
- const entries = readdirSync7(commandsDir, { withFileTypes: true });
22934
+ const entries = readdirSync9(commandsDir, { withFileTypes: true });
22565
22935
  const commands = [];
22566
22936
  for (const entry of entries) {
22567
22937
  if (!isMarkdownFile(entry))
22568
22938
  continue;
22569
- const commandPath = join40(commandsDir, entry.name);
22939
+ const commandPath = join42(commandsDir, entry.name);
22570
22940
  const commandName = basename2(entry.name, ".md");
22571
22941
  try {
22572
- const content = readFileSync22(commandPath, "utf-8");
22942
+ const content = readFileSync23(commandPath, "utf-8");
22573
22943
  const { data, body } = parseFrontmatter(content);
22574
22944
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
22575
22945
  const metadata = {
@@ -22612,10 +22982,10 @@ function skillToCommandInfo(skill) {
22612
22982
  }
22613
22983
  async function discoverAllCommands(options) {
22614
22984
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
22615
- const userCommandsDir = join40(getClaudeConfigDir(), "commands");
22616
- const projectCommandsDir = join40(process.cwd(), ".claude", "commands");
22617
- const opencodeGlobalDir = join40(configDir, "command");
22618
- const opencodeProjectDir = join40(process.cwd(), ".opencode", "command");
22985
+ const userCommandsDir = join42(getClaudeConfigDir(), "commands");
22986
+ const projectCommandsDir = join42(process.cwd(), ".claude", "commands");
22987
+ const opencodeGlobalDir = join42(configDir, "command");
22988
+ const opencodeProjectDir = join42(process.cwd(), ".opencode", "command");
22619
22989
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
22620
22990
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
22621
22991
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -22785,8 +23155,8 @@ ${EDIT_ERROR_REMINDER}`;
22785
23155
  };
22786
23156
  }
22787
23157
  // src/hooks/prometheus-md-only/index.ts
22788
- import { existsSync as existsSync31, readdirSync as readdirSync8 } from "fs";
22789
- import { join as join41, resolve as resolve7, relative as relative4, isAbsolute as isAbsolute3 } from "path";
23158
+ import { existsSync as existsSync34, readdirSync as readdirSync10 } from "fs";
23159
+ import { join as join43, resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3 } from "path";
22790
23160
 
22791
23161
  // src/hooks/prometheus-md-only/constants.ts
22792
23162
  init_system_directive();
@@ -22891,7 +23261,7 @@ init_logger();
22891
23261
  init_system_directive();
22892
23262
  function isAllowedFile(filePath, workspaceRoot) {
22893
23263
  const resolved = resolve7(workspaceRoot, filePath);
22894
- const rel = relative4(workspaceRoot, resolved);
23264
+ const rel = relative5(workspaceRoot, resolved);
22895
23265
  if (rel.startsWith("..") || isAbsolute3(rel)) {
22896
23266
  return false;
22897
23267
  }
@@ -22905,14 +23275,14 @@ function isAllowedFile(filePath, workspaceRoot) {
22905
23275
  return true;
22906
23276
  }
22907
23277
  function getMessageDir5(sessionID) {
22908
- if (!existsSync31(MESSAGE_STORAGE))
23278
+ if (!existsSync34(MESSAGE_STORAGE))
22909
23279
  return null;
22910
- const directPath = join41(MESSAGE_STORAGE, sessionID);
22911
- if (existsSync31(directPath))
23280
+ const directPath = join43(MESSAGE_STORAGE, sessionID);
23281
+ if (existsSync34(directPath))
22912
23282
  return directPath;
22913
- for (const dir of readdirSync8(MESSAGE_STORAGE)) {
22914
- const sessionPath = join41(MESSAGE_STORAGE, dir, sessionID);
22915
- if (existsSync31(sessionPath))
23283
+ for (const dir of readdirSync10(MESSAGE_STORAGE)) {
23284
+ const sessionPath = join43(MESSAGE_STORAGE, dir, sessionID);
23285
+ if (existsSync34(sessionPath))
22916
23286
  return sessionPath;
22917
23287
  }
22918
23288
  return null;
@@ -23026,18 +23396,18 @@ var NOTEPAD_DIR = "notepads";
23026
23396
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
23027
23397
  var PROMETHEUS_PLANS_DIR = ".sisyphus/plans";
23028
23398
  // src/features/boulder-state/storage.ts
23029
- import { existsSync as existsSync32, readFileSync as readFileSync23, writeFileSync as writeFileSync14, mkdirSync as mkdirSync11, readdirSync as readdirSync9 } from "fs";
23030
- import { dirname as dirname9, join as join42, basename as basename3 } from "path";
23399
+ import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync11 } from "fs";
23400
+ import { dirname as dirname9, join as join44, basename as basename3 } from "path";
23031
23401
  function getBoulderFilePath(directory) {
23032
- return join42(directory, BOULDER_DIR, BOULDER_FILE);
23402
+ return join44(directory, BOULDER_DIR, BOULDER_FILE);
23033
23403
  }
23034
23404
  function readBoulderState(directory) {
23035
23405
  const filePath = getBoulderFilePath(directory);
23036
- if (!existsSync32(filePath)) {
23406
+ if (!existsSync35(filePath)) {
23037
23407
  return null;
23038
23408
  }
23039
23409
  try {
23040
- const content = readFileSync23(filePath, "utf-8");
23410
+ const content = readFileSync24(filePath, "utf-8");
23041
23411
  return JSON.parse(content);
23042
23412
  } catch {
23043
23413
  return null;
@@ -23047,10 +23417,10 @@ function writeBoulderState(directory, state2) {
23047
23417
  const filePath = getBoulderFilePath(directory);
23048
23418
  try {
23049
23419
  const dir = dirname9(filePath);
23050
- if (!existsSync32(dir)) {
23051
- mkdirSync11(dir, { recursive: true });
23420
+ if (!existsSync35(dir)) {
23421
+ mkdirSync12(dir, { recursive: true });
23052
23422
  }
23053
- writeFileSync14(filePath, JSON.stringify(state2, null, 2), "utf-8");
23423
+ writeFileSync15(filePath, JSON.stringify(state2, null, 2), "utf-8");
23054
23424
  return true;
23055
23425
  } catch {
23056
23426
  return false;
@@ -23071,7 +23441,7 @@ function appendSessionId(directory, sessionId) {
23071
23441
  function clearBoulderState(directory) {
23072
23442
  const filePath = getBoulderFilePath(directory);
23073
23443
  try {
23074
- if (existsSync32(filePath)) {
23444
+ if (existsSync35(filePath)) {
23075
23445
  const { unlinkSync: unlinkSync10 } = __require("fs");
23076
23446
  unlinkSync10(filePath);
23077
23447
  }
@@ -23081,13 +23451,13 @@ function clearBoulderState(directory) {
23081
23451
  }
23082
23452
  }
23083
23453
  function findPrometheusPlans(directory) {
23084
- const plansDir = join42(directory, PROMETHEUS_PLANS_DIR);
23085
- if (!existsSync32(plansDir)) {
23454
+ const plansDir = join44(directory, PROMETHEUS_PLANS_DIR);
23455
+ if (!existsSync35(plansDir)) {
23086
23456
  return [];
23087
23457
  }
23088
23458
  try {
23089
- const files = readdirSync9(plansDir);
23090
- return files.filter((f) => f.endsWith(".md")).map((f) => join42(plansDir, f)).sort((a, b) => {
23459
+ const files = readdirSync11(plansDir);
23460
+ return files.filter((f) => f.endsWith(".md")).map((f) => join44(plansDir, f)).sort((a, b) => {
23091
23461
  const aStat = __require("fs").statSync(a);
23092
23462
  const bStat = __require("fs").statSync(b);
23093
23463
  return bStat.mtimeMs - aStat.mtimeMs;
@@ -23097,11 +23467,11 @@ function findPrometheusPlans(directory) {
23097
23467
  }
23098
23468
  }
23099
23469
  function getPlanProgress(planPath) {
23100
- if (!existsSync32(planPath)) {
23470
+ if (!existsSync35(planPath)) {
23101
23471
  return { total: 0, completed: 0, isComplete: true };
23102
23472
  }
23103
23473
  try {
23104
- const content = readFileSync23(planPath, "utf-8");
23474
+ const content = readFileSync24(planPath, "utf-8");
23105
23475
  const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || [];
23106
23476
  const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || [];
23107
23477
  const total = uncheckedMatches.length + checkedMatches.length;
@@ -23318,8 +23688,8 @@ ${contextInfo}`;
23318
23688
  }
23319
23689
  // src/hooks/atlas/index.ts
23320
23690
  import { execSync } from "child_process";
23321
- import { existsSync as existsSync33, readdirSync as readdirSync10 } from "fs";
23322
- import { join as join43 } from "path";
23691
+ import { existsSync as existsSync36, readdirSync as readdirSync12 } from "fs";
23692
+ import { join as join45 } from "path";
23323
23693
  init_logger();
23324
23694
  init_system_directive();
23325
23695
  var HOOK_NAME6 = "atlas";
@@ -23648,14 +24018,14 @@ function formatFileChanges(stats, notepadPath) {
23648
24018
  `);
23649
24019
  }
23650
24020
  function getMessageDir6(sessionID) {
23651
- if (!existsSync33(MESSAGE_STORAGE))
24021
+ if (!existsSync36(MESSAGE_STORAGE))
23652
24022
  return null;
23653
- const directPath = join43(MESSAGE_STORAGE, sessionID);
23654
- if (existsSync33(directPath))
24023
+ const directPath = join45(MESSAGE_STORAGE, sessionID);
24024
+ if (existsSync36(directPath))
23655
24025
  return directPath;
23656
- for (const dir of readdirSync10(MESSAGE_STORAGE)) {
23657
- const sessionPath = join43(MESSAGE_STORAGE, dir, sessionID);
23658
- if (existsSync33(sessionPath))
24026
+ for (const dir of readdirSync12(MESSAGE_STORAGE)) {
24027
+ const sessionPath = join45(MESSAGE_STORAGE, dir, sessionID);
24028
+ if (existsSync36(sessionPath))
23659
24029
  return sessionPath;
23660
24030
  }
23661
24031
  return null;
@@ -24009,7 +24379,7 @@ var DELEGATE_TASK_ERROR_PATTERNS = [
24009
24379
  }
24010
24380
  ];
24011
24381
  function detectDelegateTaskError(output) {
24012
- if (!output.includes("[ERROR]") && !output.includes("Invalid arguments"))
24382
+ if (!output.includes("[ERROR]") && !output.includes("Invalid arguments") && !output.includes("\u53C2\u6570\u9519\u8BEF\uFF1A"))
24013
24383
  return null;
24014
24384
  for (const errorPattern of DELEGATE_TASK_ERROR_PATTERNS) {
24015
24385
  if (output.includes(errorPattern.pattern)) {
@@ -24109,6 +24479,28 @@ function createQuestionLabelTruncatorHook() {
24109
24479
  }
24110
24480
  };
24111
24481
  }
24482
+ // src/hooks/perf-profiler/index.ts
24483
+ function createPerfProfilerHook(options) {
24484
+ return {
24485
+ event: async (input) => {
24486
+ if (input.event.type === "message.part.updated")
24487
+ return;
24488
+ const tracer = options.tracer;
24489
+ if (!tracer.isEnabled())
24490
+ return;
24491
+ const mapSizes = {};
24492
+ for (const [name, fn] of Object.entries(options.memoryProbes ?? {})) {
24493
+ try {
24494
+ mapSizes[name] = fn();
24495
+ } catch {}
24496
+ }
24497
+ tracer.snapshotMemory(input.event.type, mapSizes);
24498
+ },
24499
+ "tool.execute.before": async () => {},
24500
+ "tool.execute.after": async () => {},
24501
+ "chat.message": async () => {}
24502
+ };
24503
+ }
24112
24504
  // src/features/context-injector/collector.ts
24113
24505
  var PRIORITY_ORDER = {
24114
24506
  critical: 0,
@@ -24282,8 +24674,8 @@ function createFirstMessageVariantGate() {
24282
24674
  }
24283
24675
  // src/features/claude-code-mcp-loader/loader.ts
24284
24676
  init_shared();
24285
- import { existsSync as existsSync34, readFileSync as readFileSync24 } from "fs";
24286
- import { join as join44 } from "path";
24677
+ import { existsSync as existsSync37, readFileSync as readFileSync25 } from "fs";
24678
+ import { join as join46 } from "path";
24287
24679
 
24288
24680
  // src/features/claude-code-mcp-loader/env-expander.ts
24289
24681
  function expandEnvVars(value) {
@@ -24351,15 +24743,15 @@ function transformMcpServer(name, server) {
24351
24743
  init_logger();
24352
24744
  function getMcpConfigPaths() {
24353
24745
  const claudeConfigDir = getClaudeConfigDir();
24354
- const cwd = process.cwd();
24746
+ const cwd2 = process.cwd();
24355
24747
  return [
24356
- { path: join44(claudeConfigDir, ".mcp.json"), scope: "user" },
24357
- { path: join44(cwd, ".mcp.json"), scope: "project" },
24358
- { path: join44(cwd, ".claude", ".mcp.json"), scope: "local" }
24748
+ { path: join46(claudeConfigDir, ".mcp.json"), scope: "user" },
24749
+ { path: join46(cwd2, ".mcp.json"), scope: "project" },
24750
+ { path: join46(cwd2, ".claude", ".mcp.json"), scope: "local" }
24359
24751
  ];
24360
24752
  }
24361
24753
  async function loadMcpConfigFile(filePath) {
24362
- if (!existsSync34(filePath)) {
24754
+ if (!existsSync37(filePath)) {
24363
24755
  return null;
24364
24756
  }
24365
24757
  try {
@@ -24374,10 +24766,10 @@ function getSystemMcpServerNames() {
24374
24766
  const names = new Set;
24375
24767
  const paths = getMcpConfigPaths();
24376
24768
  for (const { path: path7 } of paths) {
24377
- if (!existsSync34(path7))
24769
+ if (!existsSync37(path7))
24378
24770
  continue;
24379
24771
  try {
24380
- const content = readFileSync24(path7, "utf-8");
24772
+ const content = readFileSync25(path7, "utf-8");
24381
24773
  const config = JSON.parse(content);
24382
24774
  if (!config?.mcpServers)
24383
24775
  continue;
@@ -24820,25 +25212,25 @@ var EXT_TO_LANG = {
24820
25212
  ".gql": "graphql"
24821
25213
  };
24822
25214
  // src/tools/lsp/config.ts
24823
- import { existsSync as existsSync35, readFileSync as readFileSync25 } from "fs";
24824
- import { join as join45 } from "path";
25215
+ import { existsSync as existsSync38, readFileSync as readFileSync26 } from "fs";
25216
+ import { join as join47 } from "path";
24825
25217
  init_shared();
24826
25218
  function loadJsonFile(path7) {
24827
- if (!existsSync35(path7))
25219
+ if (!existsSync38(path7))
24828
25220
  return null;
24829
25221
  try {
24830
- return JSON.parse(readFileSync25(path7, "utf-8"));
25222
+ return JSON.parse(readFileSync26(path7, "utf-8"));
24831
25223
  } catch {
24832
25224
  return null;
24833
25225
  }
24834
25226
  }
24835
25227
  function getConfigPaths3() {
24836
- const cwd = process.cwd();
25228
+ const cwd2 = process.cwd();
24837
25229
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
24838
25230
  return {
24839
- project: join45(cwd, ".opencode", "oh-my-opencode.json"),
24840
- user: join45(configDir, "oh-my-opencode.json"),
24841
- opencode: join45(configDir, "opencode.json")
25231
+ project: join47(cwd2, ".opencode", "oh-my-opencode.json"),
25232
+ user: join47(configDir, "oh-my-opencode.json"),
25233
+ opencode: join47(configDir, "opencode.json")
24842
25234
  };
24843
25235
  }
24844
25236
  function loadAllConfigs() {
@@ -24951,7 +25343,7 @@ function isServerInstalled(command) {
24951
25343
  return false;
24952
25344
  const cmd = command[0];
24953
25345
  if (cmd.includes("/") || cmd.includes("\\")) {
24954
- if (existsSync35(cmd))
25346
+ if (existsSync38(cmd))
24955
25347
  return true;
24956
25348
  }
24957
25349
  const isWindows2 = process.platform === "win32";
@@ -24973,23 +25365,23 @@ function isServerInstalled(command) {
24973
25365
  const paths = pathEnv.split(pathSeparator);
24974
25366
  for (const p of paths) {
24975
25367
  for (const suffix of exts) {
24976
- if (existsSync35(join45(p, cmd + suffix))) {
25368
+ if (existsSync38(join47(p, cmd + suffix))) {
24977
25369
  return true;
24978
25370
  }
24979
25371
  }
24980
25372
  }
24981
- const cwd = process.cwd();
25373
+ const cwd2 = process.cwd();
24982
25374
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
24983
- const dataDir = join45(getDataDir(), "opencode");
25375
+ const dataDir = join47(getDataDir(), "opencode");
24984
25376
  const additionalBases = [
24985
- join45(cwd, "node_modules", ".bin"),
24986
- join45(configDir, "bin"),
24987
- join45(configDir, "node_modules", ".bin"),
24988
- join45(dataDir, "bin")
25377
+ join47(cwd2, "node_modules", ".bin"),
25378
+ join47(configDir, "bin"),
25379
+ join47(configDir, "node_modules", ".bin"),
25380
+ join47(dataDir, "bin")
24989
25381
  ];
24990
25382
  for (const base of additionalBases) {
24991
25383
  for (const suffix of exts) {
24992
- if (existsSync35(join45(base, cmd + suffix))) {
25384
+ if (existsSync38(join47(base, cmd + suffix))) {
24993
25385
  return true;
24994
25386
  }
24995
25387
  }
@@ -25001,7 +25393,7 @@ function isServerInstalled(command) {
25001
25393
  }
25002
25394
  // src/tools/lsp/client.ts
25003
25395
  var {spawn: spawn6 } = globalThis.Bun;
25004
- import { readFileSync as readFileSync26 } from "fs";
25396
+ import { readFileSync as readFileSync27 } from "fs";
25005
25397
  import { extname, resolve as resolve8 } from "path";
25006
25398
  import { pathToFileURL } from "url";
25007
25399
  class LSPServerManager {
@@ -25451,7 +25843,7 @@ ${msg}`);
25451
25843
  const absPath = resolve8(filePath);
25452
25844
  if (this.openedFiles.has(absPath))
25453
25845
  return;
25454
- const text = readFileSync26(absPath, "utf-8");
25846
+ const text = readFileSync27(absPath, "utf-8");
25455
25847
  const ext = extname(absPath);
25456
25848
  const languageId = getLanguageId(ext);
25457
25849
  this.notify("textDocument/didOpen", {
@@ -25541,17 +25933,17 @@ ${msg}`);
25541
25933
  // src/tools/lsp/utils.ts
25542
25934
  import { extname as extname2, resolve as resolve9 } from "path";
25543
25935
  import { fileURLToPath as fileURLToPath2 } from "url";
25544
- import { existsSync as existsSync36, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "fs";
25936
+ import { existsSync as existsSync39, readFileSync as readFileSync28, writeFileSync as writeFileSync16 } from "fs";
25545
25937
  function findWorkspaceRoot(filePath) {
25546
25938
  let dir = resolve9(filePath);
25547
- if (!existsSync36(dir) || !__require("fs").statSync(dir).isDirectory()) {
25939
+ if (!existsSync39(dir) || !__require("fs").statSync(dir).isDirectory()) {
25548
25940
  dir = __require("path").dirname(dir);
25549
25941
  }
25550
25942
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
25551
25943
  let prevDir = "";
25552
25944
  while (dir !== prevDir) {
25553
25945
  for (const marker of markers) {
25554
- if (existsSync36(__require("path").join(dir, marker))) {
25946
+ if (existsSync39(__require("path").join(dir, marker))) {
25555
25947
  return dir;
25556
25948
  }
25557
25949
  }
@@ -25706,7 +26098,7 @@ function formatPrepareRenameResult(result) {
25706
26098
  }
25707
26099
  function applyTextEditsToFile(filePath, edits) {
25708
26100
  try {
25709
- let content = readFileSync27(filePath, "utf-8");
26101
+ let content = readFileSync28(filePath, "utf-8");
25710
26102
  const lines = content.split(`
25711
26103
  `);
25712
26104
  const sortedEdits = [...edits].sort((a, b) => {
@@ -25731,7 +26123,7 @@ function applyTextEditsToFile(filePath, edits) {
25731
26123
  `));
25732
26124
  }
25733
26125
  }
25734
- writeFileSync15(filePath, lines.join(`
26126
+ writeFileSync16(filePath, lines.join(`
25735
26127
  `), "utf-8");
25736
26128
  return { success: true, editCount: edits.length };
25737
26129
  } catch (err) {
@@ -25762,7 +26154,7 @@ function applyWorkspaceEdit(edit) {
25762
26154
  if (change.kind === "create") {
25763
26155
  try {
25764
26156
  const filePath = uriToPath(change.uri);
25765
- writeFileSync15(filePath, "", "utf-8");
26157
+ writeFileSync16(filePath, "", "utf-8");
25766
26158
  result.filesModified.push(filePath);
25767
26159
  } catch (err) {
25768
26160
  result.success = false;
@@ -25772,8 +26164,8 @@ function applyWorkspaceEdit(edit) {
25772
26164
  try {
25773
26165
  const oldPath = uriToPath(change.oldUri);
25774
26166
  const newPath = uriToPath(change.newUri);
25775
- const content = readFileSync27(oldPath, "utf-8");
25776
- writeFileSync15(newPath, content, "utf-8");
26167
+ const content = readFileSync28(oldPath, "utf-8");
26168
+ writeFileSync16(newPath, content, "utf-8");
25777
26169
  __require("fs").unlinkSync(oldPath);
25778
26170
  result.filesModified.push(newPath);
25779
26171
  } catch (err) {
@@ -38352,13 +38744,13 @@ var lsp_rename = tool({
38352
38744
  });
38353
38745
  // src/tools/ast-grep/constants.ts
38354
38746
  import { createRequire as createRequire4 } from "module";
38355
- import { dirname as dirname10, join as join47 } from "path";
38356
- import { existsSync as existsSync38, statSync as statSync4 } from "fs";
38747
+ import { dirname as dirname10, join as join49 } from "path";
38748
+ import { existsSync as existsSync41, statSync as statSync4 } from "fs";
38357
38749
 
38358
38750
  // src/tools/ast-grep/downloader.ts
38359
38751
  init_shared();
38360
- import { existsSync as existsSync37, mkdirSync as mkdirSync12, chmodSync as chmodSync2, unlinkSync as unlinkSync10 } from "fs";
38361
- import { join as join46 } from "path";
38752
+ import { existsSync as existsSync40, mkdirSync as mkdirSync13, chmodSync as chmodSync2, unlinkSync as unlinkSync10 } from "fs";
38753
+ import { join as join48 } from "path";
38362
38754
  import { homedir as homedir12 } from "os";
38363
38755
  import { createRequire as createRequire3 } from "module";
38364
38756
  var REPO2 = "ast-grep/ast-grep";
@@ -38384,19 +38776,19 @@ var PLATFORM_MAP2 = {
38384
38776
  function getCacheDir3() {
38385
38777
  if (process.platform === "win32") {
38386
38778
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
38387
- const base2 = localAppData || join46(homedir12(), "AppData", "Local");
38388
- return join46(base2, "oh-my-opencode", "bin");
38779
+ const base2 = localAppData || join48(homedir12(), "AppData", "Local");
38780
+ return join48(base2, "oh-my-opencode", "bin");
38389
38781
  }
38390
38782
  const xdgCache = process.env.XDG_CACHE_HOME;
38391
- const base = xdgCache || join46(homedir12(), ".cache");
38392
- return join46(base, "oh-my-opencode", "bin");
38783
+ const base = xdgCache || join48(homedir12(), ".cache");
38784
+ return join48(base, "oh-my-opencode", "bin");
38393
38785
  }
38394
38786
  function getBinaryName3() {
38395
38787
  return process.platform === "win32" ? "sg.exe" : "sg";
38396
38788
  }
38397
38789
  function getCachedBinaryPath2() {
38398
- const binaryPath = join46(getCacheDir3(), getBinaryName3());
38399
- return existsSync37(binaryPath) ? binaryPath : null;
38790
+ const binaryPath = join48(getCacheDir3(), getBinaryName3());
38791
+ return existsSync40(binaryPath) ? binaryPath : null;
38400
38792
  }
38401
38793
  async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38402
38794
  const platformKey = `${process.platform}-${process.arch}`;
@@ -38407,8 +38799,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38407
38799
  }
38408
38800
  const cacheDir = getCacheDir3();
38409
38801
  const binaryName = getBinaryName3();
38410
- const binaryPath = join46(cacheDir, binaryName);
38411
- if (existsSync37(binaryPath)) {
38802
+ const binaryPath = join48(cacheDir, binaryName);
38803
+ if (existsSync40(binaryPath)) {
38412
38804
  return binaryPath;
38413
38805
  }
38414
38806
  const { arch, os: os6 } = platformInfo;
@@ -38416,21 +38808,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38416
38808
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
38417
38809
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
38418
38810
  try {
38419
- if (!existsSync37(cacheDir)) {
38420
- mkdirSync12(cacheDir, { recursive: true });
38811
+ if (!existsSync40(cacheDir)) {
38812
+ mkdirSync13(cacheDir, { recursive: true });
38421
38813
  }
38422
38814
  const response = await fetch(downloadUrl, { redirect: "follow" });
38423
38815
  if (!response.ok) {
38424
38816
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
38425
38817
  }
38426
- const archivePath = join46(cacheDir, assetName);
38818
+ const archivePath = join48(cacheDir, assetName);
38427
38819
  const arrayBuffer = await response.arrayBuffer();
38428
38820
  await Bun.write(archivePath, arrayBuffer);
38429
38821
  await extractZip(archivePath, cacheDir);
38430
- if (existsSync37(archivePath)) {
38822
+ if (existsSync40(archivePath)) {
38431
38823
  unlinkSync10(archivePath);
38432
38824
  }
38433
- if (process.platform !== "win32" && existsSync37(binaryPath)) {
38825
+ if (process.platform !== "win32" && existsSync40(binaryPath)) {
38434
38826
  chmodSync2(binaryPath, 493);
38435
38827
  }
38436
38828
  console.log(`[oh-my-opencode] ast-grep binary ready.`);
@@ -38481,8 +38873,8 @@ function findSgCliPathSync() {
38481
38873
  const require2 = createRequire4(import.meta.url);
38482
38874
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
38483
38875
  const cliDir = dirname10(cliPkgPath);
38484
- const sgPath = join47(cliDir, binaryName);
38485
- if (existsSync38(sgPath) && isValidBinary(sgPath)) {
38876
+ const sgPath = join49(cliDir, binaryName);
38877
+ if (existsSync41(sgPath) && isValidBinary(sgPath)) {
38486
38878
  return sgPath;
38487
38879
  }
38488
38880
  } catch {}
@@ -38493,8 +38885,8 @@ function findSgCliPathSync() {
38493
38885
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
38494
38886
  const pkgDir = dirname10(pkgPath);
38495
38887
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
38496
- const binaryPath = join47(pkgDir, astGrepName);
38497
- if (existsSync38(binaryPath) && isValidBinary(binaryPath)) {
38888
+ const binaryPath = join49(pkgDir, astGrepName);
38889
+ if (existsSync41(binaryPath) && isValidBinary(binaryPath)) {
38498
38890
  return binaryPath;
38499
38891
  }
38500
38892
  } catch {}
@@ -38502,7 +38894,7 @@ function findSgCliPathSync() {
38502
38894
  if (process.platform === "darwin") {
38503
38895
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
38504
38896
  for (const path7 of homebrewPaths) {
38505
- if (existsSync38(path7) && isValidBinary(path7)) {
38897
+ if (existsSync41(path7) && isValidBinary(path7)) {
38506
38898
  return path7;
38507
38899
  }
38508
38900
  }
@@ -38557,11 +38949,11 @@ var DEFAULT_MAX_MATCHES = 500;
38557
38949
 
38558
38950
  // src/tools/ast-grep/cli.ts
38559
38951
  var {spawn: spawn7 } = globalThis.Bun;
38560
- import { existsSync as existsSync39 } from "fs";
38952
+ import { existsSync as existsSync42 } from "fs";
38561
38953
  var resolvedCliPath3 = null;
38562
38954
  var initPromise2 = null;
38563
38955
  async function getAstGrepPath() {
38564
- if (resolvedCliPath3 !== null && existsSync39(resolvedCliPath3)) {
38956
+ if (resolvedCliPath3 !== null && existsSync42(resolvedCliPath3)) {
38565
38957
  return resolvedCliPath3;
38566
38958
  }
38567
38959
  if (initPromise2) {
@@ -38569,7 +38961,7 @@ async function getAstGrepPath() {
38569
38961
  }
38570
38962
  initPromise2 = (async () => {
38571
38963
  const syncPath = findSgCliPathSync();
38572
- if (syncPath && existsSync39(syncPath)) {
38964
+ if (syncPath && existsSync42(syncPath)) {
38573
38965
  resolvedCliPath3 = syncPath;
38574
38966
  setSgCliPath(syncPath);
38575
38967
  return syncPath;
@@ -38603,7 +38995,7 @@ async function runSg(options) {
38603
38995
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
38604
38996
  args.push(...paths);
38605
38997
  let cliPath = getSgCliPath();
38606
- if (!existsSync39(cliPath) && cliPath !== "sg") {
38998
+ if (!existsSync42(cliPath) && cliPath !== "sg") {
38607
38999
  const downloadedPath = await getAstGrepPath();
38608
39000
  if (downloadedPath) {
38609
39001
  cliPath = downloadedPath;
@@ -38867,21 +39259,21 @@ var ast_grep_replace = tool({
38867
39259
  var {spawn: spawn9 } = globalThis.Bun;
38868
39260
 
38869
39261
  // src/tools/grep/constants.ts
38870
- import { existsSync as existsSync41 } from "fs";
38871
- import { join as join49, dirname as dirname11 } from "path";
39262
+ import { existsSync as existsSync44 } from "fs";
39263
+ import { join as join51, dirname as dirname11 } from "path";
38872
39264
  import { spawnSync as spawnSync2 } from "child_process";
38873
39265
 
38874
39266
  // src/tools/grep/downloader.ts
38875
39267
  init_shared();
38876
- import { existsSync as existsSync40, mkdirSync as mkdirSync13, chmodSync as chmodSync3, unlinkSync as unlinkSync11, readdirSync as readdirSync11 } from "fs";
38877
- import { join as join48 } from "path";
39268
+ import { existsSync as existsSync43, mkdirSync as mkdirSync14, chmodSync as chmodSync3, unlinkSync as unlinkSync11, readdirSync as readdirSync13 } from "fs";
39269
+ import { join as join50 } from "path";
38878
39270
  var {spawn: spawn8 } = globalThis.Bun;
38879
39271
  function findFileRecursive(dir, filename) {
38880
39272
  try {
38881
- const entries = readdirSync11(dir, { withFileTypes: true, recursive: true });
39273
+ const entries = readdirSync13(dir, { withFileTypes: true, recursive: true });
38882
39274
  for (const entry of entries) {
38883
39275
  if (entry.isFile() && entry.name === filename) {
38884
- return join48(entry.parentPath ?? dir, entry.name);
39276
+ return join50(entry.parentPath ?? dir, entry.name);
38885
39277
  }
38886
39278
  }
38887
39279
  } catch {
@@ -38902,11 +39294,11 @@ function getPlatformKey() {
38902
39294
  }
38903
39295
  function getInstallDir() {
38904
39296
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
38905
- return join48(homeDir, ".cache", "oh-my-opencode", "bin");
39297
+ return join50(homeDir, ".cache", "oh-my-opencode", "bin");
38906
39298
  }
38907
39299
  function getRgPath() {
38908
39300
  const isWindows2 = process.platform === "win32";
38909
- return join48(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
39301
+ return join50(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
38910
39302
  }
38911
39303
  async function downloadFile(url2, destPath) {
38912
39304
  const response = await fetch(url2);
@@ -38940,7 +39332,7 @@ async function extractZip2(archivePath, destDir) {
38940
39332
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
38941
39333
  const foundPath = findFileRecursive(destDir, binaryName);
38942
39334
  if (foundPath) {
38943
- const destPath = join48(destDir, binaryName);
39335
+ const destPath = join50(destDir, binaryName);
38944
39336
  if (foundPath !== destPath) {
38945
39337
  const { renameSync } = await import("fs");
38946
39338
  renameSync(foundPath, destPath);
@@ -38955,13 +39347,13 @@ async function downloadAndInstallRipgrep() {
38955
39347
  }
38956
39348
  const installDir = getInstallDir();
38957
39349
  const rgPath = getRgPath();
38958
- if (existsSync40(rgPath)) {
39350
+ if (existsSync43(rgPath)) {
38959
39351
  return rgPath;
38960
39352
  }
38961
- mkdirSync13(installDir, { recursive: true });
39353
+ mkdirSync14(installDir, { recursive: true });
38962
39354
  const filename = `ripgrep-${RG_VERSION}-${config3.platform}.${config3.extension}`;
38963
39355
  const url2 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
38964
- const archivePath = join48(installDir, filename);
39356
+ const archivePath = join50(installDir, filename);
38965
39357
  try {
38966
39358
  await downloadFile(url2, archivePath);
38967
39359
  if (config3.extension === "tar.gz") {
@@ -38972,12 +39364,12 @@ async function downloadAndInstallRipgrep() {
38972
39364
  if (process.platform !== "win32") {
38973
39365
  chmodSync3(rgPath, 493);
38974
39366
  }
38975
- if (!existsSync40(rgPath)) {
39367
+ if (!existsSync43(rgPath)) {
38976
39368
  throw new Error("ripgrep binary not found after extraction");
38977
39369
  }
38978
39370
  return rgPath;
38979
39371
  } finally {
38980
- if (existsSync40(archivePath)) {
39372
+ if (existsSync43(archivePath)) {
38981
39373
  try {
38982
39374
  unlinkSync11(archivePath);
38983
39375
  } catch {}
@@ -38986,7 +39378,7 @@ async function downloadAndInstallRipgrep() {
38986
39378
  }
38987
39379
  function getInstalledRipgrepPath() {
38988
39380
  const rgPath = getRgPath();
38989
- return existsSync40(rgPath) ? rgPath : null;
39381
+ return existsSync43(rgPath) ? rgPath : null;
38990
39382
  }
38991
39383
 
38992
39384
  // src/tools/grep/constants.ts
@@ -39011,14 +39403,14 @@ function getOpenCodeBundledRg() {
39011
39403
  const isWindows2 = process.platform === "win32";
39012
39404
  const rgName = isWindows2 ? "rg.exe" : "rg";
39013
39405
  const candidates = [
39014
- join49(getDataDir(), "opencode", "bin", rgName),
39015
- join49(execDir, rgName),
39016
- join49(execDir, "bin", rgName),
39017
- join49(execDir, "..", "bin", rgName),
39018
- join49(execDir, "..", "libexec", rgName)
39406
+ join51(getDataDir(), "opencode", "bin", rgName),
39407
+ join51(execDir, rgName),
39408
+ join51(execDir, "bin", rgName),
39409
+ join51(execDir, "..", "bin", rgName),
39410
+ join51(execDir, "..", "libexec", rgName)
39019
39411
  ];
39020
39412
  for (const candidate of candidates) {
39021
- if (existsSync41(candidate)) {
39413
+ if (existsSync44(candidate)) {
39022
39414
  return candidate;
39023
39415
  }
39024
39416
  }
@@ -39355,26 +39747,26 @@ async function runRgFiles(options, resolvedCli) {
39355
39747
  const isRg = cli.backend === "rg";
39356
39748
  const isWindows2 = process.platform === "win32";
39357
39749
  let command;
39358
- let cwd;
39750
+ let cwd2;
39359
39751
  if (isRg) {
39360
39752
  const args = buildRgArgs2(options);
39361
39753
  const paths = options.paths?.length ? options.paths : ["."];
39362
39754
  args.push(...paths);
39363
39755
  command = [cli.path, ...args];
39364
- cwd = undefined;
39756
+ cwd2 = undefined;
39365
39757
  } else if (isWindows2) {
39366
39758
  command = buildPowerShellCommand(options);
39367
- cwd = undefined;
39759
+ cwd2 = undefined;
39368
39760
  } else {
39369
39761
  const args = buildFindArgs(options);
39370
39762
  const paths = options.paths?.length ? options.paths : ["."];
39371
- cwd = paths[0] || ".";
39763
+ cwd2 = paths[0] || ".";
39372
39764
  command = [cli.path, ...args];
39373
39765
  }
39374
39766
  const proc = spawn10(command, {
39375
39767
  stdout: "pipe",
39376
39768
  stderr: "pipe",
39377
- cwd
39769
+ cwd: cwd2
39378
39770
  });
39379
39771
  const timeoutPromise = new Promise((_, reject) => {
39380
39772
  const id = setTimeout(() => {
@@ -39412,7 +39804,7 @@ async function runRgFiles(options, resolvedCli) {
39412
39804
  } else if (isWindows2) {
39413
39805
  filePath = line.trim();
39414
39806
  } else {
39415
- filePath = `${cwd}/${line}`;
39807
+ filePath = `${cwd2}/${line}`;
39416
39808
  }
39417
39809
  const mtime = await getFileMtime(filePath);
39418
39810
  files.push({ path: filePath, mtime });
@@ -39480,8 +39872,8 @@ var glob = tool({
39480
39872
  init_shared();
39481
39873
  init_file_utils();
39482
39874
  init_shared();
39483
- import { existsSync as existsSync42, readdirSync as readdirSync12, readFileSync as readFileSync28 } from "fs";
39484
- import { join as join50, basename as basename4, dirname as dirname12 } from "path";
39875
+ import { existsSync as existsSync45, readdirSync as readdirSync14, readFileSync as readFileSync29 } from "fs";
39876
+ import { join as join52, basename as basename4, dirname as dirname12 } from "path";
39485
39877
  // src/features/builtin-commands/templates/init-deep.ts
39486
39878
  var INIT_DEEP_TEMPLATE = `# /init-deep
39487
39879
 
@@ -40597,18 +40989,18 @@ function loadBuiltinCommands(disabledCommands) {
40597
40989
  }
40598
40990
  // src/tools/slashcommand/tools.ts
40599
40991
  function discoverCommandsFromDir2(commandsDir, scope) {
40600
- if (!existsSync42(commandsDir)) {
40992
+ if (!existsSync45(commandsDir)) {
40601
40993
  return [];
40602
40994
  }
40603
- const entries = readdirSync12(commandsDir, { withFileTypes: true });
40995
+ const entries = readdirSync14(commandsDir, { withFileTypes: true });
40604
40996
  const commands2 = [];
40605
40997
  for (const entry of entries) {
40606
40998
  if (!isMarkdownFile(entry))
40607
40999
  continue;
40608
- const commandPath = join50(commandsDir, entry.name);
41000
+ const commandPath = join52(commandsDir, entry.name);
40609
41001
  const commandName = basename4(entry.name, ".md");
40610
41002
  try {
40611
- const content = readFileSync28(commandPath, "utf-8");
41003
+ const content = readFileSync29(commandPath, "utf-8");
40612
41004
  const { data, body } = parseFrontmatter(content);
40613
41005
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
40614
41006
  const metadata = {
@@ -40634,10 +41026,10 @@ function discoverCommandsFromDir2(commandsDir, scope) {
40634
41026
  }
40635
41027
  function discoverCommandsSync() {
40636
41028
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
40637
- const userCommandsDir = join50(getClaudeConfigDir(), "commands");
40638
- const projectCommandsDir = join50(process.cwd(), ".claude", "commands");
40639
- const opencodeGlobalDir = join50(configDir, "command");
40640
- const opencodeProjectDir = join50(process.cwd(), ".opencode", "command");
41029
+ const userCommandsDir = join52(getClaudeConfigDir(), "commands");
41030
+ const projectCommandsDir = join52(process.cwd(), ".claude", "commands");
41031
+ const opencodeGlobalDir = join52(configDir, "command");
41032
+ const opencodeProjectDir = join52(process.cwd(), ".opencode", "command");
40641
41033
  const userCommands = discoverCommandsFromDir2(userCommandsDir, "user");
40642
41034
  const opencodeGlobalCommands = discoverCommandsFromDir2(opencodeGlobalDir, "opencode");
40643
41035
  const projectCommands = discoverCommandsFromDir2(projectCommandsDir, "project");
@@ -40814,13 +41206,13 @@ var slashcommand = createSlashcommandTool();
40814
41206
  // src/tools/session-manager/constants.ts
40815
41207
  init_data_path();
40816
41208
  init_shared();
40817
- import { join as join51 } from "path";
41209
+ import { join as join53 } from "path";
40818
41210
  var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
40819
- var MESSAGE_STORAGE4 = join51(OPENCODE_STORAGE9, "message");
40820
- var PART_STORAGE4 = join51(OPENCODE_STORAGE9, "part");
40821
- var SESSION_STORAGE = join51(OPENCODE_STORAGE9, "session");
40822
- var TODO_DIR2 = join51(getClaudeConfigDir(), "todos");
40823
- var TRANSCRIPT_DIR2 = join51(getClaudeConfigDir(), "transcripts");
41211
+ var MESSAGE_STORAGE4 = join53(OPENCODE_STORAGE9, "message");
41212
+ var PART_STORAGE4 = join53(OPENCODE_STORAGE9, "part");
41213
+ var SESSION_STORAGE = join53(OPENCODE_STORAGE9, "session");
41214
+ var TODO_DIR2 = join53(getClaudeConfigDir(), "todos");
41215
+ var TRANSCRIPT_DIR2 = join53(getClaudeConfigDir(), "transcripts");
40824
41216
  var SESSION_LIST_DESCRIPTION = `\u5217\u51FA\u6240\u6709 OpenCode session\uFF0C\u652F\u6301\u53EF\u9009\u8FC7\u6EE4\u3002
40825
41217
 
40826
41218
  \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
@@ -40893,11 +41285,11 @@ Has Todos: Yes (12 items, 8 completed)
40893
41285
  Has Transcript: Yes (234 entries)`;
40894
41286
 
40895
41287
  // src/tools/session-manager/storage.ts
40896
- import { existsSync as existsSync43, readdirSync as readdirSync13 } from "fs";
41288
+ import { existsSync as existsSync46, readdirSync as readdirSync15 } from "fs";
40897
41289
  import { readdir, readFile } from "fs/promises";
40898
- import { join as join52 } from "path";
41290
+ import { join as join54 } from "path";
40899
41291
  async function getMainSessions(options) {
40900
- if (!existsSync43(SESSION_STORAGE))
41292
+ if (!existsSync46(SESSION_STORAGE))
40901
41293
  return [];
40902
41294
  const sessions = [];
40903
41295
  try {
@@ -40905,13 +41297,13 @@ async function getMainSessions(options) {
40905
41297
  for (const projectDir of projectDirs) {
40906
41298
  if (!projectDir.isDirectory())
40907
41299
  continue;
40908
- const projectPath = join52(SESSION_STORAGE, projectDir.name);
41300
+ const projectPath = join54(SESSION_STORAGE, projectDir.name);
40909
41301
  const sessionFiles = await readdir(projectPath);
40910
41302
  for (const file2 of sessionFiles) {
40911
41303
  if (!file2.endsWith(".json"))
40912
41304
  continue;
40913
41305
  try {
40914
- const content = await readFile(join52(projectPath, file2), "utf-8");
41306
+ const content = await readFile(join54(projectPath, file2), "utf-8");
40915
41307
  const meta = JSON.parse(content);
40916
41308
  if (meta.parentID)
40917
41309
  continue;
@@ -40929,7 +41321,7 @@ async function getMainSessions(options) {
40929
41321
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
40930
41322
  }
40931
41323
  async function getAllSessions() {
40932
- if (!existsSync43(MESSAGE_STORAGE4))
41324
+ if (!existsSync46(MESSAGE_STORAGE4))
40933
41325
  return [];
40934
41326
  const sessions = [];
40935
41327
  async function scanDirectory(dir) {
@@ -40937,7 +41329,7 @@ async function getAllSessions() {
40937
41329
  const entries = await readdir(dir, { withFileTypes: true });
40938
41330
  for (const entry of entries) {
40939
41331
  if (entry.isDirectory()) {
40940
- const sessionPath = join52(dir, entry.name);
41332
+ const sessionPath = join54(dir, entry.name);
40941
41333
  const files = await readdir(sessionPath);
40942
41334
  if (files.some((f) => f.endsWith(".json"))) {
40943
41335
  sessions.push(entry.name);
@@ -40954,16 +41346,16 @@ async function getAllSessions() {
40954
41346
  return [...new Set(sessions)];
40955
41347
  }
40956
41348
  function getMessageDir7(sessionID) {
40957
- if (!existsSync43(MESSAGE_STORAGE4))
41349
+ if (!existsSync46(MESSAGE_STORAGE4))
40958
41350
  return "";
40959
- const directPath = join52(MESSAGE_STORAGE4, sessionID);
40960
- if (existsSync43(directPath)) {
41351
+ const directPath = join54(MESSAGE_STORAGE4, sessionID);
41352
+ if (existsSync46(directPath)) {
40961
41353
  return directPath;
40962
41354
  }
40963
41355
  try {
40964
- for (const dir of readdirSync13(MESSAGE_STORAGE4)) {
40965
- const sessionPath = join52(MESSAGE_STORAGE4, dir, sessionID);
40966
- if (existsSync43(sessionPath)) {
41356
+ for (const dir of readdirSync15(MESSAGE_STORAGE4)) {
41357
+ const sessionPath = join54(MESSAGE_STORAGE4, dir, sessionID);
41358
+ if (existsSync46(sessionPath)) {
40967
41359
  return sessionPath;
40968
41360
  }
40969
41361
  }
@@ -40977,7 +41369,7 @@ function sessionExists(sessionID) {
40977
41369
  }
40978
41370
  async function readSessionMessages(sessionID) {
40979
41371
  const messageDir = getMessageDir7(sessionID);
40980
- if (!messageDir || !existsSync43(messageDir))
41372
+ if (!messageDir || !existsSync46(messageDir))
40981
41373
  return [];
40982
41374
  const messages = [];
40983
41375
  try {
@@ -40986,7 +41378,7 @@ async function readSessionMessages(sessionID) {
40986
41378
  if (!file2.endsWith(".json"))
40987
41379
  continue;
40988
41380
  try {
40989
- const content = await readFile(join52(messageDir, file2), "utf-8");
41381
+ const content = await readFile(join54(messageDir, file2), "utf-8");
40990
41382
  const meta = JSON.parse(content);
40991
41383
  const parts = await readParts2(meta.id);
40992
41384
  messages.push({
@@ -41012,8 +41404,8 @@ async function readSessionMessages(sessionID) {
41012
41404
  });
41013
41405
  }
41014
41406
  async function readParts2(messageID) {
41015
- const partDir = join52(PART_STORAGE4, messageID);
41016
- if (!existsSync43(partDir))
41407
+ const partDir = join54(PART_STORAGE4, messageID);
41408
+ if (!existsSync46(partDir))
41017
41409
  return [];
41018
41410
  const parts = [];
41019
41411
  try {
@@ -41022,7 +41414,7 @@ async function readParts2(messageID) {
41022
41414
  if (!file2.endsWith(".json"))
41023
41415
  continue;
41024
41416
  try {
41025
- const content = await readFile(join52(partDir, file2), "utf-8");
41417
+ const content = await readFile(join54(partDir, file2), "utf-8");
41026
41418
  parts.push(JSON.parse(content));
41027
41419
  } catch {
41028
41420
  continue;
@@ -41034,14 +41426,14 @@ async function readParts2(messageID) {
41034
41426
  return parts.sort((a, b) => a.id.localeCompare(b.id));
41035
41427
  }
41036
41428
  async function readSessionTodos(sessionID) {
41037
- if (!existsSync43(TODO_DIR2))
41429
+ if (!existsSync46(TODO_DIR2))
41038
41430
  return [];
41039
41431
  try {
41040
41432
  const allFiles = await readdir(TODO_DIR2);
41041
41433
  const todoFiles = allFiles.filter((f) => f.includes(sessionID) && f.endsWith(".json"));
41042
41434
  for (const file2 of todoFiles) {
41043
41435
  try {
41044
- const content = await readFile(join52(TODO_DIR2, file2), "utf-8");
41436
+ const content = await readFile(join54(TODO_DIR2, file2), "utf-8");
41045
41437
  const data = JSON.parse(content);
41046
41438
  if (Array.isArray(data)) {
41047
41439
  return data.map((item) => ({
@@ -41061,10 +41453,10 @@ async function readSessionTodos(sessionID) {
41061
41453
  return [];
41062
41454
  }
41063
41455
  async function readSessionTranscript(sessionID) {
41064
- if (!existsSync43(TRANSCRIPT_DIR2))
41456
+ if (!existsSync46(TRANSCRIPT_DIR2))
41065
41457
  return 0;
41066
- const transcriptFile = join52(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
41067
- if (!existsSync43(transcriptFile))
41458
+ const transcriptFile = join54(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
41459
+ if (!existsSync46(transcriptFile))
41068
41460
  return 0;
41069
41461
  try {
41070
41462
  const content = await readFile(transcriptFile, "utf-8");
@@ -42266,19 +42658,19 @@ var CALL_OMO_AGENT_DESCRIPTION = `\u542F\u52A8 explore/librarian agent\u3002run_
42266
42658
 
42267
42659
  \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`;
42268
42660
  // src/tools/call-omo-agent/tools.ts
42269
- import { existsSync as existsSync44, readdirSync as readdirSync14 } from "fs";
42270
- import { join as join53 } from "path";
42661
+ import { existsSync as existsSync47, readdirSync as readdirSync16 } from "fs";
42662
+ import { join as join55 } from "path";
42271
42663
  init_shared();
42272
42664
  init_session_cursor();
42273
42665
  function getMessageDir8(sessionID) {
42274
- if (!existsSync44(MESSAGE_STORAGE))
42666
+ if (!existsSync47(MESSAGE_STORAGE))
42275
42667
  return null;
42276
- const directPath = join53(MESSAGE_STORAGE, sessionID);
42277
- if (existsSync44(directPath))
42668
+ const directPath = join55(MESSAGE_STORAGE, sessionID);
42669
+ if (existsSync47(directPath))
42278
42670
  return directPath;
42279
- for (const dir of readdirSync14(MESSAGE_STORAGE)) {
42280
- const sessionPath = join53(MESSAGE_STORAGE, dir, sessionID);
42281
- if (existsSync44(sessionPath))
42671
+ for (const dir of readdirSync16(MESSAGE_STORAGE)) {
42672
+ const sessionPath = join55(MESSAGE_STORAGE, dir, sessionID);
42673
+ if (existsSync47(sessionPath))
42282
42674
  return sessionPath;
42283
42675
  }
42284
42676
  return null;
@@ -42687,14 +43079,17 @@ If the requested information is not found, clearly state what is missing.`;
42687
43079
  }
42688
43080
  // src/tools/delegate-task/tools.ts
42689
43081
  init_constants2();
42690
- import { existsSync as existsSync45, readdirSync as readdirSync15 } from "fs";
42691
- import { join as join54 } from "path";
43082
+ import { existsSync as existsSync48, readdirSync as readdirSync17 } from "fs";
43083
+ import { join as join56 } from "path";
42692
43084
 
42693
43085
  // src/features/task-toast-manager/manager.ts
42694
43086
  class TaskToastManager {
42695
43087
  tasks = new Map;
42696
43088
  client;
42697
43089
  concurrencyManager;
43090
+ completionBatch = [];
43091
+ completionDebounceTimer;
43092
+ static COMPLETION_DEBOUNCE_MS = 800;
42698
43093
  constructor(client2, concurrencyManager) {
42699
43094
  this.client = client2;
42700
43095
  this.concurrencyManager = concurrencyManager;
@@ -42806,13 +43201,36 @@ class TaskToastManager {
42806
43201
  }).catch(() => {});
42807
43202
  }
42808
43203
  showCompletionToast(task) {
43204
+ this.removeTask(task.id);
43205
+ this.completionBatch.push(task);
43206
+ if (this.completionDebounceTimer) {
43207
+ clearTimeout(this.completionDebounceTimer);
43208
+ }
43209
+ this.completionDebounceTimer = setTimeout(() => {
43210
+ this.flushCompletionBatch();
43211
+ }, TaskToastManager.COMPLETION_DEBOUNCE_MS);
43212
+ }
43213
+ flushCompletionBatch() {
42809
43214
  const tuiClient = this.client;
42810
- if (!tuiClient.tui?.showToast)
43215
+ if (!tuiClient.tui?.showToast) {
43216
+ this.completionBatch = [];
43217
+ return;
43218
+ }
43219
+ const batch = [...this.completionBatch];
43220
+ this.completionBatch = [];
43221
+ if (batch.length === 0)
42811
43222
  return;
42812
- this.removeTask(task.id);
42813
43223
  const remaining = this.getRunningTasks();
42814
43224
  const queued = this.getQueuedTasks();
42815
- let message = `"${task.description}" finished in ${task.duration}`;
43225
+ let message;
43226
+ if (batch.length === 1) {
43227
+ message = `"${batch[0].description}" finished in ${batch[0].duration}`;
43228
+ } else {
43229
+ const lines = batch.map((t) => ` \u2713 "${t.description}" (${t.duration})`);
43230
+ message = `${batch.length} tasks completed:
43231
+ ${lines.join(`
43232
+ `)}`;
43233
+ }
42816
43234
  if (remaining.length > 0 || queued.length > 0) {
42817
43235
  message += `
42818
43236
 
@@ -42820,12 +43238,13 @@ Still running: ${remaining.length} | Queued: ${queued.length}`;
42820
43238
  }
42821
43239
  tuiClient.tui.showToast({
42822
43240
  body: {
42823
- title: "Task Completed",
43241
+ title: batch.length === 1 ? "Task Completed" : `${batch.length} Tasks Completed`,
42824
43242
  message,
42825
43243
  variant: "success",
42826
- duration: 5000
43244
+ duration: batch.length > 1 ? 7000 : 5000
42827
43245
  }
42828
43246
  }).catch(() => {});
43247
+ this.completionDebounceTimer = undefined;
42829
43248
  }
42830
43249
  }
42831
43250
  var instance = null;
@@ -42847,14 +43266,14 @@ function parseModelString(model) {
42847
43266
  return;
42848
43267
  }
42849
43268
  function getMessageDir9(sessionID) {
42850
- if (!existsSync45(MESSAGE_STORAGE))
43269
+ if (!existsSync48(MESSAGE_STORAGE))
42851
43270
  return null;
42852
- const directPath = join54(MESSAGE_STORAGE, sessionID);
42853
- if (existsSync45(directPath))
43271
+ const directPath = join56(MESSAGE_STORAGE, sessionID);
43272
+ if (existsSync48(directPath))
42854
43273
  return directPath;
42855
- for (const dir of readdirSync15(MESSAGE_STORAGE)) {
42856
- const sessionPath = join54(MESSAGE_STORAGE, dir, sessionID);
42857
- if (existsSync45(sessionPath))
43274
+ for (const dir of readdirSync17(MESSAGE_STORAGE)) {
43275
+ const sessionPath = join56(MESSAGE_STORAGE, dir, sessionID);
43276
+ if (existsSync48(sessionPath))
42858
43277
  return sessionPath;
42859
43278
  }
42860
43279
  return null;
@@ -43682,12 +44101,14 @@ class PerformanceAggregator {
43682
44101
  }
43683
44102
 
43684
44103
  // src/features/background-agent/manager.ts
43685
- import { existsSync as existsSync46, readdirSync as readdirSync16 } from "fs";
43686
- import { join as join55 } from "path";
44104
+ import { existsSync as existsSync49, readdirSync as readdirSync18 } from "fs";
44105
+ import { join as join57 } from "path";
43687
44106
  var TASK_TTL_MS = 30 * 60 * 1000;
43688
44107
  var MIN_STABILITY_TIME_MS = 10 * 1000;
43689
- var DEFAULT_STALE_TIMEOUT_MS = 180000;
44108
+ var DEFAULT_STALE_TIMEOUT_MS = 120000;
43690
44109
  var MIN_RUNTIME_BEFORE_STALE_MS = 30000;
44110
+ var STEP_TIMEOUT_MS = 600000;
44111
+ var MIN_IDLE_TIME_MS = 15000;
43691
44112
 
43692
44113
  class BackgroundManager {
43693
44114
  static cleanupManagers = new Set;
@@ -43703,6 +44124,7 @@ class BackgroundManager {
43703
44124
  shutdownTriggered = false;
43704
44125
  config;
43705
44126
  perfAggregator = new PerformanceAggregator;
44127
+ perfTracer;
43706
44128
  queuesByKey = new Map;
43707
44129
  processingKeys = new Set;
43708
44130
  constructor(ctx, config3) {
@@ -43715,6 +44137,9 @@ class BackgroundManager {
43715
44137
  this.config = config3;
43716
44138
  this.registerProcessCleanup();
43717
44139
  }
44140
+ setPerfTracer(tracer) {
44141
+ this.perfTracer = tracer;
44142
+ }
43718
44143
  async launch(input) {
43719
44144
  log("[background-agent] launch() called with:", {
43720
44145
  agent: input.agent,
@@ -43736,7 +44161,11 @@ class BackgroundManager {
43736
44161
  parentMessageID: input.parentMessageID,
43737
44162
  parentModel: input.parentModel,
43738
44163
  parentAgent: input.parentAgent,
43739
- model: input.model
44164
+ model: input.model,
44165
+ maxSteps: this.config?.maxSteps,
44166
+ maxRuntimeMs: this.config?.maxRuntimeMs,
44167
+ stepTimeoutMs: this.config?.stepTimeoutMs ?? STEP_TIMEOUT_MS,
44168
+ stepCount: 0
43740
44169
  };
43741
44170
  this.tasks.set(task.id, task);
43742
44171
  if (input.parentSessionID) {
@@ -43828,7 +44257,8 @@ class BackgroundManager {
43828
44257
  task.sessionID = sessionID;
43829
44258
  task.progress = {
43830
44259
  toolCalls: 0,
43831
- lastUpdate: new Date
44260
+ lastUpdate: new Date,
44261
+ stepStartedAt: Date.now()
43832
44262
  };
43833
44263
  task.concurrencyKey = concurrencyKey;
43834
44264
  task.concurrencyGroup = concurrencyKey;
@@ -43968,7 +44398,11 @@ class BackgroundManager {
43968
44398
  },
43969
44399
  parentAgent: input.parentAgent,
43970
44400
  concurrencyKey: input.concurrencyKey,
43971
- concurrencyGroup
44401
+ concurrencyGroup,
44402
+ maxSteps: this.config?.maxSteps,
44403
+ maxRuntimeMs: this.config?.maxRuntimeMs,
44404
+ stepTimeoutMs: this.config?.stepTimeoutMs ?? STEP_TIMEOUT_MS,
44405
+ stepCount: 0
43972
44406
  };
43973
44407
  this.tasks.set(task.id, task);
43974
44408
  subagentSessions.add(input.sessionID);
@@ -44008,12 +44442,14 @@ class BackgroundManager {
44008
44442
  existingTask.parentModel = input.parentModel;
44009
44443
  existingTask.parentAgent = input.parentAgent;
44010
44444
  existingTask.startedAt = new Date;
44445
+ existingTask.stepCount = 0;
44011
44446
  if (existingTask.progress) {
44012
44447
  existingTask.progress.phaseTiming = undefined;
44013
44448
  }
44014
44449
  existingTask.progress = {
44015
44450
  toolCalls: existingTask.progress?.toolCalls ?? 0,
44016
- lastUpdate: new Date
44451
+ lastUpdate: new Date,
44452
+ stepStartedAt: Date.now()
44017
44453
  };
44018
44454
  this.startPolling();
44019
44455
  if (existingTask.sessionID) {
@@ -44115,11 +44551,20 @@ class BackgroundManager {
44115
44551
  const task = this.findBySession(sessionID);
44116
44552
  if (!task || task.status !== "running")
44117
44553
  return;
44554
+ task.stepCount = (task.stepCount ?? 0) + 1;
44555
+ if (task.progress) {
44556
+ task.progress.stepStartedAt = Date.now();
44557
+ }
44558
+ if (this.isStepLimitExceeded(task)) {
44559
+ this.tryCompleteTask(task, `step limit (${task.maxSteps} steps)`).catch((err) => {
44560
+ log("[background-agent] Error completing task on step limit:", err);
44561
+ });
44562
+ return;
44563
+ }
44118
44564
  const startedAt = task.startedAt;
44119
44565
  if (!startedAt)
44120
44566
  return;
44121
44567
  const elapsedMs = Date.now() - startedAt.getTime();
44122
- const MIN_IDLE_TIME_MS = 5000;
44123
44568
  if (elapsedMs < MIN_IDLE_TIME_MS) {
44124
44569
  log("[background-agent] Ignoring early session.idle, elapsed:", { elapsedMs, taskId: task.id });
44125
44570
  return;
@@ -44506,6 +44951,41 @@ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Dat
44506
44951
  const runtime = now - startedAt.getTime();
44507
44952
  if (runtime < MIN_RUNTIME_BEFORE_STALE_MS)
44508
44953
  continue;
44954
+ if (this.isRuntimeLimitExceeded(task)) {
44955
+ task.status = "cancelled";
44956
+ task.error = `Runtime limit exceeded (${Math.round(runtime / 60000)}min)`;
44957
+ task.completedAt = new Date;
44958
+ if (task.concurrencyKey) {
44959
+ this.concurrencyManager.release(task.concurrencyKey);
44960
+ task.concurrencyKey = undefined;
44961
+ }
44962
+ this.client.session.abort({ path: { id: sessionID } }).catch(() => {});
44963
+ log(`[background-agent] Task ${task.id} interrupted: runtime limit`);
44964
+ try {
44965
+ await this.notifyParentSession(task);
44966
+ } catch (err) {
44967
+ log("[background-agent] Error in notifyParentSession for runtime-limit task:", { taskId: task.id, error: err });
44968
+ }
44969
+ continue;
44970
+ }
44971
+ if (this.isStepTimeoutExceeded(task)) {
44972
+ const stepTimeoutMs = task.stepTimeoutMs ?? STEP_TIMEOUT_MS;
44973
+ task.status = "cancelled";
44974
+ task.error = `Step timeout exceeded (single step > ${Math.round(stepTimeoutMs / 60000)}min)`;
44975
+ task.completedAt = new Date;
44976
+ if (task.concurrencyKey) {
44977
+ this.concurrencyManager.release(task.concurrencyKey);
44978
+ task.concurrencyKey = undefined;
44979
+ }
44980
+ this.client.session.abort({ path: { id: sessionID } }).catch(() => {});
44981
+ log(`[background-agent] Task ${task.id} interrupted: step timeout`);
44982
+ try {
44983
+ await this.notifyParentSession(task);
44984
+ } catch (err) {
44985
+ log("[background-agent] Error in notifyParentSession for step-timeout task:", { taskId: task.id, error: err });
44986
+ }
44987
+ continue;
44988
+ }
44509
44989
  const timeSinceLastUpdate = now - task.progress.lastUpdate.getTime();
44510
44990
  if (timeSinceLastUpdate <= staleTimeoutMs)
44511
44991
  continue;
@@ -44530,125 +45010,165 @@ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Dat
44530
45010
  }
44531
45011
  }
44532
45012
  }
45013
+ isStepLimitExceeded(task) {
45014
+ const maxSteps = task.maxSteps;
45015
+ if (!maxSteps || maxSteps <= 0)
45016
+ return false;
45017
+ return (task.stepCount ?? 0) >= maxSteps;
45018
+ }
45019
+ isRuntimeLimitExceeded(task) {
45020
+ const maxRuntimeMs = task.maxRuntimeMs;
45021
+ if (!maxRuntimeMs || maxRuntimeMs <= 0)
45022
+ return false;
45023
+ if (!task.startedAt)
45024
+ return false;
45025
+ const runtime = Date.now() - task.startedAt.getTime();
45026
+ return runtime >= maxRuntimeMs;
45027
+ }
45028
+ isStepTimeoutExceeded(task) {
45029
+ const stepTimeoutMs = task.stepTimeoutMs;
45030
+ if (!stepTimeoutMs || stepTimeoutMs <= 0)
45031
+ return false;
45032
+ if (!task.progress?.stepStartedAt)
45033
+ return false;
45034
+ const stepDuration = Date.now() - task.progress.stepStartedAt;
45035
+ return stepDuration >= stepTimeoutMs;
45036
+ }
44533
45037
  async pollRunningTasks() {
44534
- this.pruneStaleTasksAndNotifications();
44535
- await this.checkAndInterruptStaleTasks();
44536
- const statusResult = await this.client.session.status();
44537
- const allStatuses = statusResult.data ?? {};
44538
- for (const task of this.tasks.values()) {
44539
- if (task.status !== "running")
44540
- continue;
44541
- const sessionID = task.sessionID;
44542
- if (!sessionID)
44543
- continue;
44544
- try {
44545
- const sessionStatus = allStatuses[sessionID];
44546
- if (sessionStatus?.type === "idle") {
44547
- const hasValidOutput = await this.validateSessionHasOutput(sessionID);
44548
- if (!hasValidOutput) {
44549
- log("[background-agent] Polling idle but no valid output yet, waiting:", task.id);
44550
- continue;
44551
- }
44552
- if (task.status !== "running")
44553
- continue;
44554
- const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44555
- if (hasIncompleteTodos2) {
44556
- log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
44557
- continue;
44558
- }
44559
- await this.tryCompleteTask(task, "polling (idle status)");
45038
+ const start = this.perfTracer?.isEnabled() ? performance.now() : undefined;
45039
+ try {
45040
+ this.pruneStaleTasksAndNotifications();
45041
+ await this.checkAndInterruptStaleTasks();
45042
+ const statusResult = await this.client.session.status();
45043
+ const allStatuses = statusResult.data ?? {};
45044
+ for (const task of this.tasks.values()) {
45045
+ if (task.status !== "running")
44560
45046
  continue;
44561
- }
44562
- const messagesResult = await this.client.session.messages({
44563
- path: { id: sessionID }
44564
- });
44565
- if (!messagesResult.error && messagesResult.data) {
44566
- const messages = messagesResult.data;
44567
- const assistantMsgs = messages.filter((m) => m.info?.role === "assistant");
44568
- let toolCalls = 0;
44569
- let lastTool;
44570
- let lastMessage;
44571
- for (const msg of assistantMsgs) {
44572
- const parts = msg.parts ?? [];
44573
- for (const part of parts) {
44574
- if (part.type === "tool_use" || part.tool) {
44575
- toolCalls++;
44576
- lastTool = part.tool || part.name || "unknown";
44577
- }
44578
- if (part.type === "text" && part.text) {
44579
- lastMessage = part.text;
44580
- }
45047
+ const sessionID = task.sessionID;
45048
+ if (!sessionID)
45049
+ continue;
45050
+ try {
45051
+ const sessionStatus = allStatuses[sessionID];
45052
+ if (sessionStatus?.type === "idle") {
45053
+ const hasValidOutput = await this.validateSessionHasOutput(sessionID);
45054
+ if (!hasValidOutput) {
45055
+ log("[background-agent] Polling idle but no valid output yet, waiting:", task.id);
45056
+ continue;
44581
45057
  }
44582
- }
44583
- if (!task.progress) {
44584
- task.progress = { toolCalls: 0, lastUpdate: new Date };
44585
- }
44586
- if (task.startedAt && !task.progress.phaseTiming) {
44587
- const now = Date.now();
44588
- task.progress.phaseTiming = {
44589
- queueWaitMs: task.queuedAt ? now - task.queuedAt.getTime() : 0,
44590
- totalRunMs: now - task.startedAt.getTime(),
44591
- toolCallCount: 0
44592
- };
44593
- }
44594
- if (task.progress.phaseTiming && task.progress.phaseTiming.firstResponseMs === undefined && assistantMsgs.length > 0) {
44595
- task.progress.phaseTiming.firstResponseMs = Date.now() - task.startedAt.getTime();
44596
- }
44597
- task.progress.toolCalls = toolCalls;
44598
- task.progress.lastTool = lastTool;
44599
- task.progress.lastUpdate = new Date;
44600
- if (lastMessage) {
44601
- task.progress.lastMessage = lastMessage;
44602
- task.progress.lastMessageAt = new Date;
44603
- }
44604
- const currentMsgCount = messages.length;
44605
- const startedAt = task.startedAt;
44606
- if (!startedAt)
45058
+ if (task.status !== "running")
45059
+ continue;
45060
+ const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
45061
+ if (hasIncompleteTodos2) {
45062
+ log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
45063
+ continue;
45064
+ }
45065
+ if (this.isStepLimitExceeded(task)) {
45066
+ await this.tryCompleteTask(task, `step limit via polling (${task.maxSteps} steps)`);
45067
+ continue;
45068
+ }
45069
+ await this.tryCompleteTask(task, "polling (idle status)");
44607
45070
  continue;
44608
- const elapsedMs = Date.now() - startedAt.getTime();
44609
- if (elapsedMs >= MIN_STABILITY_TIME_MS) {
44610
- if (task.lastMsgCount === currentMsgCount) {
44611
- task.stablePolls = (task.stablePolls ?? 0) + 1;
44612
- if (task.stablePolls >= 3) {
44613
- const recheckStatus = await this.client.session.status();
44614
- const recheckData = recheckStatus.data ?? {};
44615
- const currentStatus = recheckData[sessionID];
44616
- if (currentStatus?.type !== "idle") {
44617
- log("[background-agent] Stability reached but session not idle, resetting:", {
44618
- taskId: task.id,
44619
- sessionStatus: currentStatus?.type ?? "not_in_status"
44620
- });
44621
- task.stablePolls = 0;
44622
- continue;
45071
+ }
45072
+ const messagesResult = await this.client.session.messages({
45073
+ path: { id: sessionID }
45074
+ });
45075
+ if (!messagesResult.error && messagesResult.data) {
45076
+ const messages = messagesResult.data;
45077
+ const assistantMsgs = messages.filter((m) => m.info?.role === "assistant");
45078
+ let toolCalls = 0;
45079
+ let lastTool;
45080
+ let lastMessage;
45081
+ for (const msg of assistantMsgs) {
45082
+ const parts = msg.parts ?? [];
45083
+ for (const part of parts) {
45084
+ if (part.type === "tool_use" || part.tool) {
45085
+ toolCalls++;
45086
+ lastTool = part.tool || part.name || "unknown";
44623
45087
  }
44624
- const hasValidOutput = await this.validateSessionHasOutput(sessionID);
44625
- if (!hasValidOutput) {
44626
- log("[background-agent] Stability reached but no valid output, waiting:", task.id);
44627
- continue;
45088
+ if (part.type === "text" && part.text) {
45089
+ lastMessage = part.text;
44628
45090
  }
44629
- if (task.status !== "running")
44630
- continue;
44631
- const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44632
- if (!hasIncompleteTodos2) {
44633
- await this.tryCompleteTask(task, "stability detection");
44634
- continue;
45091
+ }
45092
+ }
45093
+ if (!task.progress) {
45094
+ task.progress = { toolCalls: 0, lastUpdate: new Date };
45095
+ }
45096
+ if (task.startedAt && !task.progress.phaseTiming) {
45097
+ const now = Date.now();
45098
+ task.progress.phaseTiming = {
45099
+ queueWaitMs: task.queuedAt ? now - task.queuedAt.getTime() : 0,
45100
+ totalRunMs: now - task.startedAt.getTime(),
45101
+ toolCallCount: 0
45102
+ };
45103
+ }
45104
+ if (task.progress.phaseTiming && task.progress.phaseTiming.firstResponseMs === undefined && assistantMsgs.length > 0) {
45105
+ task.progress.phaseTiming.firstResponseMs = Date.now() - task.startedAt.getTime();
45106
+ }
45107
+ task.progress.toolCalls = toolCalls;
45108
+ task.progress.lastTool = lastTool;
45109
+ task.progress.lastUpdate = new Date;
45110
+ if (lastMessage) {
45111
+ task.progress.lastMessage = lastMessage;
45112
+ task.progress.lastMessageAt = new Date;
45113
+ }
45114
+ const currentMsgCount = messages.length;
45115
+ const startedAt = task.startedAt;
45116
+ if (!startedAt)
45117
+ continue;
45118
+ const elapsedMs = Date.now() - startedAt.getTime();
45119
+ if (elapsedMs >= MIN_STABILITY_TIME_MS) {
45120
+ if (task.lastMsgCount === currentMsgCount) {
45121
+ task.stablePolls = (task.stablePolls ?? 0) + 1;
45122
+ if (task.stablePolls >= 3) {
45123
+ const recheckStatus = await this.client.session.status();
45124
+ const recheckData = recheckStatus.data ?? {};
45125
+ const currentStatus = recheckData[sessionID];
45126
+ if (currentStatus?.type !== "idle") {
45127
+ log("[background-agent] Stability reached but session not idle, resetting:", {
45128
+ taskId: task.id,
45129
+ sessionStatus: currentStatus?.type ?? "not_in_status"
45130
+ });
45131
+ task.stablePolls = 0;
45132
+ continue;
45133
+ }
45134
+ const hasValidOutput = await this.validateSessionHasOutput(sessionID);
45135
+ if (!hasValidOutput) {
45136
+ log("[background-agent] Stability reached but no valid output, waiting:", task.id);
45137
+ continue;
45138
+ }
45139
+ if (task.status !== "running")
45140
+ continue;
45141
+ if (this.isStepLimitExceeded(task)) {
45142
+ await this.tryCompleteTask(task, `step limit via stability (${task.maxSteps} steps)`);
45143
+ continue;
45144
+ }
45145
+ const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
45146
+ if (!hasIncompleteTodos2) {
45147
+ await this.tryCompleteTask(task, "stability detection");
45148
+ continue;
45149
+ }
44635
45150
  }
45151
+ } else {
45152
+ task.stablePolls = 0;
44636
45153
  }
44637
- } else {
44638
- task.stablePolls = 0;
44639
45154
  }
45155
+ task.lastMsgCount = currentMsgCount;
44640
45156
  }
44641
- task.lastMsgCount = currentMsgCount;
45157
+ } catch (error45) {
45158
+ log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
44642
45159
  }
44643
- } catch (error45) {
44644
- log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
44645
45160
  }
44646
- }
44647
- if (!this.hasRunningTasks()) {
44648
- this.stopPolling();
44649
- if (this.perfAggregator.taskCount >= 2) {
44650
- const report = this.perfAggregator.getReport();
44651
- log("[perf] Session report:", report);
45161
+ if (!this.hasRunningTasks()) {
45162
+ this.stopPolling();
45163
+ if (this.perfAggregator.taskCount >= 2) {
45164
+ const report = this.perfAggregator.getReport();
45165
+ log("[perf] Session report:", report);
45166
+ }
45167
+ }
45168
+ } finally {
45169
+ if (start !== undefined) {
45170
+ const duration3 = performance.now() - start;
45171
+ this.perfTracer.recordPolling(duration3, this.getRunningTasks().length, new Set(...this.tasks.values().map((t) => t.parentSessionID).filter(Boolean)).size);
44652
45172
  }
44653
45173
  }
44654
45174
  }
@@ -44686,14 +45206,14 @@ function registerProcessSignal(signal, handler, exitAfter) {
44686
45206
  return listener;
44687
45207
  }
44688
45208
  function getMessageDir10(sessionID) {
44689
- if (!existsSync46(MESSAGE_STORAGE))
45209
+ if (!existsSync49(MESSAGE_STORAGE))
44690
45210
  return null;
44691
- const directPath = join55(MESSAGE_STORAGE, sessionID);
44692
- if (existsSync46(directPath))
45211
+ const directPath = join57(MESSAGE_STORAGE, sessionID);
45212
+ if (existsSync49(directPath))
44693
45213
  return directPath;
44694
- for (const dir of readdirSync16(MESSAGE_STORAGE)) {
44695
- const sessionPath = join55(MESSAGE_STORAGE, dir, sessionID);
44696
- if (existsSync46(sessionPath))
45214
+ for (const dir of readdirSync18(MESSAGE_STORAGE)) {
45215
+ const sessionPath = join57(MESSAGE_STORAGE, dir, sessionID);
45216
+ if (existsSync49(sessionPath))
44697
45217
  return sessionPath;
44698
45218
  }
44699
45219
  return null;
@@ -62607,6 +63127,7 @@ var HookNameSchema = exports_external2.enum([
62607
63127
  "edit-error-recovery",
62608
63128
  "delegate-task-retry",
62609
63129
  "prometheus-md-only",
63130
+ "perf-profiler",
62610
63131
  "start-work",
62611
63132
  "atlas"
62612
63133
  ]);
@@ -62720,11 +63241,21 @@ var DynamicContextPruningConfigSchema = exports_external2.object({
62720
63241
  }).optional()
62721
63242
  }).optional()
62722
63243
  });
63244
+ var ProfilingConfigSchema = exports_external2.object({
63245
+ enabled: exports_external2.boolean().default(false),
63246
+ output_dir: exports_external2.string().optional(),
63247
+ slow_threshold_ms: exports_external2.number().default(100),
63248
+ memory_snapshot_interval: exports_external2.number().default(5),
63249
+ trace_api: exports_external2.boolean().default(true),
63250
+ trace_fileio: exports_external2.boolean().default(true),
63251
+ trace_polling: exports_external2.boolean().default(true)
63252
+ });
62723
63253
  var ExperimentalConfigSchema = exports_external2.object({
62724
63254
  aggressive_truncation: exports_external2.boolean().optional(),
62725
63255
  auto_resume: exports_external2.boolean().optional(),
62726
63256
  truncate_all_tool_outputs: exports_external2.boolean().optional(),
62727
- dynamic_context_pruning: DynamicContextPruningConfigSchema.optional()
63257
+ dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
63258
+ profiling: ProfilingConfigSchema.optional()
62728
63259
  });
62729
63260
  var SkillSourceSchema = exports_external2.union([
62730
63261
  exports_external2.string(),
@@ -62769,7 +63300,10 @@ var BackgroundTaskConfigSchema = exports_external2.object({
62769
63300
  defaultConcurrency: exports_external2.number().min(1).optional(),
62770
63301
  providerConcurrency: exports_external2.record(exports_external2.string(), exports_external2.number().min(0)).optional(),
62771
63302
  modelConcurrency: exports_external2.record(exports_external2.string(), exports_external2.number().min(0)).optional(),
62772
- staleTimeoutMs: exports_external2.number().min(60000).optional()
63303
+ staleTimeoutMs: exports_external2.number().min(60000).optional(),
63304
+ maxSteps: exports_external2.number().min(0).optional(),
63305
+ maxRuntimeMs: exports_external2.number().min(0).optional(),
63306
+ stepTimeoutMs: exports_external2.number().min(0).optional()
62773
63307
  });
62774
63308
  var NotificationConfigSchema = exports_external2.object({
62775
63309
  force_enable: exports_external2.boolean().optional()
@@ -64864,21 +65398,21 @@ TODO \u5217\u8868\uFF1A[\u8DEF\u5F84]
64864
65398
 
64865
65399
  **\u5BF9\u4E8E\u63A2\u7D22\uFF08explore/librarian\uFF09**\uFF1A\u59CB\u7EC8\u540E\u53F0\u8FD0\u884C
64866
65400
  \`\`\`typescript
64867
- delegate_task(subagent_type="explore", run_in_background=true, ...)
64868
- delegate_task(subagent_type="librarian", run_in_background=true, ...)
65401
+ delegate_task(subagent_type="explore", run_in_background=true, load_skills=[], ...)
65402
+ delegate_task(subagent_type="librarian", run_in_background=true, load_skills=[], ...)
64869
65403
  \`\`\`
64870
65404
 
64871
65405
  **\u5BF9\u4E8E\u4EFB\u52A1\u6267\u884C**\uFF1A\u7EDD\u4E0D\u7528\u540E\u53F0\u8FD0\u884C
64872
65406
  \`\`\`typescript
64873
- delegate_task(category="...", run_in_background=false, ...)
65407
+ delegate_task(category="...", run_in_background=false, load_skills=[], ...)
64874
65408
  \`\`\`
64875
65409
 
64876
65410
  **\u5E76\u884C\u4EFB\u52A1\u7EC4**\uFF1A\u5728\u4E00\u6761\u6D88\u606F\u4E2D\u591A\u6B21\u8C03\u7528
64877
65411
  \`\`\`typescript
64878
65412
  // \u4EFB\u52A12\u30013\u30014\u662F\u72EC\u7ACB\u7684\u2014\u2014\u4E00\u8D77\u8C03\u7528
64879
- delegate_task(category="quick", prompt="\u4EFB\u52A12...")
64880
- delegate_task(category="quick", prompt="\u4EFB\u52A13...")
64881
- delegate_task(category="quick", prompt="\u4EFB\u52A14...")
65413
+ delegate_task(category="quick", prompt="\u4EFB\u52A12...", load_skills=[])
65414
+ delegate_task(category="quick", prompt="\u4EFB\u52A13...", load_skills=[])
65415
+ delegate_task(category="quick", prompt="\u4EFB\u52A14...", load_skills=[])
64882
65416
  \`\`\`
64883
65417
 
64884
65418
  **\u540E\u53F0\u7BA1\u7406**\uFF1A
@@ -65753,7 +66287,7 @@ init_file_utils();
65753
66287
  init_shared();
65754
66288
  init_logger();
65755
66289
  import { promises as fs11 } from "fs";
65756
- import { join as join57, basename as basename6 } from "path";
66290
+ import { join as join59, basename as basename6 } from "path";
65757
66291
  async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
65758
66292
  try {
65759
66293
  await fs11.access(commandsDir);
@@ -65783,7 +66317,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
65783
66317
  if (entry.isDirectory()) {
65784
66318
  if (entry.name.startsWith("."))
65785
66319
  continue;
65786
- const subDirPath = join57(commandsDir, entry.name);
66320
+ const subDirPath = join59(commandsDir, entry.name);
65787
66321
  const subPrefix = prefix ? `${prefix}:${entry.name}` : entry.name;
65788
66322
  const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
65789
66323
  commands2.push(...subCommands);
@@ -65791,7 +66325,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
65791
66325
  }
65792
66326
  if (!isMarkdownFile(entry))
65793
66327
  continue;
65794
- const commandPath = join57(commandsDir, entry.name);
66328
+ const commandPath = join59(commandsDir, entry.name);
65795
66329
  const baseCommandName = basename6(entry.name, ".md");
65796
66330
  const commandName = prefix ? `${prefix}:${baseCommandName}` : baseCommandName;
65797
66331
  try {
@@ -65838,23 +66372,23 @@ function commandsToRecord(commands2) {
65838
66372
  return result;
65839
66373
  }
65840
66374
  async function loadUserCommands() {
65841
- const userCommandsDir = join57(getClaudeConfigDir(), "commands");
66375
+ const userCommandsDir = join59(getClaudeConfigDir(), "commands");
65842
66376
  const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
65843
66377
  return commandsToRecord(commands2);
65844
66378
  }
65845
66379
  async function loadProjectCommands() {
65846
- const projectCommandsDir = join57(process.cwd(), ".claude", "commands");
66380
+ const projectCommandsDir = join59(process.cwd(), ".claude", "commands");
65847
66381
  const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
65848
66382
  return commandsToRecord(commands2);
65849
66383
  }
65850
66384
  async function loadOpencodeGlobalCommands() {
65851
66385
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
65852
- const opencodeCommandsDir = join57(configDir, "command");
66386
+ const opencodeCommandsDir = join59(configDir, "command");
65853
66387
  const commands2 = await loadCommandsFromDir(opencodeCommandsDir, "opencode");
65854
66388
  return commandsToRecord(commands2);
65855
66389
  }
65856
66390
  async function loadOpencodeProjectCommands() {
65857
- const opencodeProjectDir = join57(process.cwd(), ".opencode", "command");
66391
+ const opencodeProjectDir = join59(process.cwd(), ".opencode", "command");
65858
66392
  const commands2 = await loadCommandsFromDir(opencodeProjectDir, "opencode-project");
65859
66393
  return commandsToRecord(commands2);
65860
66394
  }
@@ -65862,8 +66396,8 @@ async function loadOpencodeProjectCommands() {
65862
66396
  init_frontmatter();
65863
66397
  init_file_utils();
65864
66398
  init_shared();
65865
- import { existsSync as existsSync48, readdirSync as readdirSync17, readFileSync as readFileSync30 } from "fs";
65866
- import { join as join58, basename as basename7 } from "path";
66399
+ import { existsSync as existsSync51, readdirSync as readdirSync19, readFileSync as readFileSync31 } from "fs";
66400
+ import { join as join60, basename as basename7 } from "path";
65867
66401
  function parseToolsConfig(toolsStr) {
65868
66402
  if (!toolsStr)
65869
66403
  return;
@@ -65877,18 +66411,18 @@ function parseToolsConfig(toolsStr) {
65877
66411
  return result;
65878
66412
  }
65879
66413
  function loadAgentsFromDir(agentsDir, scope) {
65880
- if (!existsSync48(agentsDir)) {
66414
+ if (!existsSync51(agentsDir)) {
65881
66415
  return [];
65882
66416
  }
65883
- const entries = readdirSync17(agentsDir, { withFileTypes: true });
66417
+ const entries = readdirSync19(agentsDir, { withFileTypes: true });
65884
66418
  const agents = [];
65885
66419
  for (const entry of entries) {
65886
66420
  if (!isMarkdownFile(entry))
65887
66421
  continue;
65888
- const agentPath = join58(agentsDir, entry.name);
66422
+ const agentPath = join60(agentsDir, entry.name);
65889
66423
  const agentName = basename7(entry.name, ".md");
65890
66424
  try {
65891
- const content = readFileSync30(agentPath, "utf-8");
66425
+ const content = readFileSync31(agentPath, "utf-8");
65892
66426
  const { data, body } = parseFrontmatter(content);
65893
66427
  const name = data.name || agentName;
65894
66428
  const originalDescription = data.description || "";
@@ -65915,7 +66449,7 @@ function loadAgentsFromDir(agentsDir, scope) {
65915
66449
  return agents;
65916
66450
  }
65917
66451
  function loadUserAgents() {
65918
- const userAgentsDir = join58(getClaudeConfigDir(), "agents");
66452
+ const userAgentsDir = join60(getClaudeConfigDir(), "agents");
65919
66453
  const agents = loadAgentsFromDir(userAgentsDir, "user");
65920
66454
  const result = {};
65921
66455
  for (const agent of agents) {
@@ -65924,7 +66458,7 @@ function loadUserAgents() {
65924
66458
  return result;
65925
66459
  }
65926
66460
  function loadProjectAgents() {
65927
- const projectAgentsDir = join58(process.cwd(), ".claude", "agents");
66461
+ const projectAgentsDir = join60(process.cwd(), ".claude", "agents");
65928
66462
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
65929
66463
  const result = {};
65930
66464
  for (const agent of agents) {
@@ -65936,18 +66470,18 @@ function loadProjectAgents() {
65936
66470
  init_frontmatter();
65937
66471
  init_file_utils();
65938
66472
  init_logger();
65939
- import { existsSync as existsSync49, readdirSync as readdirSync18, readFileSync as readFileSync31 } from "fs";
66473
+ import { existsSync as existsSync52, readdirSync as readdirSync20, readFileSync as readFileSync32 } from "fs";
65940
66474
  import { homedir as homedir13 } from "os";
65941
- import { join as join59, basename as basename8 } from "path";
66475
+ import { join as join61, basename as basename8 } from "path";
65942
66476
  var CLAUDE_PLUGIN_ROOT_VAR = "${CLAUDE_PLUGIN_ROOT}";
65943
66477
  function getPluginsBaseDir() {
65944
66478
  if (process.env.CLAUDE_PLUGINS_HOME) {
65945
66479
  return process.env.CLAUDE_PLUGINS_HOME;
65946
66480
  }
65947
- return join59(homedir13(), ".claude", "plugins");
66481
+ return join61(homedir13(), ".claude", "plugins");
65948
66482
  }
65949
66483
  function getInstalledPluginsPath() {
65950
- return join59(getPluginsBaseDir(), "installed_plugins.json");
66484
+ return join61(getPluginsBaseDir(), "installed_plugins.json");
65951
66485
  }
65952
66486
  function resolvePluginPath(path8, pluginRoot) {
65953
66487
  return path8.replace(CLAUDE_PLUGIN_ROOT_VAR, pluginRoot);
@@ -65972,11 +66506,11 @@ function resolvePluginPaths(obj, pluginRoot) {
65972
66506
  }
65973
66507
  function loadInstalledPlugins() {
65974
66508
  const dbPath = getInstalledPluginsPath();
65975
- if (!existsSync49(dbPath)) {
66509
+ if (!existsSync52(dbPath)) {
65976
66510
  return null;
65977
66511
  }
65978
66512
  try {
65979
- const content = readFileSync31(dbPath, "utf-8");
66513
+ const content = readFileSync32(dbPath, "utf-8");
65980
66514
  return JSON.parse(content);
65981
66515
  } catch (error92) {
65982
66516
  log("Failed to load installed plugins database", error92);
@@ -65987,15 +66521,15 @@ function getClaudeSettingsPath() {
65987
66521
  if (process.env.CLAUDE_SETTINGS_PATH) {
65988
66522
  return process.env.CLAUDE_SETTINGS_PATH;
65989
66523
  }
65990
- return join59(homedir13(), ".claude", "settings.json");
66524
+ return join61(homedir13(), ".claude", "settings.json");
65991
66525
  }
65992
66526
  function loadClaudeSettings() {
65993
66527
  const settingsPath = getClaudeSettingsPath();
65994
- if (!existsSync49(settingsPath)) {
66528
+ if (!existsSync52(settingsPath)) {
65995
66529
  return null;
65996
66530
  }
65997
66531
  try {
65998
- const content = readFileSync31(settingsPath, "utf-8");
66532
+ const content = readFileSync32(settingsPath, "utf-8");
65999
66533
  return JSON.parse(content);
66000
66534
  } catch (error92) {
66001
66535
  log("Failed to load Claude settings", error92);
@@ -66003,12 +66537,12 @@ function loadClaudeSettings() {
66003
66537
  }
66004
66538
  }
66005
66539
  function loadPluginManifest(installPath) {
66006
- const manifestPath = join59(installPath, ".claude-plugin", "plugin.json");
66007
- if (!existsSync49(manifestPath)) {
66540
+ const manifestPath = join61(installPath, ".claude-plugin", "plugin.json");
66541
+ if (!existsSync52(manifestPath)) {
66008
66542
  return null;
66009
66543
  }
66010
66544
  try {
66011
- const content = readFileSync31(manifestPath, "utf-8");
66545
+ const content = readFileSync32(manifestPath, "utf-8");
66012
66546
  return JSON.parse(content);
66013
66547
  } catch (error92) {
66014
66548
  log(`Failed to load plugin manifest from ${manifestPath}`, error92);
@@ -66055,7 +66589,7 @@ function discoverInstalledPlugins(options) {
66055
66589
  continue;
66056
66590
  }
66057
66591
  const { installPath, scope, version: version3 } = installation;
66058
- if (!existsSync49(installPath)) {
66592
+ if (!existsSync52(installPath)) {
66059
66593
  errors5.push({
66060
66594
  pluginKey,
66061
66595
  installPath,
@@ -66073,21 +66607,21 @@ function discoverInstalledPlugins(options) {
66073
66607
  pluginKey,
66074
66608
  manifest: manifest ?? undefined
66075
66609
  };
66076
- if (existsSync49(join59(installPath, "commands"))) {
66077
- loadedPlugin.commandsDir = join59(installPath, "commands");
66610
+ if (existsSync52(join61(installPath, "commands"))) {
66611
+ loadedPlugin.commandsDir = join61(installPath, "commands");
66078
66612
  }
66079
- if (existsSync49(join59(installPath, "agents"))) {
66080
- loadedPlugin.agentsDir = join59(installPath, "agents");
66613
+ if (existsSync52(join61(installPath, "agents"))) {
66614
+ loadedPlugin.agentsDir = join61(installPath, "agents");
66081
66615
  }
66082
- if (existsSync49(join59(installPath, "skills"))) {
66083
- loadedPlugin.skillsDir = join59(installPath, "skills");
66616
+ if (existsSync52(join61(installPath, "skills"))) {
66617
+ loadedPlugin.skillsDir = join61(installPath, "skills");
66084
66618
  }
66085
- const hooksPath = join59(installPath, "hooks", "hooks.json");
66086
- if (existsSync49(hooksPath)) {
66619
+ const hooksPath = join61(installPath, "hooks", "hooks.json");
66620
+ if (existsSync52(hooksPath)) {
66087
66621
  loadedPlugin.hooksPath = hooksPath;
66088
66622
  }
66089
- const mcpPath = join59(installPath, ".mcp.json");
66090
- if (existsSync49(mcpPath)) {
66623
+ const mcpPath = join61(installPath, ".mcp.json");
66624
+ if (existsSync52(mcpPath)) {
66091
66625
  loadedPlugin.mcpPath = mcpPath;
66092
66626
  }
66093
66627
  plugins.push(loadedPlugin);
@@ -66098,17 +66632,17 @@ function discoverInstalledPlugins(options) {
66098
66632
  function loadPluginCommands(plugins) {
66099
66633
  const commands2 = {};
66100
66634
  for (const plugin of plugins) {
66101
- if (!plugin.commandsDir || !existsSync49(plugin.commandsDir))
66635
+ if (!plugin.commandsDir || !existsSync52(plugin.commandsDir))
66102
66636
  continue;
66103
- const entries = readdirSync18(plugin.commandsDir, { withFileTypes: true });
66637
+ const entries = readdirSync20(plugin.commandsDir, { withFileTypes: true });
66104
66638
  for (const entry of entries) {
66105
66639
  if (!isMarkdownFile(entry))
66106
66640
  continue;
66107
- const commandPath = join59(plugin.commandsDir, entry.name);
66641
+ const commandPath = join61(plugin.commandsDir, entry.name);
66108
66642
  const commandName = basename8(entry.name, ".md");
66109
66643
  const namespacedName = `${plugin.name}:${commandName}`;
66110
66644
  try {
66111
- const content = readFileSync31(commandPath, "utf-8");
66645
+ const content = readFileSync32(commandPath, "utf-8");
66112
66646
  const { data, body } = parseFrontmatter(content);
66113
66647
  const wrappedTemplate = `<command-instruction>
66114
66648
  ${body.trim()}
@@ -66140,21 +66674,21 @@ $ARGUMENTS
66140
66674
  function loadPluginSkillsAsCommands(plugins) {
66141
66675
  const skills = {};
66142
66676
  for (const plugin of plugins) {
66143
- if (!plugin.skillsDir || !existsSync49(plugin.skillsDir))
66677
+ if (!plugin.skillsDir || !existsSync52(plugin.skillsDir))
66144
66678
  continue;
66145
- const entries = readdirSync18(plugin.skillsDir, { withFileTypes: true });
66679
+ const entries = readdirSync20(plugin.skillsDir, { withFileTypes: true });
66146
66680
  for (const entry of entries) {
66147
66681
  if (entry.name.startsWith("."))
66148
66682
  continue;
66149
- const skillPath = join59(plugin.skillsDir, entry.name);
66683
+ const skillPath = join61(plugin.skillsDir, entry.name);
66150
66684
  if (!entry.isDirectory() && !entry.isSymbolicLink())
66151
66685
  continue;
66152
66686
  const resolvedPath = resolveSymlink(skillPath);
66153
- const skillMdPath = join59(resolvedPath, "SKILL.md");
66154
- if (!existsSync49(skillMdPath))
66687
+ const skillMdPath = join61(resolvedPath, "SKILL.md");
66688
+ if (!existsSync52(skillMdPath))
66155
66689
  continue;
66156
66690
  try {
66157
- const content = readFileSync31(skillMdPath, "utf-8");
66691
+ const content = readFileSync32(skillMdPath, "utf-8");
66158
66692
  const { data, body } = parseFrontmatter(content);
66159
66693
  const skillName = data.name || entry.name;
66160
66694
  const namespacedName = `${plugin.name}:${skillName}`;
@@ -66201,17 +66735,17 @@ function parseToolsConfig2(toolsStr) {
66201
66735
  function loadPluginAgents(plugins) {
66202
66736
  const agents = {};
66203
66737
  for (const plugin of plugins) {
66204
- if (!plugin.agentsDir || !existsSync49(plugin.agentsDir))
66738
+ if (!plugin.agentsDir || !existsSync52(plugin.agentsDir))
66205
66739
  continue;
66206
- const entries = readdirSync18(plugin.agentsDir, { withFileTypes: true });
66740
+ const entries = readdirSync20(plugin.agentsDir, { withFileTypes: true });
66207
66741
  for (const entry of entries) {
66208
66742
  if (!isMarkdownFile(entry))
66209
66743
  continue;
66210
- const agentPath = join59(plugin.agentsDir, entry.name);
66744
+ const agentPath = join61(plugin.agentsDir, entry.name);
66211
66745
  const agentName = basename8(entry.name, ".md");
66212
66746
  const namespacedName = `${plugin.name}:${agentName}`;
66213
66747
  try {
66214
- const content = readFileSync31(agentPath, "utf-8");
66748
+ const content = readFileSync32(agentPath, "utf-8");
66215
66749
  const { data, body } = parseFrontmatter(content);
66216
66750
  const name = data.name || agentName;
66217
66751
  const originalDescription = data.description || "";
@@ -66237,7 +66771,7 @@ function loadPluginAgents(plugins) {
66237
66771
  async function loadPluginMcpServers(plugins) {
66238
66772
  const servers = {};
66239
66773
  for (const plugin of plugins) {
66240
- if (!plugin.mcpPath || !existsSync49(plugin.mcpPath))
66774
+ if (!plugin.mcpPath || !existsSync52(plugin.mcpPath))
66241
66775
  continue;
66242
66776
  try {
66243
66777
  const content = await Bun.file(plugin.mcpPath).text();
@@ -66269,10 +66803,10 @@ async function loadPluginMcpServers(plugins) {
66269
66803
  function loadPluginHooksConfigs(plugins) {
66270
66804
  const configs = [];
66271
66805
  for (const plugin of plugins) {
66272
- if (!plugin.hooksPath || !existsSync49(plugin.hooksPath))
66806
+ if (!plugin.hooksPath || !existsSync52(plugin.hooksPath))
66273
66807
  continue;
66274
66808
  try {
66275
- const content = readFileSync31(plugin.hooksPath, "utf-8");
66809
+ const content = readFileSync32(plugin.hooksPath, "utf-8");
66276
66810
  let config4 = JSON.parse(content);
66277
66811
  config4 = resolvePluginPaths(config4, plugin.installPath);
66278
66812
  configs.push(config4);
@@ -66658,8 +67192,8 @@ Prometheus\uFF1A"\u5FEB\u901F\u4FEE\u590D\u2014\u2014\u6211\u770B\u5230\u62FC\u5
66658
67192
 
66659
67193
  **\u5148\u505A\u7814\u7A76\uFF1A**
66660
67194
  \`\`\`typescript
66661
- 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)
66662
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u53D7\u5F71\u54CD\u4EE3\u7801] \u7684\u6D4B\u8BD5\u8986\u76D6\u7387...", run_in_background=true)
67195
+ 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=[])
67196
+ 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=[])
66663
67197
  \`\`\`
66664
67198
 
66665
67199
  **\u8BBF\u8C08\u91CD\u70B9\uFF1A**
@@ -66682,9 +67216,9 @@ delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u53D7\u5F71\u54CD\
66682
67216
  **\u8BBF\u8C08\u524D\u7814\u7A76\uFF08\u5F3A\u5236\u8981\u6C42\uFF09\uFF1A**
66683
67217
  \`\`\`typescript
66684
67218
  // \u5728\u5411\u7528\u6237\u63D0\u95EE\u4E4B\u524D\u542F\u52A8
66685
- delegate_task(subagent_type="explore", prompt="\u5728\u4EE3\u7801\u5E93\u4E2D\u67E5\u627E\u7C7B\u4F3C\u5B9E\u73B0...", run_in_background=true)
66686
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u529F\u80FD\u7C7B\u578B] \u7684\u9879\u76EE\u6A21\u5F0F...", run_in_background=true)
66687
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u6280\u672F] \u7684\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true)
67219
+ delegate_task(subagent_type="explore", prompt="\u5728\u4EE3\u7801\u5E93\u4E2D\u67E5\u627E\u7C7B\u4F3C\u5B9E\u73B0...", run_in_background=true, load_skills=[])
67220
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E [\u529F\u80FD\u7C7B\u578B] \u7684\u9879\u76EE\u6A21\u5F0F...", run_in_background=true, load_skills=[])
67221
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u6280\u672F] \u7684\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true, load_skills=[])
66688
67222
  \`\`\`
66689
67223
 
66690
67224
  **\u8BBF\u8C08\u91CD\u70B9**\uFF08\u7814\u7A76\u4E4B\u540E\uFF09\uFF1A
@@ -66723,7 +67257,7 @@ Prometheus\uFF1A"\u6211\u53D1\u73B0\u4E86\u4E00\u4E9B\u60C5\u51B5\uFF1A
66723
67257
 
66724
67258
  \u8FD0\u884C\u6B64\u68C0\u67E5\uFF1A
66725
67259
  \`\`\`typescript
66726
- 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)
67260
+ 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=[])
66727
67261
  \`\`\`
66728
67262
 
66729
67263
  #### \u7B2C2\u6B65\uFF1A\u8BE2\u95EE\u6D4B\u8BD5\u95EE\u9898\uFF08\u5F3A\u5236\u8981\u6C42\uFF09
@@ -66812,13 +67346,13 @@ delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u6D4B\u8BD5\u57FA\u7
66812
67346
 
66813
67347
  **\u5148\u505A\u7814\u7A76\uFF1A**
66814
67348
  \`\`\`typescript
66815
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u5F53\u524D\u7CFB\u7EDF\u67B6\u6784\u548C\u6A21\u5F0F...", run_in_background=true)
66816
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u9886\u57DF] \u7684\u67B6\u6784\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true)
67349
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E\u5F53\u524D\u7CFB\u7EDF\u67B6\u6784\u548C\u6A21\u5F0F...", run_in_background=true, load_skills=[])
67350
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E [\u9886\u57DF] \u7684\u67B6\u6784\u6700\u4F73\u5B9E\u8DF5...", run_in_background=true, load_skills=[])
66817
67351
  \`\`\`
66818
67352
 
66819
67353
  **Oracle \u54A8\u8BE2**\uFF08\u5F53\u98CE\u9669\u8F83\u9AD8\u65F6\u63A8\u8350\uFF09\uFF1A
66820
67354
  \`\`\`typescript
66821
- delegate_task(subagent_type="oracle", prompt="\u9700\u8981\u67B6\u6784\u54A8\u8BE2\uFF1A[\u4E0A\u4E0B\u6587]...", run_in_background=false)
67355
+ delegate_task(subagent_type="oracle", prompt="\u9700\u8981\u67B6\u6784\u54A8\u8BE2\uFF1A[\u4E0A\u4E0B\u6587]...", run_in_background=false, load_skills=[])
66822
67356
  \`\`\`
66823
67357
 
66824
67358
  **\u8BBF\u8C08\u91CD\u70B9\uFF1A**
@@ -66835,9 +67369,9 @@ delegate_task(subagent_type="oracle", prompt="\u9700\u8981\u67B6\u6784\u54A8\u8B
66835
67369
 
66836
67370
  **\u5E76\u884C\u8C03\u7814\uFF1A**
66837
67371
  \`\`\`typescript
66838
- delegate_task(subagent_type="explore", prompt="\u67E5\u627E X \u5F53\u524D\u662F\u5982\u4F55\u5904\u7406\u7684...", run_in_background=true)
66839
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Y \u7684\u5B98\u65B9\u6587\u6863...", run_in_background=true)
66840
- delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Z \u7684\u5F00\u6E90\u5B9E\u73B0...", run_in_background=true)
67372
+ delegate_task(subagent_type="explore", prompt="\u67E5\u627E X \u5F53\u524D\u662F\u5982\u4F55\u5904\u7406\u7684...", run_in_background=true, load_skills=[])
67373
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Y \u7684\u5B98\u65B9\u6587\u6863...", run_in_background=true, load_skills=[])
67374
+ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Z \u7684\u5F00\u6E90\u5B9E\u73B0...", run_in_background=true, load_skills=[])
66841
67375
  \`\`\`
66842
67376
 
66843
67377
  **\u8BBF\u8C08\u91CD\u70B9\uFF1A**
@@ -66863,17 +67397,17 @@ delegate_task(subagent_type="librarian", prompt="\u67E5\u627E Z \u7684\u5F00\u6E
66863
67397
 
66864
67398
  **\u7528\u4E8E\u7406\u89E3\u4EE3\u7801\u5E93\uFF1A**
66865
67399
  \`\`\`typescript
66866
- 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)
67400
+ 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=[])
66867
67401
  \`\`\`
66868
67402
 
66869
67403
  **\u7528\u4E8E\u5916\u90E8\u77E5\u8BC6\uFF1A**
66870
67404
  \`\`\`typescript
66871
- 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)
67405
+ 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=[])
66872
67406
  \`\`\`
66873
67407
 
66874
67408
  **\u7528\u4E8E\u5B9E\u73B0\u793A\u4F8B\uFF1A**
66875
67409
  \`\`\`typescript
66876
- 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)
67410
+ 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=[])
66877
67411
  \`\`\`
66878
67412
 
66879
67413
  ## \u8BBF\u8C08\u6A21\u5F0F\u53CD\u6A21\u5F0F
@@ -66971,6 +67505,7 @@ todoWrite([
66971
67505
  \`\`\`typescript
66972
67506
  delegate_task(
66973
67507
  subagent_type="metis",
67508
+ load_skills=[],
66974
67509
  prompt=\`\u5728\u6211\u751F\u6210\u5DE5\u4F5C\u8BA1\u5212\u4E4B\u524D\uFF0C\u5BA1\u67E5\u8FD9\u6B21\u89C4\u5212\u4F1A\u8BDD\uFF1A
66975
67510
 
66976
67511
  **\u7528\u6237\u76EE\u6807**\uFF1A{\u603B\u7ED3\u7528\u6237\u60F3\u8981\u4EC0\u4E48}
@@ -67138,7 +67673,7 @@ while (true) {
67138
67673
  const result = delegate_task(
67139
67674
  subagent_type="momus",
67140
67675
  prompt=".sisyphus/plans/{name}.md",
67141
- run_in_background=false
67676
+ run_in_background=false, load_skills=[]
67142
67677
  )
67143
67678
 
67144
67679
  if (result.verdict === "OKAY") {
@@ -67798,11 +68333,56 @@ function createConfigHandler(deps) {
67798
68333
  };
67799
68334
  };
67800
68335
  }
68336
+ // src/index.ts
68337
+ init_perf_tracer();
68338
+ init_fileio_monitor();
68339
+
68340
+ // src/tools/perf-profiler/client-patch.ts
68341
+ function patchSessionClient(client2, tracer) {
68342
+ if (!tracer.isEnabled())
68343
+ return;
68344
+ const session = client2.session;
68345
+ if (!session || typeof session !== "object")
68346
+ return;
68347
+ function wrap(methodName, extractMessageCount) {
68348
+ const original = session[methodName];
68349
+ if (typeof original !== "function")
68350
+ return;
68351
+ session[methodName] = async function(opts) {
68352
+ const start = performance.now();
68353
+ let error92;
68354
+ try {
68355
+ const result = await original.call(session, opts);
68356
+ const durationMs = performance.now() - start;
68357
+ tracer.recordApiCall(methodName, durationMs, opts?.path?.id ?? "", extractMessageCount ? extractMessageCount(result) : undefined);
68358
+ return result;
68359
+ } catch (err) {
68360
+ const durationMs = performance.now() - start;
68361
+ error92 = err instanceof Error ? err.message : String(err);
68362
+ tracer.recordApiCall(methodName, durationMs, opts?.path?.id ?? "", undefined, error92);
68363
+ throw err;
68364
+ }
68365
+ };
68366
+ }
68367
+ wrap("messages", (r) => r?.data?.length ?? undefined);
68368
+ wrap("prompt", (r) => r?.data ? 1 : undefined);
68369
+ wrap("todo", (r) => r?.data?.length ?? undefined);
68370
+ wrap("status", (r) => r?.data ? Object.keys(r.data).length : undefined);
68371
+ wrap("summarize");
68372
+ }
68373
+
67801
68374
  // src/index.ts
67802
68375
  var OhMyOpenCodePlugin = async (ctx) => {
67803
68376
  log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { directory: ctx.directory });
67804
68377
  startBackgroundCheck2();
67805
68378
  const pluginConfig = loadPluginConfig(ctx.directory, ctx);
68379
+ if (process.platform === "win32") {
68380
+ const reservedNames = scanForReservedNames(ctx.directory, 3);
68381
+ if (reservedNames.length > 0) {
68382
+ console.warn(formatReservedNamesWarning(reservedNames));
68383
+ log("[oh-my-opencode] Windows reserved device names detected:", reservedNames);
68384
+ }
68385
+ }
67806
68386
  const disabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
67807
68387
  const firstMessageVariantGate = createFirstMessageVariantGate();
67808
68388
  const isHookEnabled = (hookName) => !disabledHooks.has(hookName);
@@ -67863,6 +68443,34 @@ var OhMyOpenCodePlugin = async (ctx) => {
67863
68443
  const taskResumeInfo = createTaskResumeInfoHook();
67864
68444
  const backgroundManager = new BackgroundManager(ctx, pluginConfig.background_task);
67865
68445
  const atlasHook = isHookEnabled("atlas") ? createAtlasHook(ctx, { directory: ctx.directory, backgroundManager }) : null;
68446
+ const perfTracer = pluginConfig.experimental?.profiling?.enabled ? new PerfTracer({
68447
+ enabled: true,
68448
+ outputDir: pluginConfig.experimental.profiling.output_dir,
68449
+ slowThreshold: pluginConfig.experimental.profiling.slow_threshold_ms,
68450
+ memorySnapshotInterval: pluginConfig.experimental.profiling.memory_snapshot_interval
68451
+ }) : new PerfTracer({ enabled: false });
68452
+ const memoryProbes = {};
68453
+ if (perfTracer.isEnabled()) {
68454
+ memoryProbes.subagentSessions = () => subagentSessions.size;
68455
+ memoryProbes.backgroundRunningTasks = () => backgroundManager.getRunningTasks().length;
68456
+ memoryProbes.backgroundCompletedTasks = () => backgroundManager.getCompletedTasks().length;
68457
+ }
68458
+ const perfProfiler = isHookEnabled("perf-profiler") ? createPerfProfilerHook({
68459
+ config: pluginConfig.experimental?.profiling ?? { enabled: false, slow_threshold_ms: 100, memory_snapshot_interval: 5, trace_api: true, trace_fileio: true, trace_polling: true },
68460
+ tracer: perfTracer,
68461
+ memoryProbes
68462
+ }) : null;
68463
+ if (perfTracer.isEnabled()) {
68464
+ try {
68465
+ patchSessionClient(ctx.client, perfTracer);
68466
+ } catch {}
68467
+ try {
68468
+ setFileIOMonitor(createFileIOMonitor(perfTracer));
68469
+ } catch {}
68470
+ try {
68471
+ backgroundManager.setPerfTracer(perfTracer);
68472
+ } catch {}
68473
+ }
67866
68474
  initTaskToastManager(ctx.client);
67867
68475
  const todoContinuationEnforcer = isHookEnabled("todo-continuation-enforcer") ? createTodoContinuationEnforcer(ctx, { backgroundManager }) : null;
67868
68476
  if (sessionRecovery && todoContinuationEnforcer) {
@@ -67927,6 +68535,27 @@ var OhMyOpenCodePlugin = async (ctx) => {
67927
68535
  pluginConfig,
67928
68536
  modelCacheState
67929
68537
  });
68538
+ async function wrapWithTiming(tracer, pipeline2, hookName, fn, sessionID, tool3) {
68539
+ const start = performance.now();
68540
+ let error92;
68541
+ try {
68542
+ await fn();
68543
+ } catch (e) {
68544
+ error92 = String(e);
68545
+ throw e;
68546
+ } finally {
68547
+ tracer.recordHook(pipeline2, hookName, performance.now() - start, sessionID ?? "", tool3, error92);
68548
+ }
68549
+ }
68550
+ function getEventSessionID(input) {
68551
+ const props = input.event.properties;
68552
+ if (!props)
68553
+ return "";
68554
+ const info = props.info;
68555
+ if (input.event.type === "session.deleted" || input.event.type === "session.created")
68556
+ return info?.id ?? "";
68557
+ return props.sessionID ?? "";
68558
+ }
67930
68559
  return {
67931
68560
  tool: {
67932
68561
  ...builtinTools,
@@ -67953,10 +68582,17 @@ var OhMyOpenCodePlugin = async (ctx) => {
67953
68582
  } else {
67954
68583
  applyAgentVariant(pluginConfig, input.agent, message);
67955
68584
  }
67956
- await keywordDetector?.["chat.message"]?.(input, output);
67957
- await claudeCodeHooks["chat.message"]?.(input, output);
67958
- await autoSlashCommand?.["chat.message"]?.(input, output);
67959
- await startWork?.["chat.message"]?.(input, output);
68585
+ const pipelineStart = performance.now();
68586
+ let hookCount = 0;
68587
+ await wrapWithTiming(perfTracer, "chat.message", "keywordDetector", () => keywordDetector?.["chat.message"]?.(input, output), input.sessionID);
68588
+ hookCount++;
68589
+ await wrapWithTiming(perfTracer, "chat.message", "claudeCodeHooks", () => claudeCodeHooks["chat.message"]?.(input, output), input.sessionID);
68590
+ hookCount++;
68591
+ await wrapWithTiming(perfTracer, "chat.message", "autoSlashCommand", () => autoSlashCommand?.["chat.message"]?.(input, output), input.sessionID);
68592
+ hookCount++;
68593
+ await wrapWithTiming(perfTracer, "chat.message", "startWork", () => startWork?.["chat.message"]?.(input, output), input.sessionID);
68594
+ hookCount++;
68595
+ perfTracer.recordPipeline("chat.message", performance.now() - pipelineStart, hookCount, input.sessionID);
67960
68596
  if (ralphLoop) {
67961
68597
  const parts = output.parts;
67962
68598
  const promptText = parts?.filter((p) => p.type === "text" && p.text).map((p) => p.text).join(`
@@ -67986,27 +68622,49 @@ var OhMyOpenCodePlugin = async (ctx) => {
67986
68622
  }
67987
68623
  }
67988
68624
  },
68625
+ "chat.params": async (input, output) => {
68626
+ await thinkMode?.["chat.params"]?.(input, output);
68627
+ },
67989
68628
  "experimental.chat.messages.transform": async (input, output) => {
67990
68629
  await contextInjectorMessagesTransform?.["experimental.chat.messages.transform"]?.(input, output);
67991
68630
  await thinkingBlockValidator?.["experimental.chat.messages.transform"]?.(input, output);
67992
68631
  },
67993
68632
  config: configHandler,
67994
68633
  event: async (input) => {
67995
- await autoUpdateChecker?.event(input);
67996
- await claudeCodeHooks.event(input);
67997
- await backgroundNotificationHook?.event(input);
67998
- await sessionNotification?.(input);
67999
- await todoContinuationEnforcer?.handler(input);
68000
- await contextWindowMonitor?.event(input);
68001
- await directoryAgentsInjector?.event(input);
68002
- await directoryReadmeInjector?.event(input);
68003
- await rulesInjector?.event(input);
68004
- await thinkMode?.event(input);
68005
- await anthropicContextWindowLimitRecovery?.event(input);
68006
- await agentUsageReminder?.event(input);
68007
- await interactiveBashSession?.event(input);
68008
- await ralphLoop?.event(input);
68009
- await atlasHook?.handler(input);
68634
+ const pipelineStart = performance.now();
68635
+ let hookCount = 0;
68636
+ await perfProfiler?.event?.(input);
68637
+ const evtSessionID = getEventSessionID(input);
68638
+ await wrapWithTiming(perfTracer, "event", "autoUpdateChecker", () => autoUpdateChecker?.event(input), evtSessionID);
68639
+ hookCount++;
68640
+ await wrapWithTiming(perfTracer, "event", "claudeCodeHooks", () => claudeCodeHooks.event(input), evtSessionID);
68641
+ hookCount++;
68642
+ await wrapWithTiming(perfTracer, "event", "backgroundNotificationHook", () => backgroundNotificationHook?.event(input), evtSessionID);
68643
+ hookCount++;
68644
+ await wrapWithTiming(perfTracer, "event", "sessionNotification", () => sessionNotification?.(input), evtSessionID);
68645
+ hookCount++;
68646
+ await wrapWithTiming(perfTracer, "event", "todoContinuationEnforcer", () => todoContinuationEnforcer?.handler(input), evtSessionID);
68647
+ hookCount++;
68648
+ await wrapWithTiming(perfTracer, "event", "contextWindowMonitor", () => contextWindowMonitor?.event(input), evtSessionID);
68649
+ hookCount++;
68650
+ await wrapWithTiming(perfTracer, "event", "directoryAgentsInjector", () => directoryAgentsInjector?.event(input), evtSessionID);
68651
+ hookCount++;
68652
+ await wrapWithTiming(perfTracer, "event", "directoryReadmeInjector", () => directoryReadmeInjector?.event(input), evtSessionID);
68653
+ hookCount++;
68654
+ await wrapWithTiming(perfTracer, "event", "rulesInjector", () => rulesInjector?.event(input), evtSessionID);
68655
+ hookCount++;
68656
+ await wrapWithTiming(perfTracer, "event", "thinkMode", () => thinkMode?.event(input), evtSessionID);
68657
+ hookCount++;
68658
+ await wrapWithTiming(perfTracer, "event", "anthropicContextWindowLimitRecovery", () => anthropicContextWindowLimitRecovery?.event(input), evtSessionID);
68659
+ hookCount++;
68660
+ await wrapWithTiming(perfTracer, "event", "agentUsageReminder", () => agentUsageReminder?.event(input), evtSessionID);
68661
+ hookCount++;
68662
+ await wrapWithTiming(perfTracer, "event", "interactiveBashSession", () => interactiveBashSession?.event(input), evtSessionID);
68663
+ hookCount++;
68664
+ await wrapWithTiming(perfTracer, "event", "ralphLoop", () => ralphLoop?.event(input), evtSessionID);
68665
+ hookCount++;
68666
+ await wrapWithTiming(perfTracer, "event", "atlasHook", () => atlasHook?.handler(input), evtSessionID);
68667
+ hookCount++;
68010
68668
  const { event } = input;
68011
68669
  const props = event.properties;
68012
68670
  if (event.type === "session.created") {
@@ -68059,17 +68717,30 @@ var OhMyOpenCodePlugin = async (ctx) => {
68059
68717
  }
68060
68718
  }
68061
68719
  }
68720
+ perfTracer.recordPipeline("event", performance.now() - pipelineStart, hookCount, evtSessionID);
68721
+ perfTracer.flush();
68062
68722
  },
68063
68723
  "tool.execute.before": async (input, output) => {
68064
- await questionLabelTruncator["tool.execute.before"]?.(input, output);
68065
- await claudeCodeHooks["tool.execute.before"](input, output);
68066
- await nonInteractiveEnv?.["tool.execute.before"](input, output);
68067
- await commentChecker?.["tool.execute.before"](input, output);
68068
- await directoryAgentsInjector?.["tool.execute.before"]?.(input, output);
68069
- await directoryReadmeInjector?.["tool.execute.before"]?.(input, output);
68070
- await rulesInjector?.["tool.execute.before"]?.(input, output);
68071
- await prometheusMdOnly?.["tool.execute.before"]?.(input, output);
68072
- await atlasHook?.["tool.execute.before"]?.(input, output);
68724
+ const pipelineStart = performance.now();
68725
+ let hookCount = 0;
68726
+ await wrapWithTiming(perfTracer, "tool.execute.before", "questionLabelTruncator", () => questionLabelTruncator["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68727
+ hookCount++;
68728
+ await wrapWithTiming(perfTracer, "tool.execute.before", "claudeCodeHooks", () => claudeCodeHooks["tool.execute.before"](input, output), input.sessionID, input.tool);
68729
+ hookCount++;
68730
+ await wrapWithTiming(perfTracer, "tool.execute.before", "nonInteractiveEnv", () => nonInteractiveEnv?.["tool.execute.before"](input, output), input.sessionID, input.tool);
68731
+ hookCount++;
68732
+ await wrapWithTiming(perfTracer, "tool.execute.before", "commentChecker", () => commentChecker?.["tool.execute.before"](input, output), input.sessionID, input.tool);
68733
+ hookCount++;
68734
+ await wrapWithTiming(perfTracer, "tool.execute.before", "directoryAgentsInjector", () => directoryAgentsInjector?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68735
+ hookCount++;
68736
+ await wrapWithTiming(perfTracer, "tool.execute.before", "directoryReadmeInjector", () => directoryReadmeInjector?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68737
+ hookCount++;
68738
+ await wrapWithTiming(perfTracer, "tool.execute.before", "rulesInjector", () => rulesInjector?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68739
+ hookCount++;
68740
+ await wrapWithTiming(perfTracer, "tool.execute.before", "prometheusMdOnly", () => prometheusMdOnly?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68741
+ hookCount++;
68742
+ await wrapWithTiming(perfTracer, "tool.execute.before", "atlasHook", () => atlasHook?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68743
+ hookCount++;
68073
68744
  if (input.tool === "task") {
68074
68745
  const args = output.args;
68075
68746
  const subagentType = args.subagent_type;
@@ -68109,22 +68780,40 @@ var OhMyOpenCodePlugin = async (ctx) => {
68109
68780
  });
68110
68781
  }
68111
68782
  }
68783
+ perfTracer.recordPipeline("tool.execute.before", performance.now() - pipelineStart, hookCount, input.sessionID);
68112
68784
  },
68113
68785
  "tool.execute.after": async (input, output) => {
68114
- await claudeCodeHooks["tool.execute.after"](input, output);
68115
- await toolOutputTruncator?.["tool.execute.after"](input, output);
68116
- await contextWindowMonitor?.["tool.execute.after"](input, output);
68117
- await commentChecker?.["tool.execute.after"](input, output);
68118
- await directoryAgentsInjector?.["tool.execute.after"](input, output);
68119
- await directoryReadmeInjector?.["tool.execute.after"](input, output);
68120
- await rulesInjector?.["tool.execute.after"](input, output);
68121
- await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
68122
- await agentUsageReminder?.["tool.execute.after"](input, output);
68123
- await interactiveBashSession?.["tool.execute.after"](input, output);
68124
- await editErrorRecovery?.["tool.execute.after"](input, output);
68125
- await delegateTaskRetry?.["tool.execute.after"](input, output);
68126
- await atlasHook?.["tool.execute.after"]?.(input, output);
68127
- await taskResumeInfo["tool.execute.after"](input, output);
68786
+ const pipelineStart = performance.now();
68787
+ let hookCount = 0;
68788
+ await wrapWithTiming(perfTracer, "tool.execute.after", "claudeCodeHooks", () => claudeCodeHooks["tool.execute.after"](input, output), input.sessionID, input.tool);
68789
+ hookCount++;
68790
+ await wrapWithTiming(perfTracer, "tool.execute.after", "toolOutputTruncator", () => toolOutputTruncator?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68791
+ hookCount++;
68792
+ await wrapWithTiming(perfTracer, "tool.execute.after", "contextWindowMonitor", () => contextWindowMonitor?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68793
+ hookCount++;
68794
+ await wrapWithTiming(perfTracer, "tool.execute.after", "commentChecker", () => commentChecker?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68795
+ hookCount++;
68796
+ await wrapWithTiming(perfTracer, "tool.execute.after", "directoryAgentsInjector", () => directoryAgentsInjector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68797
+ hookCount++;
68798
+ await wrapWithTiming(perfTracer, "tool.execute.after", "directoryReadmeInjector", () => directoryReadmeInjector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68799
+ hookCount++;
68800
+ await wrapWithTiming(perfTracer, "tool.execute.after", "rulesInjector", () => rulesInjector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68801
+ hookCount++;
68802
+ await wrapWithTiming(perfTracer, "tool.execute.after", "emptyTaskResponseDetector", () => emptyTaskResponseDetector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68803
+ hookCount++;
68804
+ await wrapWithTiming(perfTracer, "tool.execute.after", "agentUsageReminder", () => agentUsageReminder?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68805
+ hookCount++;
68806
+ await wrapWithTiming(perfTracer, "tool.execute.after", "interactiveBashSession", () => interactiveBashSession?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68807
+ hookCount++;
68808
+ await wrapWithTiming(perfTracer, "tool.execute.after", "editErrorRecovery", () => editErrorRecovery?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68809
+ hookCount++;
68810
+ await wrapWithTiming(perfTracer, "tool.execute.after", "delegateTaskRetry", () => delegateTaskRetry?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68811
+ hookCount++;
68812
+ await wrapWithTiming(perfTracer, "tool.execute.after", "atlasHook", () => atlasHook?.["tool.execute.after"]?.(input, output), input.sessionID, input.tool);
68813
+ hookCount++;
68814
+ await wrapWithTiming(perfTracer, "tool.execute.after", "taskResumeInfo", () => taskResumeInfo["tool.execute.after"](input, output), input.sessionID, input.tool);
68815
+ hookCount++;
68816
+ perfTracer.recordPipeline("tool.execute.after", performance.now() - pipelineStart, hookCount, input.sessionID);
68128
68817
  }
68129
68818
  };
68130
68819
  };