@skj1724/oh-my-opencode 3.19.3 → 3.19.5

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
  }
@@ -4781,7 +4859,7 @@ var init_agent_tool_restrictions = __esm(() => {
4781
4859
  });
4782
4860
 
4783
4861
  // src/shared/model-requirements.ts
4784
- var AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS;
4862
+ var AGENT_MODEL_REQUIREMENTS;
4785
4863
  var init_model_requirements = __esm(() => {
4786
4864
  AGENT_MODEL_REQUIREMENTS = {
4787
4865
  sisyphus: {
@@ -4850,62 +4928,10 @@ var init_model_requirements = __esm(() => {
4850
4928
  ]
4851
4929
  }
4852
4930
  };
4853
- CATEGORY_MODEL_REQUIREMENTS = {
4854
- "visual-engineering": {
4855
- fallbackChain: [
4856
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" },
4857
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4858
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" }
4859
- ]
4860
- },
4861
- ultrabrain: {
4862
- fallbackChain: [
4863
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
4864
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4865
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4866
- ]
4867
- },
4868
- artistry: {
4869
- fallbackChain: [
4870
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
4871
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4872
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4873
- ]
4874
- },
4875
- quick: {
4876
- fallbackChain: [
4877
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
4878
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4879
- { providers: ["opencode"], model: "gpt-5-nano" }
4880
- ]
4881
- },
4882
- "unspecified-low": {
4883
- fallbackChain: [
4884
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4885
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
4886
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
4887
- ]
4888
- },
4889
- "unspecified-high": {
4890
- fallbackChain: [
4891
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4892
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4893
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4894
- ]
4895
- },
4896
- writing: {
4897
- fallbackChain: [
4898
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4899
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4900
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
4901
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4902
- ]
4903
- }
4904
- };
4905
4931
  });
4906
4932
 
4907
4933
  // src/shared/model-availability.ts
4908
- import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
4934
+ import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
4909
4935
  import { homedir as homedir6 } from "os";
4910
4936
  import { join as join12 } from "path";
4911
4937
  function normalizeModelName(name) {
@@ -4960,12 +4986,12 @@ async function fetchAvailableModels(_client) {
4960
4986
  const modelSet = new Set;
4961
4987
  const cacheFile = join12(getOpenCodeCacheDir(), "models.json");
4962
4988
  log("[fetchAvailableModels] reading cache file", { cacheFile });
4963
- if (!existsSync9(cacheFile)) {
4989
+ if (!existsSync10(cacheFile)) {
4964
4990
  log("[fetchAvailableModels] cache file not found, returning empty set");
4965
4991
  return modelSet;
4966
4992
  }
4967
4993
  try {
4968
- const content = readFileSync6(cacheFile, "utf-8");
4994
+ const content = readFileSync7(cacheFile, "utf-8");
4969
4995
  const data = JSON.parse(content);
4970
4996
  const providerIds = Object.keys(data);
4971
4997
  log("[fetchAvailableModels] providers found", { count: providerIds.length, providers: providerIds.slice(0, 10) });
@@ -4988,7 +5014,7 @@ async function fetchAvailableModels(_client) {
4988
5014
  }
4989
5015
  function isModelCacheAvailable() {
4990
5016
  const cacheFile = join12(getOpenCodeCacheDir(), "models.json");
4991
- return existsSync9(cacheFile);
5017
+ return existsSync10(cacheFile);
4992
5018
  }
4993
5019
  var cachedModels = null;
4994
5020
  var init_model_availability = __esm(() => {
@@ -5038,6 +5064,183 @@ var init_model_resolver = __esm(() => {
5038
5064
  init_model_availability();
5039
5065
  });
5040
5066
 
5067
+ // src/shared/perf-timer.ts
5068
+ class PerfTimer {
5069
+ marks = new Map;
5070
+ spans = [];
5071
+ mark(name) {
5072
+ this.marks.set(name, performance.now());
5073
+ }
5074
+ measure(name, startMark, endMark) {
5075
+ const start = this.marks.get(startMark);
5076
+ if (start === undefined)
5077
+ return 0;
5078
+ const end = endMark ? this.marks.get(endMark) ?? performance.now() : performance.now();
5079
+ const duration = end - start;
5080
+ this.spans.push({ name, durationMs: duration, start, end });
5081
+ return duration;
5082
+ }
5083
+ getReport() {
5084
+ return [...this.spans];
5085
+ }
5086
+ reset() {
5087
+ this.marks.clear();
5088
+ this.spans = [];
5089
+ }
5090
+ static formatDuration(start, end, options) {
5091
+ const ms = (end ?? new Date).getTime() - start.getTime();
5092
+ const absMs = Math.abs(ms);
5093
+ const totalSeconds = absMs / 1000;
5094
+ const seconds = Math.floor(totalSeconds);
5095
+ const minutes = Math.floor(seconds / 60);
5096
+ const hours = Math.floor(minutes / 60);
5097
+ const precision = options?.precision ?? "full";
5098
+ if (hours > 0) {
5099
+ if (precision === "compact") {
5100
+ return `${hours}h ${minutes % 60}m`;
5101
+ }
5102
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
5103
+ }
5104
+ if (minutes > 0) {
5105
+ return `${minutes}m ${seconds % 60}s`;
5106
+ }
5107
+ if (seconds === 0 && absMs > 0) {
5108
+ return `${(absMs / 1000).toFixed(1)}s`;
5109
+ }
5110
+ return `${seconds}s`;
5111
+ }
5112
+ }
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
+
5041
5244
  // src/shared/index.ts
5042
5245
  var init_shared = __esm(() => {
5043
5246
  init_frontmatter();
@@ -5065,6 +5268,8 @@ var init_shared = __esm(() => {
5065
5268
  init_model_requirements();
5066
5269
  init_model_resolver();
5067
5270
  init_model_availability();
5271
+ init_perf_tracer();
5272
+ init_fileio_monitor();
5068
5273
  });
5069
5274
 
5070
5275
  // node_modules/picomatch/lib/constants.js
@@ -10949,49 +11154,49 @@ var require_fast_uri = __commonJS((exports, module) => {
10949
11154
  schemelessOptions.skipEscape = true;
10950
11155
  return serialize(resolved, schemelessOptions);
10951
11156
  }
10952
- function resolveComponent(base, relative5, options, skipNormalization) {
11157
+ function resolveComponent(base, relative6, options, skipNormalization) {
10953
11158
  const target = {};
10954
11159
  if (!skipNormalization) {
10955
11160
  base = parse11(serialize(base, options), options);
10956
- relative5 = parse11(serialize(relative5, options), options);
11161
+ relative6 = parse11(serialize(relative6, options), options);
10957
11162
  }
10958
11163
  options = options || {};
10959
- if (!options.tolerant && relative5.scheme) {
10960
- target.scheme = relative5.scheme;
10961
- target.userinfo = relative5.userinfo;
10962
- target.host = relative5.host;
10963
- target.port = relative5.port;
10964
- target.path = removeDotSegments(relative5.path || "");
10965
- target.query = relative5.query;
11164
+ if (!options.tolerant && relative6.scheme) {
11165
+ target.scheme = relative6.scheme;
11166
+ target.userinfo = relative6.userinfo;
11167
+ target.host = relative6.host;
11168
+ target.port = relative6.port;
11169
+ target.path = removeDotSegments(relative6.path || "");
11170
+ target.query = relative6.query;
10966
11171
  } else {
10967
- if (relative5.userinfo !== undefined || relative5.host !== undefined || relative5.port !== undefined) {
10968
- target.userinfo = relative5.userinfo;
10969
- target.host = relative5.host;
10970
- target.port = relative5.port;
10971
- target.path = removeDotSegments(relative5.path || "");
10972
- target.query = relative5.query;
11172
+ if (relative6.userinfo !== undefined || relative6.host !== undefined || relative6.port !== undefined) {
11173
+ target.userinfo = relative6.userinfo;
11174
+ target.host = relative6.host;
11175
+ target.port = relative6.port;
11176
+ target.path = removeDotSegments(relative6.path || "");
11177
+ target.query = relative6.query;
10973
11178
  } else {
10974
- if (!relative5.path) {
11179
+ if (!relative6.path) {
10975
11180
  target.path = base.path;
10976
- if (relative5.query !== undefined) {
10977
- target.query = relative5.query;
11181
+ if (relative6.query !== undefined) {
11182
+ target.query = relative6.query;
10978
11183
  } else {
10979
11184
  target.query = base.query;
10980
11185
  }
10981
11186
  } else {
10982
- if (relative5.path[0] === "/") {
10983
- target.path = removeDotSegments(relative5.path);
11187
+ if (relative6.path[0] === "/") {
11188
+ target.path = removeDotSegments(relative6.path);
10984
11189
  } else {
10985
11190
  if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
10986
- target.path = "/" + relative5.path;
11191
+ target.path = "/" + relative6.path;
10987
11192
  } else if (!base.path) {
10988
- target.path = relative5.path;
11193
+ target.path = relative6.path;
10989
11194
  } else {
10990
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative5.path;
11195
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative6.path;
10991
11196
  }
10992
11197
  target.path = removeDotSegments(target.path);
10993
11198
  }
10994
- target.query = relative5.query;
11199
+ target.query = relative6.query;
10995
11200
  }
10996
11201
  target.userinfo = base.userinfo;
10997
11202
  target.host = base.host;
@@ -10999,7 +11204,7 @@ var require_fast_uri = __commonJS((exports, module) => {
10999
11204
  }
11000
11205
  target.scheme = base.scheme;
11001
11206
  }
11002
- target.fragment = relative5.fragment;
11207
+ target.fragment = relative6.fragment;
11003
11208
  return target;
11004
11209
  }
11005
11210
  function equal(uriA, uriB, options) {
@@ -14206,7 +14411,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
14206
14411
  var getPathKey = require_path_key();
14207
14412
  function resolveCommandAttempt(parsed, withoutPathExt) {
14208
14413
  const env = parsed.options.env || process.env;
14209
- const cwd = process.cwd();
14414
+ const cwd2 = process.cwd();
14210
14415
  const hasCustomCwd = parsed.options.cwd != null;
14211
14416
  const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled;
14212
14417
  if (shouldSwitchCwd) {
@@ -14222,7 +14427,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
14222
14427
  });
14223
14428
  } catch (e) {} finally {
14224
14429
  if (shouldSwitchCwd) {
14225
- process.chdir(cwd);
14430
+ process.chdir(cwd2);
14226
14431
  }
14227
14432
  }
14228
14433
  if (resolved) {
@@ -14429,7 +14634,7 @@ var require_cross_spawn = __commonJS((exports, module) => {
14429
14634
  });
14430
14635
 
14431
14636
  // src/hooks/todo-continuation-enforcer.ts
14432
- import { existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
14637
+ import { existsSync as existsSync3, readdirSync as readdirSync3 } from "fs";
14433
14638
  import { join as join5 } from "path";
14434
14639
 
14435
14640
  // src/features/claude-code-session-state/state.ts
@@ -14457,7 +14662,8 @@ function clearSessionAgent(sessionID) {
14457
14662
  sessionAgentMap.delete(sessionID);
14458
14663
  }
14459
14664
  // src/features/hook-message-injector/injector.ts
14460
- import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
14665
+ init_fileio_monitor();
14666
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
14461
14667
  import { join as join3 } from "path";
14462
14668
 
14463
14669
  // src/features/hook-message-injector/constants.ts
@@ -14469,11 +14675,12 @@ var PART_STORAGE = join2(OPENCODE_STORAGE, "part");
14469
14675
 
14470
14676
  // src/features/hook-message-injector/injector.ts
14471
14677
  function findNearestMessageWithFields(messageDir) {
14678
+ const monitor = getFileIOMonitor();
14472
14679
  try {
14473
- const files = readdirSync(messageDir).filter((f) => f.endsWith(".json")).sort().reverse();
14680
+ const files = (monitor?.readdirSync(messageDir) ?? readdirSync2(messageDir)).filter((f) => f.endsWith(".json")).sort().reverse();
14474
14681
  for (const file of files) {
14475
14682
  try {
14476
- const content = readFileSync(join3(messageDir, file), "utf-8");
14683
+ const content = monitor?.readFileSync(join3(messageDir, file), "utf-8") ?? readFileSync2(join3(messageDir, file), "utf-8");
14477
14684
  const msg = JSON.parse(content);
14478
14685
  if (msg.agent && msg.model?.providerID && msg.model?.modelID) {
14479
14686
  return msg;
@@ -14484,7 +14691,7 @@ function findNearestMessageWithFields(messageDir) {
14484
14691
  }
14485
14692
  for (const file of files) {
14486
14693
  try {
14487
- const content = readFileSync(join3(messageDir, file), "utf-8");
14694
+ const content = monitor?.readFileSync(join3(messageDir, file), "utf-8") ?? readFileSync2(join3(messageDir, file), "utf-8");
14488
14695
  const msg = JSON.parse(content);
14489
14696
  if (msg.agent || msg.model?.providerID && msg.model?.modelID) {
14490
14697
  return msg;
@@ -14499,11 +14706,12 @@ function findNearestMessageWithFields(messageDir) {
14499
14706
  return null;
14500
14707
  }
14501
14708
  function findFirstMessageWithAgent(messageDir) {
14709
+ const monitor = getFileIOMonitor();
14502
14710
  try {
14503
- const files = readdirSync(messageDir).filter((f) => f.endsWith(".json")).sort();
14711
+ const files = (monitor?.readdirSync(messageDir) ?? readdirSync2(messageDir)).filter((f) => f.endsWith(".json")).sort();
14504
14712
  for (const file of files) {
14505
14713
  try {
14506
- const content = readFileSync(join3(messageDir, file), "utf-8");
14714
+ const content = monitor?.readFileSync(join3(messageDir, file), "utf-8") ?? readFileSync2(join3(messageDir, file), "utf-8");
14507
14715
  const msg = JSON.parse(content);
14508
14716
  if (msg.agent) {
14509
14717
  return msg.agent;
@@ -14528,20 +14736,24 @@ function generatePartId() {
14528
14736
  return `prt_${timestamp}${random}`;
14529
14737
  }
14530
14738
  function getOrCreateMessageDir(sessionID) {
14531
- if (!existsSync(MESSAGE_STORAGE)) {
14532
- mkdirSync(MESSAGE_STORAGE, { recursive: true });
14739
+ const monitor = getFileIOMonitor();
14740
+ const _exists = (p) => monitor?.existsSync(p) ?? existsSync2(p);
14741
+ const _mkdir = (p, opts) => monitor ? undefined : mkdirSync(p, opts);
14742
+ const _readdir = (p) => monitor?.readdirSync(p) ?? readdirSync2(p);
14743
+ if (!_exists(MESSAGE_STORAGE)) {
14744
+ _mkdir(MESSAGE_STORAGE, { recursive: true });
14533
14745
  }
14534
14746
  const directPath = join3(MESSAGE_STORAGE, sessionID);
14535
- if (existsSync(directPath)) {
14747
+ if (_exists(directPath)) {
14536
14748
  return directPath;
14537
14749
  }
14538
- for (const dir of readdirSync(MESSAGE_STORAGE)) {
14750
+ for (const dir of _readdir(MESSAGE_STORAGE)) {
14539
14751
  const sessionPath = join3(MESSAGE_STORAGE, dir, sessionID);
14540
- if (existsSync(sessionPath)) {
14752
+ if (_exists(sessionPath)) {
14541
14753
  return sessionPath;
14542
14754
  }
14543
14755
  }
14544
- mkdirSync(directPath, { recursive: true });
14756
+ _mkdir(directPath, { recursive: true });
14545
14757
  return directPath;
14546
14758
  }
14547
14759
  function injectHookMessage(sessionID, hookContent, originalMessage) {
@@ -14590,12 +14802,22 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
14590
14802
  sessionID
14591
14803
  };
14592
14804
  try {
14593
- writeFileSync(join3(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
14805
+ const monitor = getFileIOMonitor();
14806
+ if (monitor) {
14807
+ monitor.writeFileSync(join3(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
14808
+ } else {
14809
+ writeFileSync2(join3(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
14810
+ }
14594
14811
  const partDir = join3(PART_STORAGE, messageID);
14595
- if (!existsSync(partDir)) {
14812
+ const _exists = (p) => monitor?.existsSync(p) ?? existsSync2(p);
14813
+ if (!_exists(partDir)) {
14596
14814
  mkdirSync(partDir, { recursive: true });
14597
14815
  }
14598
- writeFileSync(join3(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
14816
+ if (monitor) {
14817
+ monitor.writeFileSync(join3(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
14818
+ } else {
14819
+ writeFileSync2(join3(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
14820
+ }
14599
14821
  return true;
14600
14822
  } catch {
14601
14823
  return false;
@@ -14617,14 +14839,14 @@ var COUNTDOWN_SECONDS = 2;
14617
14839
  var TOAST_DURATION_MS = 900;
14618
14840
  var COUNTDOWN_GRACE_PERIOD_MS = 500;
14619
14841
  function getMessageDir(sessionID) {
14620
- if (!existsSync2(MESSAGE_STORAGE))
14842
+ if (!existsSync3(MESSAGE_STORAGE))
14621
14843
  return null;
14622
14844
  const directPath = join5(MESSAGE_STORAGE, sessionID);
14623
- if (existsSync2(directPath))
14845
+ if (existsSync3(directPath))
14624
14846
  return directPath;
14625
- for (const dir of readdirSync2(MESSAGE_STORAGE)) {
14847
+ for (const dir of readdirSync3(MESSAGE_STORAGE)) {
14626
14848
  const sessionPath = join5(MESSAGE_STORAGE, dir, sessionID);
14627
- if (existsSync2(sessionPath))
14849
+ if (existsSync3(sessionPath))
14628
14850
  return sessionPath;
14629
14851
  }
14630
14852
  return null;
@@ -15402,7 +15624,7 @@ function createSessionNotification(ctx, config = {}) {
15402
15624
  };
15403
15625
  }
15404
15626
  // src/hooks/session-recovery/storage.ts
15405
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
15627
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync4, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
15406
15628
  import { join as join7 } from "path";
15407
15629
 
15408
15630
  // src/hooks/session-recovery/constants.ts
@@ -15423,15 +15645,15 @@ function generatePartId2() {
15423
15645
  return `prt_${timestamp}${random}`;
15424
15646
  }
15425
15647
  function getMessageDir2(sessionID) {
15426
- if (!existsSync3(MESSAGE_STORAGE2))
15648
+ if (!existsSync4(MESSAGE_STORAGE2))
15427
15649
  return "";
15428
15650
  const directPath = join7(MESSAGE_STORAGE2, sessionID);
15429
- if (existsSync3(directPath)) {
15651
+ if (existsSync4(directPath)) {
15430
15652
  return directPath;
15431
15653
  }
15432
- for (const dir of readdirSync3(MESSAGE_STORAGE2)) {
15654
+ for (const dir of readdirSync4(MESSAGE_STORAGE2)) {
15433
15655
  const sessionPath = join7(MESSAGE_STORAGE2, dir, sessionID);
15434
- if (existsSync3(sessionPath)) {
15656
+ if (existsSync4(sessionPath)) {
15435
15657
  return sessionPath;
15436
15658
  }
15437
15659
  }
@@ -15439,14 +15661,14 @@ function getMessageDir2(sessionID) {
15439
15661
  }
15440
15662
  function readMessages(sessionID) {
15441
15663
  const messageDir = getMessageDir2(sessionID);
15442
- if (!messageDir || !existsSync3(messageDir))
15664
+ if (!messageDir || !existsSync4(messageDir))
15443
15665
  return [];
15444
15666
  const messages = [];
15445
- for (const file of readdirSync3(messageDir)) {
15667
+ for (const file of readdirSync4(messageDir)) {
15446
15668
  if (!file.endsWith(".json"))
15447
15669
  continue;
15448
15670
  try {
15449
- const content = readFileSync2(join7(messageDir, file), "utf-8");
15671
+ const content = readFileSync3(join7(messageDir, file), "utf-8");
15450
15672
  messages.push(JSON.parse(content));
15451
15673
  } catch {
15452
15674
  continue;
@@ -15462,14 +15684,14 @@ function readMessages(sessionID) {
15462
15684
  }
15463
15685
  function readParts(messageID) {
15464
15686
  const partDir = join7(PART_STORAGE2, messageID);
15465
- if (!existsSync3(partDir))
15687
+ if (!existsSync4(partDir))
15466
15688
  return [];
15467
15689
  const parts = [];
15468
- for (const file of readdirSync3(partDir)) {
15690
+ for (const file of readdirSync4(partDir)) {
15469
15691
  if (!file.endsWith(".json"))
15470
15692
  continue;
15471
15693
  try {
15472
- const content = readFileSync2(join7(partDir, file), "utf-8");
15694
+ const content = readFileSync3(join7(partDir, file), "utf-8");
15473
15695
  parts.push(JSON.parse(content));
15474
15696
  } catch {
15475
15697
  continue;
@@ -15500,7 +15722,7 @@ function messageHasContent(messageID) {
15500
15722
  }
15501
15723
  function injectTextPart(sessionID, messageID, text) {
15502
15724
  const partDir = join7(PART_STORAGE2, messageID);
15503
- if (!existsSync3(partDir)) {
15725
+ if (!existsSync4(partDir)) {
15504
15726
  mkdirSync2(partDir, { recursive: true });
15505
15727
  }
15506
15728
  const partId = generatePartId2();
@@ -15513,7 +15735,7 @@ function injectTextPart(sessionID, messageID, text) {
15513
15735
  synthetic: true
15514
15736
  };
15515
15737
  try {
15516
- writeFileSync2(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15738
+ writeFileSync3(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15517
15739
  return true;
15518
15740
  } catch {
15519
15741
  return false;
@@ -15609,7 +15831,7 @@ function findLastThinkingContent(sessionID, beforeMessageID) {
15609
15831
  }
15610
15832
  function prependThinkingPart(sessionID, messageID) {
15611
15833
  const partDir = join7(PART_STORAGE2, messageID);
15612
- if (!existsSync3(partDir)) {
15834
+ if (!existsSync4(partDir)) {
15613
15835
  mkdirSync2(partDir, { recursive: true });
15614
15836
  }
15615
15837
  const previousThinking = findLastThinkingContent(sessionID, messageID);
@@ -15619,11 +15841,11 @@ function prependThinkingPart(sessionID, messageID) {
15619
15841
  sessionID,
15620
15842
  messageID,
15621
15843
  type: "thinking",
15622
- thinking: previousThinking || "[Continuing from previous reasoning]",
15844
+ thinking: previousThinking || "[\u63A5\u7EED\u4E4B\u524D\u7684\u63A8\u7406]",
15623
15845
  synthetic: true
15624
15846
  };
15625
15847
  try {
15626
- writeFileSync2(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15848
+ writeFileSync3(join7(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
15627
15849
  return true;
15628
15850
  } catch {
15629
15851
  return false;
@@ -15631,15 +15853,15 @@ function prependThinkingPart(sessionID, messageID) {
15631
15853
  }
15632
15854
  function stripThinkingParts(messageID) {
15633
15855
  const partDir = join7(PART_STORAGE2, messageID);
15634
- if (!existsSync3(partDir))
15856
+ if (!existsSync4(partDir))
15635
15857
  return false;
15636
15858
  let anyRemoved = false;
15637
- for (const file of readdirSync3(partDir)) {
15859
+ for (const file of readdirSync4(partDir)) {
15638
15860
  if (!file.endsWith(".json"))
15639
15861
  continue;
15640
15862
  try {
15641
15863
  const filePath = join7(partDir, file);
15642
- const content = readFileSync2(filePath, "utf-8");
15864
+ const content = readFileSync3(filePath, "utf-8");
15643
15865
  const part = JSON.parse(content);
15644
15866
  if (THINKING_TYPES.has(part.type)) {
15645
15867
  unlinkSync(filePath);
@@ -15653,22 +15875,22 @@ function stripThinkingParts(messageID) {
15653
15875
  }
15654
15876
  function replaceEmptyTextParts(messageID, replacementText) {
15655
15877
  const partDir = join7(PART_STORAGE2, messageID);
15656
- if (!existsSync3(partDir))
15878
+ if (!existsSync4(partDir))
15657
15879
  return false;
15658
15880
  let anyReplaced = false;
15659
- for (const file of readdirSync3(partDir)) {
15881
+ for (const file of readdirSync4(partDir)) {
15660
15882
  if (!file.endsWith(".json"))
15661
15883
  continue;
15662
15884
  try {
15663
15885
  const filePath = join7(partDir, file);
15664
- const content = readFileSync2(filePath, "utf-8");
15886
+ const content = readFileSync3(filePath, "utf-8");
15665
15887
  const part = JSON.parse(content);
15666
15888
  if (part.type === "text") {
15667
15889
  const textPart = part;
15668
15890
  if (!textPart.text?.trim()) {
15669
15891
  textPart.text = replacementText;
15670
15892
  textPart.synthetic = true;
15671
- writeFileSync2(filePath, JSON.stringify(textPart, null, 2));
15893
+ writeFileSync3(filePath, JSON.stringify(textPart, null, 2));
15672
15894
  anyReplaced = true;
15673
15895
  }
15674
15896
  }
@@ -15937,25 +16159,25 @@ function createSessionRecoveryHook(ctx, options) {
15937
16159
  // src/hooks/comment-checker/cli.ts
15938
16160
  var {spawn: spawn5 } = globalThis.Bun;
15939
16161
  import { createRequire as createRequire2 } from "module";
15940
- import { dirname, join as join14 } from "path";
15941
- import { existsSync as existsSync11 } from "fs";
16162
+ import { dirname, join as join15 } from "path";
16163
+ import { existsSync as existsSync13 } from "fs";
15942
16164
  import * as fs5 from "fs";
15943
- import { tmpdir as tmpdir3 } from "os";
16165
+ import { tmpdir as tmpdir4 } from "os";
15944
16166
 
15945
16167
  // src/hooks/comment-checker/downloader.ts
15946
16168
  init_shared();
15947
16169
  var {spawn: spawn4 } = globalThis.Bun;
15948
- import { existsSync as existsSync10, mkdirSync as mkdirSync3, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync2 } from "fs";
15949
- import { join as join13 } from "path";
15950
- import { homedir as homedir7, tmpdir as tmpdir2 } from "os";
16170
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync3 } from "fs";
16171
+ import { join as join14 } from "path";
16172
+ import { homedir as homedir7, tmpdir as tmpdir3 } from "os";
15951
16173
  import { createRequire } from "module";
15952
16174
  var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
15953
- var DEBUG_FILE = join13(tmpdir2(), "comment-checker-debug.log");
16175
+ var DEBUG_FILE = join14(tmpdir3(), "comment-checker-debug.log");
15954
16176
  function debugLog(...args) {
15955
16177
  if (DEBUG) {
15956
16178
  const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
15957
16179
  `;
15958
- appendFileSync2(DEBUG_FILE, msg);
16180
+ appendFileSync3(DEBUG_FILE, msg);
15959
16181
  }
15960
16182
  }
15961
16183
  var REPO = "code-yeongyu/go-claude-code-comment-checker";
@@ -15969,19 +16191,19 @@ var PLATFORM_MAP = {
15969
16191
  function getCacheDir() {
15970
16192
  if (process.platform === "win32") {
15971
16193
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
15972
- const base2 = localAppData || join13(homedir7(), "AppData", "Local");
15973
- return join13(base2, "oh-my-opencode", "bin");
16194
+ const base2 = localAppData || join14(homedir7(), "AppData", "Local");
16195
+ return join14(base2, "oh-my-opencode", "bin");
15974
16196
  }
15975
16197
  const xdgCache = process.env.XDG_CACHE_HOME;
15976
- const base = xdgCache || join13(homedir7(), ".cache");
15977
- return join13(base, "oh-my-opencode", "bin");
16198
+ const base = xdgCache || join14(homedir7(), ".cache");
16199
+ return join14(base, "oh-my-opencode", "bin");
15978
16200
  }
15979
16201
  function getBinaryName() {
15980
16202
  return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
15981
16203
  }
15982
16204
  function getCachedBinaryPath() {
15983
- const binaryPath = join13(getCacheDir(), getBinaryName());
15984
- return existsSync10(binaryPath) ? binaryPath : null;
16205
+ const binaryPath = join14(getCacheDir(), getBinaryName());
16206
+ return existsSync12(binaryPath) ? binaryPath : null;
15985
16207
  }
15986
16208
  function getPackageVersion() {
15987
16209
  try {
@@ -16013,8 +16235,8 @@ async function downloadCommentChecker() {
16013
16235
  }
16014
16236
  const cacheDir = getCacheDir();
16015
16237
  const binaryName = getBinaryName();
16016
- const binaryPath = join13(cacheDir, binaryName);
16017
- if (existsSync10(binaryPath)) {
16238
+ const binaryPath = join14(cacheDir, binaryName);
16239
+ if (existsSync12(binaryPath)) {
16018
16240
  debugLog("Binary already cached at:", binaryPath);
16019
16241
  return binaryPath;
16020
16242
  }
@@ -16025,14 +16247,14 @@ async function downloadCommentChecker() {
16025
16247
  debugLog(`Downloading from: ${downloadUrl}`);
16026
16248
  console.log(`[oh-my-opencode] Downloading comment-checker binary...`);
16027
16249
  try {
16028
- if (!existsSync10(cacheDir)) {
16029
- mkdirSync3(cacheDir, { recursive: true });
16250
+ if (!existsSync12(cacheDir)) {
16251
+ mkdirSync4(cacheDir, { recursive: true });
16030
16252
  }
16031
16253
  const response = await fetch(downloadUrl, { redirect: "follow" });
16032
16254
  if (!response.ok) {
16033
16255
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
16034
16256
  }
16035
- const archivePath = join13(cacheDir, assetName);
16257
+ const archivePath = join14(cacheDir, assetName);
16036
16258
  const arrayBuffer = await response.arrayBuffer();
16037
16259
  await Bun.write(archivePath, arrayBuffer);
16038
16260
  debugLog(`Downloaded archive to: ${archivePath}`);
@@ -16041,10 +16263,10 @@ async function downloadCommentChecker() {
16041
16263
  } else {
16042
16264
  await extractZip(archivePath, cacheDir);
16043
16265
  }
16044
- if (existsSync10(archivePath)) {
16266
+ if (existsSync12(archivePath)) {
16045
16267
  unlinkSync2(archivePath);
16046
16268
  }
16047
- if (process.platform !== "win32" && existsSync10(binaryPath)) {
16269
+ if (process.platform !== "win32" && existsSync12(binaryPath)) {
16048
16270
  chmodSync(binaryPath, 493);
16049
16271
  }
16050
16272
  debugLog(`Successfully downloaded binary to: ${binaryPath}`);
@@ -16068,7 +16290,7 @@ async function ensureCommentCheckerBinary() {
16068
16290
 
16069
16291
  // src/hooks/comment-checker/cli.ts
16070
16292
  var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
16071
- var DEBUG_FILE2 = join14(tmpdir3(), "comment-checker-debug.log");
16293
+ var DEBUG_FILE2 = join15(tmpdir4(), "comment-checker-debug.log");
16072
16294
  function debugLog2(...args) {
16073
16295
  if (DEBUG2) {
16074
16296
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16094,8 +16316,8 @@ function findCommentCheckerPathSync() {
16094
16316
  const require2 = createRequire2(import.meta.url);
16095
16317
  const cliPkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
16096
16318
  const cliDir = dirname(cliPkgPath);
16097
- const binaryPath = join14(cliDir, "bin", binaryName);
16098
- if (existsSync11(binaryPath)) {
16319
+ const binaryPath = join15(cliDir, "bin", binaryName);
16320
+ if (existsSync13(binaryPath)) {
16099
16321
  debugLog2("found binary in main package:", binaryPath);
16100
16322
  return binaryPath;
16101
16323
  }
@@ -16116,7 +16338,7 @@ async function getCommentCheckerPath() {
16116
16338
  }
16117
16339
  initPromise = (async () => {
16118
16340
  const syncPath = findCommentCheckerPathSync();
16119
- if (syncPath && existsSync11(syncPath)) {
16341
+ if (syncPath && existsSync13(syncPath)) {
16120
16342
  resolvedCliPath = syncPath;
16121
16343
  debugLog2("using sync-resolved path:", syncPath);
16122
16344
  return syncPath;
@@ -16152,7 +16374,7 @@ async function runCommentChecker(input, cliPath, customPrompt) {
16152
16374
  debugLog2("comment-checker binary not found");
16153
16375
  return { hasComments: false, message: "" };
16154
16376
  }
16155
- if (!existsSync11(binaryPath)) {
16377
+ if (!existsSync13(binaryPath)) {
16156
16378
  debugLog2("comment-checker binary does not exist:", binaryPath);
16157
16379
  return { hasComments: false, message: "" };
16158
16380
  }
@@ -16190,11 +16412,11 @@ async function runCommentChecker(input, cliPath, customPrompt) {
16190
16412
 
16191
16413
  // src/hooks/comment-checker/index.ts
16192
16414
  import * as fs6 from "fs";
16193
- import { existsSync as existsSync12 } from "fs";
16194
- import { tmpdir as tmpdir4 } from "os";
16195
- import { join as join15 } from "path";
16415
+ import { existsSync as existsSync14 } from "fs";
16416
+ import { tmpdir as tmpdir5 } from "os";
16417
+ import { join as join16 } from "path";
16196
16418
  var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
16197
- var DEBUG_FILE3 = join15(tmpdir4(), "comment-checker-debug.log");
16419
+ var DEBUG_FILE3 = join16(tmpdir5(), "comment-checker-debug.log");
16198
16420
  function debugLog3(...args) {
16199
16421
  if (DEBUG3) {
16200
16422
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -16274,7 +16496,7 @@ function createCommentCheckerHooks(config) {
16274
16496
  }
16275
16497
  try {
16276
16498
  const cliPath = await cliPathPromise;
16277
- if (!cliPath || !existsSync12(cliPath)) {
16499
+ if (!cliPath || !existsSync14(cliPath)) {
16278
16500
  debugLog3("CLI not available, skipping comment check");
16279
16501
  return;
16280
16502
  }
@@ -16354,36 +16576,36 @@ function createToolOutputTruncatorHook(ctx, options) {
16354
16576
  };
16355
16577
  }
16356
16578
  // src/hooks/directory-agents-injector/index.ts
16357
- import { existsSync as existsSync14, readFileSync as readFileSync8 } from "fs";
16358
- import { dirname as dirname2, join as join18, resolve as resolve3 } from "path";
16579
+ import { existsSync as existsSync16, readFileSync as readFileSync9 } from "fs";
16580
+ import { dirname as dirname2, join as join19, resolve as resolve3 } from "path";
16359
16581
 
16360
16582
  // src/hooks/directory-agents-injector/storage.ts
16361
16583
  import {
16362
- existsSync as existsSync13,
16363
- mkdirSync as mkdirSync4,
16364
- readFileSync as readFileSync7,
16365
- writeFileSync as writeFileSync4,
16584
+ existsSync as existsSync15,
16585
+ mkdirSync as mkdirSync5,
16586
+ readFileSync as readFileSync8,
16587
+ writeFileSync as writeFileSync5,
16366
16588
  unlinkSync as unlinkSync3
16367
16589
  } from "fs";
16368
- import { join as join17 } from "path";
16590
+ import { join as join18 } from "path";
16369
16591
 
16370
16592
  // src/hooks/directory-agents-injector/constants.ts
16371
16593
  init_data_path();
16372
- import { join as join16 } from "path";
16594
+ import { join as join17 } from "path";
16373
16595
  var OPENCODE_STORAGE3 = getOpenCodeStorageDir();
16374
- var AGENTS_INJECTOR_STORAGE = join16(OPENCODE_STORAGE3, "directory-agents");
16596
+ var AGENTS_INJECTOR_STORAGE = join17(OPENCODE_STORAGE3, "directory-agents");
16375
16597
  var AGENTS_FILENAME = "AGENTS.md";
16376
16598
 
16377
16599
  // src/hooks/directory-agents-injector/storage.ts
16378
16600
  function getStoragePath(sessionID) {
16379
- return join17(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
16601
+ return join18(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
16380
16602
  }
16381
16603
  function loadInjectedPaths(sessionID) {
16382
16604
  const filePath = getStoragePath(sessionID);
16383
- if (!existsSync13(filePath))
16605
+ if (!existsSync15(filePath))
16384
16606
  return new Set;
16385
16607
  try {
16386
- const content = readFileSync7(filePath, "utf-8");
16608
+ const content = readFileSync8(filePath, "utf-8");
16387
16609
  const data = JSON.parse(content);
16388
16610
  return new Set(data.injectedPaths);
16389
16611
  } catch {
@@ -16391,19 +16613,19 @@ function loadInjectedPaths(sessionID) {
16391
16613
  }
16392
16614
  }
16393
16615
  function saveInjectedPaths(sessionID, paths) {
16394
- if (!existsSync13(AGENTS_INJECTOR_STORAGE)) {
16395
- mkdirSync4(AGENTS_INJECTOR_STORAGE, { recursive: true });
16616
+ if (!existsSync15(AGENTS_INJECTOR_STORAGE)) {
16617
+ mkdirSync5(AGENTS_INJECTOR_STORAGE, { recursive: true });
16396
16618
  }
16397
16619
  const data = {
16398
16620
  sessionID,
16399
16621
  injectedPaths: [...paths],
16400
16622
  updatedAt: Date.now()
16401
16623
  };
16402
- writeFileSync4(getStoragePath(sessionID), JSON.stringify(data, null, 2));
16624
+ writeFileSync5(getStoragePath(sessionID), JSON.stringify(data, null, 2));
16403
16625
  }
16404
16626
  function clearInjectedPaths(sessionID) {
16405
16627
  const filePath = getStoragePath(sessionID);
16406
- if (existsSync13(filePath)) {
16628
+ if (existsSync15(filePath)) {
16407
16629
  unlinkSync3(filePath);
16408
16630
  }
16409
16631
  }
@@ -16433,8 +16655,8 @@ function createDirectoryAgentsInjectorHook(ctx) {
16433
16655
  while (true) {
16434
16656
  const isRootDir = current === ctx.directory;
16435
16657
  if (!isRootDir) {
16436
- const agentsPath = join18(current, AGENTS_FILENAME);
16437
- if (existsSync14(agentsPath)) {
16658
+ const agentsPath = join19(current, AGENTS_FILENAME);
16659
+ if (existsSync16(agentsPath)) {
16438
16660
  found.push(agentsPath);
16439
16661
  }
16440
16662
  }
@@ -16461,7 +16683,7 @@ function createDirectoryAgentsInjectorHook(ctx) {
16461
16683
  if (cache.has(agentsDir))
16462
16684
  continue;
16463
16685
  try {
16464
- const content = readFileSync8(agentsPath, "utf-8");
16686
+ const content = readFileSync9(agentsPath, "utf-8");
16465
16687
  const { result, truncated } = await truncator.truncate(sessionID, content);
16466
16688
  const truncationNotice = truncated ? `
16467
16689
 
@@ -16531,36 +16753,36 @@ ${result}${truncationNotice}`;
16531
16753
  };
16532
16754
  }
16533
16755
  // src/hooks/directory-readme-injector/index.ts
16534
- import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
16535
- import { dirname as dirname3, join as join21, resolve as resolve4 } from "path";
16756
+ import { existsSync as existsSync18, readFileSync as readFileSync11 } from "fs";
16757
+ import { dirname as dirname3, join as join22, resolve as resolve4 } from "path";
16536
16758
 
16537
16759
  // src/hooks/directory-readme-injector/storage.ts
16538
16760
  import {
16539
- existsSync as existsSync15,
16540
- mkdirSync as mkdirSync5,
16541
- readFileSync as readFileSync9,
16542
- writeFileSync as writeFileSync5,
16761
+ existsSync as existsSync17,
16762
+ mkdirSync as mkdirSync6,
16763
+ readFileSync as readFileSync10,
16764
+ writeFileSync as writeFileSync6,
16543
16765
  unlinkSync as unlinkSync4
16544
16766
  } from "fs";
16545
- import { join as join20 } from "path";
16767
+ import { join as join21 } from "path";
16546
16768
 
16547
16769
  // src/hooks/directory-readme-injector/constants.ts
16548
16770
  init_data_path();
16549
- import { join as join19 } from "path";
16771
+ import { join as join20 } from "path";
16550
16772
  var OPENCODE_STORAGE4 = getOpenCodeStorageDir();
16551
- var README_INJECTOR_STORAGE = join19(OPENCODE_STORAGE4, "directory-readme");
16773
+ var README_INJECTOR_STORAGE = join20(OPENCODE_STORAGE4, "directory-readme");
16552
16774
  var README_FILENAME = "README.md";
16553
16775
 
16554
16776
  // src/hooks/directory-readme-injector/storage.ts
16555
16777
  function getStoragePath2(sessionID) {
16556
- return join20(README_INJECTOR_STORAGE, `${sessionID}.json`);
16778
+ return join21(README_INJECTOR_STORAGE, `${sessionID}.json`);
16557
16779
  }
16558
16780
  function loadInjectedPaths2(sessionID) {
16559
16781
  const filePath = getStoragePath2(sessionID);
16560
- if (!existsSync15(filePath))
16782
+ if (!existsSync17(filePath))
16561
16783
  return new Set;
16562
16784
  try {
16563
- const content = readFileSync9(filePath, "utf-8");
16785
+ const content = readFileSync10(filePath, "utf-8");
16564
16786
  const data = JSON.parse(content);
16565
16787
  return new Set(data.injectedPaths);
16566
16788
  } catch {
@@ -16568,19 +16790,19 @@ function loadInjectedPaths2(sessionID) {
16568
16790
  }
16569
16791
  }
16570
16792
  function saveInjectedPaths2(sessionID, paths) {
16571
- if (!existsSync15(README_INJECTOR_STORAGE)) {
16572
- mkdirSync5(README_INJECTOR_STORAGE, { recursive: true });
16793
+ if (!existsSync17(README_INJECTOR_STORAGE)) {
16794
+ mkdirSync6(README_INJECTOR_STORAGE, { recursive: true });
16573
16795
  }
16574
16796
  const data = {
16575
16797
  sessionID,
16576
16798
  injectedPaths: [...paths],
16577
16799
  updatedAt: Date.now()
16578
16800
  };
16579
- writeFileSync5(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
16801
+ writeFileSync6(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
16580
16802
  }
16581
16803
  function clearInjectedPaths2(sessionID) {
16582
16804
  const filePath = getStoragePath2(sessionID);
16583
- if (existsSync15(filePath)) {
16805
+ if (existsSync17(filePath)) {
16584
16806
  unlinkSync4(filePath);
16585
16807
  }
16586
16808
  }
@@ -16608,8 +16830,8 @@ function createDirectoryReadmeInjectorHook(ctx) {
16608
16830
  const found = [];
16609
16831
  let current = startDir;
16610
16832
  while (true) {
16611
- const readmePath = join21(current, README_FILENAME);
16612
- if (existsSync16(readmePath)) {
16833
+ const readmePath = join22(current, README_FILENAME);
16834
+ if (existsSync18(readmePath)) {
16613
16835
  found.push(readmePath);
16614
16836
  }
16615
16837
  if (current === ctx.directory)
@@ -16635,7 +16857,7 @@ function createDirectoryReadmeInjectorHook(ctx) {
16635
16857
  if (cache.has(readmeDir))
16636
16858
  continue;
16637
16859
  try {
16638
- const content = readFileSync10(readmePath, "utf-8");
16860
+ const content = readFileSync11(readmePath, "utf-8");
16639
16861
  const { result, truncated } = await truncator.truncate(sessionID, content);
16640
16862
  const truncationNotice = truncated ? `
16641
16863
 
@@ -16919,22 +17141,22 @@ var TRUNCATE_CONFIG = {
16919
17141
 
16920
17142
  // src/hooks/anthropic-context-window-limit-recovery/storage.ts
16921
17143
  init_data_path();
16922
- import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
16923
- import { join as join22 } from "path";
17144
+ import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
17145
+ import { join as join23 } from "path";
16924
17146
  var OPENCODE_STORAGE5 = getOpenCodeStorageDir();
16925
- var MESSAGE_STORAGE3 = join22(OPENCODE_STORAGE5, "message");
16926
- var PART_STORAGE3 = join22(OPENCODE_STORAGE5, "part");
17147
+ var MESSAGE_STORAGE3 = join23(OPENCODE_STORAGE5, "message");
17148
+ var PART_STORAGE3 = join23(OPENCODE_STORAGE5, "part");
16927
17149
  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.]";
16928
17150
  function getMessageDir3(sessionID) {
16929
- if (!existsSync17(MESSAGE_STORAGE3))
17151
+ if (!existsSync19(MESSAGE_STORAGE3))
16930
17152
  return "";
16931
- const directPath = join22(MESSAGE_STORAGE3, sessionID);
16932
- if (existsSync17(directPath)) {
17153
+ const directPath = join23(MESSAGE_STORAGE3, sessionID);
17154
+ if (existsSync19(directPath)) {
16933
17155
  return directPath;
16934
17156
  }
16935
- for (const dir of readdirSync4(MESSAGE_STORAGE3)) {
16936
- const sessionPath = join22(MESSAGE_STORAGE3, dir, sessionID);
16937
- if (existsSync17(sessionPath)) {
17157
+ for (const dir of readdirSync5(MESSAGE_STORAGE3)) {
17158
+ const sessionPath = join23(MESSAGE_STORAGE3, dir, sessionID);
17159
+ if (existsSync19(sessionPath)) {
16938
17160
  return sessionPath;
16939
17161
  }
16940
17162
  }
@@ -16942,10 +17164,10 @@ function getMessageDir3(sessionID) {
16942
17164
  }
16943
17165
  function getMessageIds(sessionID) {
16944
17166
  const messageDir = getMessageDir3(sessionID);
16945
- if (!messageDir || !existsSync17(messageDir))
17167
+ if (!messageDir || !existsSync19(messageDir))
16946
17168
  return [];
16947
17169
  const messageIds = [];
16948
- for (const file of readdirSync4(messageDir)) {
17170
+ for (const file of readdirSync5(messageDir)) {
16949
17171
  if (!file.endsWith(".json"))
16950
17172
  continue;
16951
17173
  const messageId = file.replace(".json", "");
@@ -16957,15 +17179,15 @@ function findToolResultsBySize(sessionID) {
16957
17179
  const messageIds = getMessageIds(sessionID);
16958
17180
  const results = [];
16959
17181
  for (const messageID of messageIds) {
16960
- const partDir = join22(PART_STORAGE3, messageID);
16961
- if (!existsSync17(partDir))
17182
+ const partDir = join23(PART_STORAGE3, messageID);
17183
+ if (!existsSync19(partDir))
16962
17184
  continue;
16963
- for (const file of readdirSync4(partDir)) {
17185
+ for (const file of readdirSync5(partDir)) {
16964
17186
  if (!file.endsWith(".json"))
16965
17187
  continue;
16966
17188
  try {
16967
- const partPath = join22(partDir, file);
16968
- const content = readFileSync11(partPath, "utf-8");
17189
+ const partPath = join23(partDir, file);
17190
+ const content = readFileSync12(partPath, "utf-8");
16969
17191
  const part = JSON.parse(content);
16970
17192
  if (part.type === "tool" && part.state?.output && !part.truncated) {
16971
17193
  results.push({
@@ -16985,7 +17207,7 @@ function findToolResultsBySize(sessionID) {
16985
17207
  }
16986
17208
  function truncateToolResult(partPath) {
16987
17209
  try {
16988
- const content = readFileSync11(partPath, "utf-8");
17210
+ const content = readFileSync12(partPath, "utf-8");
16989
17211
  const part = JSON.parse(content);
16990
17212
  if (!part.state?.output) {
16991
17213
  return { success: false };
@@ -16999,7 +17221,7 @@ function truncateToolResult(partPath) {
16999
17221
  part.state.time = { start: Date.now() };
17000
17222
  }
17001
17223
  part.state.time.compacted = Date.now();
17002
- writeFileSync6(partPath, JSON.stringify(part, null, 2));
17224
+ writeFileSync7(partPath, JSON.stringify(part, null, 2));
17003
17225
  return { success: true, toolName, originalSize };
17004
17226
  } catch {
17005
17227
  return { success: false };
@@ -17499,15 +17721,29 @@ function createCompactionContextInjector() {
17499
17721
  }
17500
17722
  // src/hooks/think-mode/detector.ts
17501
17723
  var ENGLISH_PATTERNS = [/\bultrathink\b/i, /\bthink\b/i];
17502
- var MULTILINGUAL_KEYWORDS = [
17724
+ var CHINESE_KEYWORDS = [
17725
+ "\u601D\u8003",
17726
+ "\u8003\u8651",
17727
+ "\u8003\u616E",
17728
+ "\u6DF1\u5165\u601D\u8003",
17729
+ "\u4ED4\u7EC6\u60F3\u60F3",
17730
+ "\u4ED4\u7EC6\u601D\u8003",
17731
+ "\u8BA4\u771F\u601D\u8003",
17732
+ "\u597D\u597D\u60F3\u60F3",
17733
+ "\u597D\u597D\u8003\u8651",
17734
+ "\u7422\u78E8",
17735
+ "\u5206\u6790\u4E00\u4E0B",
17736
+ "\u53CD\u601D",
17737
+ "\u63A8\u6572",
17738
+ "\u659F\u914C",
17739
+ "\u6DF1\u601D\u719F\u8651",
17740
+ "\u60F3\u4E00\u60F3"
17741
+ ];
17742
+ var OTHER_MULTILINGUAL_KEYWORDS = [
17503
17743
  "\uC0DD\uAC01",
17504
17744
  "\uACE0\uBBFC",
17505
17745
  "\uAC80\uD1A0",
17506
17746
  "\uC81C\uB300\uB85C",
17507
- "\u601D\u8003",
17508
- "\u8003\u8651",
17509
- "\u8003\u616E",
17510
- "\u601D\u8003",
17511
17747
  "\u8003\u3048",
17512
17748
  "\u719F\u8003",
17513
17749
  "\u0938\u094B\u091A",
@@ -17585,8 +17821,9 @@ var MULTILINGUAL_KEYWORDS = [
17585
17821
  "fikir",
17586
17822
  "berfikir"
17587
17823
  ];
17588
- var MULTILINGUAL_PATTERNS = MULTILINGUAL_KEYWORDS.map((kw) => new RegExp(kw, "i"));
17589
- var THINK_PATTERNS = [...ENGLISH_PATTERNS, ...MULTILINGUAL_PATTERNS];
17824
+ var CHINESE_PATTERNS = CHINESE_KEYWORDS.map((kw) => new RegExp(kw, "i"));
17825
+ var MULTILINGUAL_PATTERNS = OTHER_MULTILINGUAL_KEYWORDS.map((kw) => new RegExp(kw, "i"));
17826
+ var THINK_PATTERNS = [...ENGLISH_PATTERNS, ...CHINESE_PATTERNS, ...MULTILINGUAL_PATTERNS];
17590
17827
  var CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
17591
17828
  var INLINE_CODE_PATTERN = /`[^`]+`/g;
17592
17829
  function removeCodeBlocks(text) {
@@ -17734,53 +17971,55 @@ init_shared();
17734
17971
  var thinkModeState = new Map;
17735
17972
  function createThinkModeHook() {
17736
17973
  return {
17737
- "chat.params": async (output, sessionID) => {
17738
- const promptText = extractPromptText(output.parts);
17974
+ "chat.params": async (input, output) => {
17975
+ const promptText = extractPromptText(input.message.parts ?? []);
17739
17976
  const state2 = {
17740
17977
  requested: false,
17741
17978
  modelSwitched: false,
17742
17979
  thinkingConfigInjected: false
17743
17980
  };
17744
17981
  if (!detectThinkKeyword(promptText)) {
17745
- thinkModeState.set(sessionID, state2);
17982
+ thinkModeState.set(input.sessionID, state2);
17746
17983
  return;
17747
17984
  }
17748
17985
  state2.requested = true;
17749
- const currentModel = output.message.model;
17750
- if (!currentModel) {
17751
- thinkModeState.set(sessionID, state2);
17986
+ const modelID = input.model.id;
17987
+ const providerID = input.model.providerID;
17988
+ if (!modelID) {
17989
+ thinkModeState.set(input.sessionID, state2);
17752
17990
  return;
17753
17991
  }
17754
- state2.providerID = currentModel.providerID;
17755
- state2.modelID = currentModel.modelID;
17756
- if (isAlreadyHighVariant(currentModel.modelID)) {
17757
- thinkModeState.set(sessionID, state2);
17992
+ state2.providerID = providerID;
17993
+ state2.modelID = modelID;
17994
+ if (isAlreadyHighVariant(modelID)) {
17995
+ thinkModeState.set(input.sessionID, state2);
17758
17996
  return;
17759
17997
  }
17760
- const highVariant = getHighVariant(currentModel.modelID);
17761
- const thinkingConfig = getThinkingConfig(currentModel.providerID, currentModel.modelID);
17998
+ const highVariant = getHighVariant(modelID);
17999
+ const thinkingConfig = getThinkingConfig(providerID, modelID);
17762
18000
  if (highVariant) {
17763
- output.message.model = {
17764
- providerID: currentModel.providerID,
17765
- modelID: highVariant
17766
- };
18001
+ input.model.id = highVariant;
17767
18002
  state2.modelSwitched = true;
17768
18003
  log("Think mode: model switched to high variant", {
17769
- sessionID,
17770
- from: currentModel.modelID,
18004
+ sessionID: input.sessionID,
18005
+ from: modelID,
17771
18006
  to: highVariant
17772
18007
  });
17773
18008
  }
17774
18009
  if (thinkingConfig) {
17775
- Object.assign(output.message, thinkingConfig);
18010
+ const { maxTokens, ...thinkingOptions } = thinkingConfig;
18011
+ if (typeof maxTokens === "number") {
18012
+ output.maxOutputTokens = maxTokens;
18013
+ }
18014
+ Object.assign(output.options, thinkingOptions);
17776
18015
  state2.thinkingConfigInjected = true;
17777
18016
  log("Think mode: thinking config injected", {
17778
- sessionID,
17779
- provider: currentModel.providerID,
18017
+ sessionID: input.sessionID,
18018
+ provider: providerID,
17780
18019
  config: thinkingConfig
17781
18020
  });
17782
18021
  }
17783
- thinkModeState.set(sessionID, state2);
18022
+ thinkModeState.set(input.sessionID, state2);
17784
18023
  },
17785
18024
  event: async ({ event }) => {
17786
18025
  if (event.type === "session.deleted") {
@@ -17794,8 +18033,8 @@ function createThinkModeHook() {
17794
18033
  }
17795
18034
  // src/hooks/claude-code-hooks/config.ts
17796
18035
  init_shared();
17797
- import { join as join23 } from "path";
17798
- import { existsSync as existsSync18 } from "fs";
18036
+ import { join as join24 } from "path";
18037
+ import { existsSync as existsSync20 } from "fs";
17799
18038
  function normalizeHookMatcher(raw) {
17800
18039
  return {
17801
18040
  matcher: raw.matcher ?? raw.pattern ?? "*",
@@ -17821,11 +18060,11 @@ function normalizeHooksConfig(raw) {
17821
18060
  function getClaudeSettingsPaths(customPath) {
17822
18061
  const claudeConfigDir = getClaudeConfigDir();
17823
18062
  const paths = [
17824
- join23(claudeConfigDir, "settings.json"),
17825
- join23(process.cwd(), ".claude", "settings.json"),
17826
- join23(process.cwd(), ".claude", "settings.local.json")
18063
+ join24(claudeConfigDir, "settings.json"),
18064
+ join24(process.cwd(), ".claude", "settings.json"),
18065
+ join24(process.cwd(), ".claude", "settings.local.json")
17827
18066
  ];
17828
- if (customPath && existsSync18(customPath)) {
18067
+ if (customPath && existsSync20(customPath)) {
17829
18068
  paths.unshift(customPath);
17830
18069
  }
17831
18070
  return paths;
@@ -17850,7 +18089,7 @@ async function loadClaudeHooksConfig(customSettingsPath) {
17850
18089
  const paths = getClaudeSettingsPaths(customSettingsPath);
17851
18090
  let mergedConfig = {};
17852
18091
  for (const settingsPath of paths) {
17853
- if (existsSync18(settingsPath)) {
18092
+ if (existsSync20(settingsPath)) {
17854
18093
  try {
17855
18094
  const content = await Bun.file(settingsPath).text();
17856
18095
  const settings = JSON.parse(content);
@@ -17869,14 +18108,14 @@ async function loadClaudeHooksConfig(customSettingsPath) {
17869
18108
  // src/hooks/claude-code-hooks/config-loader.ts
17870
18109
  init_logger();
17871
18110
  init_shared();
17872
- import { existsSync as existsSync19 } from "fs";
17873
- import { join as join24 } from "path";
17874
- var USER_CONFIG_PATH = join24(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json");
18111
+ import { existsSync as existsSync21 } from "fs";
18112
+ import { join as join25 } from "path";
18113
+ var USER_CONFIG_PATH = join25(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json");
17875
18114
  function getProjectConfigPath() {
17876
- return join24(process.cwd(), ".opencode", "opencode-cc-plugin.json");
18115
+ return join25(process.cwd(), ".opencode", "opencode-cc-plugin.json");
17877
18116
  }
17878
18117
  async function loadConfigFromPath(path4) {
17879
- if (!existsSync19(path4)) {
18118
+ if (!existsSync21(path4)) {
17880
18119
  return null;
17881
18120
  }
17882
18121
  try {
@@ -18064,17 +18303,17 @@ init_shared();
18064
18303
  // src/hooks/claude-code-hooks/transcript.ts
18065
18304
  init_tool_name();
18066
18305
  init_shared();
18067
- import { join as join25 } from "path";
18068
- import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync20, writeFileSync as writeFileSync7, unlinkSync as unlinkSync5 } from "fs";
18069
- import { tmpdir as tmpdir5 } from "os";
18306
+ import { join as join26 } from "path";
18307
+ import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync6, existsSync as existsSync22, writeFileSync as writeFileSync8, unlinkSync as unlinkSync5 } from "fs";
18308
+ import { tmpdir as tmpdir6 } from "os";
18070
18309
  import { randomUUID } from "crypto";
18071
- var TRANSCRIPT_DIR = join25(getClaudeConfigDir(), "transcripts");
18310
+ var TRANSCRIPT_DIR = join26(getClaudeConfigDir(), "transcripts");
18072
18311
  function getTranscriptPath(sessionId) {
18073
- return join25(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
18312
+ return join26(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
18074
18313
  }
18075
18314
  function ensureTranscriptDir() {
18076
- if (!existsSync20(TRANSCRIPT_DIR)) {
18077
- mkdirSync6(TRANSCRIPT_DIR, { recursive: true });
18315
+ if (!existsSync22(TRANSCRIPT_DIR)) {
18316
+ mkdirSync7(TRANSCRIPT_DIR, { recursive: true });
18078
18317
  }
18079
18318
  }
18080
18319
  function appendTranscriptEntry(sessionId, entry) {
@@ -18082,7 +18321,7 @@ function appendTranscriptEntry(sessionId, entry) {
18082
18321
  const path4 = getTranscriptPath(sessionId);
18083
18322
  const line = JSON.stringify(entry) + `
18084
18323
  `;
18085
- appendFileSync5(path4, line);
18324
+ appendFileSync6(path4, line);
18086
18325
  }
18087
18326
  function recordToolUse(sessionId, toolName, toolInput) {
18088
18327
  appendTranscriptEntry(sessionId, {
@@ -18160,8 +18399,8 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
18160
18399
  }
18161
18400
  };
18162
18401
  entries.push(JSON.stringify(currentEntry));
18163
- const tempPath = join25(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18164
- writeFileSync7(tempPath, entries.join(`
18402
+ const tempPath = join26(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18403
+ writeFileSync8(tempPath, entries.join(`
18165
18404
  `) + `
18166
18405
  `);
18167
18406
  return tempPath;
@@ -18180,8 +18419,8 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
18180
18419
  ]
18181
18420
  }
18182
18421
  };
18183
- const tempPath = join25(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18184
- writeFileSync7(tempPath, JSON.stringify(currentEntry) + `
18422
+ const tempPath = join26(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
18423
+ writeFileSync8(tempPath, JSON.stringify(currentEntry) + `
18185
18424
  `);
18186
18425
  return tempPath;
18187
18426
  } catch {
@@ -18396,11 +18635,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
18396
18635
  init_shared();
18397
18636
 
18398
18637
  // src/hooks/claude-code-hooks/todo.ts
18399
- import { join as join26 } from "path";
18638
+ import { join as join27 } from "path";
18400
18639
  init_shared();
18401
- var TODO_DIR = join26(getClaudeConfigDir(), "todos");
18640
+ var TODO_DIR = join27(getClaudeConfigDir(), "todos");
18402
18641
  function getTodoPath(sessionId) {
18403
- return join26(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
18642
+ return join27(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
18404
18643
  }
18405
18644
 
18406
18645
  // src/hooks/claude-code-hooks/stop.ts
@@ -18842,24 +19081,24 @@ ${result.message}`;
18842
19081
  };
18843
19082
  }
18844
19083
  // src/hooks/rules-injector/index.ts
18845
- import { readFileSync as readFileSync13 } from "fs";
19084
+ import { readFileSync as readFileSync14 } from "fs";
18846
19085
  import { homedir as homedir8 } from "os";
18847
- import { relative as relative3, resolve as resolve5 } from "path";
19086
+ import { relative as relative4, resolve as resolve5 } from "path";
18848
19087
 
18849
19088
  // src/hooks/rules-injector/finder.ts
18850
19089
  import {
18851
- existsSync as existsSync21,
18852
- readdirSync as readdirSync5,
19090
+ existsSync as existsSync23,
19091
+ readdirSync as readdirSync6,
18853
19092
  realpathSync,
18854
19093
  statSync as statSync2
18855
19094
  } from "fs";
18856
- import { dirname as dirname4, join as join28, relative } from "path";
19095
+ import { dirname as dirname4, join as join29, relative as relative2 } from "path";
18857
19096
 
18858
19097
  // src/hooks/rules-injector/constants.ts
18859
19098
  init_data_path();
18860
- import { join as join27 } from "path";
19099
+ import { join as join28 } from "path";
18861
19100
  var OPENCODE_STORAGE6 = getOpenCodeStorageDir();
18862
- var RULES_INJECTOR_STORAGE = join27(OPENCODE_STORAGE6, "rules-injector");
19101
+ var RULES_INJECTOR_STORAGE = join28(OPENCODE_STORAGE6, "rules-injector");
18863
19102
  var PROJECT_MARKERS = [
18864
19103
  ".git",
18865
19104
  "pyproject.toml",
@@ -18900,8 +19139,8 @@ function findProjectRoot(startPath) {
18900
19139
  }
18901
19140
  while (true) {
18902
19141
  for (const marker of PROJECT_MARKERS) {
18903
- const markerPath = join28(current, marker);
18904
- if (existsSync21(markerPath)) {
19142
+ const markerPath = join29(current, marker);
19143
+ if (existsSync23(markerPath)) {
18905
19144
  return current;
18906
19145
  }
18907
19146
  }
@@ -18913,12 +19152,12 @@ function findProjectRoot(startPath) {
18913
19152
  }
18914
19153
  }
18915
19154
  function findRuleFilesRecursive(dir, results) {
18916
- if (!existsSync21(dir))
19155
+ if (!existsSync23(dir))
18917
19156
  return;
18918
19157
  try {
18919
- const entries = readdirSync5(dir, { withFileTypes: true });
19158
+ const entries = readdirSync6(dir, { withFileTypes: true });
18920
19159
  for (const entry of entries) {
18921
- const fullPath = join28(dir, entry.name);
19160
+ const fullPath = join29(dir, entry.name);
18922
19161
  if (entry.isDirectory()) {
18923
19162
  findRuleFilesRecursive(fullPath, results);
18924
19163
  } else if (entry.isFile()) {
@@ -18943,7 +19182,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
18943
19182
  let distance = 0;
18944
19183
  while (true) {
18945
19184
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
18946
- const ruleDir = join28(currentDir, parent, subdir);
19185
+ const ruleDir = join29(currentDir, parent, subdir);
18947
19186
  const files = [];
18948
19187
  findRuleFilesRecursive(ruleDir, files);
18949
19188
  for (const filePath of files) {
@@ -18969,8 +19208,8 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
18969
19208
  }
18970
19209
  if (projectRoot) {
18971
19210
  for (const ruleFile of PROJECT_RULE_FILES) {
18972
- const filePath = join28(projectRoot, ruleFile);
18973
- if (existsSync21(filePath)) {
19211
+ const filePath = join29(projectRoot, ruleFile);
19212
+ if (existsSync23(filePath)) {
18974
19213
  try {
18975
19214
  const stat = statSync2(filePath);
18976
19215
  if (stat.isFile()) {
@@ -18990,7 +19229,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
18990
19229
  }
18991
19230
  }
18992
19231
  }
18993
- const userRuleDir = join28(homeDir, USER_RULE_DIR);
19232
+ const userRuleDir = join29(homeDir, USER_RULE_DIR);
18994
19233
  const userFiles = [];
18995
19234
  findRuleFilesRecursive(userRuleDir, userFiles);
18996
19235
  for (const filePath of userFiles) {
@@ -19017,7 +19256,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
19017
19256
  // src/hooks/rules-injector/matcher.ts
19018
19257
  var import_picomatch = __toESM(require_picomatch2(), 1);
19019
19258
  import { createHash } from "crypto";
19020
- import { relative as relative2 } from "path";
19259
+ import { relative as relative3 } from "path";
19021
19260
  function shouldApplyRule(metadata, currentFilePath, projectRoot) {
19022
19261
  if (metadata.alwaysApply === true) {
19023
19262
  return { applies: true, reason: "alwaysApply" };
@@ -19030,7 +19269,7 @@ function shouldApplyRule(metadata, currentFilePath, projectRoot) {
19030
19269
  if (patterns.length === 0) {
19031
19270
  return { applies: false };
19032
19271
  }
19033
- const relativePath = projectRoot ? relative2(projectRoot, currentFilePath) : currentFilePath;
19272
+ const relativePath = projectRoot ? relative3(projectRoot, currentFilePath) : currentFilePath;
19034
19273
  for (const pattern of patterns) {
19035
19274
  if (import_picomatch.default.isMatch(relativePath, pattern, { dot: true, bash: true })) {
19036
19275
  return { applies: true, reason: `glob: ${pattern}` };
@@ -19179,22 +19418,22 @@ function mergeGlobs(existing, newValue) {
19179
19418
 
19180
19419
  // src/hooks/rules-injector/storage.ts
19181
19420
  import {
19182
- existsSync as existsSync22,
19183
- mkdirSync as mkdirSync7,
19184
- readFileSync as readFileSync12,
19185
- writeFileSync as writeFileSync8,
19421
+ existsSync as existsSync24,
19422
+ mkdirSync as mkdirSync8,
19423
+ readFileSync as readFileSync13,
19424
+ writeFileSync as writeFileSync9,
19186
19425
  unlinkSync as unlinkSync6
19187
19426
  } from "fs";
19188
- import { join as join29 } from "path";
19427
+ import { join as join30 } from "path";
19189
19428
  function getStoragePath3(sessionID) {
19190
- return join29(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
19429
+ return join30(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
19191
19430
  }
19192
19431
  function loadInjectedRules(sessionID) {
19193
19432
  const filePath = getStoragePath3(sessionID);
19194
- if (!existsSync22(filePath))
19433
+ if (!existsSync24(filePath))
19195
19434
  return { contentHashes: new Set, realPaths: new Set };
19196
19435
  try {
19197
- const content = readFileSync12(filePath, "utf-8");
19436
+ const content = readFileSync13(filePath, "utf-8");
19198
19437
  const data = JSON.parse(content);
19199
19438
  return {
19200
19439
  contentHashes: new Set(data.injectedHashes),
@@ -19205,8 +19444,8 @@ function loadInjectedRules(sessionID) {
19205
19444
  }
19206
19445
  }
19207
19446
  function saveInjectedRules(sessionID, data) {
19208
- if (!existsSync22(RULES_INJECTOR_STORAGE)) {
19209
- mkdirSync7(RULES_INJECTOR_STORAGE, { recursive: true });
19447
+ if (!existsSync24(RULES_INJECTOR_STORAGE)) {
19448
+ mkdirSync8(RULES_INJECTOR_STORAGE, { recursive: true });
19210
19449
  }
19211
19450
  const storageData = {
19212
19451
  sessionID,
@@ -19214,11 +19453,11 @@ function saveInjectedRules(sessionID, data) {
19214
19453
  injectedRealPaths: [...data.realPaths],
19215
19454
  updatedAt: Date.now()
19216
19455
  };
19217
- writeFileSync8(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
19456
+ writeFileSync9(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
19218
19457
  }
19219
19458
  function clearInjectedRules(sessionID) {
19220
19459
  const filePath = getStoragePath3(sessionID);
19221
- if (existsSync22(filePath)) {
19460
+ if (existsSync24(filePath)) {
19222
19461
  unlinkSync6(filePath);
19223
19462
  }
19224
19463
  }
@@ -19256,7 +19495,7 @@ function createRulesInjectorHook(ctx) {
19256
19495
  if (isDuplicateByRealPath(candidate.realPath, cache2.realPaths))
19257
19496
  continue;
19258
19497
  try {
19259
- const rawContent = readFileSync13(candidate.path, "utf-8");
19498
+ const rawContent = readFileSync14(candidate.path, "utf-8");
19260
19499
  const { metadata, body } = parseRuleFrontmatter(rawContent);
19261
19500
  let matchReason;
19262
19501
  if (candidate.isSingleFile) {
@@ -19270,7 +19509,7 @@ function createRulesInjectorHook(ctx) {
19270
19509
  const contentHash = createContentHash(body);
19271
19510
  if (isDuplicateByContentHash(contentHash, cache2.contentHashes))
19272
19511
  continue;
19273
- const relativePath = projectRoot ? relative3(projectRoot, candidate.path) : candidate.path;
19512
+ const relativePath = projectRoot ? relative4(projectRoot, candidate.path) : candidate.path;
19274
19513
  toInject.push({
19275
19514
  relativePath,
19276
19515
  matchReason,
@@ -19374,19 +19613,19 @@ init_auto_update_checker();
19374
19613
 
19375
19614
  // src/hooks/agent-usage-reminder/storage.ts
19376
19615
  import {
19377
- existsSync as existsSync25,
19378
- mkdirSync as mkdirSync8,
19379
- readFileSync as readFileSync16,
19380
- writeFileSync as writeFileSync11,
19616
+ existsSync as existsSync27,
19617
+ mkdirSync as mkdirSync9,
19618
+ readFileSync as readFileSync17,
19619
+ writeFileSync as writeFileSync12,
19381
19620
  unlinkSync as unlinkSync7
19382
19621
  } from "fs";
19383
- import { join as join34 } from "path";
19622
+ import { join as join35 } from "path";
19384
19623
 
19385
19624
  // src/hooks/agent-usage-reminder/constants.ts
19386
19625
  init_data_path();
19387
- import { join as join33 } from "path";
19626
+ import { join as join34 } from "path";
19388
19627
  var OPENCODE_STORAGE7 = getOpenCodeStorageDir();
19389
- var AGENT_USAGE_REMINDER_STORAGE = join33(OPENCODE_STORAGE7, "agent-usage-reminder");
19628
+ var AGENT_USAGE_REMINDER_STORAGE = join34(OPENCODE_STORAGE7, "agent-usage-reminder");
19390
19629
  var TARGET_TOOLS = new Set([
19391
19630
  "grep",
19392
19631
  "safe_grep",
@@ -19432,29 +19671,29 @@ delegate_task(agent="librarian", prompt="\u67E5\u627E Z \u7684\u6587\u6863")
19432
19671
 
19433
19672
  // src/hooks/agent-usage-reminder/storage.ts
19434
19673
  function getStoragePath4(sessionID) {
19435
- return join34(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
19674
+ return join35(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
19436
19675
  }
19437
19676
  function loadAgentUsageState(sessionID) {
19438
19677
  const filePath = getStoragePath4(sessionID);
19439
- if (!existsSync25(filePath))
19678
+ if (!existsSync27(filePath))
19440
19679
  return null;
19441
19680
  try {
19442
- const content = readFileSync16(filePath, "utf-8");
19681
+ const content = readFileSync17(filePath, "utf-8");
19443
19682
  return JSON.parse(content);
19444
19683
  } catch {
19445
19684
  return null;
19446
19685
  }
19447
19686
  }
19448
19687
  function saveAgentUsageState(state2) {
19449
- if (!existsSync25(AGENT_USAGE_REMINDER_STORAGE)) {
19450
- mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
19688
+ if (!existsSync27(AGENT_USAGE_REMINDER_STORAGE)) {
19689
+ mkdirSync9(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
19451
19690
  }
19452
19691
  const filePath = getStoragePath4(state2.sessionID);
19453
- writeFileSync11(filePath, JSON.stringify(state2, null, 2));
19692
+ writeFileSync12(filePath, JSON.stringify(state2, null, 2));
19454
19693
  }
19455
19694
  function clearAgentUsageState(sessionID) {
19456
19695
  const filePath = getStoragePath4(sessionID);
19457
- if (existsSync25(filePath)) {
19696
+ if (existsSync27(filePath)) {
19458
19697
  unlinkSync7(filePath);
19459
19698
  }
19460
19699
  }
@@ -19819,7 +20058,9 @@ var KEYWORD_DETECTORS = [
19819
20058
  \u5982\u679C\u590D\u6742\uFF08\u67B6\u6784\u3001\u591A\u7CFB\u7EDF\u30012 \u6B21\u4EE5\u4E0A\u5931\u8D25\u540E\u7684\u8C03\u8BD5\uFF09\uFF1A
19820
20059
  - \u54A8\u8BE2 oracle \u83B7\u53D6\u6218\u7565\u6307\u5BFC
19821
20060
 
19822
- \u7EFC\u5408\u53D1\u73B0\u540E\u518D\u7EE7\u7EED\u3002`
20061
+ \u7EFC\u5408\u53D1\u73B0\u540E\u518D\u7EE7\u7EED\u3002
20062
+ **\u4E2D\u6587\u8BED\u5883\u601D\u8003\u56DE\u590D**
20063
+ `
19823
20064
  }
19824
20065
  ];
19825
20066
 
@@ -20035,19 +20276,19 @@ function createNonInteractiveEnvHook(_ctx) {
20035
20276
  }
20036
20277
  // src/hooks/interactive-bash-session/storage.ts
20037
20278
  import {
20038
- existsSync as existsSync26,
20039
- mkdirSync as mkdirSync9,
20040
- readFileSync as readFileSync17,
20041
- writeFileSync as writeFileSync12,
20279
+ existsSync as existsSync28,
20280
+ mkdirSync as mkdirSync10,
20281
+ readFileSync as readFileSync18,
20282
+ writeFileSync as writeFileSync13,
20042
20283
  unlinkSync as unlinkSync8
20043
20284
  } from "fs";
20044
- import { join as join36 } from "path";
20285
+ import { join as join37 } from "path";
20045
20286
 
20046
20287
  // src/hooks/interactive-bash-session/constants.ts
20047
20288
  init_data_path();
20048
- import { join as join35 } from "path";
20289
+ import { join as join36 } from "path";
20049
20290
  var OPENCODE_STORAGE8 = getOpenCodeStorageDir();
20050
- var INTERACTIVE_BASH_SESSION_STORAGE = join35(OPENCODE_STORAGE8, "interactive-bash-session");
20291
+ var INTERACTIVE_BASH_SESSION_STORAGE = join36(OPENCODE_STORAGE8, "interactive-bash-session");
20051
20292
  var OMO_SESSION_PREFIX = "omo-";
20052
20293
  function buildSessionReminderMessage(sessions) {
20053
20294
  if (sessions.length === 0)
@@ -20059,14 +20300,14 @@ function buildSessionReminderMessage(sessions) {
20059
20300
 
20060
20301
  // src/hooks/interactive-bash-session/storage.ts
20061
20302
  function getStoragePath5(sessionID) {
20062
- return join36(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
20303
+ return join37(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
20063
20304
  }
20064
20305
  function loadInteractiveBashSessionState(sessionID) {
20065
20306
  const filePath = getStoragePath5(sessionID);
20066
- if (!existsSync26(filePath))
20307
+ if (!existsSync28(filePath))
20067
20308
  return null;
20068
20309
  try {
20069
- const content = readFileSync17(filePath, "utf-8");
20310
+ const content = readFileSync18(filePath, "utf-8");
20070
20311
  const serialized = JSON.parse(content);
20071
20312
  return {
20072
20313
  sessionID: serialized.sessionID,
@@ -20078,8 +20319,8 @@ function loadInteractiveBashSessionState(sessionID) {
20078
20319
  }
20079
20320
  }
20080
20321
  function saveInteractiveBashSessionState(state2) {
20081
- if (!existsSync26(INTERACTIVE_BASH_SESSION_STORAGE)) {
20082
- mkdirSync9(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
20322
+ if (!existsSync28(INTERACTIVE_BASH_SESSION_STORAGE)) {
20323
+ mkdirSync10(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
20083
20324
  }
20084
20325
  const filePath = getStoragePath5(state2.sessionID);
20085
20326
  const serialized = {
@@ -20087,11 +20328,11 @@ function saveInteractiveBashSessionState(state2) {
20087
20328
  tmuxSessions: Array.from(state2.tmuxSessions),
20088
20329
  updatedAt: state2.updatedAt
20089
20330
  };
20090
- writeFileSync12(filePath, JSON.stringify(serialized, null, 2));
20331
+ writeFileSync13(filePath, JSON.stringify(serialized, null, 2));
20091
20332
  }
20092
20333
  function clearInteractiveBashSessionState(sessionID) {
20093
20334
  const filePath = getStoragePath5(sessionID);
20094
- if (existsSync26(filePath)) {
20335
+ if (existsSync28(filePath)) {
20095
20336
  unlinkSync8(filePath);
20096
20337
  }
20097
20338
  }
@@ -20345,7 +20586,7 @@ function createThinkingBlockValidatorHook() {
20345
20586
  continue;
20346
20587
  if (hasContentParts(msg.parts) && !startsWithThinkingBlock(msg.parts)) {
20347
20588
  const previousThinking = findPreviousThinkingContent(messages, i2);
20348
- const thinkingContent = previousThinking || "[Continuing from previous reasoning]";
20589
+ const thinkingContent = previousThinking || "[\u63A5\u7EED\u4E4B\u524D\u7684\u63A8\u7406]";
20349
20590
  prependThinkingBlock(msg, thinkingContent);
20350
20591
  }
20351
20592
  }
@@ -20355,13 +20596,13 @@ function createThinkingBlockValidatorHook() {
20355
20596
  // src/hooks/ralph-loop/index.ts
20356
20597
  init_logger();
20357
20598
  init_system_directive();
20358
- import { existsSync as existsSync28, readFileSync as readFileSync19, readdirSync as readdirSync6 } from "fs";
20359
- import { join as join38 } from "path";
20599
+ import { existsSync as existsSync30, readFileSync as readFileSync20, readdirSync as readdirSync7 } from "fs";
20600
+ import { join as join39 } from "path";
20360
20601
 
20361
20602
  // src/hooks/ralph-loop/storage.ts
20362
20603
  init_frontmatter();
20363
- import { existsSync as existsSync27, readFileSync as readFileSync18, writeFileSync as writeFileSync13, unlinkSync as unlinkSync9, mkdirSync as mkdirSync10 } from "fs";
20364
- import { dirname as dirname6, join as join37 } from "path";
20604
+ import { existsSync as existsSync29, readFileSync as readFileSync19, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, mkdirSync as mkdirSync11 } from "fs";
20605
+ import { dirname as dirname6, join as join38 } from "path";
20365
20606
 
20366
20607
  // src/hooks/ralph-loop/constants.ts
20367
20608
  var HOOK_NAME3 = "ralph-loop";
@@ -20371,15 +20612,15 @@ var DEFAULT_COMPLETION_PROMISE = "DONE";
20371
20612
 
20372
20613
  // src/hooks/ralph-loop/storage.ts
20373
20614
  function getStateFilePath(directory, customPath) {
20374
- return customPath ? join37(directory, customPath) : join37(directory, DEFAULT_STATE_FILE);
20615
+ return customPath ? join38(directory, customPath) : join38(directory, DEFAULT_STATE_FILE);
20375
20616
  }
20376
20617
  function readState(directory, customPath) {
20377
20618
  const filePath = getStateFilePath(directory, customPath);
20378
- if (!existsSync27(filePath)) {
20619
+ if (!existsSync29(filePath)) {
20379
20620
  return null;
20380
20621
  }
20381
20622
  try {
20382
- const content = readFileSync18(filePath, "utf-8");
20623
+ const content = readFileSync19(filePath, "utf-8");
20383
20624
  const { data, body } = parseFrontmatter(content);
20384
20625
  const active = data.active;
20385
20626
  const iteration = data.iteration;
@@ -20413,8 +20654,8 @@ function writeState(directory, state2, customPath) {
20413
20654
  const filePath = getStateFilePath(directory, customPath);
20414
20655
  try {
20415
20656
  const dir = dirname6(filePath);
20416
- if (!existsSync27(dir)) {
20417
- mkdirSync10(dir, { recursive: true });
20657
+ if (!existsSync29(dir)) {
20658
+ mkdirSync11(dir, { recursive: true });
20418
20659
  }
20419
20660
  const sessionIdLine = state2.session_id ? `session_id: "${state2.session_id}"
20420
20661
  ` : "";
@@ -20429,7 +20670,7 @@ started_at: "${state2.started_at}"
20429
20670
  ${sessionIdLine}${ultraworkLine}---
20430
20671
  ${state2.prompt}
20431
20672
  `;
20432
- writeFileSync13(filePath, content, "utf-8");
20673
+ writeFileSync14(filePath, content, "utf-8");
20433
20674
  return true;
20434
20675
  } catch {
20435
20676
  return false;
@@ -20438,7 +20679,7 @@ ${state2.prompt}
20438
20679
  function clearState(directory, customPath) {
20439
20680
  const filePath = getStateFilePath(directory, customPath);
20440
20681
  try {
20441
- if (existsSync27(filePath)) {
20682
+ if (existsSync29(filePath)) {
20442
20683
  unlinkSync9(filePath);
20443
20684
  }
20444
20685
  return true;
@@ -20459,14 +20700,14 @@ function incrementIteration(directory, customPath) {
20459
20700
 
20460
20701
  // src/hooks/ralph-loop/index.ts
20461
20702
  function getMessageDir4(sessionID) {
20462
- if (!existsSync28(MESSAGE_STORAGE))
20703
+ if (!existsSync30(MESSAGE_STORAGE))
20463
20704
  return null;
20464
- const directPath = join38(MESSAGE_STORAGE, sessionID);
20465
- if (existsSync28(directPath))
20705
+ const directPath = join39(MESSAGE_STORAGE, sessionID);
20706
+ if (existsSync30(directPath))
20466
20707
  return directPath;
20467
- for (const dir of readdirSync6(MESSAGE_STORAGE)) {
20468
- const sessionPath = join38(MESSAGE_STORAGE, dir, sessionID);
20469
- if (existsSync28(sessionPath))
20708
+ for (const dir of readdirSync7(MESSAGE_STORAGE)) {
20709
+ const sessionPath = join39(MESSAGE_STORAGE, dir, sessionID);
20710
+ if (existsSync30(sessionPath))
20470
20711
  return sessionPath;
20471
20712
  }
20472
20713
  return null;
@@ -20503,9 +20744,9 @@ function createRalphLoopHook(ctx, options) {
20503
20744
  if (!transcriptPath)
20504
20745
  return false;
20505
20746
  try {
20506
- if (!existsSync28(transcriptPath))
20747
+ if (!existsSync30(transcriptPath))
20507
20748
  return false;
20508
- const content = readFileSync19(transcriptPath, "utf-8");
20749
+ const content = readFileSync20(transcriptPath, "utf-8");
20509
20750
  const pattern = new RegExp(`<promise>\\s*${escapeRegex(promise)}\\s*</promise>`, "is");
20510
20751
  const lines = content.split(`
20511
20752
  `).filter((l) => l.trim());
@@ -20819,8 +21060,8 @@ function extractPromptText3(parts) {
20819
21060
  // src/hooks/auto-slash-command/executor.ts
20820
21061
  init_shared();
20821
21062
  init_file_utils();
20822
- import { existsSync as existsSync30, readdirSync as readdirSync7, readFileSync as readFileSync22 } from "fs";
20823
- import { join as join40, basename as basename2, dirname as dirname8 } from "path";
21063
+ import { existsSync as existsSync32, readdirSync as readdirSync8, readFileSync as readFileSync23 } from "fs";
21064
+ import { join as join41, basename as basename2, dirname as dirname8 } from "path";
20824
21065
  // src/features/opencode-skill-loader/loader.ts
20825
21066
  init_js_yaml();
20826
21067
  init_frontmatter();
@@ -20828,7 +21069,7 @@ init_file_utils();
20828
21069
  init_shared();
20829
21070
  init_opencode_config_dir();
20830
21071
  import { promises as fs9 } from "fs";
20831
- import { join as join39, basename } from "path";
21072
+ import { join as join40, basename } from "path";
20832
21073
  function parseSkillMcpConfigFromFrontmatter(content) {
20833
21074
  const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
20834
21075
  if (!frontmatterMatch)
@@ -20844,7 +21085,7 @@ function parseSkillMcpConfigFromFrontmatter(content) {
20844
21085
  return;
20845
21086
  }
20846
21087
  async function loadMcpJsonFromDir(skillDir) {
20847
- const mcpJsonPath = join39(skillDir, "mcp.json");
21088
+ const mcpJsonPath = join40(skillDir, "mcp.json");
20848
21089
  try {
20849
21090
  const content = await fs9.readFile(mcpJsonPath, "utf-8");
20850
21091
  const parsed = JSON.parse(content);
@@ -20925,11 +21166,11 @@ async function loadSkillsFromDir(skillsDir, scope) {
20925
21166
  for (const entry of entries) {
20926
21167
  if (entry.name.startsWith("."))
20927
21168
  continue;
20928
- const entryPath = join39(skillsDir, entry.name);
21169
+ const entryPath = join40(skillsDir, entry.name);
20929
21170
  if (entry.isDirectory() || entry.isSymbolicLink()) {
20930
21171
  const resolvedPath = await resolveSymlinkAsync(entryPath);
20931
21172
  const dirName = entry.name;
20932
- const skillMdPath = join39(resolvedPath, "SKILL.md");
21173
+ const skillMdPath = join40(resolvedPath, "SKILL.md");
20933
21174
  try {
20934
21175
  await fs9.access(skillMdPath);
20935
21176
  const skill = await loadSkillFromPath(skillMdPath, resolvedPath, dirName, scope);
@@ -20937,7 +21178,7 @@ async function loadSkillsFromDir(skillsDir, scope) {
20937
21178
  skills.push(skill);
20938
21179
  continue;
20939
21180
  } catch {}
20940
- const namedSkillMdPath = join39(resolvedPath, `${dirName}.md`);
21181
+ const namedSkillMdPath = join40(resolvedPath, `${dirName}.md`);
20941
21182
  try {
20942
21183
  await fs9.access(namedSkillMdPath);
20943
21184
  const skill = await loadSkillFromPath(namedSkillMdPath, resolvedPath, dirName, scope);
@@ -20965,23 +21206,23 @@ function skillsToRecord(skills) {
20965
21206
  return result;
20966
21207
  }
20967
21208
  async function loadUserSkills() {
20968
- const userSkillsDir = join39(getClaudeConfigDir(), "skills");
21209
+ const userSkillsDir = join40(getClaudeConfigDir(), "skills");
20969
21210
  const skills = await loadSkillsFromDir(userSkillsDir, "user");
20970
21211
  return skillsToRecord(skills);
20971
21212
  }
20972
21213
  async function loadProjectSkills() {
20973
- const projectSkillsDir = join39(process.cwd(), ".claude", "skills");
21214
+ const projectSkillsDir = join40(process.cwd(), ".claude", "skills");
20974
21215
  const skills = await loadSkillsFromDir(projectSkillsDir, "project");
20975
21216
  return skillsToRecord(skills);
20976
21217
  }
20977
21218
  async function loadOpencodeGlobalSkills() {
20978
21219
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
20979
- const opencodeSkillsDir = join39(configDir, "skills");
21220
+ const opencodeSkillsDir = join40(configDir, "skills");
20980
21221
  const skills = await loadSkillsFromDir(opencodeSkillsDir, "opencode");
20981
21222
  return skillsToRecord(skills);
20982
21223
  }
20983
21224
  async function loadOpencodeProjectSkills() {
20984
- const opencodeProjectDir = join39(process.cwd(), ".opencode", "skills");
21225
+ const opencodeProjectDir = join40(process.cwd(), ".opencode", "skills");
20985
21226
  const skills = await loadSkillsFromDir(opencodeProjectDir, "opencode-project");
20986
21227
  return skillsToRecord(skills);
20987
21228
  }
@@ -21010,26 +21251,26 @@ async function discoverSkills(options = {}) {
21010
21251
  return [...opencodeProjectSkills, ...projectSkills, ...opencodeGlobalSkills, ...userSkills];
21011
21252
  }
21012
21253
  async function discoverUserClaudeSkills() {
21013
- const userSkillsDir = join39(getClaudeConfigDir(), "skills");
21254
+ const userSkillsDir = join40(getClaudeConfigDir(), "skills");
21014
21255
  return loadSkillsFromDir(userSkillsDir, "user");
21015
21256
  }
21016
21257
  async function discoverProjectClaudeSkills() {
21017
- const projectSkillsDir = join39(process.cwd(), ".claude", "skills");
21258
+ const projectSkillsDir = join40(process.cwd(), ".claude", "skills");
21018
21259
  return loadSkillsFromDir(projectSkillsDir, "project");
21019
21260
  }
21020
21261
  async function discoverOpencodeGlobalSkills() {
21021
21262
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
21022
- const opencodeSkillsDir = join39(configDir, "skills");
21263
+ const opencodeSkillsDir = join40(configDir, "skills");
21023
21264
  return loadSkillsFromDir(opencodeSkillsDir, "opencode");
21024
21265
  }
21025
21266
  async function discoverOpencodeProjectSkills() {
21026
- const opencodeProjectDir = join39(process.cwd(), ".opencode", "skills");
21267
+ const opencodeProjectDir = join40(process.cwd(), ".opencode", "skills");
21027
21268
  return loadSkillsFromDir(opencodeProjectDir, "opencode-project");
21028
21269
  }
21029
21270
  // src/features/opencode-skill-loader/merger.ts
21030
21271
  init_frontmatter();
21031
21272
  init_deep_merge();
21032
- import { readFileSync as readFileSync20, existsSync as existsSync29 } from "fs";
21273
+ import { readFileSync as readFileSync21, existsSync as existsSync31 } from "fs";
21033
21274
  import { dirname as dirname7, resolve as resolve6, isAbsolute as isAbsolute2 } from "path";
21034
21275
  import { homedir as homedir11 } from "os";
21035
21276
  var SCOPE_PRIORITY = {
@@ -21077,9 +21318,9 @@ function resolveFilePath2(from, configDir) {
21077
21318
  }
21078
21319
  function loadSkillFromFile(filePath) {
21079
21320
  try {
21080
- if (!existsSync29(filePath))
21321
+ if (!existsSync31(filePath))
21081
21322
  return null;
21082
- const content = readFileSync20(filePath, "utf-8");
21323
+ const content = readFileSync21(filePath, "utf-8");
21083
21324
  const { data, body } = parseFrontmatter(content);
21084
21325
  return { template: body, metadata: data };
21085
21326
  } catch {
@@ -22426,7 +22667,7 @@ function createBuiltinSkills() {
22426
22667
 
22427
22668
  // src/features/opencode-skill-loader/skill-content.ts
22428
22669
  init_frontmatter();
22429
- import { readFileSync as readFileSync21 } from "fs";
22670
+ import { readFileSync as readFileSync22 } from "fs";
22430
22671
  var cachedSkills = null;
22431
22672
  async function getAllSkills() {
22432
22673
  if (cachedSkills)
@@ -22459,7 +22700,7 @@ async function getAllSkills() {
22459
22700
  }
22460
22701
  async function extractSkillTemplate(skill) {
22461
22702
  if (skill.path) {
22462
- const content = readFileSync21(skill.path, "utf-8");
22703
+ const content = readFileSync22(skill.path, "utf-8");
22463
22704
  const { body } = parseFrontmatter(content);
22464
22705
  return body.trim();
22465
22706
  }
@@ -22561,18 +22802,18 @@ async function resolveMultipleSkillsAsync(skillNames, options) {
22561
22802
  }
22562
22803
  // src/hooks/auto-slash-command/executor.ts
22563
22804
  function discoverCommandsFromDir(commandsDir, scope) {
22564
- if (!existsSync30(commandsDir)) {
22805
+ if (!existsSync32(commandsDir)) {
22565
22806
  return [];
22566
22807
  }
22567
- const entries = readdirSync7(commandsDir, { withFileTypes: true });
22808
+ const entries = readdirSync8(commandsDir, { withFileTypes: true });
22568
22809
  const commands = [];
22569
22810
  for (const entry of entries) {
22570
22811
  if (!isMarkdownFile(entry))
22571
22812
  continue;
22572
- const commandPath = join40(commandsDir, entry.name);
22813
+ const commandPath = join41(commandsDir, entry.name);
22573
22814
  const commandName = basename2(entry.name, ".md");
22574
22815
  try {
22575
- const content = readFileSync22(commandPath, "utf-8");
22816
+ const content = readFileSync23(commandPath, "utf-8");
22576
22817
  const { data, body } = parseFrontmatter(content);
22577
22818
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
22578
22819
  const metadata = {
@@ -22615,10 +22856,10 @@ function skillToCommandInfo(skill) {
22615
22856
  }
22616
22857
  async function discoverAllCommands(options) {
22617
22858
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
22618
- const userCommandsDir = join40(getClaudeConfigDir(), "commands");
22619
- const projectCommandsDir = join40(process.cwd(), ".claude", "commands");
22620
- const opencodeGlobalDir = join40(configDir, "command");
22621
- const opencodeProjectDir = join40(process.cwd(), ".opencode", "command");
22859
+ const userCommandsDir = join41(getClaudeConfigDir(), "commands");
22860
+ const projectCommandsDir = join41(process.cwd(), ".claude", "commands");
22861
+ const opencodeGlobalDir = join41(configDir, "command");
22862
+ const opencodeProjectDir = join41(process.cwd(), ".opencode", "command");
22622
22863
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
22623
22864
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
22624
22865
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -22788,8 +23029,8 @@ ${EDIT_ERROR_REMINDER}`;
22788
23029
  };
22789
23030
  }
22790
23031
  // src/hooks/prometheus-md-only/index.ts
22791
- import { existsSync as existsSync31, readdirSync as readdirSync8 } from "fs";
22792
- import { join as join41, resolve as resolve7, relative as relative4, isAbsolute as isAbsolute3 } from "path";
23032
+ import { existsSync as existsSync33, readdirSync as readdirSync9 } from "fs";
23033
+ import { join as join42, resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3 } from "path";
22793
23034
 
22794
23035
  // src/hooks/prometheus-md-only/constants.ts
22795
23036
  init_system_directive();
@@ -22894,7 +23135,7 @@ init_logger();
22894
23135
  init_system_directive();
22895
23136
  function isAllowedFile(filePath, workspaceRoot) {
22896
23137
  const resolved = resolve7(workspaceRoot, filePath);
22897
- const rel = relative4(workspaceRoot, resolved);
23138
+ const rel = relative5(workspaceRoot, resolved);
22898
23139
  if (rel.startsWith("..") || isAbsolute3(rel)) {
22899
23140
  return false;
22900
23141
  }
@@ -22908,14 +23149,14 @@ function isAllowedFile(filePath, workspaceRoot) {
22908
23149
  return true;
22909
23150
  }
22910
23151
  function getMessageDir5(sessionID) {
22911
- if (!existsSync31(MESSAGE_STORAGE))
23152
+ if (!existsSync33(MESSAGE_STORAGE))
22912
23153
  return null;
22913
- const directPath = join41(MESSAGE_STORAGE, sessionID);
22914
- if (existsSync31(directPath))
23154
+ const directPath = join42(MESSAGE_STORAGE, sessionID);
23155
+ if (existsSync33(directPath))
22915
23156
  return directPath;
22916
- for (const dir of readdirSync8(MESSAGE_STORAGE)) {
22917
- const sessionPath = join41(MESSAGE_STORAGE, dir, sessionID);
22918
- if (existsSync31(sessionPath))
23157
+ for (const dir of readdirSync9(MESSAGE_STORAGE)) {
23158
+ const sessionPath = join42(MESSAGE_STORAGE, dir, sessionID);
23159
+ if (existsSync33(sessionPath))
22919
23160
  return sessionPath;
22920
23161
  }
22921
23162
  return null;
@@ -23029,18 +23270,18 @@ var NOTEPAD_DIR = "notepads";
23029
23270
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
23030
23271
  var PROMETHEUS_PLANS_DIR = ".sisyphus/plans";
23031
23272
  // src/features/boulder-state/storage.ts
23032
- import { existsSync as existsSync32, readFileSync as readFileSync23, writeFileSync as writeFileSync14, mkdirSync as mkdirSync11, readdirSync as readdirSync9 } from "fs";
23033
- import { dirname as dirname9, join as join42, basename as basename3 } from "path";
23273
+ import { existsSync as existsSync34, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync10 } from "fs";
23274
+ import { dirname as dirname9, join as join43, basename as basename3 } from "path";
23034
23275
  function getBoulderFilePath(directory) {
23035
- return join42(directory, BOULDER_DIR, BOULDER_FILE);
23276
+ return join43(directory, BOULDER_DIR, BOULDER_FILE);
23036
23277
  }
23037
23278
  function readBoulderState(directory) {
23038
23279
  const filePath = getBoulderFilePath(directory);
23039
- if (!existsSync32(filePath)) {
23280
+ if (!existsSync34(filePath)) {
23040
23281
  return null;
23041
23282
  }
23042
23283
  try {
23043
- const content = readFileSync23(filePath, "utf-8");
23284
+ const content = readFileSync24(filePath, "utf-8");
23044
23285
  return JSON.parse(content);
23045
23286
  } catch {
23046
23287
  return null;
@@ -23050,10 +23291,10 @@ function writeBoulderState(directory, state2) {
23050
23291
  const filePath = getBoulderFilePath(directory);
23051
23292
  try {
23052
23293
  const dir = dirname9(filePath);
23053
- if (!existsSync32(dir)) {
23054
- mkdirSync11(dir, { recursive: true });
23294
+ if (!existsSync34(dir)) {
23295
+ mkdirSync12(dir, { recursive: true });
23055
23296
  }
23056
- writeFileSync14(filePath, JSON.stringify(state2, null, 2), "utf-8");
23297
+ writeFileSync15(filePath, JSON.stringify(state2, null, 2), "utf-8");
23057
23298
  return true;
23058
23299
  } catch {
23059
23300
  return false;
@@ -23074,7 +23315,7 @@ function appendSessionId(directory, sessionId) {
23074
23315
  function clearBoulderState(directory) {
23075
23316
  const filePath = getBoulderFilePath(directory);
23076
23317
  try {
23077
- if (existsSync32(filePath)) {
23318
+ if (existsSync34(filePath)) {
23078
23319
  const { unlinkSync: unlinkSync10 } = __require("fs");
23079
23320
  unlinkSync10(filePath);
23080
23321
  }
@@ -23084,13 +23325,13 @@ function clearBoulderState(directory) {
23084
23325
  }
23085
23326
  }
23086
23327
  function findPrometheusPlans(directory) {
23087
- const plansDir = join42(directory, PROMETHEUS_PLANS_DIR);
23088
- if (!existsSync32(plansDir)) {
23328
+ const plansDir = join43(directory, PROMETHEUS_PLANS_DIR);
23329
+ if (!existsSync34(plansDir)) {
23089
23330
  return [];
23090
23331
  }
23091
23332
  try {
23092
- const files = readdirSync9(plansDir);
23093
- return files.filter((f) => f.endsWith(".md")).map((f) => join42(plansDir, f)).sort((a, b) => {
23333
+ const files = readdirSync10(plansDir);
23334
+ return files.filter((f) => f.endsWith(".md")).map((f) => join43(plansDir, f)).sort((a, b) => {
23094
23335
  const aStat = __require("fs").statSync(a);
23095
23336
  const bStat = __require("fs").statSync(b);
23096
23337
  return bStat.mtimeMs - aStat.mtimeMs;
@@ -23100,11 +23341,11 @@ function findPrometheusPlans(directory) {
23100
23341
  }
23101
23342
  }
23102
23343
  function getPlanProgress(planPath) {
23103
- if (!existsSync32(planPath)) {
23344
+ if (!existsSync34(planPath)) {
23104
23345
  return { total: 0, completed: 0, isComplete: true };
23105
23346
  }
23106
23347
  try {
23107
- const content = readFileSync23(planPath, "utf-8");
23348
+ const content = readFileSync24(planPath, "utf-8");
23108
23349
  const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || [];
23109
23350
  const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || [];
23110
23351
  const total = uncheckedMatches.length + checkedMatches.length;
@@ -23321,8 +23562,8 @@ ${contextInfo}`;
23321
23562
  }
23322
23563
  // src/hooks/atlas/index.ts
23323
23564
  import { execSync } from "child_process";
23324
- import { existsSync as existsSync33, readdirSync as readdirSync10 } from "fs";
23325
- import { join as join43 } from "path";
23565
+ import { existsSync as existsSync35, readdirSync as readdirSync11 } from "fs";
23566
+ import { join as join44 } from "path";
23326
23567
  init_logger();
23327
23568
  init_system_directive();
23328
23569
  var HOOK_NAME6 = "atlas";
@@ -23651,14 +23892,14 @@ function formatFileChanges(stats, notepadPath) {
23651
23892
  `);
23652
23893
  }
23653
23894
  function getMessageDir6(sessionID) {
23654
- if (!existsSync33(MESSAGE_STORAGE))
23895
+ if (!existsSync35(MESSAGE_STORAGE))
23655
23896
  return null;
23656
- const directPath = join43(MESSAGE_STORAGE, sessionID);
23657
- if (existsSync33(directPath))
23897
+ const directPath = join44(MESSAGE_STORAGE, sessionID);
23898
+ if (existsSync35(directPath))
23658
23899
  return directPath;
23659
- for (const dir of readdirSync10(MESSAGE_STORAGE)) {
23660
- const sessionPath = join43(MESSAGE_STORAGE, dir, sessionID);
23661
- if (existsSync33(sessionPath))
23900
+ for (const dir of readdirSync11(MESSAGE_STORAGE)) {
23901
+ const sessionPath = join44(MESSAGE_STORAGE, dir, sessionID);
23902
+ if (existsSync35(sessionPath))
23662
23903
  return sessionPath;
23663
23904
  }
23664
23905
  return null;
@@ -24112,6 +24353,28 @@ function createQuestionLabelTruncatorHook() {
24112
24353
  }
24113
24354
  };
24114
24355
  }
24356
+ // src/hooks/perf-profiler/index.ts
24357
+ function createPerfProfilerHook(options) {
24358
+ return {
24359
+ event: async (input) => {
24360
+ if (input.event.type === "message.part.updated")
24361
+ return;
24362
+ const tracer = options.tracer;
24363
+ if (!tracer.isEnabled())
24364
+ return;
24365
+ const mapSizes = {};
24366
+ for (const [name, fn] of Object.entries(options.memoryProbes ?? {})) {
24367
+ try {
24368
+ mapSizes[name] = fn();
24369
+ } catch {}
24370
+ }
24371
+ tracer.snapshotMemory(input.event.type, mapSizes);
24372
+ },
24373
+ "tool.execute.before": async () => {},
24374
+ "tool.execute.after": async () => {},
24375
+ "chat.message": async () => {}
24376
+ };
24377
+ }
24115
24378
  // src/features/context-injector/collector.ts
24116
24379
  var PRIORITY_ORDER = {
24117
24380
  critical: 0,
@@ -24285,8 +24548,8 @@ function createFirstMessageVariantGate() {
24285
24548
  }
24286
24549
  // src/features/claude-code-mcp-loader/loader.ts
24287
24550
  init_shared();
24288
- import { existsSync as existsSync34, readFileSync as readFileSync24 } from "fs";
24289
- import { join as join44 } from "path";
24551
+ import { existsSync as existsSync36, readFileSync as readFileSync25 } from "fs";
24552
+ import { join as join45 } from "path";
24290
24553
 
24291
24554
  // src/features/claude-code-mcp-loader/env-expander.ts
24292
24555
  function expandEnvVars(value) {
@@ -24354,15 +24617,15 @@ function transformMcpServer(name, server) {
24354
24617
  init_logger();
24355
24618
  function getMcpConfigPaths() {
24356
24619
  const claudeConfigDir = getClaudeConfigDir();
24357
- const cwd = process.cwd();
24620
+ const cwd2 = process.cwd();
24358
24621
  return [
24359
- { path: join44(claudeConfigDir, ".mcp.json"), scope: "user" },
24360
- { path: join44(cwd, ".mcp.json"), scope: "project" },
24361
- { path: join44(cwd, ".claude", ".mcp.json"), scope: "local" }
24622
+ { path: join45(claudeConfigDir, ".mcp.json"), scope: "user" },
24623
+ { path: join45(cwd2, ".mcp.json"), scope: "project" },
24624
+ { path: join45(cwd2, ".claude", ".mcp.json"), scope: "local" }
24362
24625
  ];
24363
24626
  }
24364
24627
  async function loadMcpConfigFile(filePath) {
24365
- if (!existsSync34(filePath)) {
24628
+ if (!existsSync36(filePath)) {
24366
24629
  return null;
24367
24630
  }
24368
24631
  try {
@@ -24377,10 +24640,10 @@ function getSystemMcpServerNames() {
24377
24640
  const names = new Set;
24378
24641
  const paths = getMcpConfigPaths();
24379
24642
  for (const { path: path7 } of paths) {
24380
- if (!existsSync34(path7))
24643
+ if (!existsSync36(path7))
24381
24644
  continue;
24382
24645
  try {
24383
- const content = readFileSync24(path7, "utf-8");
24646
+ const content = readFileSync25(path7, "utf-8");
24384
24647
  const config = JSON.parse(content);
24385
24648
  if (!config?.mcpServers)
24386
24649
  continue;
@@ -24823,25 +25086,25 @@ var EXT_TO_LANG = {
24823
25086
  ".gql": "graphql"
24824
25087
  };
24825
25088
  // src/tools/lsp/config.ts
24826
- import { existsSync as existsSync35, readFileSync as readFileSync25 } from "fs";
24827
- import { join as join45 } from "path";
25089
+ import { existsSync as existsSync37, readFileSync as readFileSync26 } from "fs";
25090
+ import { join as join46 } from "path";
24828
25091
  init_shared();
24829
25092
  function loadJsonFile(path7) {
24830
- if (!existsSync35(path7))
25093
+ if (!existsSync37(path7))
24831
25094
  return null;
24832
25095
  try {
24833
- return JSON.parse(readFileSync25(path7, "utf-8"));
25096
+ return JSON.parse(readFileSync26(path7, "utf-8"));
24834
25097
  } catch {
24835
25098
  return null;
24836
25099
  }
24837
25100
  }
24838
25101
  function getConfigPaths3() {
24839
- const cwd = process.cwd();
25102
+ const cwd2 = process.cwd();
24840
25103
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
24841
25104
  return {
24842
- project: join45(cwd, ".opencode", "oh-my-opencode.json"),
24843
- user: join45(configDir, "oh-my-opencode.json"),
24844
- opencode: join45(configDir, "opencode.json")
25105
+ project: join46(cwd2, ".opencode", "oh-my-opencode.json"),
25106
+ user: join46(configDir, "oh-my-opencode.json"),
25107
+ opencode: join46(configDir, "opencode.json")
24845
25108
  };
24846
25109
  }
24847
25110
  function loadAllConfigs() {
@@ -24954,7 +25217,7 @@ function isServerInstalled(command) {
24954
25217
  return false;
24955
25218
  const cmd = command[0];
24956
25219
  if (cmd.includes("/") || cmd.includes("\\")) {
24957
- if (existsSync35(cmd))
25220
+ if (existsSync37(cmd))
24958
25221
  return true;
24959
25222
  }
24960
25223
  const isWindows2 = process.platform === "win32";
@@ -24976,23 +25239,23 @@ function isServerInstalled(command) {
24976
25239
  const paths = pathEnv.split(pathSeparator);
24977
25240
  for (const p of paths) {
24978
25241
  for (const suffix of exts) {
24979
- if (existsSync35(join45(p, cmd + suffix))) {
25242
+ if (existsSync37(join46(p, cmd + suffix))) {
24980
25243
  return true;
24981
25244
  }
24982
25245
  }
24983
25246
  }
24984
- const cwd = process.cwd();
25247
+ const cwd2 = process.cwd();
24985
25248
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
24986
- const dataDir = join45(getDataDir(), "opencode");
25249
+ const dataDir = join46(getDataDir(), "opencode");
24987
25250
  const additionalBases = [
24988
- join45(cwd, "node_modules", ".bin"),
24989
- join45(configDir, "bin"),
24990
- join45(configDir, "node_modules", ".bin"),
24991
- join45(dataDir, "bin")
25251
+ join46(cwd2, "node_modules", ".bin"),
25252
+ join46(configDir, "bin"),
25253
+ join46(configDir, "node_modules", ".bin"),
25254
+ join46(dataDir, "bin")
24992
25255
  ];
24993
25256
  for (const base of additionalBases) {
24994
25257
  for (const suffix of exts) {
24995
- if (existsSync35(join45(base, cmd + suffix))) {
25258
+ if (existsSync37(join46(base, cmd + suffix))) {
24996
25259
  return true;
24997
25260
  }
24998
25261
  }
@@ -25004,7 +25267,7 @@ function isServerInstalled(command) {
25004
25267
  }
25005
25268
  // src/tools/lsp/client.ts
25006
25269
  var {spawn: spawn6 } = globalThis.Bun;
25007
- import { readFileSync as readFileSync26 } from "fs";
25270
+ import { readFileSync as readFileSync27 } from "fs";
25008
25271
  import { extname, resolve as resolve8 } from "path";
25009
25272
  import { pathToFileURL } from "url";
25010
25273
  class LSPServerManager {
@@ -25454,7 +25717,7 @@ ${msg}`);
25454
25717
  const absPath = resolve8(filePath);
25455
25718
  if (this.openedFiles.has(absPath))
25456
25719
  return;
25457
- const text = readFileSync26(absPath, "utf-8");
25720
+ const text = readFileSync27(absPath, "utf-8");
25458
25721
  const ext = extname(absPath);
25459
25722
  const languageId = getLanguageId(ext);
25460
25723
  this.notify("textDocument/didOpen", {
@@ -25544,17 +25807,17 @@ ${msg}`);
25544
25807
  // src/tools/lsp/utils.ts
25545
25808
  import { extname as extname2, resolve as resolve9 } from "path";
25546
25809
  import { fileURLToPath as fileURLToPath2 } from "url";
25547
- import { existsSync as existsSync36, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "fs";
25810
+ import { existsSync as existsSync38, readFileSync as readFileSync28, writeFileSync as writeFileSync16 } from "fs";
25548
25811
  function findWorkspaceRoot(filePath) {
25549
25812
  let dir = resolve9(filePath);
25550
- if (!existsSync36(dir) || !__require("fs").statSync(dir).isDirectory()) {
25813
+ if (!existsSync38(dir) || !__require("fs").statSync(dir).isDirectory()) {
25551
25814
  dir = __require("path").dirname(dir);
25552
25815
  }
25553
25816
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
25554
25817
  let prevDir = "";
25555
25818
  while (dir !== prevDir) {
25556
25819
  for (const marker of markers) {
25557
- if (existsSync36(__require("path").join(dir, marker))) {
25820
+ if (existsSync38(__require("path").join(dir, marker))) {
25558
25821
  return dir;
25559
25822
  }
25560
25823
  }
@@ -25709,7 +25972,7 @@ function formatPrepareRenameResult(result) {
25709
25972
  }
25710
25973
  function applyTextEditsToFile(filePath, edits) {
25711
25974
  try {
25712
- let content = readFileSync27(filePath, "utf-8");
25975
+ let content = readFileSync28(filePath, "utf-8");
25713
25976
  const lines = content.split(`
25714
25977
  `);
25715
25978
  const sortedEdits = [...edits].sort((a, b) => {
@@ -25734,7 +25997,7 @@ function applyTextEditsToFile(filePath, edits) {
25734
25997
  `));
25735
25998
  }
25736
25999
  }
25737
- writeFileSync15(filePath, lines.join(`
26000
+ writeFileSync16(filePath, lines.join(`
25738
26001
  `), "utf-8");
25739
26002
  return { success: true, editCount: edits.length };
25740
26003
  } catch (err) {
@@ -25765,7 +26028,7 @@ function applyWorkspaceEdit(edit) {
25765
26028
  if (change.kind === "create") {
25766
26029
  try {
25767
26030
  const filePath = uriToPath(change.uri);
25768
- writeFileSync15(filePath, "", "utf-8");
26031
+ writeFileSync16(filePath, "", "utf-8");
25769
26032
  result.filesModified.push(filePath);
25770
26033
  } catch (err) {
25771
26034
  result.success = false;
@@ -25775,8 +26038,8 @@ function applyWorkspaceEdit(edit) {
25775
26038
  try {
25776
26039
  const oldPath = uriToPath(change.oldUri);
25777
26040
  const newPath = uriToPath(change.newUri);
25778
- const content = readFileSync27(oldPath, "utf-8");
25779
- writeFileSync15(newPath, content, "utf-8");
26041
+ const content = readFileSync28(oldPath, "utf-8");
26042
+ writeFileSync16(newPath, content, "utf-8");
25780
26043
  __require("fs").unlinkSync(oldPath);
25781
26044
  result.filesModified.push(newPath);
25782
26045
  } catch (err) {
@@ -38355,13 +38618,13 @@ var lsp_rename = tool({
38355
38618
  });
38356
38619
  // src/tools/ast-grep/constants.ts
38357
38620
  import { createRequire as createRequire4 } from "module";
38358
- import { dirname as dirname10, join as join47 } from "path";
38359
- import { existsSync as existsSync38, statSync as statSync4 } from "fs";
38621
+ import { dirname as dirname10, join as join48 } from "path";
38622
+ import { existsSync as existsSync40, statSync as statSync4 } from "fs";
38360
38623
 
38361
38624
  // src/tools/ast-grep/downloader.ts
38362
38625
  init_shared();
38363
- import { existsSync as existsSync37, mkdirSync as mkdirSync12, chmodSync as chmodSync2, unlinkSync as unlinkSync10 } from "fs";
38364
- import { join as join46 } from "path";
38626
+ import { existsSync as existsSync39, mkdirSync as mkdirSync13, chmodSync as chmodSync2, unlinkSync as unlinkSync10 } from "fs";
38627
+ import { join as join47 } from "path";
38365
38628
  import { homedir as homedir12 } from "os";
38366
38629
  import { createRequire as createRequire3 } from "module";
38367
38630
  var REPO2 = "ast-grep/ast-grep";
@@ -38387,19 +38650,19 @@ var PLATFORM_MAP2 = {
38387
38650
  function getCacheDir3() {
38388
38651
  if (process.platform === "win32") {
38389
38652
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
38390
- const base2 = localAppData || join46(homedir12(), "AppData", "Local");
38391
- return join46(base2, "oh-my-opencode", "bin");
38653
+ const base2 = localAppData || join47(homedir12(), "AppData", "Local");
38654
+ return join47(base2, "oh-my-opencode", "bin");
38392
38655
  }
38393
38656
  const xdgCache = process.env.XDG_CACHE_HOME;
38394
- const base = xdgCache || join46(homedir12(), ".cache");
38395
- return join46(base, "oh-my-opencode", "bin");
38657
+ const base = xdgCache || join47(homedir12(), ".cache");
38658
+ return join47(base, "oh-my-opencode", "bin");
38396
38659
  }
38397
38660
  function getBinaryName3() {
38398
38661
  return process.platform === "win32" ? "sg.exe" : "sg";
38399
38662
  }
38400
38663
  function getCachedBinaryPath2() {
38401
- const binaryPath = join46(getCacheDir3(), getBinaryName3());
38402
- return existsSync37(binaryPath) ? binaryPath : null;
38664
+ const binaryPath = join47(getCacheDir3(), getBinaryName3());
38665
+ return existsSync39(binaryPath) ? binaryPath : null;
38403
38666
  }
38404
38667
  async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38405
38668
  const platformKey = `${process.platform}-${process.arch}`;
@@ -38410,8 +38673,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38410
38673
  }
38411
38674
  const cacheDir = getCacheDir3();
38412
38675
  const binaryName = getBinaryName3();
38413
- const binaryPath = join46(cacheDir, binaryName);
38414
- if (existsSync37(binaryPath)) {
38676
+ const binaryPath = join47(cacheDir, binaryName);
38677
+ if (existsSync39(binaryPath)) {
38415
38678
  return binaryPath;
38416
38679
  }
38417
38680
  const { arch, os: os6 } = platformInfo;
@@ -38419,21 +38682,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
38419
38682
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
38420
38683
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
38421
38684
  try {
38422
- if (!existsSync37(cacheDir)) {
38423
- mkdirSync12(cacheDir, { recursive: true });
38685
+ if (!existsSync39(cacheDir)) {
38686
+ mkdirSync13(cacheDir, { recursive: true });
38424
38687
  }
38425
38688
  const response = await fetch(downloadUrl, { redirect: "follow" });
38426
38689
  if (!response.ok) {
38427
38690
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
38428
38691
  }
38429
- const archivePath = join46(cacheDir, assetName);
38692
+ const archivePath = join47(cacheDir, assetName);
38430
38693
  const arrayBuffer = await response.arrayBuffer();
38431
38694
  await Bun.write(archivePath, arrayBuffer);
38432
38695
  await extractZip(archivePath, cacheDir);
38433
- if (existsSync37(archivePath)) {
38696
+ if (existsSync39(archivePath)) {
38434
38697
  unlinkSync10(archivePath);
38435
38698
  }
38436
- if (process.platform !== "win32" && existsSync37(binaryPath)) {
38699
+ if (process.platform !== "win32" && existsSync39(binaryPath)) {
38437
38700
  chmodSync2(binaryPath, 493);
38438
38701
  }
38439
38702
  console.log(`[oh-my-opencode] ast-grep binary ready.`);
@@ -38484,8 +38747,8 @@ function findSgCliPathSync() {
38484
38747
  const require2 = createRequire4(import.meta.url);
38485
38748
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
38486
38749
  const cliDir = dirname10(cliPkgPath);
38487
- const sgPath = join47(cliDir, binaryName);
38488
- if (existsSync38(sgPath) && isValidBinary(sgPath)) {
38750
+ const sgPath = join48(cliDir, binaryName);
38751
+ if (existsSync40(sgPath) && isValidBinary(sgPath)) {
38489
38752
  return sgPath;
38490
38753
  }
38491
38754
  } catch {}
@@ -38496,8 +38759,8 @@ function findSgCliPathSync() {
38496
38759
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
38497
38760
  const pkgDir = dirname10(pkgPath);
38498
38761
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
38499
- const binaryPath = join47(pkgDir, astGrepName);
38500
- if (existsSync38(binaryPath) && isValidBinary(binaryPath)) {
38762
+ const binaryPath = join48(pkgDir, astGrepName);
38763
+ if (existsSync40(binaryPath) && isValidBinary(binaryPath)) {
38501
38764
  return binaryPath;
38502
38765
  }
38503
38766
  } catch {}
@@ -38505,7 +38768,7 @@ function findSgCliPathSync() {
38505
38768
  if (process.platform === "darwin") {
38506
38769
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
38507
38770
  for (const path7 of homebrewPaths) {
38508
- if (existsSync38(path7) && isValidBinary(path7)) {
38771
+ if (existsSync40(path7) && isValidBinary(path7)) {
38509
38772
  return path7;
38510
38773
  }
38511
38774
  }
@@ -38560,11 +38823,11 @@ var DEFAULT_MAX_MATCHES = 500;
38560
38823
 
38561
38824
  // src/tools/ast-grep/cli.ts
38562
38825
  var {spawn: spawn7 } = globalThis.Bun;
38563
- import { existsSync as existsSync39 } from "fs";
38826
+ import { existsSync as existsSync41 } from "fs";
38564
38827
  var resolvedCliPath3 = null;
38565
38828
  var initPromise2 = null;
38566
38829
  async function getAstGrepPath() {
38567
- if (resolvedCliPath3 !== null && existsSync39(resolvedCliPath3)) {
38830
+ if (resolvedCliPath3 !== null && existsSync41(resolvedCliPath3)) {
38568
38831
  return resolvedCliPath3;
38569
38832
  }
38570
38833
  if (initPromise2) {
@@ -38572,7 +38835,7 @@ async function getAstGrepPath() {
38572
38835
  }
38573
38836
  initPromise2 = (async () => {
38574
38837
  const syncPath = findSgCliPathSync();
38575
- if (syncPath && existsSync39(syncPath)) {
38838
+ if (syncPath && existsSync41(syncPath)) {
38576
38839
  resolvedCliPath3 = syncPath;
38577
38840
  setSgCliPath(syncPath);
38578
38841
  return syncPath;
@@ -38606,7 +38869,7 @@ async function runSg(options) {
38606
38869
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
38607
38870
  args.push(...paths);
38608
38871
  let cliPath = getSgCliPath();
38609
- if (!existsSync39(cliPath) && cliPath !== "sg") {
38872
+ if (!existsSync41(cliPath) && cliPath !== "sg") {
38610
38873
  const downloadedPath = await getAstGrepPath();
38611
38874
  if (downloadedPath) {
38612
38875
  cliPath = downloadedPath;
@@ -38870,21 +39133,21 @@ var ast_grep_replace = tool({
38870
39133
  var {spawn: spawn9 } = globalThis.Bun;
38871
39134
 
38872
39135
  // src/tools/grep/constants.ts
38873
- import { existsSync as existsSync41 } from "fs";
38874
- import { join as join49, dirname as dirname11 } from "path";
39136
+ import { existsSync as existsSync43 } from "fs";
39137
+ import { join as join50, dirname as dirname11 } from "path";
38875
39138
  import { spawnSync as spawnSync2 } from "child_process";
38876
39139
 
38877
39140
  // src/tools/grep/downloader.ts
38878
39141
  init_shared();
38879
- import { existsSync as existsSync40, mkdirSync as mkdirSync13, chmodSync as chmodSync3, unlinkSync as unlinkSync11, readdirSync as readdirSync11 } from "fs";
38880
- import { join as join48 } from "path";
39142
+ import { existsSync as existsSync42, mkdirSync as mkdirSync14, chmodSync as chmodSync3, unlinkSync as unlinkSync11, readdirSync as readdirSync12 } from "fs";
39143
+ import { join as join49 } from "path";
38881
39144
  var {spawn: spawn8 } = globalThis.Bun;
38882
39145
  function findFileRecursive(dir, filename) {
38883
39146
  try {
38884
- const entries = readdirSync11(dir, { withFileTypes: true, recursive: true });
39147
+ const entries = readdirSync12(dir, { withFileTypes: true, recursive: true });
38885
39148
  for (const entry of entries) {
38886
39149
  if (entry.isFile() && entry.name === filename) {
38887
- return join48(entry.parentPath ?? dir, entry.name);
39150
+ return join49(entry.parentPath ?? dir, entry.name);
38888
39151
  }
38889
39152
  }
38890
39153
  } catch {
@@ -38905,11 +39168,11 @@ function getPlatformKey() {
38905
39168
  }
38906
39169
  function getInstallDir() {
38907
39170
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
38908
- return join48(homeDir, ".cache", "oh-my-opencode", "bin");
39171
+ return join49(homeDir, ".cache", "oh-my-opencode", "bin");
38909
39172
  }
38910
39173
  function getRgPath() {
38911
39174
  const isWindows2 = process.platform === "win32";
38912
- return join48(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
39175
+ return join49(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
38913
39176
  }
38914
39177
  async function downloadFile(url2, destPath) {
38915
39178
  const response = await fetch(url2);
@@ -38943,7 +39206,7 @@ async function extractZip2(archivePath, destDir) {
38943
39206
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
38944
39207
  const foundPath = findFileRecursive(destDir, binaryName);
38945
39208
  if (foundPath) {
38946
- const destPath = join48(destDir, binaryName);
39209
+ const destPath = join49(destDir, binaryName);
38947
39210
  if (foundPath !== destPath) {
38948
39211
  const { renameSync } = await import("fs");
38949
39212
  renameSync(foundPath, destPath);
@@ -38958,13 +39221,13 @@ async function downloadAndInstallRipgrep() {
38958
39221
  }
38959
39222
  const installDir = getInstallDir();
38960
39223
  const rgPath = getRgPath();
38961
- if (existsSync40(rgPath)) {
39224
+ if (existsSync42(rgPath)) {
38962
39225
  return rgPath;
38963
39226
  }
38964
- mkdirSync13(installDir, { recursive: true });
39227
+ mkdirSync14(installDir, { recursive: true });
38965
39228
  const filename = `ripgrep-${RG_VERSION}-${config3.platform}.${config3.extension}`;
38966
39229
  const url2 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
38967
- const archivePath = join48(installDir, filename);
39230
+ const archivePath = join49(installDir, filename);
38968
39231
  try {
38969
39232
  await downloadFile(url2, archivePath);
38970
39233
  if (config3.extension === "tar.gz") {
@@ -38975,12 +39238,12 @@ async function downloadAndInstallRipgrep() {
38975
39238
  if (process.platform !== "win32") {
38976
39239
  chmodSync3(rgPath, 493);
38977
39240
  }
38978
- if (!existsSync40(rgPath)) {
39241
+ if (!existsSync42(rgPath)) {
38979
39242
  throw new Error("ripgrep binary not found after extraction");
38980
39243
  }
38981
39244
  return rgPath;
38982
39245
  } finally {
38983
- if (existsSync40(archivePath)) {
39246
+ if (existsSync42(archivePath)) {
38984
39247
  try {
38985
39248
  unlinkSync11(archivePath);
38986
39249
  } catch {}
@@ -38989,7 +39252,7 @@ async function downloadAndInstallRipgrep() {
38989
39252
  }
38990
39253
  function getInstalledRipgrepPath() {
38991
39254
  const rgPath = getRgPath();
38992
- return existsSync40(rgPath) ? rgPath : null;
39255
+ return existsSync42(rgPath) ? rgPath : null;
38993
39256
  }
38994
39257
 
38995
39258
  // src/tools/grep/constants.ts
@@ -39014,14 +39277,14 @@ function getOpenCodeBundledRg() {
39014
39277
  const isWindows2 = process.platform === "win32";
39015
39278
  const rgName = isWindows2 ? "rg.exe" : "rg";
39016
39279
  const candidates = [
39017
- join49(getDataDir(), "opencode", "bin", rgName),
39018
- join49(execDir, rgName),
39019
- join49(execDir, "bin", rgName),
39020
- join49(execDir, "..", "bin", rgName),
39021
- join49(execDir, "..", "libexec", rgName)
39280
+ join50(getDataDir(), "opencode", "bin", rgName),
39281
+ join50(execDir, rgName),
39282
+ join50(execDir, "bin", rgName),
39283
+ join50(execDir, "..", "bin", rgName),
39284
+ join50(execDir, "..", "libexec", rgName)
39022
39285
  ];
39023
39286
  for (const candidate of candidates) {
39024
- if (existsSync41(candidate)) {
39287
+ if (existsSync43(candidate)) {
39025
39288
  return candidate;
39026
39289
  }
39027
39290
  }
@@ -39358,26 +39621,26 @@ async function runRgFiles(options, resolvedCli) {
39358
39621
  const isRg = cli.backend === "rg";
39359
39622
  const isWindows2 = process.platform === "win32";
39360
39623
  let command;
39361
- let cwd;
39624
+ let cwd2;
39362
39625
  if (isRg) {
39363
39626
  const args = buildRgArgs2(options);
39364
39627
  const paths = options.paths?.length ? options.paths : ["."];
39365
39628
  args.push(...paths);
39366
39629
  command = [cli.path, ...args];
39367
- cwd = undefined;
39630
+ cwd2 = undefined;
39368
39631
  } else if (isWindows2) {
39369
39632
  command = buildPowerShellCommand(options);
39370
- cwd = undefined;
39633
+ cwd2 = undefined;
39371
39634
  } else {
39372
39635
  const args = buildFindArgs(options);
39373
39636
  const paths = options.paths?.length ? options.paths : ["."];
39374
- cwd = paths[0] || ".";
39637
+ cwd2 = paths[0] || ".";
39375
39638
  command = [cli.path, ...args];
39376
39639
  }
39377
39640
  const proc = spawn10(command, {
39378
39641
  stdout: "pipe",
39379
39642
  stderr: "pipe",
39380
- cwd
39643
+ cwd: cwd2
39381
39644
  });
39382
39645
  const timeoutPromise = new Promise((_, reject) => {
39383
39646
  const id = setTimeout(() => {
@@ -39415,7 +39678,7 @@ async function runRgFiles(options, resolvedCli) {
39415
39678
  } else if (isWindows2) {
39416
39679
  filePath = line.trim();
39417
39680
  } else {
39418
- filePath = `${cwd}/${line}`;
39681
+ filePath = `${cwd2}/${line}`;
39419
39682
  }
39420
39683
  const mtime = await getFileMtime(filePath);
39421
39684
  files.push({ path: filePath, mtime });
@@ -39483,8 +39746,8 @@ var glob = tool({
39483
39746
  init_shared();
39484
39747
  init_file_utils();
39485
39748
  init_shared();
39486
- import { existsSync as existsSync42, readdirSync as readdirSync12, readFileSync as readFileSync28 } from "fs";
39487
- import { join as join50, basename as basename4, dirname as dirname12 } from "path";
39749
+ import { existsSync as existsSync44, readdirSync as readdirSync13, readFileSync as readFileSync29 } from "fs";
39750
+ import { join as join51, basename as basename4, dirname as dirname12 } from "path";
39488
39751
  // src/features/builtin-commands/templates/init-deep.ts
39489
39752
  var INIT_DEEP_TEMPLATE = `# /init-deep
39490
39753
 
@@ -40600,18 +40863,18 @@ function loadBuiltinCommands(disabledCommands) {
40600
40863
  }
40601
40864
  // src/tools/slashcommand/tools.ts
40602
40865
  function discoverCommandsFromDir2(commandsDir, scope) {
40603
- if (!existsSync42(commandsDir)) {
40866
+ if (!existsSync44(commandsDir)) {
40604
40867
  return [];
40605
40868
  }
40606
- const entries = readdirSync12(commandsDir, { withFileTypes: true });
40869
+ const entries = readdirSync13(commandsDir, { withFileTypes: true });
40607
40870
  const commands2 = [];
40608
40871
  for (const entry of entries) {
40609
40872
  if (!isMarkdownFile(entry))
40610
40873
  continue;
40611
- const commandPath = join50(commandsDir, entry.name);
40874
+ const commandPath = join51(commandsDir, entry.name);
40612
40875
  const commandName = basename4(entry.name, ".md");
40613
40876
  try {
40614
- const content = readFileSync28(commandPath, "utf-8");
40877
+ const content = readFileSync29(commandPath, "utf-8");
40615
40878
  const { data, body } = parseFrontmatter(content);
40616
40879
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
40617
40880
  const metadata = {
@@ -40637,10 +40900,10 @@ function discoverCommandsFromDir2(commandsDir, scope) {
40637
40900
  }
40638
40901
  function discoverCommandsSync() {
40639
40902
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
40640
- const userCommandsDir = join50(getClaudeConfigDir(), "commands");
40641
- const projectCommandsDir = join50(process.cwd(), ".claude", "commands");
40642
- const opencodeGlobalDir = join50(configDir, "command");
40643
- const opencodeProjectDir = join50(process.cwd(), ".opencode", "command");
40903
+ const userCommandsDir = join51(getClaudeConfigDir(), "commands");
40904
+ const projectCommandsDir = join51(process.cwd(), ".claude", "commands");
40905
+ const opencodeGlobalDir = join51(configDir, "command");
40906
+ const opencodeProjectDir = join51(process.cwd(), ".opencode", "command");
40644
40907
  const userCommands = discoverCommandsFromDir2(userCommandsDir, "user");
40645
40908
  const opencodeGlobalCommands = discoverCommandsFromDir2(opencodeGlobalDir, "opencode");
40646
40909
  const projectCommands = discoverCommandsFromDir2(projectCommandsDir, "project");
@@ -40817,13 +41080,13 @@ var slashcommand = createSlashcommandTool();
40817
41080
  // src/tools/session-manager/constants.ts
40818
41081
  init_data_path();
40819
41082
  init_shared();
40820
- import { join as join51 } from "path";
41083
+ import { join as join52 } from "path";
40821
41084
  var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
40822
- var MESSAGE_STORAGE4 = join51(OPENCODE_STORAGE9, "message");
40823
- var PART_STORAGE4 = join51(OPENCODE_STORAGE9, "part");
40824
- var SESSION_STORAGE = join51(OPENCODE_STORAGE9, "session");
40825
- var TODO_DIR2 = join51(getClaudeConfigDir(), "todos");
40826
- var TRANSCRIPT_DIR2 = join51(getClaudeConfigDir(), "transcripts");
41085
+ var MESSAGE_STORAGE4 = join52(OPENCODE_STORAGE9, "message");
41086
+ var PART_STORAGE4 = join52(OPENCODE_STORAGE9, "part");
41087
+ var SESSION_STORAGE = join52(OPENCODE_STORAGE9, "session");
41088
+ var TODO_DIR2 = join52(getClaudeConfigDir(), "todos");
41089
+ var TRANSCRIPT_DIR2 = join52(getClaudeConfigDir(), "transcripts");
40827
41090
  var SESSION_LIST_DESCRIPTION = `\u5217\u51FA\u6240\u6709 OpenCode session\uFF0C\u652F\u6301\u53EF\u9009\u8FC7\u6EE4\u3002
40828
41091
 
40829
41092
  \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
@@ -40896,11 +41159,11 @@ Has Todos: Yes (12 items, 8 completed)
40896
41159
  Has Transcript: Yes (234 entries)`;
40897
41160
 
40898
41161
  // src/tools/session-manager/storage.ts
40899
- import { existsSync as existsSync43, readdirSync as readdirSync13 } from "fs";
41162
+ import { existsSync as existsSync45, readdirSync as readdirSync14 } from "fs";
40900
41163
  import { readdir, readFile } from "fs/promises";
40901
- import { join as join52 } from "path";
41164
+ import { join as join53 } from "path";
40902
41165
  async function getMainSessions(options) {
40903
- if (!existsSync43(SESSION_STORAGE))
41166
+ if (!existsSync45(SESSION_STORAGE))
40904
41167
  return [];
40905
41168
  const sessions = [];
40906
41169
  try {
@@ -40908,13 +41171,13 @@ async function getMainSessions(options) {
40908
41171
  for (const projectDir of projectDirs) {
40909
41172
  if (!projectDir.isDirectory())
40910
41173
  continue;
40911
- const projectPath = join52(SESSION_STORAGE, projectDir.name);
41174
+ const projectPath = join53(SESSION_STORAGE, projectDir.name);
40912
41175
  const sessionFiles = await readdir(projectPath);
40913
41176
  for (const file2 of sessionFiles) {
40914
41177
  if (!file2.endsWith(".json"))
40915
41178
  continue;
40916
41179
  try {
40917
- const content = await readFile(join52(projectPath, file2), "utf-8");
41180
+ const content = await readFile(join53(projectPath, file2), "utf-8");
40918
41181
  const meta = JSON.parse(content);
40919
41182
  if (meta.parentID)
40920
41183
  continue;
@@ -40932,7 +41195,7 @@ async function getMainSessions(options) {
40932
41195
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
40933
41196
  }
40934
41197
  async function getAllSessions() {
40935
- if (!existsSync43(MESSAGE_STORAGE4))
41198
+ if (!existsSync45(MESSAGE_STORAGE4))
40936
41199
  return [];
40937
41200
  const sessions = [];
40938
41201
  async function scanDirectory(dir) {
@@ -40940,7 +41203,7 @@ async function getAllSessions() {
40940
41203
  const entries = await readdir(dir, { withFileTypes: true });
40941
41204
  for (const entry of entries) {
40942
41205
  if (entry.isDirectory()) {
40943
- const sessionPath = join52(dir, entry.name);
41206
+ const sessionPath = join53(dir, entry.name);
40944
41207
  const files = await readdir(sessionPath);
40945
41208
  if (files.some((f) => f.endsWith(".json"))) {
40946
41209
  sessions.push(entry.name);
@@ -40957,16 +41220,16 @@ async function getAllSessions() {
40957
41220
  return [...new Set(sessions)];
40958
41221
  }
40959
41222
  function getMessageDir7(sessionID) {
40960
- if (!existsSync43(MESSAGE_STORAGE4))
41223
+ if (!existsSync45(MESSAGE_STORAGE4))
40961
41224
  return "";
40962
- const directPath = join52(MESSAGE_STORAGE4, sessionID);
40963
- if (existsSync43(directPath)) {
41225
+ const directPath = join53(MESSAGE_STORAGE4, sessionID);
41226
+ if (existsSync45(directPath)) {
40964
41227
  return directPath;
40965
41228
  }
40966
41229
  try {
40967
- for (const dir of readdirSync13(MESSAGE_STORAGE4)) {
40968
- const sessionPath = join52(MESSAGE_STORAGE4, dir, sessionID);
40969
- if (existsSync43(sessionPath)) {
41230
+ for (const dir of readdirSync14(MESSAGE_STORAGE4)) {
41231
+ const sessionPath = join53(MESSAGE_STORAGE4, dir, sessionID);
41232
+ if (existsSync45(sessionPath)) {
40970
41233
  return sessionPath;
40971
41234
  }
40972
41235
  }
@@ -40980,7 +41243,7 @@ function sessionExists(sessionID) {
40980
41243
  }
40981
41244
  async function readSessionMessages(sessionID) {
40982
41245
  const messageDir = getMessageDir7(sessionID);
40983
- if (!messageDir || !existsSync43(messageDir))
41246
+ if (!messageDir || !existsSync45(messageDir))
40984
41247
  return [];
40985
41248
  const messages = [];
40986
41249
  try {
@@ -40989,7 +41252,7 @@ async function readSessionMessages(sessionID) {
40989
41252
  if (!file2.endsWith(".json"))
40990
41253
  continue;
40991
41254
  try {
40992
- const content = await readFile(join52(messageDir, file2), "utf-8");
41255
+ const content = await readFile(join53(messageDir, file2), "utf-8");
40993
41256
  const meta = JSON.parse(content);
40994
41257
  const parts = await readParts2(meta.id);
40995
41258
  messages.push({
@@ -41015,8 +41278,8 @@ async function readSessionMessages(sessionID) {
41015
41278
  });
41016
41279
  }
41017
41280
  async function readParts2(messageID) {
41018
- const partDir = join52(PART_STORAGE4, messageID);
41019
- if (!existsSync43(partDir))
41281
+ const partDir = join53(PART_STORAGE4, messageID);
41282
+ if (!existsSync45(partDir))
41020
41283
  return [];
41021
41284
  const parts = [];
41022
41285
  try {
@@ -41025,7 +41288,7 @@ async function readParts2(messageID) {
41025
41288
  if (!file2.endsWith(".json"))
41026
41289
  continue;
41027
41290
  try {
41028
- const content = await readFile(join52(partDir, file2), "utf-8");
41291
+ const content = await readFile(join53(partDir, file2), "utf-8");
41029
41292
  parts.push(JSON.parse(content));
41030
41293
  } catch {
41031
41294
  continue;
@@ -41037,14 +41300,14 @@ async function readParts2(messageID) {
41037
41300
  return parts.sort((a, b) => a.id.localeCompare(b.id));
41038
41301
  }
41039
41302
  async function readSessionTodos(sessionID) {
41040
- if (!existsSync43(TODO_DIR2))
41303
+ if (!existsSync45(TODO_DIR2))
41041
41304
  return [];
41042
41305
  try {
41043
41306
  const allFiles = await readdir(TODO_DIR2);
41044
41307
  const todoFiles = allFiles.filter((f) => f.includes(sessionID) && f.endsWith(".json"));
41045
41308
  for (const file2 of todoFiles) {
41046
41309
  try {
41047
- const content = await readFile(join52(TODO_DIR2, file2), "utf-8");
41310
+ const content = await readFile(join53(TODO_DIR2, file2), "utf-8");
41048
41311
  const data = JSON.parse(content);
41049
41312
  if (Array.isArray(data)) {
41050
41313
  return data.map((item) => ({
@@ -41064,10 +41327,10 @@ async function readSessionTodos(sessionID) {
41064
41327
  return [];
41065
41328
  }
41066
41329
  async function readSessionTranscript(sessionID) {
41067
- if (!existsSync43(TRANSCRIPT_DIR2))
41330
+ if (!existsSync45(TRANSCRIPT_DIR2))
41068
41331
  return 0;
41069
- const transcriptFile = join52(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
41070
- if (!existsSync43(transcriptFile))
41332
+ const transcriptFile = join53(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
41333
+ if (!existsSync45(transcriptFile))
41071
41334
  return 0;
41072
41335
  try {
41073
41336
  const content = await readFile(transcriptFile, "utf-8");
@@ -41888,19 +42151,6 @@ var BACKGROUND_CANCEL_DESCRIPTION = `\u53D6\u6D88\u6B63\u5728\u8FD0\u884C\u7684\
41888
42151
  // src/tools/background-task/tools.ts
41889
42152
  init_logger();
41890
42153
  init_session_cursor();
41891
- function formatDuration(start, end) {
41892
- const duration3 = (end ?? new Date).getTime() - start.getTime();
41893
- const seconds = Math.floor(duration3 / 1000);
41894
- const minutes = Math.floor(seconds / 60);
41895
- const hours = Math.floor(minutes / 60);
41896
- if (hours > 0) {
41897
- return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
41898
- } else if (minutes > 0) {
41899
- return `${minutes}m ${seconds % 60}s`;
41900
- } else {
41901
- return `${seconds}s`;
41902
- }
41903
- }
41904
42154
  function delay(ms) {
41905
42155
  return new Promise((resolve10) => setTimeout(resolve10, ms));
41906
42156
  }
@@ -41912,9 +42162,9 @@ function truncateText(text, maxLength) {
41912
42162
  function formatTaskStatus(task) {
41913
42163
  let duration3;
41914
42164
  if (task.status === "pending" && task.queuedAt) {
41915
- duration3 = formatDuration(task.queuedAt, undefined);
42165
+ duration3 = PerfTimer.formatDuration(task.queuedAt, undefined);
41916
42166
  } else if (task.startedAt) {
41917
- duration3 = formatDuration(task.startedAt, task.completedAt);
42167
+ duration3 = PerfTimer.formatDuration(task.startedAt, task.completedAt);
41918
42168
  } else {
41919
42169
  duration3 = "N/A";
41920
42170
  }
@@ -41951,6 +42201,18 @@ ${truncated}
41951
42201
  > **Failed**: The task encountered an error. Check the last message for details.`;
41952
42202
  }
41953
42203
  const durationLabel = task.status === "pending" ? "Queued for" : "Duration";
42204
+ let perfBlock = "";
42205
+ if (task.progress?.phaseTiming) {
42206
+ const pt = task.progress.phaseTiming;
42207
+ const queueWait = PerfTimer.formatDuration(new Date(0), new Date(pt.queueWaitMs));
42208
+ perfBlock = `
42209
+
42210
+ ### Performance
42211
+ | Metric | Value |
42212
+ |--------|-------|
42213
+ | Queue wait | ${queueWait} |
42214
+ | Tool calls | ${pt.toolCallCount} |`;
42215
+ }
41954
42216
  return `# Task Status
41955
42217
 
41956
42218
  | Field | Value |
@@ -41966,7 +42228,8 @@ ${statusNote}
41966
42228
 
41967
42229
  \`\`\`
41968
42230
  ${promptPreview}
41969
- \`\`\`${lastMessageSection}`;
42231
+ \`\`\`${lastMessageSection}${perfBlock}
42232
+ }`;
41970
42233
  }
41971
42234
  async function formatTaskResult(task, client2) {
41972
42235
  if (!task.sessionID) {
@@ -41980,12 +42243,25 @@ async function formatTaskResult(task, client2) {
41980
42243
  }
41981
42244
  const messages = messagesResult.data ?? messagesResult;
41982
42245
  if (!Array.isArray(messages) || messages.length === 0) {
42246
+ const duration4 = PerfTimer.formatDuration(task.startedAt ?? new Date, task.completedAt);
42247
+ let perfBlock2 = "";
42248
+ if (task.progress?.phaseTiming) {
42249
+ const pt = task.progress.phaseTiming;
42250
+ const queueWait = PerfTimer.formatDuration(new Date(0), new Date(pt.queueWaitMs));
42251
+ perfBlock2 = `
42252
+
42253
+ ### Performance
42254
+ | Metric | Value |
42255
+ |--------|-------|
42256
+ | Queue wait | ${queueWait} |
42257
+ | Tool calls | ${pt.toolCallCount} |`;
42258
+ }
41983
42259
  return `Task Result
41984
42260
 
41985
42261
  Task ID: ${task.id}
41986
42262
  Description: ${task.description}
41987
- Duration: ${formatDuration(task.startedAt ?? new Date, task.completedAt)}
41988
- Session ID: ${task.sessionID}
42263
+ Duration: ${duration4}
42264
+ Session ID: ${task.sessionID}${perfBlock2}
41989
42265
 
41990
42266
  ---
41991
42267
 
@@ -41993,12 +42269,25 @@ Session ID: ${task.sessionID}
41993
42269
  }
41994
42270
  const relevantMessages = messages.filter((m) => m.info?.role === "assistant" || m.info?.role === "tool");
41995
42271
  if (relevantMessages.length === 0) {
42272
+ const duration4 = PerfTimer.formatDuration(task.startedAt ?? new Date, task.completedAt);
42273
+ let perfBlock2 = "";
42274
+ if (task.progress?.phaseTiming) {
42275
+ const pt = task.progress.phaseTiming;
42276
+ const queueWait = PerfTimer.formatDuration(new Date(0), new Date(pt.queueWaitMs));
42277
+ perfBlock2 = `
42278
+
42279
+ ### Performance
42280
+ | Metric | Value |
42281
+ |--------|-------|
42282
+ | Queue wait | ${queueWait} |
42283
+ | Tool calls | ${pt.toolCallCount} |`;
42284
+ }
41996
42285
  return `Task Result
41997
42286
 
41998
42287
  Task ID: ${task.id}
41999
42288
  Description: ${task.description}
42000
- Duration: ${formatDuration(task.startedAt ?? new Date, task.completedAt)}
42001
- Session ID: ${task.sessionID}
42289
+ Duration: ${duration4}
42290
+ Session ID: ${task.sessionID}${perfBlock2}
42002
42291
 
42003
42292
  ---
42004
42293
 
@@ -42011,13 +42300,25 @@ Session ID: ${task.sessionID}
42011
42300
  });
42012
42301
  const newMessages = consumeNewMessages(task.sessionID, sortedMessages);
42013
42302
  if (newMessages.length === 0) {
42014
- const duration4 = formatDuration(task.startedAt ?? new Date, task.completedAt);
42303
+ const duration4 = PerfTimer.formatDuration(task.startedAt ?? new Date, task.completedAt);
42304
+ let perfBlock2 = "";
42305
+ if (task.progress?.phaseTiming) {
42306
+ const pt = task.progress.phaseTiming;
42307
+ const queueWait = PerfTimer.formatDuration(new Date(0), new Date(pt.queueWaitMs));
42308
+ perfBlock2 = `
42309
+
42310
+ ### Performance
42311
+ | Metric | Value |
42312
+ |--------|-------|
42313
+ | Queue wait | ${queueWait} |
42314
+ | Tool calls | ${pt.toolCallCount} |`;
42315
+ }
42015
42316
  return `Task Result
42016
42317
 
42017
42318
  Task ID: ${task.id}
42018
42319
  Description: ${task.description}
42019
42320
  Duration: ${duration4}
42020
- Session ID: ${task.sessionID}
42321
+ Session ID: ${task.sessionID}${perfBlock2}
42021
42322
 
42022
42323
  ---
42023
42324
 
@@ -42045,13 +42346,25 @@ Session ID: ${task.sessionID}
42045
42346
  const textContent = extractedContent.filter((text) => text.length > 0).join(`
42046
42347
 
42047
42348
  `);
42048
- const duration3 = formatDuration(task.startedAt ?? new Date, task.completedAt);
42349
+ const duration3 = PerfTimer.formatDuration(task.startedAt ?? new Date, task.completedAt);
42350
+ let perfBlock = "";
42351
+ if (task.progress?.phaseTiming) {
42352
+ const pt = task.progress.phaseTiming;
42353
+ const queueWait = PerfTimer.formatDuration(new Date(0), new Date(pt.queueWaitMs));
42354
+ perfBlock = `
42355
+
42356
+ ### Performance
42357
+ | Metric | Value |
42358
+ |--------|-------|
42359
+ | Queue wait | ${queueWait} |
42360
+ | Tool calls | ${pt.toolCallCount} |`;
42361
+ }
42049
42362
  return `Task Result
42050
42363
 
42051
42364
  Task ID: ${task.id}
42052
42365
  Description: ${task.description}
42053
42366
  Duration: ${duration3}
42054
- Session ID: ${task.sessionID}
42367
+ Session ID: ${task.sessionID}${perfBlock}
42055
42368
 
42056
42369
  ---
42057
42370
 
@@ -42219,19 +42532,19 @@ var CALL_OMO_AGENT_DESCRIPTION = `\u542F\u52A8 explore/librarian agent\u3002run_
42219
42532
 
42220
42533
  \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`;
42221
42534
  // src/tools/call-omo-agent/tools.ts
42222
- import { existsSync as existsSync44, readdirSync as readdirSync14 } from "fs";
42223
- import { join as join53 } from "path";
42535
+ import { existsSync as existsSync46, readdirSync as readdirSync15 } from "fs";
42536
+ import { join as join54 } from "path";
42224
42537
  init_shared();
42225
42538
  init_session_cursor();
42226
42539
  function getMessageDir8(sessionID) {
42227
- if (!existsSync44(MESSAGE_STORAGE))
42540
+ if (!existsSync46(MESSAGE_STORAGE))
42228
42541
  return null;
42229
- const directPath = join53(MESSAGE_STORAGE, sessionID);
42230
- if (existsSync44(directPath))
42542
+ const directPath = join54(MESSAGE_STORAGE, sessionID);
42543
+ if (existsSync46(directPath))
42231
42544
  return directPath;
42232
- for (const dir of readdirSync14(MESSAGE_STORAGE)) {
42233
- const sessionPath = join53(MESSAGE_STORAGE, dir, sessionID);
42234
- if (existsSync44(sessionPath))
42545
+ for (const dir of readdirSync15(MESSAGE_STORAGE)) {
42546
+ const sessionPath = join54(MESSAGE_STORAGE, dir, sessionID);
42547
+ if (existsSync46(sessionPath))
42235
42548
  return sessionPath;
42236
42549
  }
42237
42550
  return null;
@@ -42640,8 +42953,8 @@ If the requested information is not found, clearly state what is missing.`;
42640
42953
  }
42641
42954
  // src/tools/delegate-task/tools.ts
42642
42955
  init_constants2();
42643
- import { existsSync as existsSync45, readdirSync as readdirSync15 } from "fs";
42644
- import { join as join54 } from "path";
42956
+ import { existsSync as existsSync47, readdirSync as readdirSync16 } from "fs";
42957
+ import { join as join55 } from "path";
42645
42958
 
42646
42959
  // src/features/task-toast-manager/manager.ts
42647
42960
  class TaskToastManager {
@@ -42687,14 +43000,7 @@ class TaskToastManager {
42687
43000
  return Array.from(this.tasks.values()).filter((t) => t.status === "queued").sort((a, b) => a.startedAt.getTime() - b.startedAt.getTime());
42688
43001
  }
42689
43002
  formatDuration(startedAt) {
42690
- const seconds = Math.floor((Date.now() - startedAt.getTime()) / 1000);
42691
- if (seconds < 60)
42692
- return `${seconds}s`;
42693
- const minutes = Math.floor(seconds / 60);
42694
- if (minutes < 60)
42695
- return `${minutes}m ${seconds % 60}s`;
42696
- const hours = Math.floor(minutes / 60);
42697
- return `${hours}h ${minutes % 60}m`;
43003
+ return PerfTimer.formatDuration(startedAt, undefined, { precision: "compact" });
42698
43004
  }
42699
43005
  getConcurrencyInfo() {
42700
43006
  if (!this.concurrencyManager)
@@ -42798,9 +43104,6 @@ function initTaskToastManager(client2, concurrencyManager) {
42798
43104
  }
42799
43105
  // src/tools/delegate-task/tools.ts
42800
43106
  init_shared();
42801
- init_model_availability();
42802
- init_model_resolver();
42803
- init_model_requirements();
42804
43107
  var SISYPHUS_JUNIOR_AGENT = "sisyphus-junior";
42805
43108
  function parseModelString(model) {
42806
43109
  const parts = model.split("/");
@@ -42810,29 +43113,18 @@ function parseModelString(model) {
42810
43113
  return;
42811
43114
  }
42812
43115
  function getMessageDir9(sessionID) {
42813
- if (!existsSync45(MESSAGE_STORAGE))
43116
+ if (!existsSync47(MESSAGE_STORAGE))
42814
43117
  return null;
42815
- const directPath = join54(MESSAGE_STORAGE, sessionID);
42816
- if (existsSync45(directPath))
43118
+ const directPath = join55(MESSAGE_STORAGE, sessionID);
43119
+ if (existsSync47(directPath))
42817
43120
  return directPath;
42818
- for (const dir of readdirSync15(MESSAGE_STORAGE)) {
42819
- const sessionPath = join54(MESSAGE_STORAGE, dir, sessionID);
42820
- if (existsSync45(sessionPath))
43121
+ for (const dir of readdirSync16(MESSAGE_STORAGE)) {
43122
+ const sessionPath = join55(MESSAGE_STORAGE, dir, sessionID);
43123
+ if (existsSync47(sessionPath))
42821
43124
  return sessionPath;
42822
43125
  }
42823
43126
  return null;
42824
43127
  }
42825
- function formatDuration2(start, end) {
42826
- const duration3 = (end ?? new Date).getTime() - start.getTime();
42827
- const seconds = Math.floor(duration3 / 1000);
42828
- const minutes = Math.floor(seconds / 60);
42829
- const hours = Math.floor(minutes / 60);
42830
- if (hours > 0)
42831
- return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
42832
- if (minutes > 0)
42833
- return `${minutes}m ${seconds % 60}s`;
42834
- return `${seconds}s`;
42835
- }
42836
43128
  function formatDetailedError(error45, ctx) {
42837
43129
  const message = error45 instanceof Error ? error45.message : String(error45);
42838
43130
  const stack = error45 instanceof Error ? error45.stack : undefined;
@@ -43145,7 +43437,7 @@ Session ID: ${args.session_id}`;
43145
43437
  const textParts = lastMessage?.parts?.filter((p) => p.type === "text" || p.type === "reasoning") ?? [];
43146
43438
  const textContent = textParts.map((p) => p.text ?? "").filter(Boolean).join(`
43147
43439
  `);
43148
- const duration3 = formatDuration2(startTime);
43440
+ const duration3 = PerfTimer.formatDuration(startTime);
43149
43441
  return `\u4EFB\u52A1\u5DF2\u7EE7\u7EED\u5E76\u5728 ${duration3} \u5185\u5B8C\u6210\u3002
43150
43442
 
43151
43443
  Session ID: ${args.session_id}
@@ -43186,195 +43478,21 @@ ${textContent || "(\u65E0\u6587\u672C\u8F93\u51FA)"}
43186
43478
 
43187
43479
  ` + "\uFF08\u66FF\u6362\u4E3A\u4F60\u504F\u597D\u7684 provider/model\uFF09";
43188
43480
  }
43189
- const availableModels = await fetchAvailableModels(client2);
43190
43481
  const resolved = resolveCategoryConfig(args.category, {
43191
43482
  userCategories,
43192
43483
  inheritedModel,
43193
43484
  systemDefaultModel
43194
43485
  });
43195
43486
  if (!resolved) {
43196
- return `\u672A\u77E5\u7684\u5206\u7C7B\uFF1A"${args.category}"\u3002\u53EF\u7528\u7684\u5206\u7C7B\uFF1A${Object.keys({ ...DEFAULT_CATEGORIES, ...userCategories }).join(", ")}`;
43197
- }
43198
- const requirement = CATEGORY_MODEL_REQUIREMENTS[args.category];
43199
- let actualModel;
43200
- if (!requirement) {
43201
- actualModel = resolved.model;
43202
- modelInfo = { model: actualModel, type: "system-default", source: "system-default" };
43203
- } else {
43204
- const { model: resolvedModel, source, variant: resolvedVariant } = resolveModelWithFallback({
43205
- userModel: userCategories?.[args.category]?.model ?? sisyphusJuniorModel,
43206
- fallbackChain: requirement.fallbackChain,
43207
- availableModels,
43208
- systemDefaultModel
43209
- });
43210
- actualModel = resolvedModel;
43211
- if (!parseModelString(actualModel)) {
43212
- return `\u65E0\u6548\u7684\u6A21\u578B\u683C\u5F0F"${actualModel}"\u3002\u671F\u671B"provider/model"\u683C\u5F0F\uFF08\u4F8B\u5982 "anthropic/claude-sonnet-4-5"\uFF09\u3002`;
43213
- }
43214
- let type2;
43215
- switch (source) {
43216
- case "override":
43217
- type2 = "user-defined";
43218
- break;
43219
- case "provider-fallback":
43220
- type2 = "category-default";
43221
- break;
43222
- case "system-default":
43223
- type2 = "system-default";
43224
- break;
43225
- }
43226
- modelInfo = { model: actualModel, type: type2, source };
43227
- const parsedModel = parseModelString(actualModel);
43228
- const variantToUse = userCategories?.[args.category]?.variant ?? resolvedVariant;
43229
- categoryModel = parsedModel ? variantToUse ? { ...parsedModel, variant: variantToUse } : parsedModel : undefined;
43487
+ return `\u672A\u77E5\u7684\u5206\u7C7B\uFF1A${args.category}\u3002\u53EF\u7528\u7684\u5206\u7C7B\uFF1A${categoryExamples}`;
43230
43488
  }
43231
43489
  agentToUse = SISYPHUS_JUNIOR_AGENT;
43232
- if (!categoryModel) {
43233
- const parsedModel = parseModelString(actualModel);
43234
- categoryModel = parsedModel ?? undefined;
43235
- }
43236
- categoryPromptAppend = resolved.promptAppend || undefined;
43237
- const isUnstableAgent = resolved.config.is_unstable_agent === true || actualModel.toLowerCase().includes("gemini");
43238
- const isRunInBackgroundExplicitlyFalse = args.run_in_background === false || args.run_in_background === "false";
43239
- log("[delegate_task] unstable agent detection", {
43240
- category: args.category,
43241
- actualModel,
43242
- isUnstableAgent,
43243
- run_in_background_value: args.run_in_background,
43244
- run_in_background_type: typeof args.run_in_background,
43245
- isRunInBackgroundExplicitlyFalse,
43246
- willForceBackground: isUnstableAgent && isRunInBackgroundExplicitlyFalse
43247
- });
43248
- if (isUnstableAgent && isRunInBackgroundExplicitlyFalse) {
43249
- const systemContent2 = buildSystemContent({ skillContent, categoryPromptAppend });
43250
- try {
43251
- const task = await manager.launch({
43252
- description: args.description,
43253
- prompt: args.prompt,
43254
- agent: agentToUse,
43255
- parentSessionID: ctx.sessionID,
43256
- parentMessageID: ctx.messageID,
43257
- parentModel,
43258
- parentAgent,
43259
- model: categoryModel,
43260
- skills: args.load_skills.length > 0 ? args.load_skills : undefined,
43261
- skillContent: systemContent2
43262
- });
43263
- const WAIT_FOR_SESSION_INTERVAL_MS = 100;
43264
- const WAIT_FOR_SESSION_TIMEOUT_MS = 30000;
43265
- const waitStart = Date.now();
43266
- while (!task.sessionID && Date.now() - waitStart < WAIT_FOR_SESSION_TIMEOUT_MS) {
43267
- if (ctx.abort?.aborted) {
43268
- return `\u7B49\u5F85 session \u542F\u52A8\u65F6\u88AB\u4E2D\u6B62\u3002
43269
-
43270
- Task ID: ${task.id}`;
43271
- }
43272
- await new Promise((resolve10) => setTimeout(resolve10, WAIT_FOR_SESSION_INTERVAL_MS));
43273
- }
43274
- const sessionID = task.sessionID;
43275
- if (!sessionID) {
43276
- return formatDetailedError(new Error(`\u4EFB\u52A1\u5728\u8D85\u65F6\uFF0830\u79D2\uFF09\u5185\u672A\u80FD\u542F\u52A8\u3002Task ID: ${task.id}\uFF0CStatus: ${task.status}`), {
43277
- operation: "\u542F\u52A8\u53D7\u76D1\u63A7\u7684\u540E\u53F0\u4EFB\u52A1",
43278
- args,
43279
- agent: agentToUse,
43280
- category: args.category
43281
- });
43282
- }
43283
- ctx.metadata?.({
43284
- title: args.description,
43285
- metadata: {
43286
- prompt: args.prompt,
43287
- agent: agentToUse,
43288
- category: args.category,
43289
- load_skills: args.load_skills,
43290
- description: args.description,
43291
- run_in_background: args.run_in_background,
43292
- sessionId: sessionID,
43293
- command: args.command
43294
- }
43295
- });
43296
- const startTime = new Date;
43297
- const POLL_INTERVAL_MS = 500;
43298
- const MAX_POLL_TIME_MS = 10 * 60 * 1000;
43299
- const MIN_STABILITY_TIME_MS = 1e4;
43300
- const STABILITY_POLLS_REQUIRED = 3;
43301
- const pollStart = Date.now();
43302
- let lastMsgCount = 0;
43303
- let stablePolls = 0;
43304
- while (Date.now() - pollStart < MAX_POLL_TIME_MS) {
43305
- if (ctx.abort?.aborted) {
43306
- return `\u4EFB\u52A1\u5DF2\u4E2D\u6B62\uFF08\u6B63\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C\uFF09\u3002
43307
-
43308
- Session ID: ${sessionID}`;
43309
- }
43310
- await new Promise((resolve10) => setTimeout(resolve10, POLL_INTERVAL_MS));
43311
- const statusResult = await client2.session.status();
43312
- const allStatuses = statusResult.data ?? {};
43313
- const sessionStatus = allStatuses[sessionID];
43314
- if (sessionStatus && sessionStatus.type !== "idle") {
43315
- stablePolls = 0;
43316
- lastMsgCount = 0;
43317
- continue;
43318
- }
43319
- if (Date.now() - pollStart < MIN_STABILITY_TIME_MS)
43320
- continue;
43321
- const messagesCheck = await client2.session.messages({ path: { id: sessionID } });
43322
- const msgs = messagesCheck.data ?? messagesCheck;
43323
- const currentMsgCount = msgs.length;
43324
- if (currentMsgCount === lastMsgCount) {
43325
- stablePolls++;
43326
- if (stablePolls >= STABILITY_POLLS_REQUIRED)
43327
- break;
43328
- } else {
43329
- stablePolls = 0;
43330
- lastMsgCount = currentMsgCount;
43331
- }
43332
- }
43333
- const messagesResult = await client2.session.messages({ path: { id: sessionID } });
43334
- const messages = messagesResult.data ?? messagesResult;
43335
- const assistantMessages = messages.filter((m) => m.info?.role === "assistant").sort((a, b) => (b.info?.time?.created ?? 0) - (a.info?.time?.created ?? 0));
43336
- const lastMessage = assistantMessages[0];
43337
- if (!lastMessage) {
43338
- return `\u672A\u627E\u5230 assistant \u7684\u54CD\u5E94\uFF08\u4EFB\u52A1\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C\uFF09\u3002
43339
-
43340
- Session ID: ${sessionID}`;
43341
- }
43342
- const textParts = lastMessage?.parts?.filter((p) => p.type === "text" || p.type === "reasoning") ?? [];
43343
- const textContent = textParts.map((p) => p.text ?? "").filter(Boolean).join(`
43344
- `);
43345
- const duration3 = formatDuration2(startTime);
43346
- return `\u53D7\u76D1\u63A7\u4EFB\u52A1\u6210\u529F\u5B8C\u6210
43347
-
43348
- \u91CD\u8981\u63D0\u793A\uFF1A\u6B64\u6A21\u578B\uFF08${actualModel}\uFF09\u88AB\u6807\u8BB0\u4E3A\u4E0D\u7A33\u5B9A/\u5B9E\u9A8C\u6027\u3002
43349
- \u4F60\u7684 run_in_background=false \u5DF2\u81EA\u52A8\u8F6C\u6362\u4E3A\u540E\u53F0\u6A21\u5F0F\u4EE5\u8FDB\u884C\u53EF\u9760\u6027\u76D1\u63A7\u3002
43350
-
43351
- \u8017\u65F6\uFF1A${duration3}
43352
- Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}
43353
- Session ID: ${sessionID}
43354
-
43355
- \u76D1\u63A7\u8BF4\u660E\uFF1A
43356
- - \u4EFB\u52A1\u5DF2\u88AB\u76D1\u63A7\u5E76\u6210\u529F\u5B8C\u6210
43357
- - \u5982\u679C\u4F60\u53D1\u73B0\u6B64 agent \u5728\u540E\u7EED\u8C03\u7528\u4E2D\u884C\u4E3A\u5F02\u5E38\uFF0C\u8BF7\u4E3B\u52A8\u76D1\u63A7\u5176\u8FDB\u5EA6
43358
- - \u5982 agent \u4F3C\u4E4E\u5361\u4F4F\u6216\u4EA7\u751F\u5783\u573E\u8F93\u51FA\uFF0C\u4F7F\u7528 background_cancel(task_id="...") \u4E2D\u6B62
43359
- - \u770B\u5230\u6B64\u6D88\u606F\u65F6\u4E0D\u8981\u81EA\u52A8\u91CD\u8BD5 \u2014 \u4EFB\u52A1\u5DF2\u6210\u529F\u5B8C\u6210
43360
-
43361
- ---
43362
-
43363
- \u7ED3\u679C\uFF1A
43364
-
43365
- ${textContent || "(\u65E0\u6587\u672C\u8F93\u51FA)"}
43366
-
43367
- ---
43368
- \u7EE7\u7EED\u6B64 session\uFF1Asession_id="${sessionID}"`;
43369
- } catch (error45) {
43370
- return formatDetailedError(error45, {
43371
- operation: "\u542F\u52A8\u53D7\u76D1\u63A7\u7684\u540E\u53F0\u4EFB\u52A1",
43372
- args,
43373
- agent: agentToUse,
43374
- category: args.category
43375
- });
43376
- }
43377
- }
43490
+ categoryModel = parseModelString(resolved.model);
43491
+ categoryPromptAppend = resolved.promptAppend;
43492
+ modelInfo = {
43493
+ type: "category-default",
43494
+ model: resolved.model
43495
+ };
43378
43496
  } else {
43379
43497
  if (!args.subagent_type?.trim()) {
43380
43498
  return `Agent \u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\u3002`;
@@ -43612,7 +43730,7 @@ Session ID: ${sessionID}`;
43612
43730
  const textParts = lastMessage?.parts?.filter((p) => p.type === "text" || p.type === "reasoning") ?? [];
43613
43731
  const textContent = textParts.map((p) => p.text ?? "").filter(Boolean).join(`
43614
43732
  `);
43615
- const duration3 = formatDuration2(startTime);
43733
+ const duration3 = PerfTimer.formatDuration(startTime);
43616
43734
  if (toastManager) {
43617
43735
  toastManager.removeTask(taskId);
43618
43736
  }
@@ -43770,9 +43888,68 @@ class ConcurrencyManager {
43770
43888
  }
43771
43889
  }
43772
43890
 
43891
+ // src/features/background-agent/perf-aggregator.ts
43892
+ function percentile(sorted, p) {
43893
+ if (sorted.length === 0)
43894
+ return 0;
43895
+ const index = Math.ceil(p / 100 * sorted.length) - 1;
43896
+ return sorted[Math.max(0, Math.min(index, sorted.length - 1))];
43897
+ }
43898
+
43899
+ class PerformanceAggregator {
43900
+ tasks = [];
43901
+ recordTaskCompletion(task) {
43902
+ if (!task.progress?.phaseTiming)
43903
+ return;
43904
+ this.tasks.push({
43905
+ agent: task.agent,
43906
+ toolCalls: task.progress.phaseTiming.toolCallCount,
43907
+ phaseTiming: task.progress.phaseTiming
43908
+ });
43909
+ }
43910
+ getReport() {
43911
+ const byAgent = new Map;
43912
+ const queueWaits = [];
43913
+ let totalToolCalls = 0;
43914
+ for (const t of this.tasks) {
43915
+ const list = byAgent.get(t.agent) ?? [];
43916
+ list.push(t.phaseTiming.totalRunMs);
43917
+ byAgent.set(t.agent, list);
43918
+ queueWaits.push(t.phaseTiming.queueWaitMs);
43919
+ totalToolCalls += t.toolCalls;
43920
+ }
43921
+ const tasksByAgent = new Map;
43922
+ for (const [agent, durations] of byAgent) {
43923
+ const sorted = [...durations].sort((a, b) => a - b);
43924
+ const totalMs = durations.reduce((s, d) => s + d, 0);
43925
+ tasksByAgent.set(agent, {
43926
+ count: durations.length,
43927
+ avgMs: Math.round(totalMs / durations.length),
43928
+ p50Ms: Math.round(percentile(sorted, 50)),
43929
+ p95Ms: Math.round(percentile(sorted, 95)),
43930
+ totalMs
43931
+ });
43932
+ }
43933
+ const sortedQueue = [...queueWaits].sort((a, b) => a - b);
43934
+ const queueWaitStats = {
43935
+ avgMs: queueWaits.length > 0 ? Math.round(queueWaits.reduce((s, q) => s + q, 0) / queueWaits.length) : 0,
43936
+ p50Ms: Math.round(percentile(sortedQueue, 50)),
43937
+ p95Ms: Math.round(percentile(sortedQueue, 95)),
43938
+ maxMs: queueWaits.length > 0 ? Math.max(...queueWaits) : 0
43939
+ };
43940
+ return { totalTasks: this.tasks.length, tasksByAgent, totalToolCalls, queueWaitStats };
43941
+ }
43942
+ reset() {
43943
+ this.tasks = [];
43944
+ }
43945
+ get taskCount() {
43946
+ return this.tasks.length;
43947
+ }
43948
+ }
43949
+
43773
43950
  // src/features/background-agent/manager.ts
43774
- import { existsSync as existsSync46, readdirSync as readdirSync16 } from "fs";
43775
- import { join as join55 } from "path";
43951
+ import { existsSync as existsSync48, readdirSync as readdirSync17 } from "fs";
43952
+ import { join as join56 } from "path";
43776
43953
  var TASK_TTL_MS = 30 * 60 * 1000;
43777
43954
  var MIN_STABILITY_TIME_MS = 10 * 1000;
43778
43955
  var DEFAULT_STALE_TIMEOUT_MS = 180000;
@@ -43791,6 +43968,8 @@ class BackgroundManager {
43791
43968
  concurrencyManager;
43792
43969
  shutdownTriggered = false;
43793
43970
  config;
43971
+ perfAggregator = new PerformanceAggregator;
43972
+ perfTracer;
43794
43973
  queuesByKey = new Map;
43795
43974
  processingKeys = new Set;
43796
43975
  constructor(ctx, config3) {
@@ -43803,6 +43982,9 @@ class BackgroundManager {
43803
43982
  this.config = config3;
43804
43983
  this.registerProcessCleanup();
43805
43984
  }
43985
+ setPerfTracer(tracer) {
43986
+ this.perfTracer = tracer;
43987
+ }
43806
43988
  async launch(input) {
43807
43989
  log("[background-agent] launch() called with:", {
43808
43990
  agent: input.agent,
@@ -44096,6 +44278,9 @@ class BackgroundManager {
44096
44278
  existingTask.parentModel = input.parentModel;
44097
44279
  existingTask.parentAgent = input.parentAgent;
44098
44280
  existingTask.startedAt = new Date;
44281
+ if (existingTask.progress) {
44282
+ existingTask.progress.phaseTiming = undefined;
44283
+ }
44099
44284
  existingTask.progress = {
44100
44285
  toolCalls: existingTask.progress?.toolCalls ?? 0,
44101
44286
  lastUpdate: new Date
@@ -44397,6 +44582,7 @@ class BackgroundManager {
44397
44582
  log("[background-agent] Task already completed, skipping:", { taskId: task.id, status: task.status, source });
44398
44583
  return false;
44399
44584
  }
44585
+ const perfSnapshot = task.progress?.phaseTiming ? { ...task.progress.phaseTiming } : undefined;
44400
44586
  task.status = "completed";
44401
44587
  task.completedAt = new Date;
44402
44588
  if (task.concurrencyKey) {
@@ -44405,15 +44591,16 @@ class BackgroundManager {
44405
44591
  }
44406
44592
  this.markForNotification(task);
44407
44593
  try {
44408
- await this.notifyParentSession(task);
44594
+ await this.notifyParentSession(task, perfSnapshot);
44409
44595
  log(`[background-agent] Task completed via ${source}:`, task.id);
44410
44596
  } catch (err) {
44411
44597
  log("[background-agent] Error in notifyParentSession:", { taskId: task.id, error: err });
44412
44598
  }
44599
+ this.perfAggregator.recordTaskCompletion(task);
44413
44600
  return true;
44414
44601
  }
44415
- async notifyParentSession(task) {
44416
- const duration3 = this.formatDuration(task.startedAt ?? new Date, task.completedAt);
44602
+ async notifyParentSession(task, perfSnapshot) {
44603
+ const duration3 = PerfTimer.formatDuration(task.startedAt ?? new Date, task.completedAt);
44417
44604
  log("[background-agent] notifyParentSession called for task:", task.id);
44418
44605
  const toastManager = getTaskToastManager();
44419
44606
  if (toastManager) {
@@ -44435,6 +44622,16 @@ class BackgroundManager {
44435
44622
  const statusText = task.status === "completed" ? "COMPLETED" : "CANCELLED";
44436
44623
  const errorInfo = task.error ? `
44437
44624
  **Error:** ${task.error}` : "";
44625
+ const fallbackTaskLine = "- `" + task.id + "`: " + task.description;
44626
+ const perfSummary = (() => {
44627
+ if (!perfSnapshot)
44628
+ return "";
44629
+ const completed = Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.status !== "running" && t.status !== "pending");
44630
+ const ms = completed.reduce((s, t) => s + (t.progress?.phaseTiming?.totalRunMs ?? 0), 0);
44631
+ const avgSec = completed.length > 0 ? Math.round(ms / completed.length / 1000) : 0;
44632
+ const toolTotal = completed.reduce((s, t) => s + (t.progress?.phaseTiming?.toolCallCount ?? 0), 0);
44633
+ return "\u5E73\u5747\u8017\u65F6: " + avgSec + "s | \u603BTool: " + toolTotal;
44634
+ })();
44438
44635
  let notification;
44439
44636
  if (allComplete) {
44440
44637
  const completedTasks = Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.status !== "running" && t.status !== "pending").map((t) => `- \`${t.id}\`: ${t.description}`).join(`
@@ -44443,7 +44640,8 @@ class BackgroundManager {
44443
44640
  [\u6240\u6709\u540E\u53F0\u4EFB\u52A1\u5DF2\u5B8C\u6210]
44444
44641
 
44445
44642
  **\u5DF2\u5B8C\u6210\uFF1A**
44446
- ${completedTasks || `- \`${task.id}\`: ${task.description}`}
44643
+ ${completedTasks || fallbackTaskLine}
44644
+ ${perfSummary}
44447
44645
 
44448
44646
  \u4F7F\u7528 \`background_output(task_id="<id>")\` \u83B7\u53D6\u6BCF\u4E2A\u4EFB\u52A1\u7684\u7ED3\u679C\u3002
44449
44647
  </system-reminder>`;
@@ -44453,6 +44651,7 @@ ${completedTasks || `- \`${task.id}\`: ${task.description}`}
44453
44651
  **ID:** \`${task.id}\`
44454
44652
  **\u63CF\u8FF0\uFF1A** ${task.description}
44455
44653
  **\u8017\u65F6\uFF1A** ${duration3}${errorInfo}
44654
+ ${perfSnapshot ? `| \u6392\u961F ${PerfTimer.formatDuration(new Date(0), new Date(perfSnapshot.queueWaitMs))} | Tool ${perfSnapshot.toolCallCount} \u6B21` : ""}
44456
44655
 
44457
44656
  **\u8FD8\u6709 ${remainingCount} \u4E2A\u4EFB\u52A1\u6B63\u5728\u8FDB\u884C\u4E2D\u3002** \u6240\u6709\u4EFB\u52A1\u5B8C\u6210\u540E\u4F60\u4F1A\u6536\u5230\u901A\u77E5\u3002
44458
44657
  \u4E0D\u8981\u8F6E\u8BE2\u2014\u2014\u7EE7\u7EED\u6709\u6548\u7387\u7684\u5DE5\u4F5C\u3002
@@ -44511,18 +44710,6 @@ ${completedTasks || `- \`${task.id}\`: ${task.description}`}
44511
44710
  }
44512
44711
  }, 5 * 60 * 1000);
44513
44712
  }
44514
- formatDuration(start, end) {
44515
- const duration3 = (end ?? new Date).getTime() - start.getTime();
44516
- const seconds = Math.floor(duration3 / 1000);
44517
- const minutes = Math.floor(seconds / 60);
44518
- const hours = Math.floor(minutes / 60);
44519
- if (hours > 0) {
44520
- return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
44521
- } else if (minutes > 0) {
44522
- return `${minutes}m ${seconds % 60}s`;
44523
- }
44524
- return `${seconds}s`;
44525
- }
44526
44713
  hasRunningTasks() {
44527
44714
  for (const task of this.tasks.values()) {
44528
44715
  if (task.status === "running")
@@ -44614,110 +44801,133 @@ ${completedTasks || `- \`${task.id}\`: ${task.description}`}
44614
44801
  }
44615
44802
  }
44616
44803
  async pollRunningTasks() {
44617
- this.pruneStaleTasksAndNotifications();
44618
- await this.checkAndInterruptStaleTasks();
44619
- const statusResult = await this.client.session.status();
44620
- const allStatuses = statusResult.data ?? {};
44621
- for (const task of this.tasks.values()) {
44622
- if (task.status !== "running")
44623
- continue;
44624
- const sessionID = task.sessionID;
44625
- if (!sessionID)
44626
- continue;
44627
- try {
44628
- const sessionStatus = allStatuses[sessionID];
44629
- if (sessionStatus?.type === "idle") {
44630
- const hasValidOutput = await this.validateSessionHasOutput(sessionID);
44631
- if (!hasValidOutput) {
44632
- log("[background-agent] Polling idle but no valid output yet, waiting:", task.id);
44633
- continue;
44634
- }
44635
- if (task.status !== "running")
44636
- continue;
44637
- const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44638
- if (hasIncompleteTodos2) {
44639
- log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
44640
- continue;
44641
- }
44642
- await this.tryCompleteTask(task, "polling (idle status)");
44804
+ const start = this.perfTracer?.isEnabled() ? performance.now() : undefined;
44805
+ try {
44806
+ this.pruneStaleTasksAndNotifications();
44807
+ await this.checkAndInterruptStaleTasks();
44808
+ const statusResult = await this.client.session.status();
44809
+ const allStatuses = statusResult.data ?? {};
44810
+ for (const task of this.tasks.values()) {
44811
+ if (task.status !== "running")
44643
44812
  continue;
44644
- }
44645
- const messagesResult = await this.client.session.messages({
44646
- path: { id: sessionID }
44647
- });
44648
- if (!messagesResult.error && messagesResult.data) {
44649
- const messages = messagesResult.data;
44650
- const assistantMsgs = messages.filter((m) => m.info?.role === "assistant");
44651
- let toolCalls = 0;
44652
- let lastTool;
44653
- let lastMessage;
44654
- for (const msg of assistantMsgs) {
44655
- const parts = msg.parts ?? [];
44656
- for (const part of parts) {
44657
- if (part.type === "tool_use" || part.tool) {
44658
- toolCalls++;
44659
- lastTool = part.tool || part.name || "unknown";
44660
- }
44661
- if (part.type === "text" && part.text) {
44662
- lastMessage = part.text;
44663
- }
44813
+ const sessionID = task.sessionID;
44814
+ if (!sessionID)
44815
+ continue;
44816
+ try {
44817
+ const sessionStatus = allStatuses[sessionID];
44818
+ if (sessionStatus?.type === "idle") {
44819
+ const hasValidOutput = await this.validateSessionHasOutput(sessionID);
44820
+ if (!hasValidOutput) {
44821
+ log("[background-agent] Polling idle but no valid output yet, waiting:", task.id);
44822
+ continue;
44664
44823
  }
44665
- }
44666
- if (!task.progress) {
44667
- task.progress = { toolCalls: 0, lastUpdate: new Date };
44668
- }
44669
- task.progress.toolCalls = toolCalls;
44670
- task.progress.lastTool = lastTool;
44671
- task.progress.lastUpdate = new Date;
44672
- if (lastMessage) {
44673
- task.progress.lastMessage = lastMessage;
44674
- task.progress.lastMessageAt = new Date;
44675
- }
44676
- const currentMsgCount = messages.length;
44677
- const startedAt = task.startedAt;
44678
- if (!startedAt)
44824
+ if (task.status !== "running")
44825
+ continue;
44826
+ const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44827
+ if (hasIncompleteTodos2) {
44828
+ log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
44829
+ continue;
44830
+ }
44831
+ await this.tryCompleteTask(task, "polling (idle status)");
44679
44832
  continue;
44680
- const elapsedMs = Date.now() - startedAt.getTime();
44681
- if (elapsedMs >= MIN_STABILITY_TIME_MS) {
44682
- if (task.lastMsgCount === currentMsgCount) {
44683
- task.stablePolls = (task.stablePolls ?? 0) + 1;
44684
- if (task.stablePolls >= 3) {
44685
- const recheckStatus = await this.client.session.status();
44686
- const recheckData = recheckStatus.data ?? {};
44687
- const currentStatus = recheckData[sessionID];
44688
- if (currentStatus?.type !== "idle") {
44689
- log("[background-agent] Stability reached but session not idle, resetting:", {
44690
- taskId: task.id,
44691
- sessionStatus: currentStatus?.type ?? "not_in_status"
44692
- });
44693
- task.stablePolls = 0;
44694
- continue;
44833
+ }
44834
+ const messagesResult = await this.client.session.messages({
44835
+ path: { id: sessionID }
44836
+ });
44837
+ if (!messagesResult.error && messagesResult.data) {
44838
+ const messages = messagesResult.data;
44839
+ const assistantMsgs = messages.filter((m) => m.info?.role === "assistant");
44840
+ let toolCalls = 0;
44841
+ let lastTool;
44842
+ let lastMessage;
44843
+ for (const msg of assistantMsgs) {
44844
+ const parts = msg.parts ?? [];
44845
+ for (const part of parts) {
44846
+ if (part.type === "tool_use" || part.tool) {
44847
+ toolCalls++;
44848
+ lastTool = part.tool || part.name || "unknown";
44695
44849
  }
44696
- const hasValidOutput = await this.validateSessionHasOutput(sessionID);
44697
- if (!hasValidOutput) {
44698
- log("[background-agent] Stability reached but no valid output, waiting:", task.id);
44699
- continue;
44850
+ if (part.type === "text" && part.text) {
44851
+ lastMessage = part.text;
44700
44852
  }
44701
- if (task.status !== "running")
44702
- continue;
44703
- const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44704
- if (!hasIncompleteTodos2) {
44705
- await this.tryCompleteTask(task, "stability detection");
44706
- continue;
44853
+ }
44854
+ }
44855
+ if (!task.progress) {
44856
+ task.progress = { toolCalls: 0, lastUpdate: new Date };
44857
+ }
44858
+ if (task.startedAt && !task.progress.phaseTiming) {
44859
+ const now = Date.now();
44860
+ task.progress.phaseTiming = {
44861
+ queueWaitMs: task.queuedAt ? now - task.queuedAt.getTime() : 0,
44862
+ totalRunMs: now - task.startedAt.getTime(),
44863
+ toolCallCount: 0
44864
+ };
44865
+ }
44866
+ if (task.progress.phaseTiming && task.progress.phaseTiming.firstResponseMs === undefined && assistantMsgs.length > 0) {
44867
+ task.progress.phaseTiming.firstResponseMs = Date.now() - task.startedAt.getTime();
44868
+ }
44869
+ task.progress.toolCalls = toolCalls;
44870
+ task.progress.lastTool = lastTool;
44871
+ task.progress.lastUpdate = new Date;
44872
+ if (lastMessage) {
44873
+ task.progress.lastMessage = lastMessage;
44874
+ task.progress.lastMessageAt = new Date;
44875
+ }
44876
+ const currentMsgCount = messages.length;
44877
+ const startedAt = task.startedAt;
44878
+ if (!startedAt)
44879
+ continue;
44880
+ const elapsedMs = Date.now() - startedAt.getTime();
44881
+ if (elapsedMs >= MIN_STABILITY_TIME_MS) {
44882
+ if (task.lastMsgCount === currentMsgCount) {
44883
+ task.stablePolls = (task.stablePolls ?? 0) + 1;
44884
+ if (task.stablePolls >= 3) {
44885
+ const recheckStatus = await this.client.session.status();
44886
+ const recheckData = recheckStatus.data ?? {};
44887
+ const currentStatus = recheckData[sessionID];
44888
+ if (currentStatus?.type !== "idle") {
44889
+ log("[background-agent] Stability reached but session not idle, resetting:", {
44890
+ taskId: task.id,
44891
+ sessionStatus: currentStatus?.type ?? "not_in_status"
44892
+ });
44893
+ task.stablePolls = 0;
44894
+ continue;
44895
+ }
44896
+ const hasValidOutput = await this.validateSessionHasOutput(sessionID);
44897
+ if (!hasValidOutput) {
44898
+ log("[background-agent] Stability reached but no valid output, waiting:", task.id);
44899
+ continue;
44900
+ }
44901
+ if (task.status !== "running")
44902
+ continue;
44903
+ const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
44904
+ if (!hasIncompleteTodos2) {
44905
+ await this.tryCompleteTask(task, "stability detection");
44906
+ continue;
44907
+ }
44707
44908
  }
44909
+ } else {
44910
+ task.stablePolls = 0;
44708
44911
  }
44709
- } else {
44710
- task.stablePolls = 0;
44711
44912
  }
44913
+ task.lastMsgCount = currentMsgCount;
44712
44914
  }
44713
- task.lastMsgCount = currentMsgCount;
44915
+ } catch (error45) {
44916
+ log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
44714
44917
  }
44715
- } catch (error45) {
44716
- log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
44717
44918
  }
44718
- }
44719
- if (!this.hasRunningTasks()) {
44720
- this.stopPolling();
44919
+ if (!this.hasRunningTasks()) {
44920
+ this.stopPolling();
44921
+ if (this.perfAggregator.taskCount >= 2) {
44922
+ const report = this.perfAggregator.getReport();
44923
+ log("[perf] Session report:", report);
44924
+ }
44925
+ }
44926
+ } finally {
44927
+ if (start !== undefined) {
44928
+ const duration3 = performance.now() - start;
44929
+ this.perfTracer.recordPolling(duration3, this.getRunningTasks().length, new Set(...this.tasks.values().map((t) => t.parentSessionID).filter(Boolean)).size);
44930
+ }
44721
44931
  }
44722
44932
  }
44723
44933
  shutdown() {
@@ -44738,6 +44948,7 @@ ${completedTasks || `- \`${task.id}\`: ${task.description}`}
44738
44948
  this.pendingByParent.clear();
44739
44949
  this.queuesByKey.clear();
44740
44950
  this.processingKeys.clear();
44951
+ this.perfAggregator.reset();
44741
44952
  this.unregisterProcessCleanup();
44742
44953
  log("[background-agent] Shutdown complete");
44743
44954
  }
@@ -44753,14 +44964,14 @@ function registerProcessSignal(signal, handler, exitAfter) {
44753
44964
  return listener;
44754
44965
  }
44755
44966
  function getMessageDir10(sessionID) {
44756
- if (!existsSync46(MESSAGE_STORAGE))
44967
+ if (!existsSync48(MESSAGE_STORAGE))
44757
44968
  return null;
44758
- const directPath = join55(MESSAGE_STORAGE, sessionID);
44759
- if (existsSync46(directPath))
44969
+ const directPath = join56(MESSAGE_STORAGE, sessionID);
44970
+ if (existsSync48(directPath))
44760
44971
  return directPath;
44761
- for (const dir of readdirSync16(MESSAGE_STORAGE)) {
44762
- const sessionPath = join55(MESSAGE_STORAGE, dir, sessionID);
44763
- if (existsSync46(sessionPath))
44972
+ for (const dir of readdirSync17(MESSAGE_STORAGE)) {
44973
+ const sessionPath = join56(MESSAGE_STORAGE, dir, sessionID);
44974
+ if (existsSync48(sessionPath))
44764
44975
  return sessionPath;
44765
44976
  }
44766
44977
  return null;
@@ -62674,6 +62885,7 @@ var HookNameSchema = exports_external2.enum([
62674
62885
  "edit-error-recovery",
62675
62886
  "delegate-task-retry",
62676
62887
  "prometheus-md-only",
62888
+ "perf-profiler",
62677
62889
  "start-work",
62678
62890
  "atlas"
62679
62891
  ]);
@@ -62787,11 +62999,21 @@ var DynamicContextPruningConfigSchema = exports_external2.object({
62787
62999
  }).optional()
62788
63000
  }).optional()
62789
63001
  });
63002
+ var ProfilingConfigSchema = exports_external2.object({
63003
+ enabled: exports_external2.boolean().default(false),
63004
+ output_dir: exports_external2.string().optional(),
63005
+ slow_threshold_ms: exports_external2.number().default(100),
63006
+ memory_snapshot_interval: exports_external2.number().default(5),
63007
+ trace_api: exports_external2.boolean().default(true),
63008
+ trace_fileio: exports_external2.boolean().default(true),
63009
+ trace_polling: exports_external2.boolean().default(true)
63010
+ });
62790
63011
  var ExperimentalConfigSchema = exports_external2.object({
62791
63012
  aggressive_truncation: exports_external2.boolean().optional(),
62792
63013
  auto_resume: exports_external2.boolean().optional(),
62793
63014
  truncate_all_tool_outputs: exports_external2.boolean().optional(),
62794
- dynamic_context_pruning: DynamicContextPruningConfigSchema.optional()
63015
+ dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
63016
+ profiling: ProfilingConfigSchema.optional()
62795
63017
  });
62796
63018
  var SkillSourceSchema = exports_external2.union([
62797
63019
  exports_external2.string(),
@@ -65820,7 +66042,7 @@ init_file_utils();
65820
66042
  init_shared();
65821
66043
  init_logger();
65822
66044
  import { promises as fs11 } from "fs";
65823
- import { join as join57, basename as basename6 } from "path";
66045
+ import { join as join58, basename as basename6 } from "path";
65824
66046
  async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
65825
66047
  try {
65826
66048
  await fs11.access(commandsDir);
@@ -65850,7 +66072,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
65850
66072
  if (entry.isDirectory()) {
65851
66073
  if (entry.name.startsWith("."))
65852
66074
  continue;
65853
- const subDirPath = join57(commandsDir, entry.name);
66075
+ const subDirPath = join58(commandsDir, entry.name);
65854
66076
  const subPrefix = prefix ? `${prefix}:${entry.name}` : entry.name;
65855
66077
  const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
65856
66078
  commands2.push(...subCommands);
@@ -65858,7 +66080,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
65858
66080
  }
65859
66081
  if (!isMarkdownFile(entry))
65860
66082
  continue;
65861
- const commandPath = join57(commandsDir, entry.name);
66083
+ const commandPath = join58(commandsDir, entry.name);
65862
66084
  const baseCommandName = basename6(entry.name, ".md");
65863
66085
  const commandName = prefix ? `${prefix}:${baseCommandName}` : baseCommandName;
65864
66086
  try {
@@ -65905,23 +66127,23 @@ function commandsToRecord(commands2) {
65905
66127
  return result;
65906
66128
  }
65907
66129
  async function loadUserCommands() {
65908
- const userCommandsDir = join57(getClaudeConfigDir(), "commands");
66130
+ const userCommandsDir = join58(getClaudeConfigDir(), "commands");
65909
66131
  const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
65910
66132
  return commandsToRecord(commands2);
65911
66133
  }
65912
66134
  async function loadProjectCommands() {
65913
- const projectCommandsDir = join57(process.cwd(), ".claude", "commands");
66135
+ const projectCommandsDir = join58(process.cwd(), ".claude", "commands");
65914
66136
  const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
65915
66137
  return commandsToRecord(commands2);
65916
66138
  }
65917
66139
  async function loadOpencodeGlobalCommands() {
65918
66140
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
65919
- const opencodeCommandsDir = join57(configDir, "command");
66141
+ const opencodeCommandsDir = join58(configDir, "command");
65920
66142
  const commands2 = await loadCommandsFromDir(opencodeCommandsDir, "opencode");
65921
66143
  return commandsToRecord(commands2);
65922
66144
  }
65923
66145
  async function loadOpencodeProjectCommands() {
65924
- const opencodeProjectDir = join57(process.cwd(), ".opencode", "command");
66146
+ const opencodeProjectDir = join58(process.cwd(), ".opencode", "command");
65925
66147
  const commands2 = await loadCommandsFromDir(opencodeProjectDir, "opencode-project");
65926
66148
  return commandsToRecord(commands2);
65927
66149
  }
@@ -65929,8 +66151,8 @@ async function loadOpencodeProjectCommands() {
65929
66151
  init_frontmatter();
65930
66152
  init_file_utils();
65931
66153
  init_shared();
65932
- import { existsSync as existsSync48, readdirSync as readdirSync17, readFileSync as readFileSync30 } from "fs";
65933
- import { join as join58, basename as basename7 } from "path";
66154
+ import { existsSync as existsSync50, readdirSync as readdirSync18, readFileSync as readFileSync31 } from "fs";
66155
+ import { join as join59, basename as basename7 } from "path";
65934
66156
  function parseToolsConfig(toolsStr) {
65935
66157
  if (!toolsStr)
65936
66158
  return;
@@ -65944,18 +66166,18 @@ function parseToolsConfig(toolsStr) {
65944
66166
  return result;
65945
66167
  }
65946
66168
  function loadAgentsFromDir(agentsDir, scope) {
65947
- if (!existsSync48(agentsDir)) {
66169
+ if (!existsSync50(agentsDir)) {
65948
66170
  return [];
65949
66171
  }
65950
- const entries = readdirSync17(agentsDir, { withFileTypes: true });
66172
+ const entries = readdirSync18(agentsDir, { withFileTypes: true });
65951
66173
  const agents = [];
65952
66174
  for (const entry of entries) {
65953
66175
  if (!isMarkdownFile(entry))
65954
66176
  continue;
65955
- const agentPath = join58(agentsDir, entry.name);
66177
+ const agentPath = join59(agentsDir, entry.name);
65956
66178
  const agentName = basename7(entry.name, ".md");
65957
66179
  try {
65958
- const content = readFileSync30(agentPath, "utf-8");
66180
+ const content = readFileSync31(agentPath, "utf-8");
65959
66181
  const { data, body } = parseFrontmatter(content);
65960
66182
  const name = data.name || agentName;
65961
66183
  const originalDescription = data.description || "";
@@ -65982,7 +66204,7 @@ function loadAgentsFromDir(agentsDir, scope) {
65982
66204
  return agents;
65983
66205
  }
65984
66206
  function loadUserAgents() {
65985
- const userAgentsDir = join58(getClaudeConfigDir(), "agents");
66207
+ const userAgentsDir = join59(getClaudeConfigDir(), "agents");
65986
66208
  const agents = loadAgentsFromDir(userAgentsDir, "user");
65987
66209
  const result = {};
65988
66210
  for (const agent of agents) {
@@ -65991,7 +66213,7 @@ function loadUserAgents() {
65991
66213
  return result;
65992
66214
  }
65993
66215
  function loadProjectAgents() {
65994
- const projectAgentsDir = join58(process.cwd(), ".claude", "agents");
66216
+ const projectAgentsDir = join59(process.cwd(), ".claude", "agents");
65995
66217
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
65996
66218
  const result = {};
65997
66219
  for (const agent of agents) {
@@ -66003,18 +66225,18 @@ function loadProjectAgents() {
66003
66225
  init_frontmatter();
66004
66226
  init_file_utils();
66005
66227
  init_logger();
66006
- import { existsSync as existsSync49, readdirSync as readdirSync18, readFileSync as readFileSync31 } from "fs";
66228
+ import { existsSync as existsSync51, readdirSync as readdirSync19, readFileSync as readFileSync32 } from "fs";
66007
66229
  import { homedir as homedir13 } from "os";
66008
- import { join as join59, basename as basename8 } from "path";
66230
+ import { join as join60, basename as basename8 } from "path";
66009
66231
  var CLAUDE_PLUGIN_ROOT_VAR = "${CLAUDE_PLUGIN_ROOT}";
66010
66232
  function getPluginsBaseDir() {
66011
66233
  if (process.env.CLAUDE_PLUGINS_HOME) {
66012
66234
  return process.env.CLAUDE_PLUGINS_HOME;
66013
66235
  }
66014
- return join59(homedir13(), ".claude", "plugins");
66236
+ return join60(homedir13(), ".claude", "plugins");
66015
66237
  }
66016
66238
  function getInstalledPluginsPath() {
66017
- return join59(getPluginsBaseDir(), "installed_plugins.json");
66239
+ return join60(getPluginsBaseDir(), "installed_plugins.json");
66018
66240
  }
66019
66241
  function resolvePluginPath(path8, pluginRoot) {
66020
66242
  return path8.replace(CLAUDE_PLUGIN_ROOT_VAR, pluginRoot);
@@ -66039,11 +66261,11 @@ function resolvePluginPaths(obj, pluginRoot) {
66039
66261
  }
66040
66262
  function loadInstalledPlugins() {
66041
66263
  const dbPath = getInstalledPluginsPath();
66042
- if (!existsSync49(dbPath)) {
66264
+ if (!existsSync51(dbPath)) {
66043
66265
  return null;
66044
66266
  }
66045
66267
  try {
66046
- const content = readFileSync31(dbPath, "utf-8");
66268
+ const content = readFileSync32(dbPath, "utf-8");
66047
66269
  return JSON.parse(content);
66048
66270
  } catch (error92) {
66049
66271
  log("Failed to load installed plugins database", error92);
@@ -66054,15 +66276,15 @@ function getClaudeSettingsPath() {
66054
66276
  if (process.env.CLAUDE_SETTINGS_PATH) {
66055
66277
  return process.env.CLAUDE_SETTINGS_PATH;
66056
66278
  }
66057
- return join59(homedir13(), ".claude", "settings.json");
66279
+ return join60(homedir13(), ".claude", "settings.json");
66058
66280
  }
66059
66281
  function loadClaudeSettings() {
66060
66282
  const settingsPath = getClaudeSettingsPath();
66061
- if (!existsSync49(settingsPath)) {
66283
+ if (!existsSync51(settingsPath)) {
66062
66284
  return null;
66063
66285
  }
66064
66286
  try {
66065
- const content = readFileSync31(settingsPath, "utf-8");
66287
+ const content = readFileSync32(settingsPath, "utf-8");
66066
66288
  return JSON.parse(content);
66067
66289
  } catch (error92) {
66068
66290
  log("Failed to load Claude settings", error92);
@@ -66070,12 +66292,12 @@ function loadClaudeSettings() {
66070
66292
  }
66071
66293
  }
66072
66294
  function loadPluginManifest(installPath) {
66073
- const manifestPath = join59(installPath, ".claude-plugin", "plugin.json");
66074
- if (!existsSync49(manifestPath)) {
66295
+ const manifestPath = join60(installPath, ".claude-plugin", "plugin.json");
66296
+ if (!existsSync51(manifestPath)) {
66075
66297
  return null;
66076
66298
  }
66077
66299
  try {
66078
- const content = readFileSync31(manifestPath, "utf-8");
66300
+ const content = readFileSync32(manifestPath, "utf-8");
66079
66301
  return JSON.parse(content);
66080
66302
  } catch (error92) {
66081
66303
  log(`Failed to load plugin manifest from ${manifestPath}`, error92);
@@ -66122,7 +66344,7 @@ function discoverInstalledPlugins(options) {
66122
66344
  continue;
66123
66345
  }
66124
66346
  const { installPath, scope, version: version3 } = installation;
66125
- if (!existsSync49(installPath)) {
66347
+ if (!existsSync51(installPath)) {
66126
66348
  errors5.push({
66127
66349
  pluginKey,
66128
66350
  installPath,
@@ -66140,21 +66362,21 @@ function discoverInstalledPlugins(options) {
66140
66362
  pluginKey,
66141
66363
  manifest: manifest ?? undefined
66142
66364
  };
66143
- if (existsSync49(join59(installPath, "commands"))) {
66144
- loadedPlugin.commandsDir = join59(installPath, "commands");
66365
+ if (existsSync51(join60(installPath, "commands"))) {
66366
+ loadedPlugin.commandsDir = join60(installPath, "commands");
66145
66367
  }
66146
- if (existsSync49(join59(installPath, "agents"))) {
66147
- loadedPlugin.agentsDir = join59(installPath, "agents");
66368
+ if (existsSync51(join60(installPath, "agents"))) {
66369
+ loadedPlugin.agentsDir = join60(installPath, "agents");
66148
66370
  }
66149
- if (existsSync49(join59(installPath, "skills"))) {
66150
- loadedPlugin.skillsDir = join59(installPath, "skills");
66371
+ if (existsSync51(join60(installPath, "skills"))) {
66372
+ loadedPlugin.skillsDir = join60(installPath, "skills");
66151
66373
  }
66152
- const hooksPath = join59(installPath, "hooks", "hooks.json");
66153
- if (existsSync49(hooksPath)) {
66374
+ const hooksPath = join60(installPath, "hooks", "hooks.json");
66375
+ if (existsSync51(hooksPath)) {
66154
66376
  loadedPlugin.hooksPath = hooksPath;
66155
66377
  }
66156
- const mcpPath = join59(installPath, ".mcp.json");
66157
- if (existsSync49(mcpPath)) {
66378
+ const mcpPath = join60(installPath, ".mcp.json");
66379
+ if (existsSync51(mcpPath)) {
66158
66380
  loadedPlugin.mcpPath = mcpPath;
66159
66381
  }
66160
66382
  plugins.push(loadedPlugin);
@@ -66165,17 +66387,17 @@ function discoverInstalledPlugins(options) {
66165
66387
  function loadPluginCommands(plugins) {
66166
66388
  const commands2 = {};
66167
66389
  for (const plugin of plugins) {
66168
- if (!plugin.commandsDir || !existsSync49(plugin.commandsDir))
66390
+ if (!plugin.commandsDir || !existsSync51(plugin.commandsDir))
66169
66391
  continue;
66170
- const entries = readdirSync18(plugin.commandsDir, { withFileTypes: true });
66392
+ const entries = readdirSync19(plugin.commandsDir, { withFileTypes: true });
66171
66393
  for (const entry of entries) {
66172
66394
  if (!isMarkdownFile(entry))
66173
66395
  continue;
66174
- const commandPath = join59(plugin.commandsDir, entry.name);
66396
+ const commandPath = join60(plugin.commandsDir, entry.name);
66175
66397
  const commandName = basename8(entry.name, ".md");
66176
66398
  const namespacedName = `${plugin.name}:${commandName}`;
66177
66399
  try {
66178
- const content = readFileSync31(commandPath, "utf-8");
66400
+ const content = readFileSync32(commandPath, "utf-8");
66179
66401
  const { data, body } = parseFrontmatter(content);
66180
66402
  const wrappedTemplate = `<command-instruction>
66181
66403
  ${body.trim()}
@@ -66207,21 +66429,21 @@ $ARGUMENTS
66207
66429
  function loadPluginSkillsAsCommands(plugins) {
66208
66430
  const skills = {};
66209
66431
  for (const plugin of plugins) {
66210
- if (!plugin.skillsDir || !existsSync49(plugin.skillsDir))
66432
+ if (!plugin.skillsDir || !existsSync51(plugin.skillsDir))
66211
66433
  continue;
66212
- const entries = readdirSync18(plugin.skillsDir, { withFileTypes: true });
66434
+ const entries = readdirSync19(plugin.skillsDir, { withFileTypes: true });
66213
66435
  for (const entry of entries) {
66214
66436
  if (entry.name.startsWith("."))
66215
66437
  continue;
66216
- const skillPath = join59(plugin.skillsDir, entry.name);
66438
+ const skillPath = join60(plugin.skillsDir, entry.name);
66217
66439
  if (!entry.isDirectory() && !entry.isSymbolicLink())
66218
66440
  continue;
66219
66441
  const resolvedPath = resolveSymlink(skillPath);
66220
- const skillMdPath = join59(resolvedPath, "SKILL.md");
66221
- if (!existsSync49(skillMdPath))
66442
+ const skillMdPath = join60(resolvedPath, "SKILL.md");
66443
+ if (!existsSync51(skillMdPath))
66222
66444
  continue;
66223
66445
  try {
66224
- const content = readFileSync31(skillMdPath, "utf-8");
66446
+ const content = readFileSync32(skillMdPath, "utf-8");
66225
66447
  const { data, body } = parseFrontmatter(content);
66226
66448
  const skillName = data.name || entry.name;
66227
66449
  const namespacedName = `${plugin.name}:${skillName}`;
@@ -66268,17 +66490,17 @@ function parseToolsConfig2(toolsStr) {
66268
66490
  function loadPluginAgents(plugins) {
66269
66491
  const agents = {};
66270
66492
  for (const plugin of plugins) {
66271
- if (!plugin.agentsDir || !existsSync49(plugin.agentsDir))
66493
+ if (!plugin.agentsDir || !existsSync51(plugin.agentsDir))
66272
66494
  continue;
66273
- const entries = readdirSync18(plugin.agentsDir, { withFileTypes: true });
66495
+ const entries = readdirSync19(plugin.agentsDir, { withFileTypes: true });
66274
66496
  for (const entry of entries) {
66275
66497
  if (!isMarkdownFile(entry))
66276
66498
  continue;
66277
- const agentPath = join59(plugin.agentsDir, entry.name);
66499
+ const agentPath = join60(plugin.agentsDir, entry.name);
66278
66500
  const agentName = basename8(entry.name, ".md");
66279
66501
  const namespacedName = `${plugin.name}:${agentName}`;
66280
66502
  try {
66281
- const content = readFileSync31(agentPath, "utf-8");
66503
+ const content = readFileSync32(agentPath, "utf-8");
66282
66504
  const { data, body } = parseFrontmatter(content);
66283
66505
  const name = data.name || agentName;
66284
66506
  const originalDescription = data.description || "";
@@ -66304,7 +66526,7 @@ function loadPluginAgents(plugins) {
66304
66526
  async function loadPluginMcpServers(plugins) {
66305
66527
  const servers = {};
66306
66528
  for (const plugin of plugins) {
66307
- if (!plugin.mcpPath || !existsSync49(plugin.mcpPath))
66529
+ if (!plugin.mcpPath || !existsSync51(plugin.mcpPath))
66308
66530
  continue;
66309
66531
  try {
66310
66532
  const content = await Bun.file(plugin.mcpPath).text();
@@ -66336,10 +66558,10 @@ async function loadPluginMcpServers(plugins) {
66336
66558
  function loadPluginHooksConfigs(plugins) {
66337
66559
  const configs = [];
66338
66560
  for (const plugin of plugins) {
66339
- if (!plugin.hooksPath || !existsSync49(plugin.hooksPath))
66561
+ if (!plugin.hooksPath || !existsSync51(plugin.hooksPath))
66340
66562
  continue;
66341
66563
  try {
66342
- const content = readFileSync31(plugin.hooksPath, "utf-8");
66564
+ const content = readFileSync32(plugin.hooksPath, "utf-8");
66343
66565
  let config4 = JSON.parse(content);
66344
66566
  config4 = resolvePluginPaths(config4, plugin.installPath);
66345
66567
  configs.push(config4);
@@ -67865,6 +68087,44 @@ function createConfigHandler(deps) {
67865
68087
  };
67866
68088
  };
67867
68089
  }
68090
+ // src/index.ts
68091
+ init_perf_tracer();
68092
+ init_fileio_monitor();
68093
+
68094
+ // src/tools/perf-profiler/client-patch.ts
68095
+ function patchSessionClient(client2, tracer) {
68096
+ if (!tracer.isEnabled())
68097
+ return;
68098
+ const session = client2.session;
68099
+ if (!session || typeof session !== "object")
68100
+ return;
68101
+ function wrap(methodName, extractMessageCount) {
68102
+ const original = session[methodName];
68103
+ if (typeof original !== "function")
68104
+ return;
68105
+ session[methodName] = async function(opts) {
68106
+ const start = performance.now();
68107
+ let error92;
68108
+ try {
68109
+ const result = await original.call(session, opts);
68110
+ const durationMs = performance.now() - start;
68111
+ tracer.recordApiCall(methodName, durationMs, opts?.path?.id ?? "", extractMessageCount ? extractMessageCount(result) : undefined);
68112
+ return result;
68113
+ } catch (err) {
68114
+ const durationMs = performance.now() - start;
68115
+ error92 = err instanceof Error ? err.message : String(err);
68116
+ tracer.recordApiCall(methodName, durationMs, opts?.path?.id ?? "", undefined, error92);
68117
+ throw err;
68118
+ }
68119
+ };
68120
+ }
68121
+ wrap("messages", (r) => r?.data?.length ?? undefined);
68122
+ wrap("prompt", (r) => r?.data ? 1 : undefined);
68123
+ wrap("todo", (r) => r?.data?.length ?? undefined);
68124
+ wrap("status", (r) => r?.data ? Object.keys(r.data).length : undefined);
68125
+ wrap("summarize");
68126
+ }
68127
+
67868
68128
  // src/index.ts
67869
68129
  var OhMyOpenCodePlugin = async (ctx) => {
67870
68130
  log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { directory: ctx.directory });
@@ -67930,6 +68190,34 @@ var OhMyOpenCodePlugin = async (ctx) => {
67930
68190
  const taskResumeInfo = createTaskResumeInfoHook();
67931
68191
  const backgroundManager = new BackgroundManager(ctx, pluginConfig.background_task);
67932
68192
  const atlasHook = isHookEnabled("atlas") ? createAtlasHook(ctx, { directory: ctx.directory, backgroundManager }) : null;
68193
+ const perfTracer = pluginConfig.experimental?.profiling?.enabled ? new PerfTracer({
68194
+ enabled: true,
68195
+ outputDir: pluginConfig.experimental.profiling.output_dir,
68196
+ slowThreshold: pluginConfig.experimental.profiling.slow_threshold_ms,
68197
+ memorySnapshotInterval: pluginConfig.experimental.profiling.memory_snapshot_interval
68198
+ }) : new PerfTracer({ enabled: false });
68199
+ const memoryProbes = {};
68200
+ if (perfTracer.isEnabled()) {
68201
+ memoryProbes.subagentSessions = () => subagentSessions.size;
68202
+ memoryProbes.backgroundRunningTasks = () => backgroundManager.getRunningTasks().length;
68203
+ memoryProbes.backgroundCompletedTasks = () => backgroundManager.getCompletedTasks().length;
68204
+ }
68205
+ const perfProfiler = isHookEnabled("perf-profiler") ? createPerfProfilerHook({
68206
+ config: pluginConfig.experimental?.profiling ?? { enabled: false, slow_threshold_ms: 100, memory_snapshot_interval: 5, trace_api: true, trace_fileio: true, trace_polling: true },
68207
+ tracer: perfTracer,
68208
+ memoryProbes
68209
+ }) : null;
68210
+ if (perfTracer.isEnabled()) {
68211
+ try {
68212
+ patchSessionClient(ctx.client, perfTracer);
68213
+ } catch {}
68214
+ try {
68215
+ setFileIOMonitor(createFileIOMonitor(perfTracer));
68216
+ } catch {}
68217
+ try {
68218
+ backgroundManager.setPerfTracer(perfTracer);
68219
+ } catch {}
68220
+ }
67933
68221
  initTaskToastManager(ctx.client);
67934
68222
  const todoContinuationEnforcer = isHookEnabled("todo-continuation-enforcer") ? createTodoContinuationEnforcer(ctx, { backgroundManager }) : null;
67935
68223
  if (sessionRecovery && todoContinuationEnforcer) {
@@ -67994,6 +68282,27 @@ var OhMyOpenCodePlugin = async (ctx) => {
67994
68282
  pluginConfig,
67995
68283
  modelCacheState
67996
68284
  });
68285
+ async function wrapWithTiming(tracer, pipeline2, hookName, fn, sessionID, tool3) {
68286
+ const start = performance.now();
68287
+ let error92;
68288
+ try {
68289
+ await fn();
68290
+ } catch (e) {
68291
+ error92 = String(e);
68292
+ throw e;
68293
+ } finally {
68294
+ tracer.recordHook(pipeline2, hookName, performance.now() - start, sessionID ?? "", tool3, error92);
68295
+ }
68296
+ }
68297
+ function getEventSessionID(input) {
68298
+ const props = input.event.properties;
68299
+ if (!props)
68300
+ return "";
68301
+ const info = props.info;
68302
+ if (input.event.type === "session.deleted" || input.event.type === "session.created")
68303
+ return info?.id ?? "";
68304
+ return props.sessionID ?? "";
68305
+ }
67997
68306
  return {
67998
68307
  tool: {
67999
68308
  ...builtinTools,
@@ -68020,10 +68329,17 @@ var OhMyOpenCodePlugin = async (ctx) => {
68020
68329
  } else {
68021
68330
  applyAgentVariant(pluginConfig, input.agent, message);
68022
68331
  }
68023
- await keywordDetector?.["chat.message"]?.(input, output);
68024
- await claudeCodeHooks["chat.message"]?.(input, output);
68025
- await autoSlashCommand?.["chat.message"]?.(input, output);
68026
- await startWork?.["chat.message"]?.(input, output);
68332
+ const pipelineStart = performance.now();
68333
+ let hookCount = 0;
68334
+ await wrapWithTiming(perfTracer, "chat.message", "keywordDetector", () => keywordDetector?.["chat.message"]?.(input, output), input.sessionID);
68335
+ hookCount++;
68336
+ await wrapWithTiming(perfTracer, "chat.message", "claudeCodeHooks", () => claudeCodeHooks["chat.message"]?.(input, output), input.sessionID);
68337
+ hookCount++;
68338
+ await wrapWithTiming(perfTracer, "chat.message", "autoSlashCommand", () => autoSlashCommand?.["chat.message"]?.(input, output), input.sessionID);
68339
+ hookCount++;
68340
+ await wrapWithTiming(perfTracer, "chat.message", "startWork", () => startWork?.["chat.message"]?.(input, output), input.sessionID);
68341
+ hookCount++;
68342
+ perfTracer.recordPipeline("chat.message", performance.now() - pipelineStart, hookCount, input.sessionID);
68027
68343
  if (ralphLoop) {
68028
68344
  const parts = output.parts;
68029
68345
  const promptText = parts?.filter((p) => p.type === "text" && p.text).map((p) => p.text).join(`
@@ -68053,27 +68369,49 @@ var OhMyOpenCodePlugin = async (ctx) => {
68053
68369
  }
68054
68370
  }
68055
68371
  },
68372
+ "chat.params": async (input, output) => {
68373
+ await thinkMode?.["chat.params"]?.(input, output);
68374
+ },
68056
68375
  "experimental.chat.messages.transform": async (input, output) => {
68057
68376
  await contextInjectorMessagesTransform?.["experimental.chat.messages.transform"]?.(input, output);
68058
68377
  await thinkingBlockValidator?.["experimental.chat.messages.transform"]?.(input, output);
68059
68378
  },
68060
68379
  config: configHandler,
68061
68380
  event: async (input) => {
68062
- await autoUpdateChecker?.event(input);
68063
- await claudeCodeHooks.event(input);
68064
- await backgroundNotificationHook?.event(input);
68065
- await sessionNotification?.(input);
68066
- await todoContinuationEnforcer?.handler(input);
68067
- await contextWindowMonitor?.event(input);
68068
- await directoryAgentsInjector?.event(input);
68069
- await directoryReadmeInjector?.event(input);
68070
- await rulesInjector?.event(input);
68071
- await thinkMode?.event(input);
68072
- await anthropicContextWindowLimitRecovery?.event(input);
68073
- await agentUsageReminder?.event(input);
68074
- await interactiveBashSession?.event(input);
68075
- await ralphLoop?.event(input);
68076
- await atlasHook?.handler(input);
68381
+ const pipelineStart = performance.now();
68382
+ let hookCount = 0;
68383
+ await perfProfiler?.event?.(input);
68384
+ const evtSessionID = getEventSessionID(input);
68385
+ await wrapWithTiming(perfTracer, "event", "autoUpdateChecker", () => autoUpdateChecker?.event(input), evtSessionID);
68386
+ hookCount++;
68387
+ await wrapWithTiming(perfTracer, "event", "claudeCodeHooks", () => claudeCodeHooks.event(input), evtSessionID);
68388
+ hookCount++;
68389
+ await wrapWithTiming(perfTracer, "event", "backgroundNotificationHook", () => backgroundNotificationHook?.event(input), evtSessionID);
68390
+ hookCount++;
68391
+ await wrapWithTiming(perfTracer, "event", "sessionNotification", () => sessionNotification?.(input), evtSessionID);
68392
+ hookCount++;
68393
+ await wrapWithTiming(perfTracer, "event", "todoContinuationEnforcer", () => todoContinuationEnforcer?.handler(input), evtSessionID);
68394
+ hookCount++;
68395
+ await wrapWithTiming(perfTracer, "event", "contextWindowMonitor", () => contextWindowMonitor?.event(input), evtSessionID);
68396
+ hookCount++;
68397
+ await wrapWithTiming(perfTracer, "event", "directoryAgentsInjector", () => directoryAgentsInjector?.event(input), evtSessionID);
68398
+ hookCount++;
68399
+ await wrapWithTiming(perfTracer, "event", "directoryReadmeInjector", () => directoryReadmeInjector?.event(input), evtSessionID);
68400
+ hookCount++;
68401
+ await wrapWithTiming(perfTracer, "event", "rulesInjector", () => rulesInjector?.event(input), evtSessionID);
68402
+ hookCount++;
68403
+ await wrapWithTiming(perfTracer, "event", "thinkMode", () => thinkMode?.event(input), evtSessionID);
68404
+ hookCount++;
68405
+ await wrapWithTiming(perfTracer, "event", "anthropicContextWindowLimitRecovery", () => anthropicContextWindowLimitRecovery?.event(input), evtSessionID);
68406
+ hookCount++;
68407
+ await wrapWithTiming(perfTracer, "event", "agentUsageReminder", () => agentUsageReminder?.event(input), evtSessionID);
68408
+ hookCount++;
68409
+ await wrapWithTiming(perfTracer, "event", "interactiveBashSession", () => interactiveBashSession?.event(input), evtSessionID);
68410
+ hookCount++;
68411
+ await wrapWithTiming(perfTracer, "event", "ralphLoop", () => ralphLoop?.event(input), evtSessionID);
68412
+ hookCount++;
68413
+ await wrapWithTiming(perfTracer, "event", "atlasHook", () => atlasHook?.handler(input), evtSessionID);
68414
+ hookCount++;
68077
68415
  const { event } = input;
68078
68416
  const props = event.properties;
68079
68417
  if (event.type === "session.created") {
@@ -68126,17 +68464,30 @@ var OhMyOpenCodePlugin = async (ctx) => {
68126
68464
  }
68127
68465
  }
68128
68466
  }
68467
+ perfTracer.recordPipeline("event", performance.now() - pipelineStart, hookCount, evtSessionID);
68468
+ perfTracer.flush();
68129
68469
  },
68130
68470
  "tool.execute.before": async (input, output) => {
68131
- await questionLabelTruncator["tool.execute.before"]?.(input, output);
68132
- await claudeCodeHooks["tool.execute.before"](input, output);
68133
- await nonInteractiveEnv?.["tool.execute.before"](input, output);
68134
- await commentChecker?.["tool.execute.before"](input, output);
68135
- await directoryAgentsInjector?.["tool.execute.before"]?.(input, output);
68136
- await directoryReadmeInjector?.["tool.execute.before"]?.(input, output);
68137
- await rulesInjector?.["tool.execute.before"]?.(input, output);
68138
- await prometheusMdOnly?.["tool.execute.before"]?.(input, output);
68139
- await atlasHook?.["tool.execute.before"]?.(input, output);
68471
+ const pipelineStart = performance.now();
68472
+ let hookCount = 0;
68473
+ await wrapWithTiming(perfTracer, "tool.execute.before", "questionLabelTruncator", () => questionLabelTruncator["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68474
+ hookCount++;
68475
+ await wrapWithTiming(perfTracer, "tool.execute.before", "claudeCodeHooks", () => claudeCodeHooks["tool.execute.before"](input, output), input.sessionID, input.tool);
68476
+ hookCount++;
68477
+ await wrapWithTiming(perfTracer, "tool.execute.before", "nonInteractiveEnv", () => nonInteractiveEnv?.["tool.execute.before"](input, output), input.sessionID, input.tool);
68478
+ hookCount++;
68479
+ await wrapWithTiming(perfTracer, "tool.execute.before", "commentChecker", () => commentChecker?.["tool.execute.before"](input, output), input.sessionID, input.tool);
68480
+ hookCount++;
68481
+ await wrapWithTiming(perfTracer, "tool.execute.before", "directoryAgentsInjector", () => directoryAgentsInjector?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68482
+ hookCount++;
68483
+ await wrapWithTiming(perfTracer, "tool.execute.before", "directoryReadmeInjector", () => directoryReadmeInjector?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68484
+ hookCount++;
68485
+ await wrapWithTiming(perfTracer, "tool.execute.before", "rulesInjector", () => rulesInjector?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68486
+ hookCount++;
68487
+ await wrapWithTiming(perfTracer, "tool.execute.before", "prometheusMdOnly", () => prometheusMdOnly?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68488
+ hookCount++;
68489
+ await wrapWithTiming(perfTracer, "tool.execute.before", "atlasHook", () => atlasHook?.["tool.execute.before"]?.(input, output), input.sessionID, input.tool);
68490
+ hookCount++;
68140
68491
  if (input.tool === "task") {
68141
68492
  const args = output.args;
68142
68493
  const subagentType = args.subagent_type;
@@ -68176,22 +68527,40 @@ var OhMyOpenCodePlugin = async (ctx) => {
68176
68527
  });
68177
68528
  }
68178
68529
  }
68530
+ perfTracer.recordPipeline("tool.execute.before", performance.now() - pipelineStart, hookCount, input.sessionID);
68179
68531
  },
68180
68532
  "tool.execute.after": async (input, output) => {
68181
- await claudeCodeHooks["tool.execute.after"](input, output);
68182
- await toolOutputTruncator?.["tool.execute.after"](input, output);
68183
- await contextWindowMonitor?.["tool.execute.after"](input, output);
68184
- await commentChecker?.["tool.execute.after"](input, output);
68185
- await directoryAgentsInjector?.["tool.execute.after"](input, output);
68186
- await directoryReadmeInjector?.["tool.execute.after"](input, output);
68187
- await rulesInjector?.["tool.execute.after"](input, output);
68188
- await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
68189
- await agentUsageReminder?.["tool.execute.after"](input, output);
68190
- await interactiveBashSession?.["tool.execute.after"](input, output);
68191
- await editErrorRecovery?.["tool.execute.after"](input, output);
68192
- await delegateTaskRetry?.["tool.execute.after"](input, output);
68193
- await atlasHook?.["tool.execute.after"]?.(input, output);
68194
- await taskResumeInfo["tool.execute.after"](input, output);
68533
+ const pipelineStart = performance.now();
68534
+ let hookCount = 0;
68535
+ await wrapWithTiming(perfTracer, "tool.execute.after", "claudeCodeHooks", () => claudeCodeHooks["tool.execute.after"](input, output), input.sessionID, input.tool);
68536
+ hookCount++;
68537
+ await wrapWithTiming(perfTracer, "tool.execute.after", "toolOutputTruncator", () => toolOutputTruncator?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68538
+ hookCount++;
68539
+ await wrapWithTiming(perfTracer, "tool.execute.after", "contextWindowMonitor", () => contextWindowMonitor?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68540
+ hookCount++;
68541
+ await wrapWithTiming(perfTracer, "tool.execute.after", "commentChecker", () => commentChecker?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68542
+ hookCount++;
68543
+ await wrapWithTiming(perfTracer, "tool.execute.after", "directoryAgentsInjector", () => directoryAgentsInjector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68544
+ hookCount++;
68545
+ await wrapWithTiming(perfTracer, "tool.execute.after", "directoryReadmeInjector", () => directoryReadmeInjector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68546
+ hookCount++;
68547
+ await wrapWithTiming(perfTracer, "tool.execute.after", "rulesInjector", () => rulesInjector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68548
+ hookCount++;
68549
+ await wrapWithTiming(perfTracer, "tool.execute.after", "emptyTaskResponseDetector", () => emptyTaskResponseDetector?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68550
+ hookCount++;
68551
+ await wrapWithTiming(perfTracer, "tool.execute.after", "agentUsageReminder", () => agentUsageReminder?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68552
+ hookCount++;
68553
+ await wrapWithTiming(perfTracer, "tool.execute.after", "interactiveBashSession", () => interactiveBashSession?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68554
+ hookCount++;
68555
+ await wrapWithTiming(perfTracer, "tool.execute.after", "editErrorRecovery", () => editErrorRecovery?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68556
+ hookCount++;
68557
+ await wrapWithTiming(perfTracer, "tool.execute.after", "delegateTaskRetry", () => delegateTaskRetry?.["tool.execute.after"](input, output), input.sessionID, input.tool);
68558
+ hookCount++;
68559
+ await wrapWithTiming(perfTracer, "tool.execute.after", "atlasHook", () => atlasHook?.["tool.execute.after"]?.(input, output), input.sessionID, input.tool);
68560
+ hookCount++;
68561
+ await wrapWithTiming(perfTracer, "tool.execute.after", "taskResumeInfo", () => taskResumeInfo["tool.execute.after"](input, output), input.sessionID, input.tool);
68562
+ hookCount++;
68563
+ perfTracer.recordPipeline("tool.execute.after", performance.now() - pipelineStart, hookCount, input.sessionID);
68195
68564
  }
68196
68565
  };
68197
68566
  };