@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/bin/oh-my-opencode.js +39 -32
- package/dist/cli/index.js +68 -2
- package/dist/config/schema.d.ts +30 -0
- package/dist/features/background-agent/index.d.ts +1 -0
- package/dist/features/background-agent/manager.d.ts +4 -1
- package/dist/features/background-agent/perf-aggregator.d.ts +26 -0
- package/dist/features/background-agent/types.d.ts +15 -0
- package/dist/features/hook-message-injector/injector.d.ts +0 -6
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/perf-profiler/index.d.ts +2 -0
- package/dist/hooks/perf-profiler/index.test.d.ts +1 -0
- package/dist/hooks/perf-profiler/types.d.ts +42 -0
- package/dist/hooks/think-mode/index.d.ts +26 -2
- package/dist/hooks/think-mode/types.d.ts +14 -12
- package/dist/index.js +1391 -1022
- package/dist/shared/fileio-monitor.d.ts +10 -0
- package/dist/shared/fileio-monitor.test.d.ts +1 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/perf-timer.d.ts +26 -0
- package/dist/shared/perf-timer.test.d.ts +1 -0
- package/dist/shared/perf-tracer.d.ts +73 -0
- package/dist/shared/perf-tracer.test.d.ts +1 -0
- package/dist/tools/perf-profiler/client-patch.d.ts +2 -0
- package/package.json +1 -1
- package/postinstall.mjs +20 -0
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
|
|
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 &&
|
|
2854
|
+
if (customPath && existsSync5(customPath)) {
|
|
2777
2855
|
return customPath;
|
|
2778
2856
|
}
|
|
2779
2857
|
for (const path3 of defaultPaths) {
|
|
2780
|
-
if (
|
|
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,
|
|
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,
|
|
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:
|
|
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
|
|
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,
|
|
3009
|
+
function resolveFilePath(filePath, cwd2) {
|
|
2932
3010
|
if (isAbsolute(filePath)) {
|
|
2933
3011
|
return filePath;
|
|
2934
3012
|
}
|
|
2935
|
-
return join8(
|
|
3013
|
+
return join8(cwd2, filePath);
|
|
2936
3014
|
}
|
|
2937
3015
|
function readFileContent(resolvedPath) {
|
|
2938
|
-
if (!
|
|
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 =
|
|
3023
|
+
const content = readFileSync4(resolvedPath, "utf-8");
|
|
2946
3024
|
return content;
|
|
2947
3025
|
}
|
|
2948
|
-
async function resolveFileReferencesInText(text,
|
|
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,
|
|
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,
|
|
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
|
|
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 (
|
|
4250
|
+
if (existsSync7(jsoncPath)) {
|
|
4173
4251
|
return { format: "jsonc", path: jsoncPath };
|
|
4174
4252
|
}
|
|
4175
|
-
if (
|
|
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
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
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 (!
|
|
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 =
|
|
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
|
|
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,
|
|
11157
|
+
function resolveComponent(base, relative6, options, skipNormalization) {
|
|
10953
11158
|
const target = {};
|
|
10954
11159
|
if (!skipNormalization) {
|
|
10955
11160
|
base = parse11(serialize(base, options), options);
|
|
10956
|
-
|
|
11161
|
+
relative6 = parse11(serialize(relative6, options), options);
|
|
10957
11162
|
}
|
|
10958
11163
|
options = options || {};
|
|
10959
|
-
if (!options.tolerant &&
|
|
10960
|
-
target.scheme =
|
|
10961
|
-
target.userinfo =
|
|
10962
|
-
target.host =
|
|
10963
|
-
target.port =
|
|
10964
|
-
target.path = removeDotSegments(
|
|
10965
|
-
target.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 (
|
|
10968
|
-
target.userinfo =
|
|
10969
|
-
target.host =
|
|
10970
|
-
target.port =
|
|
10971
|
-
target.path = removeDotSegments(
|
|
10972
|
-
target.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 (!
|
|
11179
|
+
if (!relative6.path) {
|
|
10975
11180
|
target.path = base.path;
|
|
10976
|
-
if (
|
|
10977
|
-
target.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 (
|
|
10983
|
-
target.path = removeDotSegments(
|
|
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 = "/" +
|
|
11191
|
+
target.path = "/" + relative6.path;
|
|
10987
11192
|
} else if (!base.path) {
|
|
10988
|
-
target.path =
|
|
11193
|
+
target.path = relative6.path;
|
|
10989
11194
|
} else {
|
|
10990
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
14532
|
-
|
|
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 (
|
|
14747
|
+
if (_exists(directPath)) {
|
|
14536
14748
|
return directPath;
|
|
14537
14749
|
}
|
|
14538
|
-
for (const dir of
|
|
14750
|
+
for (const dir of _readdir(MESSAGE_STORAGE)) {
|
|
14539
14751
|
const sessionPath = join3(MESSAGE_STORAGE, dir, sessionID);
|
|
14540
|
-
if (
|
|
14752
|
+
if (_exists(sessionPath)) {
|
|
14541
14753
|
return sessionPath;
|
|
14542
14754
|
}
|
|
14543
14755
|
}
|
|
14544
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14812
|
+
const _exists = (p) => monitor?.existsSync(p) ?? existsSync2(p);
|
|
14813
|
+
if (!_exists(partDir)) {
|
|
14596
14814
|
mkdirSync(partDir, { recursive: true });
|
|
14597
14815
|
}
|
|
14598
|
-
|
|
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 (!
|
|
14842
|
+
if (!existsSync3(MESSAGE_STORAGE))
|
|
14621
14843
|
return null;
|
|
14622
14844
|
const directPath = join5(MESSAGE_STORAGE, sessionID);
|
|
14623
|
-
if (
|
|
14845
|
+
if (existsSync3(directPath))
|
|
14624
14846
|
return directPath;
|
|
14625
|
-
for (const dir of
|
|
14847
|
+
for (const dir of readdirSync3(MESSAGE_STORAGE)) {
|
|
14626
14848
|
const sessionPath = join5(MESSAGE_STORAGE, dir, sessionID);
|
|
14627
|
-
if (
|
|
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
|
|
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 (!
|
|
15648
|
+
if (!existsSync4(MESSAGE_STORAGE2))
|
|
15427
15649
|
return "";
|
|
15428
15650
|
const directPath = join7(MESSAGE_STORAGE2, sessionID);
|
|
15429
|
-
if (
|
|
15651
|
+
if (existsSync4(directPath)) {
|
|
15430
15652
|
return directPath;
|
|
15431
15653
|
}
|
|
15432
|
-
for (const dir of
|
|
15654
|
+
for (const dir of readdirSync4(MESSAGE_STORAGE2)) {
|
|
15433
15655
|
const sessionPath = join7(MESSAGE_STORAGE2, dir, sessionID);
|
|
15434
|
-
if (
|
|
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 || !
|
|
15664
|
+
if (!messageDir || !existsSync4(messageDir))
|
|
15443
15665
|
return [];
|
|
15444
15666
|
const messages = [];
|
|
15445
|
-
for (const file of
|
|
15667
|
+
for (const file of readdirSync4(messageDir)) {
|
|
15446
15668
|
if (!file.endsWith(".json"))
|
|
15447
15669
|
continue;
|
|
15448
15670
|
try {
|
|
15449
|
-
const content =
|
|
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 (!
|
|
15687
|
+
if (!existsSync4(partDir))
|
|
15466
15688
|
return [];
|
|
15467
15689
|
const parts = [];
|
|
15468
|
-
for (const file of
|
|
15690
|
+
for (const file of readdirSync4(partDir)) {
|
|
15469
15691
|
if (!file.endsWith(".json"))
|
|
15470
15692
|
continue;
|
|
15471
15693
|
try {
|
|
15472
|
-
const content =
|
|
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 (!
|
|
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
|
-
|
|
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 (!
|
|
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 || "[
|
|
15844
|
+
thinking: previousThinking || "[\u63A5\u7EED\u4E4B\u524D\u7684\u63A8\u7406]",
|
|
15623
15845
|
synthetic: true
|
|
15624
15846
|
};
|
|
15625
15847
|
try {
|
|
15626
|
-
|
|
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 (!
|
|
15856
|
+
if (!existsSync4(partDir))
|
|
15635
15857
|
return false;
|
|
15636
15858
|
let anyRemoved = false;
|
|
15637
|
-
for (const file of
|
|
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 =
|
|
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 (!
|
|
15878
|
+
if (!existsSync4(partDir))
|
|
15657
15879
|
return false;
|
|
15658
15880
|
let anyReplaced = false;
|
|
15659
|
-
for (const file of
|
|
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 =
|
|
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
|
-
|
|
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
|
|
15941
|
-
import { existsSync as
|
|
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
|
|
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
|
|
15949
|
-
import { join as
|
|
15950
|
-
import { homedir as homedir7, tmpdir as
|
|
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 =
|
|
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
|
-
|
|
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 ||
|
|
15973
|
-
return
|
|
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 ||
|
|
15977
|
-
return
|
|
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 =
|
|
15984
|
-
return
|
|
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 =
|
|
16017
|
-
if (
|
|
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 (!
|
|
16029
|
-
|
|
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 =
|
|
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 (
|
|
16266
|
+
if (existsSync12(archivePath)) {
|
|
16045
16267
|
unlinkSync2(archivePath);
|
|
16046
16268
|
}
|
|
16047
|
-
if (process.platform !== "win32" &&
|
|
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 =
|
|
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 =
|
|
16098
|
-
if (
|
|
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 &&
|
|
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 (!
|
|
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
|
|
16194
|
-
import { tmpdir as
|
|
16195
|
-
import { join as
|
|
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 =
|
|
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 || !
|
|
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
|
|
16358
|
-
import { dirname as dirname2, join as
|
|
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
|
|
16363
|
-
mkdirSync as
|
|
16364
|
-
readFileSync as
|
|
16365
|
-
writeFileSync as
|
|
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
|
|
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
|
|
16594
|
+
import { join as join17 } from "path";
|
|
16373
16595
|
var OPENCODE_STORAGE3 = getOpenCodeStorageDir();
|
|
16374
|
-
var AGENTS_INJECTOR_STORAGE =
|
|
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
|
|
16601
|
+
return join18(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
16380
16602
|
}
|
|
16381
16603
|
function loadInjectedPaths(sessionID) {
|
|
16382
16604
|
const filePath = getStoragePath(sessionID);
|
|
16383
|
-
if (!
|
|
16605
|
+
if (!existsSync15(filePath))
|
|
16384
16606
|
return new Set;
|
|
16385
16607
|
try {
|
|
16386
|
-
const content =
|
|
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 (!
|
|
16395
|
-
|
|
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
|
-
|
|
16624
|
+
writeFileSync5(getStoragePath(sessionID), JSON.stringify(data, null, 2));
|
|
16403
16625
|
}
|
|
16404
16626
|
function clearInjectedPaths(sessionID) {
|
|
16405
16627
|
const filePath = getStoragePath(sessionID);
|
|
16406
|
-
if (
|
|
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 =
|
|
16437
|
-
if (
|
|
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 =
|
|
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
|
|
16535
|
-
import { dirname as dirname3, join as
|
|
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
|
|
16540
|
-
mkdirSync as
|
|
16541
|
-
readFileSync as
|
|
16542
|
-
writeFileSync as
|
|
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
|
|
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
|
|
16771
|
+
import { join as join20 } from "path";
|
|
16550
16772
|
var OPENCODE_STORAGE4 = getOpenCodeStorageDir();
|
|
16551
|
-
var README_INJECTOR_STORAGE =
|
|
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
|
|
16778
|
+
return join21(README_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
16557
16779
|
}
|
|
16558
16780
|
function loadInjectedPaths2(sessionID) {
|
|
16559
16781
|
const filePath = getStoragePath2(sessionID);
|
|
16560
|
-
if (!
|
|
16782
|
+
if (!existsSync17(filePath))
|
|
16561
16783
|
return new Set;
|
|
16562
16784
|
try {
|
|
16563
|
-
const content =
|
|
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 (!
|
|
16572
|
-
|
|
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
|
-
|
|
16801
|
+
writeFileSync6(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
|
|
16580
16802
|
}
|
|
16581
16803
|
function clearInjectedPaths2(sessionID) {
|
|
16582
16804
|
const filePath = getStoragePath2(sessionID);
|
|
16583
|
-
if (
|
|
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 =
|
|
16612
|
-
if (
|
|
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 =
|
|
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
|
|
16923
|
-
import { join as
|
|
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 =
|
|
16926
|
-
var PART_STORAGE3 =
|
|
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 (!
|
|
17151
|
+
if (!existsSync19(MESSAGE_STORAGE3))
|
|
16930
17152
|
return "";
|
|
16931
|
-
const directPath =
|
|
16932
|
-
if (
|
|
17153
|
+
const directPath = join23(MESSAGE_STORAGE3, sessionID);
|
|
17154
|
+
if (existsSync19(directPath)) {
|
|
16933
17155
|
return directPath;
|
|
16934
17156
|
}
|
|
16935
|
-
for (const dir of
|
|
16936
|
-
const sessionPath =
|
|
16937
|
-
if (
|
|
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 || !
|
|
17167
|
+
if (!messageDir || !existsSync19(messageDir))
|
|
16946
17168
|
return [];
|
|
16947
17169
|
const messageIds = [];
|
|
16948
|
-
for (const file of
|
|
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 =
|
|
16961
|
-
if (!
|
|
17182
|
+
const partDir = join23(PART_STORAGE3, messageID);
|
|
17183
|
+
if (!existsSync19(partDir))
|
|
16962
17184
|
continue;
|
|
16963
|
-
for (const file of
|
|
17185
|
+
for (const file of readdirSync5(partDir)) {
|
|
16964
17186
|
if (!file.endsWith(".json"))
|
|
16965
17187
|
continue;
|
|
16966
17188
|
try {
|
|
16967
|
-
const partPath =
|
|
16968
|
-
const content =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
17589
|
-
var
|
|
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 (
|
|
17738
|
-
const promptText = extractPromptText(
|
|
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
|
|
17750
|
-
|
|
17751
|
-
|
|
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 =
|
|
17755
|
-
state2.modelID =
|
|
17756
|
-
if (isAlreadyHighVariant(
|
|
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(
|
|
17761
|
-
const thinkingConfig = getThinkingConfig(
|
|
17998
|
+
const highVariant = getHighVariant(modelID);
|
|
17999
|
+
const thinkingConfig = getThinkingConfig(providerID, modelID);
|
|
17762
18000
|
if (highVariant) {
|
|
17763
|
-
|
|
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:
|
|
18004
|
+
sessionID: input.sessionID,
|
|
18005
|
+
from: modelID,
|
|
17771
18006
|
to: highVariant
|
|
17772
18007
|
});
|
|
17773
18008
|
}
|
|
17774
18009
|
if (thinkingConfig) {
|
|
17775
|
-
|
|
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:
|
|
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
|
|
17798
|
-
import { existsSync as
|
|
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
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
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 &&
|
|
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 (
|
|
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
|
|
17873
|
-
import { join as
|
|
17874
|
-
var USER_CONFIG_PATH =
|
|
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
|
|
18115
|
+
return join25(process.cwd(), ".opencode", "opencode-cc-plugin.json");
|
|
17877
18116
|
}
|
|
17878
18117
|
async function loadConfigFromPath(path4) {
|
|
17879
|
-
if (!
|
|
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
|
|
18068
|
-
import { mkdirSync as
|
|
18069
|
-
import { tmpdir as
|
|
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 =
|
|
18310
|
+
var TRANSCRIPT_DIR = join26(getClaudeConfigDir(), "transcripts");
|
|
18072
18311
|
function getTranscriptPath(sessionId) {
|
|
18073
|
-
return
|
|
18312
|
+
return join26(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
|
|
18074
18313
|
}
|
|
18075
18314
|
function ensureTranscriptDir() {
|
|
18076
|
-
if (!
|
|
18077
|
-
|
|
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
|
-
|
|
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 =
|
|
18164
|
-
|
|
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 =
|
|
18184
|
-
|
|
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
|
|
18638
|
+
import { join as join27 } from "path";
|
|
18400
18639
|
init_shared();
|
|
18401
|
-
var TODO_DIR =
|
|
18640
|
+
var TODO_DIR = join27(getClaudeConfigDir(), "todos");
|
|
18402
18641
|
function getTodoPath(sessionId) {
|
|
18403
|
-
return
|
|
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
|
|
19084
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
18846
19085
|
import { homedir as homedir8 } from "os";
|
|
18847
|
-
import { relative as
|
|
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
|
|
18852
|
-
readdirSync as
|
|
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
|
|
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
|
|
19099
|
+
import { join as join28 } from "path";
|
|
18861
19100
|
var OPENCODE_STORAGE6 = getOpenCodeStorageDir();
|
|
18862
|
-
var RULES_INJECTOR_STORAGE =
|
|
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 =
|
|
18904
|
-
if (
|
|
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 (!
|
|
19155
|
+
if (!existsSync23(dir))
|
|
18917
19156
|
return;
|
|
18918
19157
|
try {
|
|
18919
|
-
const entries =
|
|
19158
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
18920
19159
|
for (const entry of entries) {
|
|
18921
|
-
const fullPath =
|
|
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 =
|
|
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 =
|
|
18973
|
-
if (
|
|
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 =
|
|
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
|
|
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 ?
|
|
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
|
|
19183
|
-
mkdirSync as
|
|
19184
|
-
readFileSync as
|
|
19185
|
-
writeFileSync as
|
|
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
|
|
19427
|
+
import { join as join30 } from "path";
|
|
19189
19428
|
function getStoragePath3(sessionID) {
|
|
19190
|
-
return
|
|
19429
|
+
return join30(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
19191
19430
|
}
|
|
19192
19431
|
function loadInjectedRules(sessionID) {
|
|
19193
19432
|
const filePath = getStoragePath3(sessionID);
|
|
19194
|
-
if (!
|
|
19433
|
+
if (!existsSync24(filePath))
|
|
19195
19434
|
return { contentHashes: new Set, realPaths: new Set };
|
|
19196
19435
|
try {
|
|
19197
|
-
const content =
|
|
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 (!
|
|
19209
|
-
|
|
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
|
-
|
|
19456
|
+
writeFileSync9(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
|
|
19218
19457
|
}
|
|
19219
19458
|
function clearInjectedRules(sessionID) {
|
|
19220
19459
|
const filePath = getStoragePath3(sessionID);
|
|
19221
|
-
if (
|
|
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 =
|
|
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 ?
|
|
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
|
|
19378
|
-
mkdirSync as
|
|
19379
|
-
readFileSync as
|
|
19380
|
-
writeFileSync as
|
|
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
|
|
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
|
|
19626
|
+
import { join as join34 } from "path";
|
|
19388
19627
|
var OPENCODE_STORAGE7 = getOpenCodeStorageDir();
|
|
19389
|
-
var AGENT_USAGE_REMINDER_STORAGE =
|
|
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
|
|
19674
|
+
return join35(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
|
|
19436
19675
|
}
|
|
19437
19676
|
function loadAgentUsageState(sessionID) {
|
|
19438
19677
|
const filePath = getStoragePath4(sessionID);
|
|
19439
|
-
if (!
|
|
19678
|
+
if (!existsSync27(filePath))
|
|
19440
19679
|
return null;
|
|
19441
19680
|
try {
|
|
19442
|
-
const content =
|
|
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 (!
|
|
19450
|
-
|
|
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
|
-
|
|
19692
|
+
writeFileSync12(filePath, JSON.stringify(state2, null, 2));
|
|
19454
19693
|
}
|
|
19455
19694
|
function clearAgentUsageState(sessionID) {
|
|
19456
19695
|
const filePath = getStoragePath4(sessionID);
|
|
19457
|
-
if (
|
|
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
|
|
20039
|
-
mkdirSync as
|
|
20040
|
-
readFileSync as
|
|
20041
|
-
writeFileSync as
|
|
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
|
|
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
|
|
20289
|
+
import { join as join36 } from "path";
|
|
20049
20290
|
var OPENCODE_STORAGE8 = getOpenCodeStorageDir();
|
|
20050
|
-
var INTERACTIVE_BASH_SESSION_STORAGE =
|
|
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
|
|
20303
|
+
return join37(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
|
|
20063
20304
|
}
|
|
20064
20305
|
function loadInteractiveBashSessionState(sessionID) {
|
|
20065
20306
|
const filePath = getStoragePath5(sessionID);
|
|
20066
|
-
if (!
|
|
20307
|
+
if (!existsSync28(filePath))
|
|
20067
20308
|
return null;
|
|
20068
20309
|
try {
|
|
20069
|
-
const content =
|
|
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 (!
|
|
20082
|
-
|
|
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
|
-
|
|
20331
|
+
writeFileSync13(filePath, JSON.stringify(serialized, null, 2));
|
|
20091
20332
|
}
|
|
20092
20333
|
function clearInteractiveBashSessionState(sessionID) {
|
|
20093
20334
|
const filePath = getStoragePath5(sessionID);
|
|
20094
|
-
if (
|
|
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 || "[
|
|
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
|
|
20359
|
-
import { join as
|
|
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
|
|
20364
|
-
import { dirname as dirname6, join as
|
|
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 ?
|
|
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 (!
|
|
20619
|
+
if (!existsSync29(filePath)) {
|
|
20379
20620
|
return null;
|
|
20380
20621
|
}
|
|
20381
20622
|
try {
|
|
20382
|
-
const content =
|
|
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 (!
|
|
20417
|
-
|
|
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
|
-
|
|
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 (
|
|
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 (!
|
|
20703
|
+
if (!existsSync30(MESSAGE_STORAGE))
|
|
20463
20704
|
return null;
|
|
20464
|
-
const directPath =
|
|
20465
|
-
if (
|
|
20705
|
+
const directPath = join39(MESSAGE_STORAGE, sessionID);
|
|
20706
|
+
if (existsSync30(directPath))
|
|
20466
20707
|
return directPath;
|
|
20467
|
-
for (const dir of
|
|
20468
|
-
const sessionPath =
|
|
20469
|
-
if (
|
|
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 (!
|
|
20747
|
+
if (!existsSync30(transcriptPath))
|
|
20507
20748
|
return false;
|
|
20508
|
-
const content =
|
|
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
|
|
20823
|
-
import { join as
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
21254
|
+
const userSkillsDir = join40(getClaudeConfigDir(), "skills");
|
|
21014
21255
|
return loadSkillsFromDir(userSkillsDir, "user");
|
|
21015
21256
|
}
|
|
21016
21257
|
async function discoverProjectClaudeSkills() {
|
|
21017
|
-
const projectSkillsDir =
|
|
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 =
|
|
21263
|
+
const opencodeSkillsDir = join40(configDir, "skills");
|
|
21023
21264
|
return loadSkillsFromDir(opencodeSkillsDir, "opencode");
|
|
21024
21265
|
}
|
|
21025
21266
|
async function discoverOpencodeProjectSkills() {
|
|
21026
|
-
const opencodeProjectDir =
|
|
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
|
|
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 (!
|
|
21321
|
+
if (!existsSync31(filePath))
|
|
21081
21322
|
return null;
|
|
21082
|
-
const content =
|
|
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
|
|
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 =
|
|
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 (!
|
|
22805
|
+
if (!existsSync32(commandsDir)) {
|
|
22565
22806
|
return [];
|
|
22566
22807
|
}
|
|
22567
|
-
const entries =
|
|
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 =
|
|
22813
|
+
const commandPath = join41(commandsDir, entry.name);
|
|
22573
22814
|
const commandName = basename2(entry.name, ".md");
|
|
22574
22815
|
try {
|
|
22575
|
-
const content =
|
|
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 =
|
|
22619
|
-
const projectCommandsDir =
|
|
22620
|
-
const opencodeGlobalDir =
|
|
22621
|
-
const opencodeProjectDir =
|
|
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
|
|
22792
|
-
import { join as
|
|
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 =
|
|
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 (!
|
|
23152
|
+
if (!existsSync33(MESSAGE_STORAGE))
|
|
22912
23153
|
return null;
|
|
22913
|
-
const directPath =
|
|
22914
|
-
if (
|
|
23154
|
+
const directPath = join42(MESSAGE_STORAGE, sessionID);
|
|
23155
|
+
if (existsSync33(directPath))
|
|
22915
23156
|
return directPath;
|
|
22916
|
-
for (const dir of
|
|
22917
|
-
const sessionPath =
|
|
22918
|
-
if (
|
|
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
|
|
23033
|
-
import { dirname as dirname9, join as
|
|
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
|
|
23276
|
+
return join43(directory, BOULDER_DIR, BOULDER_FILE);
|
|
23036
23277
|
}
|
|
23037
23278
|
function readBoulderState(directory) {
|
|
23038
23279
|
const filePath = getBoulderFilePath(directory);
|
|
23039
|
-
if (!
|
|
23280
|
+
if (!existsSync34(filePath)) {
|
|
23040
23281
|
return null;
|
|
23041
23282
|
}
|
|
23042
23283
|
try {
|
|
23043
|
-
const content =
|
|
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 (!
|
|
23054
|
-
|
|
23294
|
+
if (!existsSync34(dir)) {
|
|
23295
|
+
mkdirSync12(dir, { recursive: true });
|
|
23055
23296
|
}
|
|
23056
|
-
|
|
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 (
|
|
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 =
|
|
23088
|
-
if (!
|
|
23328
|
+
const plansDir = join43(directory, PROMETHEUS_PLANS_DIR);
|
|
23329
|
+
if (!existsSync34(plansDir)) {
|
|
23089
23330
|
return [];
|
|
23090
23331
|
}
|
|
23091
23332
|
try {
|
|
23092
|
-
const files =
|
|
23093
|
-
return files.filter((f) => f.endsWith(".md")).map((f) =>
|
|
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 (!
|
|
23344
|
+
if (!existsSync34(planPath)) {
|
|
23104
23345
|
return { total: 0, completed: 0, isComplete: true };
|
|
23105
23346
|
}
|
|
23106
23347
|
try {
|
|
23107
|
-
const content =
|
|
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
|
|
23325
|
-
import { join as
|
|
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 (!
|
|
23895
|
+
if (!existsSync35(MESSAGE_STORAGE))
|
|
23655
23896
|
return null;
|
|
23656
|
-
const directPath =
|
|
23657
|
-
if (
|
|
23897
|
+
const directPath = join44(MESSAGE_STORAGE, sessionID);
|
|
23898
|
+
if (existsSync35(directPath))
|
|
23658
23899
|
return directPath;
|
|
23659
|
-
for (const dir of
|
|
23660
|
-
const sessionPath =
|
|
23661
|
-
if (
|
|
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
|
|
24289
|
-
import { join as
|
|
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
|
|
24620
|
+
const cwd2 = process.cwd();
|
|
24358
24621
|
return [
|
|
24359
|
-
{ path:
|
|
24360
|
-
{ path:
|
|
24361
|
-
{ path:
|
|
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 (!
|
|
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 (!
|
|
24643
|
+
if (!existsSync36(path7))
|
|
24381
24644
|
continue;
|
|
24382
24645
|
try {
|
|
24383
|
-
const content =
|
|
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
|
|
24827
|
-
import { join as
|
|
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 (!
|
|
25093
|
+
if (!existsSync37(path7))
|
|
24831
25094
|
return null;
|
|
24832
25095
|
try {
|
|
24833
|
-
return JSON.parse(
|
|
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
|
|
25102
|
+
const cwd2 = process.cwd();
|
|
24840
25103
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
24841
25104
|
return {
|
|
24842
|
-
project:
|
|
24843
|
-
user:
|
|
24844
|
-
opencode:
|
|
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 (
|
|
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 (
|
|
25242
|
+
if (existsSync37(join46(p, cmd + suffix))) {
|
|
24980
25243
|
return true;
|
|
24981
25244
|
}
|
|
24982
25245
|
}
|
|
24983
25246
|
}
|
|
24984
|
-
const
|
|
25247
|
+
const cwd2 = process.cwd();
|
|
24985
25248
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
24986
|
-
const dataDir =
|
|
25249
|
+
const dataDir = join46(getDataDir(), "opencode");
|
|
24987
25250
|
const additionalBases = [
|
|
24988
|
-
|
|
24989
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
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 (
|
|
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
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
25779
|
-
|
|
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
|
|
38359
|
-
import { existsSync as
|
|
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
|
|
38364
|
-
import { join as
|
|
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 ||
|
|
38391
|
-
return
|
|
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 ||
|
|
38395
|
-
return
|
|
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 =
|
|
38402
|
-
return
|
|
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 =
|
|
38414
|
-
if (
|
|
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 (!
|
|
38423
|
-
|
|
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 =
|
|
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 (
|
|
38696
|
+
if (existsSync39(archivePath)) {
|
|
38434
38697
|
unlinkSync10(archivePath);
|
|
38435
38698
|
}
|
|
38436
|
-
if (process.platform !== "win32" &&
|
|
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 =
|
|
38488
|
-
if (
|
|
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 =
|
|
38500
|
-
if (
|
|
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 (
|
|
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
|
|
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 &&
|
|
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 &&
|
|
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 (!
|
|
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
|
|
38874
|
-
import { join as
|
|
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
|
|
38880
|
-
import { join as
|
|
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 =
|
|
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
|
|
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
|
|
39171
|
+
return join49(homeDir, ".cache", "oh-my-opencode", "bin");
|
|
38909
39172
|
}
|
|
38910
39173
|
function getRgPath() {
|
|
38911
39174
|
const isWindows2 = process.platform === "win32";
|
|
38912
|
-
return
|
|
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 =
|
|
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 (
|
|
39224
|
+
if (existsSync42(rgPath)) {
|
|
38962
39225
|
return rgPath;
|
|
38963
39226
|
}
|
|
38964
|
-
|
|
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 =
|
|
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 (!
|
|
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 (
|
|
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
|
|
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
|
-
|
|
39018
|
-
|
|
39019
|
-
|
|
39020
|
-
|
|
39021
|
-
|
|
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 (
|
|
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
|
|
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
|
-
|
|
39630
|
+
cwd2 = undefined;
|
|
39368
39631
|
} else if (isWindows2) {
|
|
39369
39632
|
command = buildPowerShellCommand(options);
|
|
39370
|
-
|
|
39633
|
+
cwd2 = undefined;
|
|
39371
39634
|
} else {
|
|
39372
39635
|
const args = buildFindArgs(options);
|
|
39373
39636
|
const paths = options.paths?.length ? options.paths : ["."];
|
|
39374
|
-
|
|
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 = `${
|
|
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
|
|
39487
|
-
import { join as
|
|
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 (!
|
|
40866
|
+
if (!existsSync44(commandsDir)) {
|
|
40604
40867
|
return [];
|
|
40605
40868
|
}
|
|
40606
|
-
const entries =
|
|
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 =
|
|
40874
|
+
const commandPath = join51(commandsDir, entry.name);
|
|
40612
40875
|
const commandName = basename4(entry.name, ".md");
|
|
40613
40876
|
try {
|
|
40614
|
-
const content =
|
|
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 =
|
|
40641
|
-
const projectCommandsDir =
|
|
40642
|
-
const opencodeGlobalDir =
|
|
40643
|
-
const opencodeProjectDir =
|
|
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
|
|
41083
|
+
import { join as join52 } from "path";
|
|
40821
41084
|
var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
|
|
40822
|
-
var MESSAGE_STORAGE4 =
|
|
40823
|
-
var PART_STORAGE4 =
|
|
40824
|
-
var SESSION_STORAGE =
|
|
40825
|
-
var TODO_DIR2 =
|
|
40826
|
-
var TRANSCRIPT_DIR2 =
|
|
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
|
|
41162
|
+
import { existsSync as existsSync45, readdirSync as readdirSync14 } from "fs";
|
|
40900
41163
|
import { readdir, readFile } from "fs/promises";
|
|
40901
|
-
import { join as
|
|
41164
|
+
import { join as join53 } from "path";
|
|
40902
41165
|
async function getMainSessions(options) {
|
|
40903
|
-
if (!
|
|
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 =
|
|
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(
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
41223
|
+
if (!existsSync45(MESSAGE_STORAGE4))
|
|
40961
41224
|
return "";
|
|
40962
|
-
const directPath =
|
|
40963
|
-
if (
|
|
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
|
|
40968
|
-
const sessionPath =
|
|
40969
|
-
if (
|
|
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 || !
|
|
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(
|
|
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 =
|
|
41019
|
-
if (!
|
|
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(
|
|
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 (!
|
|
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(
|
|
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 (!
|
|
41330
|
+
if (!existsSync45(TRANSCRIPT_DIR2))
|
|
41068
41331
|
return 0;
|
|
41069
|
-
const transcriptFile =
|
|
41070
|
-
if (!
|
|
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: ${
|
|
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: ${
|
|
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
|
|
42223
|
-
import { join as
|
|
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 (!
|
|
42540
|
+
if (!existsSync46(MESSAGE_STORAGE))
|
|
42228
42541
|
return null;
|
|
42229
|
-
const directPath =
|
|
42230
|
-
if (
|
|
42542
|
+
const directPath = join54(MESSAGE_STORAGE, sessionID);
|
|
42543
|
+
if (existsSync46(directPath))
|
|
42231
42544
|
return directPath;
|
|
42232
|
-
for (const dir of
|
|
42233
|
-
const sessionPath =
|
|
42234
|
-
if (
|
|
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
|
|
42644
|
-
import { join as
|
|
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
|
-
|
|
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 (!
|
|
43116
|
+
if (!existsSync47(MESSAGE_STORAGE))
|
|
42814
43117
|
return null;
|
|
42815
|
-
const directPath =
|
|
42816
|
-
if (
|
|
43118
|
+
const directPath = join55(MESSAGE_STORAGE, sessionID);
|
|
43119
|
+
if (existsSync47(directPath))
|
|
42817
43120
|
return directPath;
|
|
42818
|
-
for (const dir of
|
|
42819
|
-
const sessionPath =
|
|
42820
|
-
if (
|
|
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 =
|
|
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
|
|
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
|
-
|
|
43233
|
-
|
|
43234
|
-
|
|
43235
|
-
|
|
43236
|
-
|
|
43237
|
-
|
|
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 =
|
|
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
|
|
43775
|
-
import { join as
|
|
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 =
|
|
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 ||
|
|
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.
|
|
44618
|
-
|
|
44619
|
-
|
|
44620
|
-
|
|
44621
|
-
|
|
44622
|
-
|
|
44623
|
-
|
|
44624
|
-
|
|
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
|
-
|
|
44646
|
-
|
|
44647
|
-
|
|
44648
|
-
|
|
44649
|
-
|
|
44650
|
-
|
|
44651
|
-
|
|
44652
|
-
|
|
44653
|
-
|
|
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
|
-
|
|
44667
|
-
|
|
44668
|
-
|
|
44669
|
-
|
|
44670
|
-
|
|
44671
|
-
|
|
44672
|
-
|
|
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
|
-
|
|
44681
|
-
|
|
44682
|
-
|
|
44683
|
-
|
|
44684
|
-
|
|
44685
|
-
|
|
44686
|
-
|
|
44687
|
-
|
|
44688
|
-
|
|
44689
|
-
|
|
44690
|
-
|
|
44691
|
-
|
|
44692
|
-
|
|
44693
|
-
|
|
44694
|
-
|
|
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
|
-
|
|
44697
|
-
|
|
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
|
-
|
|
44702
|
-
|
|
44703
|
-
|
|
44704
|
-
|
|
44705
|
-
|
|
44706
|
-
|
|
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
|
-
|
|
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
|
-
|
|
44720
|
-
|
|
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 (!
|
|
44967
|
+
if (!existsSync48(MESSAGE_STORAGE))
|
|
44757
44968
|
return null;
|
|
44758
|
-
const directPath =
|
|
44759
|
-
if (
|
|
44969
|
+
const directPath = join56(MESSAGE_STORAGE, sessionID);
|
|
44970
|
+
if (existsSync48(directPath))
|
|
44760
44971
|
return directPath;
|
|
44761
|
-
for (const dir of
|
|
44762
|
-
const sessionPath =
|
|
44763
|
-
if (
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
65933
|
-
import { join as
|
|
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 (!
|
|
66169
|
+
if (!existsSync50(agentsDir)) {
|
|
65948
66170
|
return [];
|
|
65949
66171
|
}
|
|
65950
|
-
const entries =
|
|
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 =
|
|
66177
|
+
const agentPath = join59(agentsDir, entry.name);
|
|
65956
66178
|
const agentName = basename7(entry.name, ".md");
|
|
65957
66179
|
try {
|
|
65958
|
-
const content =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
66236
|
+
return join60(homedir13(), ".claude", "plugins");
|
|
66015
66237
|
}
|
|
66016
66238
|
function getInstalledPluginsPath() {
|
|
66017
|
-
return
|
|
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 (!
|
|
66264
|
+
if (!existsSync51(dbPath)) {
|
|
66043
66265
|
return null;
|
|
66044
66266
|
}
|
|
66045
66267
|
try {
|
|
66046
|
-
const content =
|
|
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
|
|
66279
|
+
return join60(homedir13(), ".claude", "settings.json");
|
|
66058
66280
|
}
|
|
66059
66281
|
function loadClaudeSettings() {
|
|
66060
66282
|
const settingsPath = getClaudeSettingsPath();
|
|
66061
|
-
if (!
|
|
66283
|
+
if (!existsSync51(settingsPath)) {
|
|
66062
66284
|
return null;
|
|
66063
66285
|
}
|
|
66064
66286
|
try {
|
|
66065
|
-
const content =
|
|
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 =
|
|
66074
|
-
if (!
|
|
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 =
|
|
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 (!
|
|
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 (
|
|
66144
|
-
loadedPlugin.commandsDir =
|
|
66365
|
+
if (existsSync51(join60(installPath, "commands"))) {
|
|
66366
|
+
loadedPlugin.commandsDir = join60(installPath, "commands");
|
|
66145
66367
|
}
|
|
66146
|
-
if (
|
|
66147
|
-
loadedPlugin.agentsDir =
|
|
66368
|
+
if (existsSync51(join60(installPath, "agents"))) {
|
|
66369
|
+
loadedPlugin.agentsDir = join60(installPath, "agents");
|
|
66148
66370
|
}
|
|
66149
|
-
if (
|
|
66150
|
-
loadedPlugin.skillsDir =
|
|
66371
|
+
if (existsSync51(join60(installPath, "skills"))) {
|
|
66372
|
+
loadedPlugin.skillsDir = join60(installPath, "skills");
|
|
66151
66373
|
}
|
|
66152
|
-
const hooksPath =
|
|
66153
|
-
if (
|
|
66374
|
+
const hooksPath = join60(installPath, "hooks", "hooks.json");
|
|
66375
|
+
if (existsSync51(hooksPath)) {
|
|
66154
66376
|
loadedPlugin.hooksPath = hooksPath;
|
|
66155
66377
|
}
|
|
66156
|
-
const mcpPath =
|
|
66157
|
-
if (
|
|
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 || !
|
|
66390
|
+
if (!plugin.commandsDir || !existsSync51(plugin.commandsDir))
|
|
66169
66391
|
continue;
|
|
66170
|
-
const entries =
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
66432
|
+
if (!plugin.skillsDir || !existsSync51(plugin.skillsDir))
|
|
66211
66433
|
continue;
|
|
66212
|
-
const entries =
|
|
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 =
|
|
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 =
|
|
66221
|
-
if (!
|
|
66442
|
+
const skillMdPath = join60(resolvedPath, "SKILL.md");
|
|
66443
|
+
if (!existsSync51(skillMdPath))
|
|
66222
66444
|
continue;
|
|
66223
66445
|
try {
|
|
66224
|
-
const content =
|
|
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 || !
|
|
66493
|
+
if (!plugin.agentsDir || !existsSync51(plugin.agentsDir))
|
|
66272
66494
|
continue;
|
|
66273
|
-
const entries =
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
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 || !
|
|
66561
|
+
if (!plugin.hooksPath || !existsSync51(plugin.hooksPath))
|
|
66340
66562
|
continue;
|
|
66341
66563
|
try {
|
|
66342
|
-
const content =
|
|
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
|
-
|
|
68024
|
-
|
|
68025
|
-
await
|
|
68026
|
-
|
|
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
|
-
|
|
68063
|
-
|
|
68064
|
-
await
|
|
68065
|
-
|
|
68066
|
-
await
|
|
68067
|
-
|
|
68068
|
-
await
|
|
68069
|
-
|
|
68070
|
-
await
|
|
68071
|
-
|
|
68072
|
-
await
|
|
68073
|
-
|
|
68074
|
-
await
|
|
68075
|
-
|
|
68076
|
-
await
|
|
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
|
-
|
|
68132
|
-
|
|
68133
|
-
await
|
|
68134
|
-
|
|
68135
|
-
await
|
|
68136
|
-
|
|
68137
|
-
await
|
|
68138
|
-
|
|
68139
|
-
await
|
|
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
|
-
|
|
68182
|
-
|
|
68183
|
-
await
|
|
68184
|
-
|
|
68185
|
-
await
|
|
68186
|
-
|
|
68187
|
-
await
|
|
68188
|
-
|
|
68189
|
-
await
|
|
68190
|
-
|
|
68191
|
-
await
|
|
68192
|
-
|
|
68193
|
-
await
|
|
68194
|
-
|
|
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
|
};
|