oh-my-opencode 3.8.5 → 3.10.0
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/README.ja.md +3 -3
- package/README.ko.md +3 -3
- package/README.md +3 -3
- package/README.ru.md +367 -0
- package/README.zh-cn.md +3 -3
- package/bin/oh-my-opencode.js +96 -34
- package/bin/platform.d.ts +14 -0
- package/bin/platform.js +44 -0
- package/bin/platform.test.ts +56 -1
- package/dist/agents/atlas/agent.d.ts +1 -1
- package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -0
- package/dist/agents/env-context.d.ts +1 -1
- package/dist/agents/hephaestus.d.ts +1 -1
- package/dist/agents/sisyphus-gemini-overlays.d.ts +2 -0
- package/dist/agents/sisyphus.d.ts +1 -1
- package/dist/cli/config-manager/antigravity-provider-configuration.d.ts +3 -3
- package/dist/cli/index.js +208 -64
- package/dist/cli/run/event-state.d.ts +2 -0
- package/dist/cli/run/poll-for-completion.d.ts +2 -0
- package/dist/config/schema/agent-overrides.d.ts +1 -0
- package/dist/config/schema/categories.d.ts +2 -0
- package/dist/config/schema/hooks.d.ts +1 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +3 -12
- package/dist/create-hooks.d.ts +1 -0
- package/dist/features/background-agent/manager.d.ts +9 -0
- package/dist/features/boulder-state/storage.d.ts +1 -1
- package/dist/features/boulder-state/types.d.ts +2 -0
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/claude-code-plugin-loader/types.d.ts +13 -3
- package/dist/features/context-injector/types.d.ts +2 -2
- package/dist/features/hook-message-injector/injector.d.ts +2 -0
- package/dist/hooks/anthropic-context-window-limit-recovery/types.d.ts +1 -0
- package/dist/hooks/atlas/boulder-continuation-injector.d.ts +1 -0
- package/dist/hooks/atlas/types.d.ts +1 -0
- package/dist/hooks/background-notification/hook.d.ts +11 -0
- package/dist/hooks/claude-code-hooks/dispatch-hook.d.ts +4 -0
- package/dist/hooks/claude-code-hooks/execute-http-hook.d.ts +4 -0
- package/dist/hooks/claude-code-hooks/types.d.ts +9 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/no-hephaestus-non-gpt/hook.d.ts +5 -1
- package/dist/hooks/ralph-loop/completion-promise-detector.d.ts +1 -0
- package/dist/hooks/ralph-loop/loop-state-controller.d.ts +2 -0
- package/dist/hooks/ralph-loop/ralph-loop-hook.d.ts +1 -0
- package/dist/hooks/ralph-loop/types.d.ts +1 -0
- package/dist/hooks/read-image-resizer/hook.d.ts +12 -0
- package/dist/hooks/read-image-resizer/image-dimensions.d.ts +2 -0
- package/dist/hooks/read-image-resizer/image-resizer.d.ts +3 -0
- package/dist/hooks/read-image-resizer/index.d.ts +1 -0
- package/dist/hooks/read-image-resizer/types.d.ts +14 -0
- package/dist/hooks/session-notification.d.ts +1 -0
- package/dist/hooks/start-work/index.d.ts +3 -0
- package/dist/hooks/start-work/parse-user-request.d.ts +5 -0
- package/dist/hooks/start-work/worktree-detector.d.ts +1 -0
- package/dist/hooks/stop-continuation-guard/hook.d.ts +6 -1
- package/dist/hooks/think-mode/hook.d.ts +14 -2
- package/dist/hooks/think-mode/switcher.d.ts +0 -56
- package/dist/hooks/think-mode/types.d.ts +1 -15
- package/dist/hooks/todo-continuation-enforcer/constants.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer/pending-question-detection.d.ts +14 -0
- package/dist/index.js +2203 -704
- package/dist/oh-my-opencode.schema.json +10 -14
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
- package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
- package/dist/shared/model-suggestion-retry.d.ts +4 -2
- package/dist/shared/prompt-timeout-context.d.ts +12 -0
- package/dist/shared/spawn-with-windows-hide.d.ts +15 -0
- package/dist/tools/delegate-task/category-resolver.d.ts +1 -0
- package/dist/tools/delegate-task/skill-resolver.d.ts +1 -0
- package/dist/tools/delegate-task/token-limiter.d.ts +4 -0
- package/dist/tools/delegate-task/types.d.ts +9 -0
- package/dist/tools/hashline-edit/tool-description.d.ts +1 -1
- package/dist/tools/hashline-edit/validation.d.ts +1 -0
- package/package.json +13 -8
- package/postinstall.mjs +23 -7
package/dist/index.js
CHANGED
|
@@ -4,25 +4,43 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
7
12
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
8
20
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
21
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
22
|
for (let key of __getOwnPropNames(mod))
|
|
11
23
|
if (!__hasOwnProp.call(to, key))
|
|
12
24
|
__defProp(to, key, {
|
|
13
|
-
get: (
|
|
25
|
+
get: __accessProp.bind(mod, key),
|
|
14
26
|
enumerable: true
|
|
15
27
|
});
|
|
28
|
+
if (canCache)
|
|
29
|
+
cache.set(mod, to);
|
|
16
30
|
return to;
|
|
17
31
|
};
|
|
18
32
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __returnValue = (v) => v;
|
|
34
|
+
function __exportSetter(name, newValue) {
|
|
35
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
36
|
+
}
|
|
19
37
|
var __export = (target, all) => {
|
|
20
38
|
for (var name in all)
|
|
21
39
|
__defProp(target, name, {
|
|
22
40
|
get: all[name],
|
|
23
41
|
enumerable: true,
|
|
24
42
|
configurable: true,
|
|
25
|
-
set: (
|
|
43
|
+
set: __exportSetter.bind(all, name)
|
|
26
44
|
});
|
|
27
45
|
};
|
|
28
46
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -5248,10 +5266,10 @@ WHY THIS FORMAT IS MANDATORY:
|
|
|
5248
5266
|
`, PLAN_AGENT_NAMES, PLAN_FAMILY_NAMES;
|
|
5249
5267
|
var init_constants = __esm(() => {
|
|
5250
5268
|
DEFAULT_CATEGORIES = {
|
|
5251
|
-
"visual-engineering": { model: "google/gemini-3-pro", variant: "high" },
|
|
5269
|
+
"visual-engineering": { model: "google/gemini-3.1-pro", variant: "high" },
|
|
5252
5270
|
ultrabrain: { model: "openai/gpt-5.3-codex", variant: "xhigh" },
|
|
5253
5271
|
deep: { model: "openai/gpt-5.3-codex", variant: "medium" },
|
|
5254
|
-
artistry: { model: "google/gemini-3-pro", variant: "high" },
|
|
5272
|
+
artistry: { model: "google/gemini-3.1-pro", variant: "high" },
|
|
5255
5273
|
quick: { model: "anthropic/claude-haiku-4-5" },
|
|
5256
5274
|
"unspecified-low": { model: "anthropic/claude-sonnet-4-6" },
|
|
5257
5275
|
"unspecified-high": { model: "anthropic/claude-opus-4-6", variant: "max" },
|
|
@@ -8167,7 +8185,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
8167
8185
|
const schOrFunc = root.refs[ref];
|
|
8168
8186
|
if (schOrFunc)
|
|
8169
8187
|
return schOrFunc;
|
|
8170
|
-
let _sch =
|
|
8188
|
+
let _sch = resolve13.call(this, root, ref);
|
|
8171
8189
|
if (_sch === undefined) {
|
|
8172
8190
|
const schema2 = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
8173
8191
|
const { schemaId } = this.opts;
|
|
@@ -8194,7 +8212,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
8194
8212
|
function sameSchemaEnv(s1, s2) {
|
|
8195
8213
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
8196
8214
|
}
|
|
8197
|
-
function
|
|
8215
|
+
function resolve13(root, ref) {
|
|
8198
8216
|
let sch;
|
|
8199
8217
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
8200
8218
|
ref = sch;
|
|
@@ -8724,7 +8742,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
8724
8742
|
}
|
|
8725
8743
|
return uri;
|
|
8726
8744
|
}
|
|
8727
|
-
function
|
|
8745
|
+
function resolve13(baseURI, relativeURI, options) {
|
|
8728
8746
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
8729
8747
|
const resolved = resolveComponent(parse7(baseURI, schemelessOptions), parse7(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
8730
8748
|
schemelessOptions.skipEscape = true;
|
|
@@ -8952,7 +8970,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
8952
8970
|
var fastUri = {
|
|
8953
8971
|
SCHEMES,
|
|
8954
8972
|
normalize: normalize2,
|
|
8955
|
-
resolve:
|
|
8973
|
+
resolve: resolve13,
|
|
8956
8974
|
resolveComponent,
|
|
8957
8975
|
equal,
|
|
8958
8976
|
serialize,
|
|
@@ -11833,12 +11851,12 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
11833
11851
|
if (typeof Promise !== "function") {
|
|
11834
11852
|
throw new TypeError("callback not provided");
|
|
11835
11853
|
}
|
|
11836
|
-
return new Promise(function(
|
|
11854
|
+
return new Promise(function(resolve13, reject) {
|
|
11837
11855
|
isexe(path11, options || {}, function(er, is) {
|
|
11838
11856
|
if (er) {
|
|
11839
11857
|
reject(er);
|
|
11840
11858
|
} else {
|
|
11841
|
-
|
|
11859
|
+
resolve13(is);
|
|
11842
11860
|
}
|
|
11843
11861
|
});
|
|
11844
11862
|
});
|
|
@@ -11900,27 +11918,27 @@ var require_which = __commonJS((exports, module) => {
|
|
|
11900
11918
|
opt = {};
|
|
11901
11919
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
11902
11920
|
const found = [];
|
|
11903
|
-
const step = (i2) => new Promise((
|
|
11921
|
+
const step = (i2) => new Promise((resolve13, reject) => {
|
|
11904
11922
|
if (i2 === pathEnv.length)
|
|
11905
|
-
return opt.all && found.length ?
|
|
11923
|
+
return opt.all && found.length ? resolve13(found) : reject(getNotFoundError(cmd));
|
|
11906
11924
|
const ppRaw = pathEnv[i2];
|
|
11907
11925
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
11908
11926
|
const pCmd = path11.join(pathPart, cmd);
|
|
11909
11927
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
11910
|
-
|
|
11928
|
+
resolve13(subStep(p, i2, 0));
|
|
11911
11929
|
});
|
|
11912
|
-
const subStep = (p, i2, ii) => new Promise((
|
|
11930
|
+
const subStep = (p, i2, ii) => new Promise((resolve13, reject) => {
|
|
11913
11931
|
if (ii === pathExt.length)
|
|
11914
|
-
return
|
|
11932
|
+
return resolve13(step(i2 + 1));
|
|
11915
11933
|
const ext = pathExt[ii];
|
|
11916
11934
|
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
|
|
11917
11935
|
if (!er && is) {
|
|
11918
11936
|
if (opt.all)
|
|
11919
11937
|
found.push(p + ext);
|
|
11920
11938
|
else
|
|
11921
|
-
return
|
|
11939
|
+
return resolve13(p + ext);
|
|
11922
11940
|
}
|
|
11923
|
-
return
|
|
11941
|
+
return resolve13(subStep(p, i2, ii + 1));
|
|
11924
11942
|
});
|
|
11925
11943
|
});
|
|
11926
11944
|
return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
|
|
@@ -12239,7 +12257,7 @@ var COUNTDOWN_SECONDS = 2;
|
|
|
12239
12257
|
var TOAST_DURATION_MS = 900;
|
|
12240
12258
|
var COUNTDOWN_GRACE_PERIOD_MS = 500;
|
|
12241
12259
|
var ABORT_WINDOW_MS = 3000;
|
|
12242
|
-
var CONTINUATION_COOLDOWN_MS =
|
|
12260
|
+
var CONTINUATION_COOLDOWN_MS = 5000;
|
|
12243
12261
|
var MAX_CONSECUTIVE_FAILURES = 5;
|
|
12244
12262
|
var FAILURE_RESET_WINDOW_MS = 5 * 60 * 1000;
|
|
12245
12263
|
// src/features/run-continuation-state/constants.ts
|
|
@@ -17101,14 +17119,15 @@ var AGENT_MODEL_REQUIREMENTS = {
|
|
|
17101
17119
|
},
|
|
17102
17120
|
hephaestus: {
|
|
17103
17121
|
fallbackChain: [
|
|
17104
|
-
{ providers: ["openai", "
|
|
17122
|
+
{ providers: ["openai", "venice", "opencode"], model: "gpt-5.3-codex", variant: "medium" },
|
|
17123
|
+
{ providers: ["github-copilot"], model: "gpt-5.2", variant: "medium" }
|
|
17105
17124
|
],
|
|
17106
|
-
requiresProvider: ["openai", "github-copilot", "opencode"]
|
|
17125
|
+
requiresProvider: ["openai", "github-copilot", "venice", "opencode"]
|
|
17107
17126
|
},
|
|
17108
17127
|
oracle: {
|
|
17109
17128
|
fallbackChain: [
|
|
17110
17129
|
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
|
|
17111
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
|
|
17130
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" },
|
|
17112
17131
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }
|
|
17113
17132
|
]
|
|
17114
17133
|
},
|
|
@@ -17141,7 +17160,7 @@ var AGENT_MODEL_REQUIREMENTS = {
|
|
|
17141
17160
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
|
|
17142
17161
|
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
|
|
17143
17162
|
{ providers: ["opencode"], model: "kimi-k2.5-free" },
|
|
17144
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
|
|
17163
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" }
|
|
17145
17164
|
]
|
|
17146
17165
|
},
|
|
17147
17166
|
metis: {
|
|
@@ -17149,14 +17168,14 @@ var AGENT_MODEL_REQUIREMENTS = {
|
|
|
17149
17168
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
|
|
17150
17169
|
{ providers: ["opencode"], model: "kimi-k2.5-free" },
|
|
17151
17170
|
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
|
|
17152
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
|
|
17171
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" }
|
|
17153
17172
|
]
|
|
17154
17173
|
},
|
|
17155
17174
|
momus: {
|
|
17156
17175
|
fallbackChain: [
|
|
17157
17176
|
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
|
|
17158
17177
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
|
|
17159
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
|
|
17178
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" }
|
|
17160
17179
|
]
|
|
17161
17180
|
},
|
|
17162
17181
|
atlas: {
|
|
@@ -17170,33 +17189,33 @@ var AGENT_MODEL_REQUIREMENTS = {
|
|
|
17170
17189
|
var CATEGORY_MODEL_REQUIREMENTS = {
|
|
17171
17190
|
"visual-engineering": {
|
|
17172
17191
|
fallbackChain: [
|
|
17173
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
|
|
17192
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" },
|
|
17174
17193
|
{ providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
|
|
17175
17194
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }
|
|
17176
17195
|
]
|
|
17177
17196
|
},
|
|
17178
17197
|
ultrabrain: {
|
|
17179
17198
|
fallbackChain: [
|
|
17180
|
-
{ providers: ["openai", "
|
|
17181
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
|
|
17199
|
+
{ providers: ["openai", "opencode"], model: "gpt-5.3-codex", variant: "xhigh" },
|
|
17200
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" },
|
|
17182
17201
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }
|
|
17183
17202
|
]
|
|
17184
17203
|
},
|
|
17185
17204
|
deep: {
|
|
17186
17205
|
fallbackChain: [
|
|
17187
|
-
{ providers: ["openai", "
|
|
17206
|
+
{ providers: ["openai", "opencode"], model: "gpt-5.3-codex", variant: "medium" },
|
|
17188
17207
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
|
|
17189
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
|
|
17208
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" }
|
|
17190
17209
|
],
|
|
17191
17210
|
requiresModel: "gpt-5.3-codex"
|
|
17192
17211
|
},
|
|
17193
17212
|
artistry: {
|
|
17194
17213
|
fallbackChain: [
|
|
17195
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
|
|
17214
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro", variant: "high" },
|
|
17196
17215
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
|
|
17197
17216
|
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
|
|
17198
17217
|
],
|
|
17199
|
-
requiresModel: "gemini-3-pro"
|
|
17218
|
+
requiresModel: "gemini-3.1-pro"
|
|
17200
17219
|
},
|
|
17201
17220
|
quick: {
|
|
17202
17221
|
fallbackChain: [
|
|
@@ -17208,7 +17227,7 @@ var CATEGORY_MODEL_REQUIREMENTS = {
|
|
|
17208
17227
|
"unspecified-low": {
|
|
17209
17228
|
fallbackChain: [
|
|
17210
17229
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
|
|
17211
|
-
{ providers: ["openai", "
|
|
17230
|
+
{ providers: ["openai", "opencode"], model: "gpt-5.3-codex", variant: "medium" },
|
|
17212
17231
|
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
|
|
17213
17232
|
]
|
|
17214
17233
|
},
|
|
@@ -17216,11 +17235,12 @@ var CATEGORY_MODEL_REQUIREMENTS = {
|
|
|
17216
17235
|
fallbackChain: [
|
|
17217
17236
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
|
|
17218
17237
|
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
|
|
17219
|
-
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
|
|
17238
|
+
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" }
|
|
17220
17239
|
]
|
|
17221
17240
|
},
|
|
17222
17241
|
writing: {
|
|
17223
17242
|
fallbackChain: [
|
|
17243
|
+
{ providers: ["opencode"], model: "kimi-k2.5-free" },
|
|
17224
17244
|
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
|
|
17225
17245
|
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" }
|
|
17226
17246
|
]
|
|
@@ -17684,10 +17704,10 @@ function isModelCacheAvailable() {
|
|
|
17684
17704
|
// src/shared/provider-model-id-transform.ts
|
|
17685
17705
|
function transformModelForProvider(provider, model) {
|
|
17686
17706
|
if (provider === "github-copilot") {
|
|
17687
|
-
return model.replace("claude-opus-4-6", "claude-opus-4.6").replace("claude-sonnet-4-6", "claude-sonnet-4.6").replace("claude-sonnet-4-5", "claude-sonnet-4.5").replace("claude-haiku-4-5", "claude-haiku-4.5").replace("claude-sonnet-4", "claude-sonnet-4").replace(/gemini-3-pro(?!-)/g, "gemini-3-pro-preview").replace(/gemini-3-flash(?!-)/g, "gemini-3-flash-preview");
|
|
17707
|
+
return model.replace("claude-opus-4-6", "claude-opus-4.6").replace("claude-sonnet-4-6", "claude-sonnet-4.6").replace("claude-sonnet-4-5", "claude-sonnet-4.5").replace("claude-haiku-4-5", "claude-haiku-4.5").replace("claude-sonnet-4", "claude-sonnet-4").replace(/gemini-3\.1-pro(?!-)/g, "gemini-3.1-pro-preview").replace(/gemini-3-flash(?!-)/g, "gemini-3-flash-preview");
|
|
17688
17708
|
}
|
|
17689
17709
|
if (provider === "google") {
|
|
17690
|
-
return model.replace(/gemini-3-pro(?!-)/g, "gemini-3-pro-preview").replace(/gemini-3-flash(?!-)/g, "gemini-3-flash-preview");
|
|
17710
|
+
return model.replace(/gemini-3\.1-pro(?!-)/g, "gemini-3.1-pro-preview").replace(/gemini-3-flash(?!-)/g, "gemini-3-flash-preview");
|
|
17691
17711
|
}
|
|
17692
17712
|
return model;
|
|
17693
17713
|
}
|
|
@@ -18012,8 +18032,10 @@ function isAnyProviderConnected(providers, availableModels) {
|
|
|
18012
18032
|
}
|
|
18013
18033
|
// src/features/hook-message-injector/injector.ts
|
|
18014
18034
|
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync7, readdirSync, writeFileSync as writeFileSync4 } from "fs";
|
|
18035
|
+
import { randomBytes } from "crypto";
|
|
18015
18036
|
import { join as join12 } from "path";
|
|
18016
18037
|
init_logger();
|
|
18038
|
+
var processPrefix = randomBytes(4).toString("hex");
|
|
18017
18039
|
function convertSDKMessageToStoredMessage(msg) {
|
|
18018
18040
|
const info = msg.info;
|
|
18019
18041
|
if (!info)
|
|
@@ -18545,6 +18567,42 @@ async function enforceMainPaneWidth(mainPaneId, windowWidth, mainPaneSizeOrOptio
|
|
|
18545
18567
|
}
|
|
18546
18568
|
// src/shared/model-suggestion-retry.ts
|
|
18547
18569
|
init_logger();
|
|
18570
|
+
|
|
18571
|
+
// src/shared/prompt-timeout-context.ts
|
|
18572
|
+
var PROMPT_TIMEOUT_MS = 120000;
|
|
18573
|
+
function createPromptTimeoutContext(args, timeoutMs) {
|
|
18574
|
+
const timeoutController = new AbortController;
|
|
18575
|
+
let timeoutID = null;
|
|
18576
|
+
let timedOut = false;
|
|
18577
|
+
const abortOnUpstreamSignal = () => {
|
|
18578
|
+
timeoutController.abort(args.signal?.reason);
|
|
18579
|
+
};
|
|
18580
|
+
if (args.signal) {
|
|
18581
|
+
if (args.signal.aborted) {
|
|
18582
|
+
timeoutController.abort(args.signal.reason);
|
|
18583
|
+
} else {
|
|
18584
|
+
args.signal.addEventListener("abort", abortOnUpstreamSignal, { once: true });
|
|
18585
|
+
}
|
|
18586
|
+
}
|
|
18587
|
+
timeoutID = setTimeout(() => {
|
|
18588
|
+
timedOut = true;
|
|
18589
|
+
timeoutController.abort(new Error(`prompt timed out after ${timeoutMs}ms`));
|
|
18590
|
+
}, timeoutMs);
|
|
18591
|
+
return {
|
|
18592
|
+
signal: timeoutController.signal,
|
|
18593
|
+
wasTimedOut: () => timedOut,
|
|
18594
|
+
cleanup: () => {
|
|
18595
|
+
if (timeoutID !== null) {
|
|
18596
|
+
clearTimeout(timeoutID);
|
|
18597
|
+
}
|
|
18598
|
+
if (args.signal) {
|
|
18599
|
+
args.signal.removeEventListener("abort", abortOnUpstreamSignal);
|
|
18600
|
+
}
|
|
18601
|
+
}
|
|
18602
|
+
};
|
|
18603
|
+
}
|
|
18604
|
+
|
|
18605
|
+
// src/shared/model-suggestion-retry.ts
|
|
18548
18606
|
function extractMessage(error) {
|
|
18549
18607
|
if (typeof error === "string")
|
|
18550
18608
|
return error;
|
|
@@ -18602,24 +18660,47 @@ function parseModelSuggestion(error) {
|
|
|
18602
18660
|
}
|
|
18603
18661
|
return null;
|
|
18604
18662
|
}
|
|
18605
|
-
async function promptWithModelSuggestionRetry(client, args) {
|
|
18606
|
-
const
|
|
18607
|
-
|
|
18608
|
-
const
|
|
18609
|
-
|
|
18610
|
-
|
|
18611
|
-
}, 120000);
|
|
18663
|
+
async function promptWithModelSuggestionRetry(client, args, options = {}) {
|
|
18664
|
+
const timeoutMs = options.timeoutMs ?? PROMPT_TIMEOUT_MS;
|
|
18665
|
+
const timeoutContext = createPromptTimeoutContext(args, timeoutMs);
|
|
18666
|
+
const promptPromise = client.session.promptAsync({
|
|
18667
|
+
...args,
|
|
18668
|
+
signal: timeoutContext.signal
|
|
18612
18669
|
});
|
|
18613
18670
|
try {
|
|
18614
|
-
await
|
|
18671
|
+
await promptPromise;
|
|
18672
|
+
if (timeoutContext.wasTimedOut()) {
|
|
18673
|
+
throw new Error(`promptAsync timed out after ${timeoutMs}ms`);
|
|
18674
|
+
}
|
|
18675
|
+
} catch (error) {
|
|
18676
|
+
if (timeoutContext.wasTimedOut()) {
|
|
18677
|
+
throw new Error(`promptAsync timed out after ${timeoutMs}ms`);
|
|
18678
|
+
}
|
|
18679
|
+
throw error;
|
|
18615
18680
|
} finally {
|
|
18616
|
-
|
|
18617
|
-
clearTimeout(timeoutID);
|
|
18681
|
+
timeoutContext.cleanup();
|
|
18618
18682
|
}
|
|
18619
18683
|
}
|
|
18620
|
-
async function promptSyncWithModelSuggestionRetry(client, args) {
|
|
18684
|
+
async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
|
|
18685
|
+
const timeoutMs = options.timeoutMs ?? PROMPT_TIMEOUT_MS;
|
|
18621
18686
|
try {
|
|
18622
|
-
|
|
18687
|
+
const timeoutContext = createPromptTimeoutContext(args, timeoutMs);
|
|
18688
|
+
try {
|
|
18689
|
+
await client.session.prompt({
|
|
18690
|
+
...args,
|
|
18691
|
+
signal: timeoutContext.signal
|
|
18692
|
+
});
|
|
18693
|
+
if (timeoutContext.wasTimedOut()) {
|
|
18694
|
+
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
18695
|
+
}
|
|
18696
|
+
} catch (error) {
|
|
18697
|
+
if (timeoutContext.wasTimedOut()) {
|
|
18698
|
+
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
18699
|
+
}
|
|
18700
|
+
throw error;
|
|
18701
|
+
} finally {
|
|
18702
|
+
timeoutContext.cleanup();
|
|
18703
|
+
}
|
|
18623
18704
|
} catch (error) {
|
|
18624
18705
|
const suggestion = parseModelSuggestion(error);
|
|
18625
18706
|
if (!suggestion || !args.body.model) {
|
|
@@ -18629,7 +18710,7 @@ async function promptSyncWithModelSuggestionRetry(client, args) {
|
|
|
18629
18710
|
original: `${suggestion.providerID}/${suggestion.modelID}`,
|
|
18630
18711
|
suggested: suggestion.suggestion
|
|
18631
18712
|
});
|
|
18632
|
-
|
|
18713
|
+
const retryArgs = {
|
|
18633
18714
|
...args,
|
|
18634
18715
|
body: {
|
|
18635
18716
|
...args.body,
|
|
@@ -18638,7 +18719,24 @@ async function promptSyncWithModelSuggestionRetry(client, args) {
|
|
|
18638
18719
|
modelID: suggestion.suggestion
|
|
18639
18720
|
}
|
|
18640
18721
|
}
|
|
18641
|
-
}
|
|
18722
|
+
};
|
|
18723
|
+
const timeoutContext = createPromptTimeoutContext(retryArgs, timeoutMs);
|
|
18724
|
+
try {
|
|
18725
|
+
await client.session.prompt({
|
|
18726
|
+
...retryArgs,
|
|
18727
|
+
signal: timeoutContext.signal
|
|
18728
|
+
});
|
|
18729
|
+
if (timeoutContext.wasTimedOut()) {
|
|
18730
|
+
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
18731
|
+
}
|
|
18732
|
+
} catch (retryError) {
|
|
18733
|
+
if (timeoutContext.wasTimedOut()) {
|
|
18734
|
+
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
18735
|
+
}
|
|
18736
|
+
throw retryError;
|
|
18737
|
+
} finally {
|
|
18738
|
+
timeoutContext.cleanup();
|
|
18739
|
+
}
|
|
18642
18740
|
}
|
|
18643
18741
|
}
|
|
18644
18742
|
// src/shared/opencode-server-auth.ts
|
|
@@ -19159,9 +19257,31 @@ function isLastAssistantMessageAborted(messages) {
|
|
|
19159
19257
|
return errorName === "MessageAbortedError" || errorName === "AbortError";
|
|
19160
19258
|
}
|
|
19161
19259
|
|
|
19260
|
+
// src/hooks/todo-continuation-enforcer/pending-question-detection.ts
|
|
19261
|
+
init_logger();
|
|
19262
|
+
function hasUnansweredQuestion(messages) {
|
|
19263
|
+
if (!messages || messages.length === 0)
|
|
19264
|
+
return false;
|
|
19265
|
+
for (let i2 = messages.length - 1;i2 >= 0; i2--) {
|
|
19266
|
+
const msg = messages[i2];
|
|
19267
|
+
const role = msg.info?.role ?? msg.role;
|
|
19268
|
+
if (role === "user")
|
|
19269
|
+
return false;
|
|
19270
|
+
if (role === "assistant" && msg.parts) {
|
|
19271
|
+
const hasQuestion = msg.parts.some((part) => (part.type === "tool_use" || part.type === "tool-invocation") && (part.name === "question" || part.toolName === "question"));
|
|
19272
|
+
if (hasQuestion) {
|
|
19273
|
+
log(`[${HOOK_NAME}] Detected pending question tool in last assistant message`);
|
|
19274
|
+
return true;
|
|
19275
|
+
}
|
|
19276
|
+
return false;
|
|
19277
|
+
}
|
|
19278
|
+
}
|
|
19279
|
+
return false;
|
|
19280
|
+
}
|
|
19281
|
+
|
|
19162
19282
|
// src/hooks/todo-continuation-enforcer/todo.ts
|
|
19163
19283
|
function getIncompleteCount(todos) {
|
|
19164
|
-
return todos.filter((todo) => todo.status !== "completed" && todo.status !== "cancelled").length;
|
|
19284
|
+
return todos.filter((todo) => todo.status !== "completed" && todo.status !== "cancelled" && todo.status !== "blocked" && todo.status !== "deleted").length;
|
|
19165
19285
|
}
|
|
19166
19286
|
|
|
19167
19287
|
// src/hooks/todo-continuation-enforcer/countdown.ts
|
|
@@ -19377,6 +19497,10 @@ async function handleSessionIdle(args) {
|
|
|
19377
19497
|
log(`[${HOOK_NAME}] Skipped: last assistant message was aborted (API fallback)`, { sessionID });
|
|
19378
19498
|
return;
|
|
19379
19499
|
}
|
|
19500
|
+
if (hasUnansweredQuestion(messages)) {
|
|
19501
|
+
log(`[${HOOK_NAME}] Skipped: pending question awaiting user response`, { sessionID });
|
|
19502
|
+
return;
|
|
19503
|
+
}
|
|
19380
19504
|
} catch (error) {
|
|
19381
19505
|
log(`[${HOOK_NAME}] Messages fetch failed, continuing`, { sessionID, error: String(error) });
|
|
19382
19506
|
}
|
|
@@ -20103,6 +20227,7 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
20103
20227
|
idleConfirmationDelay: 1500,
|
|
20104
20228
|
skipIfIncompleteTodos: true,
|
|
20105
20229
|
maxTrackedSessions: 100,
|
|
20230
|
+
enforceMainSessionFilter: true,
|
|
20106
20231
|
...config
|
|
20107
20232
|
};
|
|
20108
20233
|
const scheduler = createIdleNotificationScheduler({
|
|
@@ -20135,9 +20260,11 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
20135
20260
|
const shouldNotifyForSession = (sessionID) => {
|
|
20136
20261
|
if (subagentSessions.has(sessionID))
|
|
20137
20262
|
return false;
|
|
20138
|
-
|
|
20139
|
-
|
|
20140
|
-
|
|
20263
|
+
if (mergedConfig.enforceMainSessionFilter) {
|
|
20264
|
+
const mainSessionID = getMainSessionID();
|
|
20265
|
+
if (mainSessionID && sessionID !== mainSessionID)
|
|
20266
|
+
return false;
|
|
20267
|
+
}
|
|
20141
20268
|
return true;
|
|
20142
20269
|
};
|
|
20143
20270
|
const getEventToolName = (properties) => {
|
|
@@ -34526,7 +34653,7 @@ var TRUNCATE_CONFIG = {
|
|
|
34526
34653
|
function getOrCreateRetryState(autoCompactState, sessionID) {
|
|
34527
34654
|
let state2 = autoCompactState.retryStateBySession.get(sessionID);
|
|
34528
34655
|
if (!state2) {
|
|
34529
|
-
state2 = { attempt: 0, lastAttemptTime: 0 };
|
|
34656
|
+
state2 = { attempt: 0, lastAttemptTime: 0, firstAttemptTime: 0 };
|
|
34530
34657
|
autoCompactState.retryStateBySession.set(sessionID, state2);
|
|
34531
34658
|
}
|
|
34532
34659
|
return state2;
|
|
@@ -35222,8 +35349,26 @@ function resolveCompactionModel(pluginConfig, sessionID, originalProviderID, ori
|
|
|
35222
35349
|
}
|
|
35223
35350
|
|
|
35224
35351
|
// src/hooks/anthropic-context-window-limit-recovery/summarize-retry-strategy.ts
|
|
35352
|
+
var SUMMARIZE_RETRY_TOTAL_TIMEOUT_MS = 120000;
|
|
35225
35353
|
async function runSummarizeRetryStrategy(params) {
|
|
35226
35354
|
const retryState = getOrCreateRetryState(params.autoCompactState, params.sessionID);
|
|
35355
|
+
const now = Date.now();
|
|
35356
|
+
if (retryState.firstAttemptTime === 0) {
|
|
35357
|
+
retryState.firstAttemptTime = now;
|
|
35358
|
+
}
|
|
35359
|
+
const elapsedTimeMs = now - retryState.firstAttemptTime;
|
|
35360
|
+
if (elapsedTimeMs >= SUMMARIZE_RETRY_TOTAL_TIMEOUT_MS) {
|
|
35361
|
+
clearSessionState(params.autoCompactState, params.sessionID);
|
|
35362
|
+
await params.client.tui.showToast({
|
|
35363
|
+
body: {
|
|
35364
|
+
title: "Auto Compact Timed Out",
|
|
35365
|
+
message: "Compaction retries exceeded the timeout window. Please start a new session.",
|
|
35366
|
+
variant: "error",
|
|
35367
|
+
duration: 5000
|
|
35368
|
+
}
|
|
35369
|
+
}).catch(() => {});
|
|
35370
|
+
return;
|
|
35371
|
+
}
|
|
35227
35372
|
if (params.errorType?.includes("non-empty content")) {
|
|
35228
35373
|
const attempt = getEmptyContentAttempt(params.autoCompactState, params.sessionID);
|
|
35229
35374
|
if (attempt < 3) {
|
|
@@ -35253,6 +35398,7 @@ async function runSummarizeRetryStrategy(params) {
|
|
|
35253
35398
|
}
|
|
35254
35399
|
if (Date.now() - retryState.lastAttemptTime > 300000) {
|
|
35255
35400
|
retryState.attempt = 0;
|
|
35401
|
+
retryState.firstAttemptTime = Date.now();
|
|
35256
35402
|
params.autoCompactState.truncateStateBySession.delete(params.sessionID);
|
|
35257
35403
|
}
|
|
35258
35404
|
if (retryState.attempt < RETRY_CONFIG.maxAttempts) {
|
|
@@ -35280,8 +35426,21 @@ async function runSummarizeRetryStrategy(params) {
|
|
|
35280
35426
|
});
|
|
35281
35427
|
return;
|
|
35282
35428
|
} catch {
|
|
35429
|
+
const remainingTimeMs = SUMMARIZE_RETRY_TOTAL_TIMEOUT_MS - (Date.now() - retryState.firstAttemptTime);
|
|
35430
|
+
if (remainingTimeMs <= 0) {
|
|
35431
|
+
clearSessionState(params.autoCompactState, params.sessionID);
|
|
35432
|
+
await params.client.tui.showToast({
|
|
35433
|
+
body: {
|
|
35434
|
+
title: "Auto Compact Timed Out",
|
|
35435
|
+
message: "Compaction retries exceeded the timeout window. Please start a new session.",
|
|
35436
|
+
variant: "error",
|
|
35437
|
+
duration: 5000
|
|
35438
|
+
}
|
|
35439
|
+
}).catch(() => {});
|
|
35440
|
+
return;
|
|
35441
|
+
}
|
|
35283
35442
|
const delay3 = RETRY_CONFIG.initialDelayMs * Math.pow(RETRY_CONFIG.backoffFactor, retryState.attempt - 1);
|
|
35284
|
-
const cappedDelay = Math.min(delay3, RETRY_CONFIG.maxDelayMs);
|
|
35443
|
+
const cappedDelay = Math.min(delay3, RETRY_CONFIG.maxDelayMs, remainingTimeMs);
|
|
35285
35444
|
setTimeout(() => {
|
|
35286
35445
|
runSummarizeRetryStrategy(params);
|
|
35287
35446
|
}, cappedDelay);
|
|
@@ -35877,24 +36036,11 @@ function extractModelPrefix(modelID) {
|
|
|
35877
36036
|
function normalizeModelID(modelID) {
|
|
35878
36037
|
return modelID.replace(/\.(\d+)/g, "-$1");
|
|
35879
36038
|
}
|
|
35880
|
-
function resolveProvider(providerID, modelID) {
|
|
35881
|
-
if (providerID === "github-copilot") {
|
|
35882
|
-
const modelLower = modelID.toLowerCase();
|
|
35883
|
-
if (modelLower.includes("claude"))
|
|
35884
|
-
return "anthropic";
|
|
35885
|
-
if (modelLower.includes("gemini"))
|
|
35886
|
-
return "google";
|
|
35887
|
-
if (modelLower.includes("gpt") || modelLower.includes("o1") || modelLower.includes("o3")) {
|
|
35888
|
-
return "openai";
|
|
35889
|
-
}
|
|
35890
|
-
}
|
|
35891
|
-
return providerID;
|
|
35892
|
-
}
|
|
35893
36039
|
var HIGH_VARIANT_MAP = {
|
|
35894
36040
|
"claude-sonnet-4-6": "claude-sonnet-4-6-high",
|
|
35895
36041
|
"claude-opus-4-6": "claude-opus-4-6-high",
|
|
35896
|
-
"gemini-3-pro": "gemini-3-pro-high",
|
|
35897
|
-
"gemini-3-pro-low": "gemini-3-pro-high",
|
|
36042
|
+
"gemini-3-1-pro": "gemini-3-1-pro-high",
|
|
36043
|
+
"gemini-3-1-pro-low": "gemini-3-1-pro-high",
|
|
35898
36044
|
"gemini-3-flash": "gemini-3-flash-high",
|
|
35899
36045
|
"gpt-5": "gpt-5-high",
|
|
35900
36046
|
"gpt-5-mini": "gpt-5-mini-high",
|
|
@@ -35909,74 +36055,10 @@ var HIGH_VARIANT_MAP = {
|
|
|
35909
36055
|
"gpt-5-2": "gpt-5-2-high",
|
|
35910
36056
|
"gpt-5-2-chat-latest": "gpt-5-2-chat-latest-high",
|
|
35911
36057
|
"gpt-5-2-pro": "gpt-5-2-pro-high",
|
|
35912
|
-
"antigravity-gemini-3-pro": "antigravity-gemini-3-pro-high",
|
|
36058
|
+
"antigravity-gemini-3-1-pro": "antigravity-gemini-3-1-pro-high",
|
|
35913
36059
|
"antigravity-gemini-3-flash": "antigravity-gemini-3-flash-high"
|
|
35914
36060
|
};
|
|
35915
36061
|
var ALREADY_HIGH = new Set(Object.values(HIGH_VARIANT_MAP));
|
|
35916
|
-
var THINKING_CONFIGS = {
|
|
35917
|
-
anthropic: {
|
|
35918
|
-
thinking: {
|
|
35919
|
-
type: "enabled",
|
|
35920
|
-
budgetTokens: 64000
|
|
35921
|
-
},
|
|
35922
|
-
maxTokens: 128000
|
|
35923
|
-
},
|
|
35924
|
-
"google-vertex-anthropic": {
|
|
35925
|
-
thinking: {
|
|
35926
|
-
type: "enabled",
|
|
35927
|
-
budgetTokens: 64000
|
|
35928
|
-
},
|
|
35929
|
-
maxTokens: 128000
|
|
35930
|
-
},
|
|
35931
|
-
"amazon-bedrock": {
|
|
35932
|
-
reasoningConfig: {
|
|
35933
|
-
type: "enabled",
|
|
35934
|
-
budgetTokens: 32000
|
|
35935
|
-
},
|
|
35936
|
-
maxTokens: 64000
|
|
35937
|
-
},
|
|
35938
|
-
google: {
|
|
35939
|
-
providerOptions: {
|
|
35940
|
-
google: {
|
|
35941
|
-
thinkingConfig: {
|
|
35942
|
-
thinkingLevel: "HIGH"
|
|
35943
|
-
}
|
|
35944
|
-
}
|
|
35945
|
-
}
|
|
35946
|
-
},
|
|
35947
|
-
"google-vertex": {
|
|
35948
|
-
providerOptions: {
|
|
35949
|
-
"google-vertex": {
|
|
35950
|
-
thinkingConfig: {
|
|
35951
|
-
thinkingLevel: "HIGH"
|
|
35952
|
-
}
|
|
35953
|
-
}
|
|
35954
|
-
}
|
|
35955
|
-
},
|
|
35956
|
-
openai: {
|
|
35957
|
-
reasoning_effort: "high"
|
|
35958
|
-
},
|
|
35959
|
-
"zai-coding-plan": {
|
|
35960
|
-
providerOptions: {
|
|
35961
|
-
"zai-coding-plan": {
|
|
35962
|
-
extra_body: {
|
|
35963
|
-
thinking: {
|
|
35964
|
-
type: "disabled"
|
|
35965
|
-
}
|
|
35966
|
-
}
|
|
35967
|
-
}
|
|
35968
|
-
}
|
|
35969
|
-
}
|
|
35970
|
-
};
|
|
35971
|
-
var THINKING_CAPABLE_MODELS = {
|
|
35972
|
-
anthropic: ["claude-sonnet-4", "claude-opus-4", "claude-3"],
|
|
35973
|
-
"google-vertex-anthropic": ["claude-sonnet-4", "claude-opus-4", "claude-3"],
|
|
35974
|
-
"amazon-bedrock": ["claude", "anthropic"],
|
|
35975
|
-
google: ["gemini-2", "gemini-3"],
|
|
35976
|
-
"google-vertex": ["gemini-2", "gemini-3"],
|
|
35977
|
-
openai: ["gpt-5", "o1", "o3"],
|
|
35978
|
-
"zai-coding-plan": ["glm"]
|
|
35979
|
-
};
|
|
35980
36062
|
function getHighVariant(modelID) {
|
|
35981
36063
|
const normalized = normalizeModelID(modelID);
|
|
35982
36064
|
const { prefix, base } = extractModelPrefix(normalized);
|
|
@@ -35994,65 +36076,28 @@ function isAlreadyHighVariant(modelID) {
|
|
|
35994
36076
|
const { base } = extractModelPrefix(normalized);
|
|
35995
36077
|
return ALREADY_HIGH.has(base) || base.endsWith("-high");
|
|
35996
36078
|
}
|
|
35997
|
-
function isThinkingProvider(provider) {
|
|
35998
|
-
return provider in THINKING_CONFIGS;
|
|
35999
|
-
}
|
|
36000
|
-
function getThinkingConfig(providerID, modelID) {
|
|
36001
|
-
const normalized = normalizeModelID(modelID);
|
|
36002
|
-
const { base } = extractModelPrefix(normalized);
|
|
36003
|
-
if (isAlreadyHighVariant(normalized)) {
|
|
36004
|
-
return null;
|
|
36005
|
-
}
|
|
36006
|
-
const resolvedProvider = resolveProvider(providerID, modelID);
|
|
36007
|
-
if (!isThinkingProvider(resolvedProvider)) {
|
|
36008
|
-
return null;
|
|
36009
|
-
}
|
|
36010
|
-
const config2 = THINKING_CONFIGS[resolvedProvider];
|
|
36011
|
-
const capablePatterns = THINKING_CAPABLE_MODELS[resolvedProvider];
|
|
36012
|
-
const baseLower = base.toLowerCase();
|
|
36013
|
-
const isCapable = capablePatterns.some((pattern) => baseLower.includes(pattern.toLowerCase()));
|
|
36014
|
-
return isCapable ? config2 : null;
|
|
36015
|
-
}
|
|
36016
36079
|
// src/hooks/think-mode/hook.ts
|
|
36017
36080
|
var thinkModeState = new Map;
|
|
36018
36081
|
function createThinkModeHook() {
|
|
36019
|
-
function isDisabledThinkingConfig(config2) {
|
|
36020
|
-
const thinkingConfig = config2.thinking;
|
|
36021
|
-
if (typeof thinkingConfig === "object" && thinkingConfig !== null && "type" in thinkingConfig && thinkingConfig.type === "disabled") {
|
|
36022
|
-
return true;
|
|
36023
|
-
}
|
|
36024
|
-
const providerOptions = config2.providerOptions;
|
|
36025
|
-
if (typeof providerOptions !== "object" || providerOptions === null) {
|
|
36026
|
-
return false;
|
|
36027
|
-
}
|
|
36028
|
-
return Object.values(providerOptions).some((providerConfig) => {
|
|
36029
|
-
if (typeof providerConfig !== "object" || providerConfig === null) {
|
|
36030
|
-
return false;
|
|
36031
|
-
}
|
|
36032
|
-
const providerConfigMap = providerConfig;
|
|
36033
|
-
const extraBody = providerConfigMap.extra_body;
|
|
36034
|
-
if (typeof extraBody !== "object" || extraBody === null) {
|
|
36035
|
-
return false;
|
|
36036
|
-
}
|
|
36037
|
-
const extraBodyMap = extraBody;
|
|
36038
|
-
const extraThinking = extraBodyMap.thinking;
|
|
36039
|
-
return typeof extraThinking === "object" && extraThinking !== null && extraThinking.type === "disabled";
|
|
36040
|
-
});
|
|
36041
|
-
}
|
|
36042
36082
|
return {
|
|
36043
|
-
"chat.
|
|
36083
|
+
"chat.message": async (input, output) => {
|
|
36044
36084
|
const promptText = extractPromptText(output.parts);
|
|
36085
|
+
const sessionID = input.sessionID;
|
|
36045
36086
|
const state3 = {
|
|
36046
36087
|
requested: false,
|
|
36047
36088
|
modelSwitched: false,
|
|
36048
|
-
|
|
36089
|
+
variantSet: false
|
|
36049
36090
|
};
|
|
36050
36091
|
if (!detectThinkKeyword(promptText)) {
|
|
36051
36092
|
thinkModeState.set(sessionID, state3);
|
|
36052
36093
|
return;
|
|
36053
36094
|
}
|
|
36054
36095
|
state3.requested = true;
|
|
36055
|
-
|
|
36096
|
+
if (typeof output.message.variant === "string") {
|
|
36097
|
+
thinkModeState.set(sessionID, state3);
|
|
36098
|
+
return;
|
|
36099
|
+
}
|
|
36100
|
+
const currentModel = input.model;
|
|
36056
36101
|
if (!currentModel) {
|
|
36057
36102
|
thinkModeState.set(sessionID, state3);
|
|
36058
36103
|
return;
|
|
@@ -36064,50 +36109,20 @@ function createThinkModeHook() {
|
|
|
36064
36109
|
return;
|
|
36065
36110
|
}
|
|
36066
36111
|
const highVariant = getHighVariant(currentModel.modelID);
|
|
36067
|
-
const thinkingConfig = getThinkingConfig(currentModel.providerID, currentModel.modelID);
|
|
36068
36112
|
if (highVariant) {
|
|
36069
36113
|
output.message.model = {
|
|
36070
36114
|
providerID: currentModel.providerID,
|
|
36071
36115
|
modelID: highVariant
|
|
36072
36116
|
};
|
|
36117
|
+
output.message.variant = "high";
|
|
36073
36118
|
state3.modelSwitched = true;
|
|
36119
|
+
state3.variantSet = true;
|
|
36074
36120
|
log("Think mode: model switched to high variant", {
|
|
36075
36121
|
sessionID,
|
|
36076
36122
|
from: currentModel.modelID,
|
|
36077
36123
|
to: highVariant
|
|
36078
36124
|
});
|
|
36079
36125
|
}
|
|
36080
|
-
if (thinkingConfig) {
|
|
36081
|
-
const messageData = output.message;
|
|
36082
|
-
const agentThinking = messageData.thinking;
|
|
36083
|
-
const agentProviderOptions = messageData.providerOptions;
|
|
36084
|
-
const agentDisabledThinking = agentThinking?.type === "disabled";
|
|
36085
|
-
const agentHasCustomProviderOptions = Boolean(agentProviderOptions);
|
|
36086
|
-
if (agentDisabledThinking) {
|
|
36087
|
-
log("Think mode: skipping - agent has thinking disabled", {
|
|
36088
|
-
sessionID,
|
|
36089
|
-
provider: currentModel.providerID
|
|
36090
|
-
});
|
|
36091
|
-
} else if (agentHasCustomProviderOptions) {
|
|
36092
|
-
log("Think mode: skipping - agent has custom providerOptions", {
|
|
36093
|
-
sessionID,
|
|
36094
|
-
provider: currentModel.providerID
|
|
36095
|
-
});
|
|
36096
|
-
} else if (!isDisabledThinkingConfig(thinkingConfig)) {
|
|
36097
|
-
Object.assign(output.message, thinkingConfig);
|
|
36098
|
-
state3.thinkingConfigInjected = true;
|
|
36099
|
-
log("Think mode: thinking config injected", {
|
|
36100
|
-
sessionID,
|
|
36101
|
-
provider: currentModel.providerID,
|
|
36102
|
-
config: thinkingConfig
|
|
36103
|
-
});
|
|
36104
|
-
} else {
|
|
36105
|
-
log("Think mode: skipping disabled thinking config", {
|
|
36106
|
-
sessionID,
|
|
36107
|
-
provider: currentModel.providerID
|
|
36108
|
-
});
|
|
36109
|
-
}
|
|
36110
|
-
}
|
|
36111
36126
|
thinkModeState.set(sessionID, state3);
|
|
36112
36127
|
},
|
|
36113
36128
|
event: async ({ event }) => {
|
|
@@ -36652,6 +36667,76 @@ function isHookCommandDisabled(eventType, command, config2) {
|
|
|
36652
36667
|
});
|
|
36653
36668
|
}
|
|
36654
36669
|
|
|
36670
|
+
// src/hooks/claude-code-hooks/execute-http-hook.ts
|
|
36671
|
+
var DEFAULT_HTTP_HOOK_TIMEOUT_S = 30;
|
|
36672
|
+
var ALLOWED_SCHEMES = new Set(["http:", "https:"]);
|
|
36673
|
+
function interpolateEnvVars(value, allowedEnvVars) {
|
|
36674
|
+
const allowedSet = new Set(allowedEnvVars);
|
|
36675
|
+
return value.replace(/\$\{(\w+)\}|\$(\w+)/g, (_match, bracedVar, bareVar) => {
|
|
36676
|
+
const varName = bracedVar ?? bareVar;
|
|
36677
|
+
if (allowedSet.has(varName)) {
|
|
36678
|
+
return process.env[varName] ?? "";
|
|
36679
|
+
}
|
|
36680
|
+
return "";
|
|
36681
|
+
});
|
|
36682
|
+
}
|
|
36683
|
+
function resolveHeaders(hook) {
|
|
36684
|
+
const headers = {
|
|
36685
|
+
"Content-Type": "application/json"
|
|
36686
|
+
};
|
|
36687
|
+
if (!hook.headers)
|
|
36688
|
+
return headers;
|
|
36689
|
+
const allowedEnvVars = hook.allowedEnvVars ?? [];
|
|
36690
|
+
for (const [key, value] of Object.entries(hook.headers)) {
|
|
36691
|
+
headers[key] = interpolateEnvVars(value, allowedEnvVars);
|
|
36692
|
+
}
|
|
36693
|
+
return headers;
|
|
36694
|
+
}
|
|
36695
|
+
async function executeHttpHook(hook, stdin) {
|
|
36696
|
+
try {
|
|
36697
|
+
const parsed = new URL(hook.url);
|
|
36698
|
+
if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
|
|
36699
|
+
return {
|
|
36700
|
+
exitCode: 1,
|
|
36701
|
+
stderr: `HTTP hook URL scheme "${parsed.protocol}" is not allowed. Only http: and https: are permitted.`
|
|
36702
|
+
};
|
|
36703
|
+
}
|
|
36704
|
+
} catch {
|
|
36705
|
+
return { exitCode: 1, stderr: `HTTP hook URL is invalid: ${hook.url}` };
|
|
36706
|
+
}
|
|
36707
|
+
const timeoutS = hook.timeout ?? DEFAULT_HTTP_HOOK_TIMEOUT_S;
|
|
36708
|
+
const headers = resolveHeaders(hook);
|
|
36709
|
+
try {
|
|
36710
|
+
const response = await fetch(hook.url, {
|
|
36711
|
+
method: "POST",
|
|
36712
|
+
headers,
|
|
36713
|
+
body: stdin,
|
|
36714
|
+
signal: AbortSignal.timeout(timeoutS * 1000)
|
|
36715
|
+
});
|
|
36716
|
+
if (!response.ok) {
|
|
36717
|
+
return {
|
|
36718
|
+
exitCode: 1,
|
|
36719
|
+
stderr: `HTTP hook returned status ${response.status}: ${response.statusText}`,
|
|
36720
|
+
stdout: await response.text().catch(() => "")
|
|
36721
|
+
};
|
|
36722
|
+
}
|
|
36723
|
+
const body = await response.text();
|
|
36724
|
+
if (!body) {
|
|
36725
|
+
return { exitCode: 0, stdout: "", stderr: "" };
|
|
36726
|
+
}
|
|
36727
|
+
try {
|
|
36728
|
+
const parsed = JSON.parse(body);
|
|
36729
|
+
if (typeof parsed.exitCode === "number") {
|
|
36730
|
+
return { exitCode: parsed.exitCode, stdout: body, stderr: "" };
|
|
36731
|
+
}
|
|
36732
|
+
} catch {}
|
|
36733
|
+
return { exitCode: 0, stdout: body, stderr: "" };
|
|
36734
|
+
} catch (error45) {
|
|
36735
|
+
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
36736
|
+
return { exitCode: 1, stderr: `HTTP hook error: ${message}` };
|
|
36737
|
+
}
|
|
36738
|
+
}
|
|
36739
|
+
|
|
36655
36740
|
// src/hooks/claude-code-hooks/plugin-config.ts
|
|
36656
36741
|
var isWindows = process.platform === "win32";
|
|
36657
36742
|
var DEFAULT_CONFIG = {
|
|
@@ -36659,6 +36744,19 @@ var DEFAULT_CONFIG = {
|
|
|
36659
36744
|
zshPath: "/bin/zsh"
|
|
36660
36745
|
};
|
|
36661
36746
|
|
|
36747
|
+
// src/hooks/claude-code-hooks/dispatch-hook.ts
|
|
36748
|
+
function getHookIdentifier(hook) {
|
|
36749
|
+
if (hook.type === "http")
|
|
36750
|
+
return hook.url;
|
|
36751
|
+
return hook.command.split("/").pop() || hook.command;
|
|
36752
|
+
}
|
|
36753
|
+
async function dispatchHook(hook, stdinJson, cwd) {
|
|
36754
|
+
if (hook.type === "http") {
|
|
36755
|
+
return executeHttpHook(hook, stdinJson);
|
|
36756
|
+
}
|
|
36757
|
+
return executeHookCommand(hook.command, stdinJson, cwd, { forceZsh: DEFAULT_CONFIG.forceZsh, zshPath: DEFAULT_CONFIG.zshPath });
|
|
36758
|
+
}
|
|
36759
|
+
|
|
36662
36760
|
// src/hooks/claude-code-hooks/user-prompt-submit.ts
|
|
36663
36761
|
var USER_PROMPT_SUBMIT_TAG_OPEN = "<user-prompt-submit-hook>";
|
|
36664
36762
|
var USER_PROMPT_SUBMIT_TAG_CLOSE = "</user-prompt-submit-hook>";
|
|
@@ -36693,13 +36791,14 @@ async function executeUserPromptSubmitHooks(ctx, config2, extendedConfig) {
|
|
|
36693
36791
|
if (!matcher.hooks || matcher.hooks.length === 0)
|
|
36694
36792
|
continue;
|
|
36695
36793
|
for (const hook of matcher.hooks) {
|
|
36696
|
-
if (hook.type !== "command")
|
|
36794
|
+
if (hook.type !== "command" && hook.type !== "http")
|
|
36697
36795
|
continue;
|
|
36698
|
-
|
|
36699
|
-
|
|
36796
|
+
const hookName = getHookIdentifier(hook);
|
|
36797
|
+
if (isHookCommandDisabled("UserPromptSubmit", hookName, extendedConfig ?? null)) {
|
|
36798
|
+
log("UserPromptSubmit hook command skipped (disabled by config)", { command: hookName });
|
|
36700
36799
|
continue;
|
|
36701
36800
|
}
|
|
36702
|
-
const result = await
|
|
36801
|
+
const result = await dispatchHook(hook, JSON.stringify(stdinData), ctx.cwd);
|
|
36703
36802
|
if (result.stdout) {
|
|
36704
36803
|
const output = result.stdout.trim();
|
|
36705
36804
|
if (output.startsWith(USER_PROMPT_SUBMIT_TAG_OPEN)) {
|
|
@@ -36976,16 +37075,16 @@ async function executePreCompactHooks(ctx, config2, extendedConfig) {
|
|
|
36976
37075
|
if (!matcher.hooks || matcher.hooks.length === 0)
|
|
36977
37076
|
continue;
|
|
36978
37077
|
for (const hook of matcher.hooks) {
|
|
36979
|
-
if (hook.type !== "command")
|
|
37078
|
+
if (hook.type !== "command" && hook.type !== "http")
|
|
36980
37079
|
continue;
|
|
36981
|
-
|
|
36982
|
-
|
|
37080
|
+
const hookName = getHookIdentifier(hook);
|
|
37081
|
+
if (isHookCommandDisabled("PreCompact", hookName, extendedConfig ?? null)) {
|
|
37082
|
+
log("PreCompact hook command skipped (disabled by config)", { command: hookName });
|
|
36983
37083
|
continue;
|
|
36984
37084
|
}
|
|
36985
|
-
const hookName = hook.command.split("/").pop() || hook.command;
|
|
36986
37085
|
if (!firstHookName)
|
|
36987
37086
|
firstHookName = hookName;
|
|
36988
|
-
const result = await
|
|
37087
|
+
const result = await dispatchHook(hook, JSON.stringify(stdinData), ctx.cwd);
|
|
36989
37088
|
if (result.exitCode === 2) {
|
|
36990
37089
|
log("PreCompact hook blocked", { hookName, stderr: result.stderr });
|
|
36991
37090
|
continue;
|
|
@@ -37083,13 +37182,14 @@ async function executeStopHooks(ctx, config2, extendedConfig) {
|
|
|
37083
37182
|
if (!matcher.hooks || matcher.hooks.length === 0)
|
|
37084
37183
|
continue;
|
|
37085
37184
|
for (const hook of matcher.hooks) {
|
|
37086
|
-
if (hook.type !== "command")
|
|
37185
|
+
if (hook.type !== "command" && hook.type !== "http")
|
|
37087
37186
|
continue;
|
|
37088
|
-
|
|
37089
|
-
|
|
37187
|
+
const hookName = getHookIdentifier(hook);
|
|
37188
|
+
if (isHookCommandDisabled("Stop", hookName, extendedConfig ?? null)) {
|
|
37189
|
+
log("Stop hook command skipped (disabled by config)", { command: hookName });
|
|
37090
37190
|
continue;
|
|
37091
37191
|
}
|
|
37092
|
-
const result = await
|
|
37192
|
+
const result = await dispatchHook(hook, JSON.stringify(stdinData), ctx.cwd);
|
|
37093
37193
|
if (result.exitCode === 2) {
|
|
37094
37194
|
const reason = result.stderr || result.stdout || "Blocked by stop hook";
|
|
37095
37195
|
return {
|
|
@@ -37238,16 +37338,16 @@ async function executePostToolUseHooks(ctx, config2, extendedConfig) {
|
|
|
37238
37338
|
if (!matcher.hooks || matcher.hooks.length === 0)
|
|
37239
37339
|
continue;
|
|
37240
37340
|
for (const hook of matcher.hooks) {
|
|
37241
|
-
if (hook.type !== "command")
|
|
37341
|
+
if (hook.type !== "command" && hook.type !== "http")
|
|
37242
37342
|
continue;
|
|
37243
|
-
|
|
37244
|
-
|
|
37343
|
+
const hookName = getHookIdentifier(hook);
|
|
37344
|
+
if (isHookCommandDisabled("PostToolUse", hookName, extendedConfig ?? null)) {
|
|
37345
|
+
log("PostToolUse hook command skipped (disabled by config)", { command: hookName, toolName: ctx.toolName });
|
|
37245
37346
|
continue;
|
|
37246
37347
|
}
|
|
37247
|
-
const hookName = hook.command.split("/").pop() || hook.command;
|
|
37248
37348
|
if (!firstHookName)
|
|
37249
37349
|
firstHookName = hookName;
|
|
37250
|
-
const result = await
|
|
37350
|
+
const result = await dispatchHook(hook, JSON.stringify(stdinData), ctx.cwd);
|
|
37251
37351
|
if (result.stdout) {
|
|
37252
37352
|
messages.push(result.stdout);
|
|
37253
37353
|
}
|
|
@@ -37475,16 +37575,16 @@ async function executePreToolUseHooks(ctx, config2, extendedConfig) {
|
|
|
37475
37575
|
if (!matcher.hooks || matcher.hooks.length === 0)
|
|
37476
37576
|
continue;
|
|
37477
37577
|
for (const hook of matcher.hooks) {
|
|
37478
|
-
if (hook.type !== "command")
|
|
37578
|
+
if (hook.type !== "command" && hook.type !== "http")
|
|
37479
37579
|
continue;
|
|
37480
|
-
|
|
37481
|
-
|
|
37580
|
+
const hookName = getHookIdentifier(hook);
|
|
37581
|
+
if (isHookCommandDisabled("PreToolUse", hookName, extendedConfig ?? null)) {
|
|
37582
|
+
log("PreToolUse hook command skipped (disabled by config)", { command: hookName, toolName: ctx.toolName });
|
|
37482
37583
|
continue;
|
|
37483
37584
|
}
|
|
37484
|
-
const hookName = hook.command.split("/").pop() || hook.command;
|
|
37485
37585
|
if (!firstHookName)
|
|
37486
37586
|
firstHookName = hookName;
|
|
37487
|
-
const result = await
|
|
37587
|
+
const result = await dispatchHook(hook, JSON.stringify(stdinData), ctx.cwd);
|
|
37488
37588
|
if (result.exitCode === 2) {
|
|
37489
37589
|
return {
|
|
37490
37590
|
decision: "deny",
|
|
@@ -38165,7 +38265,11 @@ function createBackgroundNotificationHook(manager) {
|
|
|
38165
38265
|
const eventHandler = async ({ event }) => {
|
|
38166
38266
|
manager.handleEvent(event);
|
|
38167
38267
|
};
|
|
38268
|
+
const chatMessageHandler = async (input, output) => {
|
|
38269
|
+
manager.injectPendingNotificationsIntoChatMessage(output, input.sessionID);
|
|
38270
|
+
};
|
|
38168
38271
|
return {
|
|
38272
|
+
"chat.message": chatMessageHandler,
|
|
38169
38273
|
event: eventHandler
|
|
38170
38274
|
};
|
|
38171
38275
|
}
|
|
@@ -38481,6 +38585,64 @@ function getConfigContext() {
|
|
|
38481
38585
|
function getConfigDir() {
|
|
38482
38586
|
return getConfigContext().paths.configDir;
|
|
38483
38587
|
}
|
|
38588
|
+
// src/shared/spawn-with-windows-hide.ts
|
|
38589
|
+
var {spawn: bunSpawn } = globalThis.Bun;
|
|
38590
|
+
import { spawn as nodeSpawn } from "child_process";
|
|
38591
|
+
import { Readable } from "stream";
|
|
38592
|
+
function toReadableStream(stream) {
|
|
38593
|
+
if (!stream) {
|
|
38594
|
+
return;
|
|
38595
|
+
}
|
|
38596
|
+
return Readable.toWeb(stream);
|
|
38597
|
+
}
|
|
38598
|
+
function wrapNodeProcess(proc) {
|
|
38599
|
+
let resolveExited;
|
|
38600
|
+
let exitCode = null;
|
|
38601
|
+
const exited = new Promise((resolve5) => {
|
|
38602
|
+
resolveExited = resolve5;
|
|
38603
|
+
});
|
|
38604
|
+
proc.on("exit", (code) => {
|
|
38605
|
+
exitCode = code ?? 1;
|
|
38606
|
+
resolveExited(exitCode);
|
|
38607
|
+
});
|
|
38608
|
+
proc.on("error", () => {
|
|
38609
|
+
if (exitCode === null) {
|
|
38610
|
+
exitCode = 1;
|
|
38611
|
+
resolveExited(1);
|
|
38612
|
+
}
|
|
38613
|
+
});
|
|
38614
|
+
return {
|
|
38615
|
+
get exitCode() {
|
|
38616
|
+
return exitCode;
|
|
38617
|
+
},
|
|
38618
|
+
exited,
|
|
38619
|
+
stdout: toReadableStream(proc.stdout),
|
|
38620
|
+
stderr: toReadableStream(proc.stderr),
|
|
38621
|
+
kill(signal) {
|
|
38622
|
+
try {
|
|
38623
|
+
if (!signal) {
|
|
38624
|
+
proc.kill();
|
|
38625
|
+
return;
|
|
38626
|
+
}
|
|
38627
|
+
proc.kill(signal);
|
|
38628
|
+
} catch {}
|
|
38629
|
+
}
|
|
38630
|
+
};
|
|
38631
|
+
}
|
|
38632
|
+
function spawnWithWindowsHide(command, options) {
|
|
38633
|
+
if (process.platform !== "win32") {
|
|
38634
|
+
return bunSpawn(command, options);
|
|
38635
|
+
}
|
|
38636
|
+
const [cmd, ...args] = command;
|
|
38637
|
+
const proc = nodeSpawn(cmd, args, {
|
|
38638
|
+
cwd: options.cwd,
|
|
38639
|
+
env: options.env,
|
|
38640
|
+
stdio: [options.stdin ?? "pipe", options.stdout ?? "pipe", options.stderr ?? "pipe"],
|
|
38641
|
+
windowsHide: true,
|
|
38642
|
+
shell: true
|
|
38643
|
+
});
|
|
38644
|
+
return wrapNodeProcess(proc);
|
|
38645
|
+
}
|
|
38484
38646
|
// src/cli/config-manager/bun-install.ts
|
|
38485
38647
|
var BUN_INSTALL_TIMEOUT_SECONDS = 60;
|
|
38486
38648
|
var BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
|
|
@@ -38490,7 +38652,7 @@ async function runBunInstall() {
|
|
|
38490
38652
|
}
|
|
38491
38653
|
async function runBunInstallWithDetails() {
|
|
38492
38654
|
try {
|
|
38493
|
-
const proc =
|
|
38655
|
+
const proc = spawnWithWindowsHide(["bun", "install"], {
|
|
38494
38656
|
cwd: getConfigDir(),
|
|
38495
38657
|
stdout: "inherit",
|
|
38496
38658
|
stderr: "inherit"
|
|
@@ -38932,6 +39094,16 @@ function clearAgentUsageState(sessionID) {
|
|
|
38932
39094
|
}
|
|
38933
39095
|
|
|
38934
39096
|
// src/hooks/agent-usage-reminder/hook.ts
|
|
39097
|
+
var ORCHESTRATOR_AGENTS = new Set([
|
|
39098
|
+
"sisyphus",
|
|
39099
|
+
"sisyphus-junior",
|
|
39100
|
+
"atlas",
|
|
39101
|
+
"hephaestus",
|
|
39102
|
+
"prometheus"
|
|
39103
|
+
]);
|
|
39104
|
+
function isOrchestratorAgent(agentName) {
|
|
39105
|
+
return ORCHESTRATOR_AGENTS.has(getAgentConfigKey(agentName));
|
|
39106
|
+
}
|
|
38935
39107
|
function createAgentUsageReminderHook(_ctx) {
|
|
38936
39108
|
const sessionStates = new Map;
|
|
38937
39109
|
function getOrCreateState(sessionID) {
|
|
@@ -38959,6 +39131,10 @@ function createAgentUsageReminderHook(_ctx) {
|
|
|
38959
39131
|
}
|
|
38960
39132
|
const toolExecuteAfter = async (input, output) => {
|
|
38961
39133
|
const { tool, sessionID } = input;
|
|
39134
|
+
const agent = getSessionAgent(sessionID);
|
|
39135
|
+
if (agent && !isOrchestratorAgent(agent)) {
|
|
39136
|
+
return;
|
|
39137
|
+
}
|
|
38962
39138
|
const toolLower = tool.toLowerCase();
|
|
38963
39139
|
if (AGENT_TOOLS.has(toolLower)) {
|
|
38964
39140
|
markAgentUsed(sessionID);
|
|
@@ -39000,12 +39176,9 @@ function createAgentUsageReminderHook(_ctx) {
|
|
|
39000
39176
|
function extractModelName(model) {
|
|
39001
39177
|
return model.includes("/") ? model.split("/").pop() ?? model : model;
|
|
39002
39178
|
}
|
|
39003
|
-
var GPT_MODEL_PREFIXES = ["gpt-", "gpt4", "o1", "o3", "o4"];
|
|
39004
39179
|
function isGptModel(model) {
|
|
39005
|
-
if (model.startsWith("openai/") || model.startsWith("github-copilot/gpt-"))
|
|
39006
|
-
return true;
|
|
39007
39180
|
const modelName = extractModelName(model).toLowerCase();
|
|
39008
|
-
return
|
|
39181
|
+
return modelName.includes("gpt");
|
|
39009
39182
|
}
|
|
39010
39183
|
var GEMINI_PROVIDERS = ["google/", "google-vertex/"];
|
|
39011
39184
|
function isGeminiModel(model) {
|
|
@@ -40241,7 +40414,7 @@ function isOmoSession(sessionName) {
|
|
|
40241
40414
|
async function killAllTrackedSessions(state3) {
|
|
40242
40415
|
for (const sessionName of state3.tmuxSessions) {
|
|
40243
40416
|
try {
|
|
40244
|
-
const proc =
|
|
40417
|
+
const proc = spawnWithWindowsHide(["tmux", "kill-session", "-t", sessionName], {
|
|
40245
40418
|
stdout: "ignore",
|
|
40246
40419
|
stderr: "ignore"
|
|
40247
40420
|
});
|
|
@@ -40561,6 +40734,7 @@ function readState(directory, customPath) {
|
|
|
40561
40734
|
active: isActive,
|
|
40562
40735
|
iteration: iterationNum,
|
|
40563
40736
|
max_iterations: Number(data.max_iterations) || DEFAULT_MAX_ITERATIONS,
|
|
40737
|
+
message_count_at_start: typeof data.message_count_at_start === "number" ? data.message_count_at_start : typeof data.message_count_at_start === "string" && data.message_count_at_start.trim() !== "" ? Number(data.message_count_at_start) : undefined,
|
|
40564
40738
|
completion_promise: stripQuotes(data.completion_promise) || DEFAULT_COMPLETION_PROMISE,
|
|
40565
40739
|
started_at: stripQuotes(data.started_at) || new Date().toISOString(),
|
|
40566
40740
|
prompt: body.trim(),
|
|
@@ -40584,6 +40758,8 @@ function writeState(directory, state3, customPath) {
|
|
|
40584
40758
|
const ultraworkLine = state3.ultrawork !== undefined ? `ultrawork: ${state3.ultrawork}
|
|
40585
40759
|
` : "";
|
|
40586
40760
|
const strategyLine = state3.strategy ? `strategy: "${state3.strategy}"
|
|
40761
|
+
` : "";
|
|
40762
|
+
const messageCountAtStartLine = typeof state3.message_count_at_start === "number" ? `message_count_at_start: ${state3.message_count_at_start}
|
|
40587
40763
|
` : "";
|
|
40588
40764
|
const content = `---
|
|
40589
40765
|
active: ${state3.active}
|
|
@@ -40591,7 +40767,7 @@ iteration: ${state3.iteration}
|
|
|
40591
40767
|
max_iterations: ${state3.max_iterations}
|
|
40592
40768
|
completion_promise: "${state3.completion_promise}"
|
|
40593
40769
|
started_at: "${state3.started_at}"
|
|
40594
|
-
${sessionIdLine}${ultraworkLine}${strategyLine}---
|
|
40770
|
+
${sessionIdLine}${ultraworkLine}${strategyLine}${messageCountAtStartLine}---
|
|
40595
40771
|
${state3.prompt}
|
|
40596
40772
|
`;
|
|
40597
40773
|
writeFileSync16(filePath, content, "utf-8");
|
|
@@ -40662,6 +40838,7 @@ function createLoopStateController(options) {
|
|
|
40662
40838
|
active: true,
|
|
40663
40839
|
iteration: 1,
|
|
40664
40840
|
max_iterations: loopOptions?.maxIterations ?? config2?.default_max_iterations ?? DEFAULT_MAX_ITERATIONS,
|
|
40841
|
+
message_count_at_start: loopOptions?.messageCountAtStart,
|
|
40665
40842
|
completion_promise: loopOptions?.completionPromise ?? DEFAULT_COMPLETION_PROMISE,
|
|
40666
40843
|
ultrawork: loopOptions?.ultrawork,
|
|
40667
40844
|
strategy: loopOptions?.strategy ?? config2?.default_strategy ?? "continue",
|
|
@@ -40709,6 +40886,17 @@ function createLoopStateController(options) {
|
|
|
40709
40886
|
return null;
|
|
40710
40887
|
}
|
|
40711
40888
|
return state3;
|
|
40889
|
+
},
|
|
40890
|
+
setMessageCountAtStart(sessionID, messageCountAtStart) {
|
|
40891
|
+
const state3 = readState(directory, stateDir);
|
|
40892
|
+
if (!state3 || state3.session_id !== sessionID) {
|
|
40893
|
+
return null;
|
|
40894
|
+
}
|
|
40895
|
+
state3.message_count_at_start = messageCountAtStart;
|
|
40896
|
+
if (!writeState(directory, state3, stateDir)) {
|
|
40897
|
+
return null;
|
|
40898
|
+
}
|
|
40899
|
+
return state3;
|
|
40712
40900
|
}
|
|
40713
40901
|
};
|
|
40714
40902
|
}
|
|
@@ -40779,12 +40967,13 @@ async function detectCompletionInSessionMessages(ctx, options) {
|
|
|
40779
40967
|
const messagesResponse = response;
|
|
40780
40968
|
const responseData = typeof messagesResponse === "object" && messagesResponse !== null && "data" in messagesResponse ? messagesResponse.data : undefined;
|
|
40781
40969
|
const messageArray = Array.isArray(messagesResponse) ? messagesResponse : Array.isArray(responseData) ? responseData : [];
|
|
40782
|
-
const
|
|
40970
|
+
const scopedMessages = typeof options.sinceMessageIndex === "number" && options.sinceMessageIndex >= 0 && options.sinceMessageIndex < messageArray.length ? messageArray.slice(options.sinceMessageIndex) : messageArray;
|
|
40971
|
+
const assistantMessages = scopedMessages.filter((msg) => msg.info?.role === "assistant");
|
|
40783
40972
|
if (assistantMessages.length === 0)
|
|
40784
40973
|
return false;
|
|
40785
40974
|
const pattern = buildPromisePattern(options.promise);
|
|
40786
|
-
|
|
40787
|
-
|
|
40975
|
+
for (let index = assistantMessages.length - 1;index >= 0; index -= 1) {
|
|
40976
|
+
const assistant = assistantMessages[index];
|
|
40788
40977
|
if (!assistant.parts)
|
|
40789
40978
|
continue;
|
|
40790
40979
|
let responseText = "";
|
|
@@ -40936,14 +41125,6 @@ async function continueIteration(ctx, state3, options) {
|
|
|
40936
41125
|
if (!newSessionID) {
|
|
40937
41126
|
return;
|
|
40938
41127
|
}
|
|
40939
|
-
const boundState = options.loopState.setSessionID(newSessionID);
|
|
40940
|
-
if (!boundState) {
|
|
40941
|
-
log(`[${HOOK_NAME3}] Failed to bind loop state to new session`, {
|
|
40942
|
-
previousSessionID: options.previousSessionID,
|
|
40943
|
-
newSessionID
|
|
40944
|
-
});
|
|
40945
|
-
return;
|
|
40946
|
-
}
|
|
40947
41128
|
await injectContinuationPrompt(ctx, {
|
|
40948
41129
|
sessionID: newSessionID,
|
|
40949
41130
|
inheritFromSessionID: options.previousSessionID,
|
|
@@ -40952,6 +41133,14 @@ async function continueIteration(ctx, state3, options) {
|
|
|
40952
41133
|
apiTimeoutMs: options.apiTimeoutMs
|
|
40953
41134
|
});
|
|
40954
41135
|
await selectSessionInTui(ctx.client, newSessionID);
|
|
41136
|
+
const boundState = options.loopState.setSessionID(newSessionID);
|
|
41137
|
+
if (!boundState) {
|
|
41138
|
+
log(`[${HOOK_NAME3}] Failed to bind loop state to new session`, {
|
|
41139
|
+
previousSessionID: options.previousSessionID,
|
|
41140
|
+
newSessionID
|
|
41141
|
+
});
|
|
41142
|
+
return;
|
|
41143
|
+
}
|
|
40955
41144
|
return;
|
|
40956
41145
|
}
|
|
40957
41146
|
await injectContinuationPrompt(ctx, {
|
|
@@ -40964,106 +41153,117 @@ async function continueIteration(ctx, state3, options) {
|
|
|
40964
41153
|
|
|
40965
41154
|
// src/hooks/ralph-loop/ralph-loop-event-handler.ts
|
|
40966
41155
|
function createRalphLoopEventHandler(ctx, options) {
|
|
41156
|
+
const inFlightSessions = new Set;
|
|
40967
41157
|
return async ({ event }) => {
|
|
40968
41158
|
const props = event.properties;
|
|
40969
41159
|
if (event.type === "session.idle") {
|
|
40970
41160
|
const sessionID = props?.sessionID;
|
|
40971
41161
|
if (!sessionID)
|
|
40972
41162
|
return;
|
|
40973
|
-
if (
|
|
40974
|
-
log(`[${HOOK_NAME3}] Skipped: in
|
|
40975
|
-
return;
|
|
40976
|
-
}
|
|
40977
|
-
const state3 = options.loopState.getState();
|
|
40978
|
-
if (!state3 || !state3.active) {
|
|
41163
|
+
if (inFlightSessions.has(sessionID)) {
|
|
41164
|
+
log(`[${HOOK_NAME3}] Skipped: handler in flight`, { sessionID });
|
|
40979
41165
|
return;
|
|
40980
41166
|
}
|
|
40981
|
-
|
|
40982
|
-
|
|
40983
|
-
|
|
40984
|
-
|
|
40985
|
-
|
|
40986
|
-
|
|
40987
|
-
|
|
40988
|
-
|
|
40989
|
-
|
|
41167
|
+
inFlightSessions.add(sessionID);
|
|
41168
|
+
try {
|
|
41169
|
+
if (options.sessionRecovery.isRecovering(sessionID)) {
|
|
41170
|
+
log(`[${HOOK_NAME3}] Skipped: in recovery`, { sessionID });
|
|
41171
|
+
return;
|
|
41172
|
+
}
|
|
41173
|
+
const state3 = options.loopState.getState();
|
|
41174
|
+
if (!state3 || !state3.active) {
|
|
41175
|
+
return;
|
|
41176
|
+
}
|
|
41177
|
+
if (state3.session_id && state3.session_id !== sessionID) {
|
|
41178
|
+
if (options.checkSessionExists) {
|
|
41179
|
+
try {
|
|
41180
|
+
const exists = await options.checkSessionExists(state3.session_id);
|
|
41181
|
+
if (!exists) {
|
|
41182
|
+
options.loopState.clear();
|
|
41183
|
+
log(`[${HOOK_NAME3}] Cleared orphaned state from deleted session`, {
|
|
41184
|
+
orphanedSessionId: state3.session_id,
|
|
41185
|
+
currentSessionId: sessionID
|
|
41186
|
+
});
|
|
41187
|
+
return;
|
|
41188
|
+
}
|
|
41189
|
+
} catch (err) {
|
|
41190
|
+
log(`[${HOOK_NAME3}] Failed to check session existence`, {
|
|
41191
|
+
sessionId: state3.session_id,
|
|
41192
|
+
error: String(err)
|
|
40990
41193
|
});
|
|
40991
|
-
return;
|
|
40992
41194
|
}
|
|
40993
|
-
} catch (err) {
|
|
40994
|
-
log(`[${HOOK_NAME3}] Failed to check session existence`, {
|
|
40995
|
-
sessionId: state3.session_id,
|
|
40996
|
-
error: String(err)
|
|
40997
|
-
});
|
|
40998
41195
|
}
|
|
41196
|
+
return;
|
|
40999
41197
|
}
|
|
41000
|
-
|
|
41001
|
-
|
|
41002
|
-
|
|
41003
|
-
const completionViaTranscript = detectCompletionInTranscript(transcriptPath, state3.completion_promise);
|
|
41004
|
-
const completionViaApi = completionViaTranscript ? false : await detectCompletionInSessionMessages(ctx, {
|
|
41005
|
-
sessionID,
|
|
41006
|
-
promise: state3.completion_promise,
|
|
41007
|
-
apiTimeoutMs: options.apiTimeoutMs,
|
|
41008
|
-
directory: options.directory
|
|
41009
|
-
});
|
|
41010
|
-
if (completionViaTranscript || completionViaApi) {
|
|
41011
|
-
log(`[${HOOK_NAME3}] Completion detected!`, {
|
|
41198
|
+
const transcriptPath = options.getTranscriptPath(sessionID);
|
|
41199
|
+
const completionViaTranscript = detectCompletionInTranscript(transcriptPath, state3.completion_promise);
|
|
41200
|
+
const completionViaApi = completionViaTranscript ? false : await detectCompletionInSessionMessages(ctx, {
|
|
41012
41201
|
sessionID,
|
|
41013
|
-
iteration: state3.iteration,
|
|
41014
41202
|
promise: state3.completion_promise,
|
|
41015
|
-
|
|
41203
|
+
apiTimeoutMs: options.apiTimeoutMs,
|
|
41204
|
+
directory: options.directory,
|
|
41205
|
+
sinceMessageIndex: state3.message_count_at_start
|
|
41016
41206
|
});
|
|
41017
|
-
|
|
41018
|
-
|
|
41019
|
-
|
|
41020
|
-
|
|
41021
|
-
|
|
41022
|
-
|
|
41023
|
-
|
|
41024
|
-
|
|
41207
|
+
if (completionViaTranscript || completionViaApi) {
|
|
41208
|
+
log(`[${HOOK_NAME3}] Completion detected!`, {
|
|
41209
|
+
sessionID,
|
|
41210
|
+
iteration: state3.iteration,
|
|
41211
|
+
promise: state3.completion_promise,
|
|
41212
|
+
detectedVia: completionViaTranscript ? "transcript_file" : "session_messages_api"
|
|
41213
|
+
});
|
|
41214
|
+
options.loopState.clear();
|
|
41215
|
+
const title = state3.ultrawork ? "ULTRAWORK LOOP COMPLETE!" : "Ralph Loop Complete!";
|
|
41216
|
+
const message = state3.ultrawork ? `JUST ULW ULW! Task completed after ${state3.iteration} iteration(s)` : `Task completed after ${state3.iteration} iteration(s)`;
|
|
41217
|
+
await ctx.client.tui?.showToast?.({ body: { title, message, variant: "success", duration: 5000 } }).catch(() => {});
|
|
41218
|
+
return;
|
|
41219
|
+
}
|
|
41220
|
+
if (state3.iteration >= state3.max_iterations) {
|
|
41221
|
+
log(`[${HOOK_NAME3}] Max iterations reached`, {
|
|
41222
|
+
sessionID,
|
|
41223
|
+
iteration: state3.iteration,
|
|
41224
|
+
max: state3.max_iterations
|
|
41225
|
+
});
|
|
41226
|
+
options.loopState.clear();
|
|
41227
|
+
await ctx.client.tui?.showToast?.({
|
|
41228
|
+
body: { title: "Ralph Loop Stopped", message: `Max iterations (${state3.max_iterations}) reached without completion`, variant: "warning", duration: 5000 }
|
|
41229
|
+
}).catch(() => {});
|
|
41230
|
+
return;
|
|
41231
|
+
}
|
|
41232
|
+
const newState = options.loopState.incrementIteration();
|
|
41233
|
+
if (!newState) {
|
|
41234
|
+
log(`[${HOOK_NAME3}] Failed to increment iteration`, { sessionID });
|
|
41235
|
+
return;
|
|
41236
|
+
}
|
|
41237
|
+
log(`[${HOOK_NAME3}] Continuing loop`, {
|
|
41025
41238
|
sessionID,
|
|
41026
|
-
iteration:
|
|
41027
|
-
max:
|
|
41239
|
+
iteration: newState.iteration,
|
|
41240
|
+
max: newState.max_iterations
|
|
41028
41241
|
});
|
|
41029
|
-
options.loopState.clear();
|
|
41030
41242
|
await ctx.client.tui?.showToast?.({
|
|
41031
|
-
body: {
|
|
41243
|
+
body: {
|
|
41244
|
+
title: "Ralph Loop",
|
|
41245
|
+
message: `Iteration ${newState.iteration}/${newState.max_iterations}`,
|
|
41246
|
+
variant: "info",
|
|
41247
|
+
duration: 2000
|
|
41248
|
+
}
|
|
41032
41249
|
}).catch(() => {});
|
|
41033
|
-
|
|
41034
|
-
|
|
41035
|
-
|
|
41036
|
-
|
|
41037
|
-
|
|
41038
|
-
|
|
41039
|
-
|
|
41040
|
-
|
|
41041
|
-
|
|
41042
|
-
|
|
41043
|
-
|
|
41044
|
-
|
|
41045
|
-
await ctx.client.tui?.showToast?.({
|
|
41046
|
-
body: {
|
|
41047
|
-
title: "Ralph Loop",
|
|
41048
|
-
message: `Iteration ${newState.iteration}/${newState.max_iterations}`,
|
|
41049
|
-
variant: "info",
|
|
41050
|
-
duration: 2000
|
|
41250
|
+
try {
|
|
41251
|
+
await continueIteration(ctx, newState, {
|
|
41252
|
+
previousSessionID: sessionID,
|
|
41253
|
+
directory: options.directory,
|
|
41254
|
+
apiTimeoutMs: options.apiTimeoutMs,
|
|
41255
|
+
loopState: options.loopState
|
|
41256
|
+
});
|
|
41257
|
+
} catch (err) {
|
|
41258
|
+
log(`[${HOOK_NAME3}] Failed to inject continuation`, {
|
|
41259
|
+
sessionID,
|
|
41260
|
+
error: String(err)
|
|
41261
|
+
});
|
|
41051
41262
|
}
|
|
41052
|
-
|
|
41053
|
-
|
|
41054
|
-
|
|
41055
|
-
previousSessionID: sessionID,
|
|
41056
|
-
directory: options.directory,
|
|
41057
|
-
apiTimeoutMs: options.apiTimeoutMs,
|
|
41058
|
-
loopState: options.loopState
|
|
41059
|
-
});
|
|
41060
|
-
} catch (err) {
|
|
41061
|
-
log(`[${HOOK_NAME3}] Failed to inject continuation`, {
|
|
41062
|
-
sessionID,
|
|
41063
|
-
error: String(err)
|
|
41064
|
-
});
|
|
41263
|
+
return;
|
|
41264
|
+
} finally {
|
|
41265
|
+
inFlightSessions.delete(sessionID);
|
|
41065
41266
|
}
|
|
41066
|
-
return;
|
|
41067
41267
|
}
|
|
41068
41268
|
if (event.type === "session.deleted") {
|
|
41069
41269
|
const sessionInfo = props?.info;
|
|
@@ -41100,6 +41300,16 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
41100
41300
|
|
|
41101
41301
|
// src/hooks/ralph-loop/ralph-loop-hook.ts
|
|
41102
41302
|
var DEFAULT_API_TIMEOUT = 5000;
|
|
41303
|
+
function getMessageCountFromResponse(messagesResponse) {
|
|
41304
|
+
if (Array.isArray(messagesResponse)) {
|
|
41305
|
+
return messagesResponse.length;
|
|
41306
|
+
}
|
|
41307
|
+
if (typeof messagesResponse === "object" && messagesResponse !== null && "data" in messagesResponse) {
|
|
41308
|
+
const data = messagesResponse.data;
|
|
41309
|
+
return Array.isArray(data) ? data.length : 0;
|
|
41310
|
+
}
|
|
41311
|
+
return 0;
|
|
41312
|
+
}
|
|
41103
41313
|
function createRalphLoopHook(ctx, options) {
|
|
41104
41314
|
const config2 = options?.config;
|
|
41105
41315
|
const stateDir = config2?.state_dir;
|
|
@@ -41122,7 +41332,20 @@ function createRalphLoopHook(ctx, options) {
|
|
|
41122
41332
|
});
|
|
41123
41333
|
return {
|
|
41124
41334
|
event,
|
|
41125
|
-
startLoop:
|
|
41335
|
+
startLoop: (sessionID, prompt, loopOptions) => {
|
|
41336
|
+
const startSuccess = loopState.startLoop(sessionID, prompt, loopOptions);
|
|
41337
|
+
if (!startSuccess || typeof loopOptions?.messageCountAtStart === "number") {
|
|
41338
|
+
return startSuccess;
|
|
41339
|
+
}
|
|
41340
|
+
ctx.client.session.messages({
|
|
41341
|
+
path: { id: sessionID },
|
|
41342
|
+
query: { directory: ctx.directory }
|
|
41343
|
+
}).then((messagesResponse) => {
|
|
41344
|
+
const messageCountAtStart = getMessageCountFromResponse(messagesResponse);
|
|
41345
|
+
loopState.setMessageCountAtStart(sessionID, messageCountAtStart);
|
|
41346
|
+
}).catch(() => {});
|
|
41347
|
+
return startSuccess;
|
|
41348
|
+
},
|
|
41126
41349
|
cancelLoop: loopState.cancelLoop,
|
|
41127
41350
|
getState: loopState.getState
|
|
41128
41351
|
};
|
|
@@ -41177,12 +41400,12 @@ var TOAST_MESSAGE2 = [
|
|
|
41177
41400
|
].join(`
|
|
41178
41401
|
`);
|
|
41179
41402
|
var SISYPHUS_DISPLAY = getAgentDisplayName("sisyphus");
|
|
41180
|
-
function showToast2(ctx, sessionID) {
|
|
41403
|
+
function showToast2(ctx, sessionID, variant) {
|
|
41181
41404
|
ctx.client.tui.showToast({
|
|
41182
41405
|
body: {
|
|
41183
41406
|
title: TOAST_TITLE2,
|
|
41184
41407
|
message: TOAST_MESSAGE2,
|
|
41185
|
-
variant
|
|
41408
|
+
variant,
|
|
41186
41409
|
duration: 1e4
|
|
41187
41410
|
}
|
|
41188
41411
|
}).catch((error45) => {
|
|
@@ -41192,14 +41415,18 @@ function showToast2(ctx, sessionID) {
|
|
|
41192
41415
|
});
|
|
41193
41416
|
});
|
|
41194
41417
|
}
|
|
41195
|
-
function createNoHephaestusNonGptHook(ctx) {
|
|
41418
|
+
function createNoHephaestusNonGptHook(ctx, options) {
|
|
41196
41419
|
return {
|
|
41197
41420
|
"chat.message": async (input, output) => {
|
|
41198
41421
|
const rawAgent = input.agent ?? getSessionAgent(input.sessionID) ?? "";
|
|
41199
41422
|
const agentKey = getAgentConfigKey(rawAgent);
|
|
41200
41423
|
const modelID = input.model?.modelID;
|
|
41424
|
+
const allowNonGptModel = options?.allowNonGptModel === true;
|
|
41201
41425
|
if (agentKey === "hephaestus" && modelID && !isGptModel(modelID)) {
|
|
41202
|
-
showToast2(ctx, input.sessionID);
|
|
41426
|
+
showToast2(ctx, input.sessionID, allowNonGptModel ? "warning" : "error");
|
|
41427
|
+
if (allowNonGptModel) {
|
|
41428
|
+
return;
|
|
41429
|
+
}
|
|
41203
41430
|
input.agent = SISYPHUS_DISPLAY;
|
|
41204
41431
|
if (output?.message) {
|
|
41205
41432
|
output.message.agent = SISYPHUS_DISPLAY;
|
|
@@ -42269,6 +42496,15 @@ $ARGUMENTS
|
|
|
42269
42496
|
// src/features/builtin-commands/templates/start-work.ts
|
|
42270
42497
|
var START_WORK_TEMPLATE = `You are starting a Sisyphus work session.
|
|
42271
42498
|
|
|
42499
|
+
## ARGUMENTS
|
|
42500
|
+
|
|
42501
|
+
- \`/start-work [plan-name] [--worktree <path>]\`
|
|
42502
|
+
- \`plan-name\` (optional): name or partial match of the plan to start
|
|
42503
|
+
- \`--worktree <path>\` (optional): absolute path to an existing git worktree to work in
|
|
42504
|
+
- If specified and valid: hook pre-sets worktree_path in boulder.json
|
|
42505
|
+
- If specified but invalid: you must run \`git worktree add <path> <branch>\` first
|
|
42506
|
+
- If omitted: you MUST choose or create a worktree (see Worktree Setup below)
|
|
42507
|
+
|
|
42272
42508
|
## WHAT TO DO
|
|
42273
42509
|
|
|
42274
42510
|
1. **Find available plans**: Search for Prometheus-generated plan files at \`.sisyphus/plans/\`
|
|
@@ -42284,17 +42520,24 @@ var START_WORK_TEMPLATE = `You are starting a Sisyphus work session.
|
|
|
42284
42520
|
- If ONE plan: auto-select it
|
|
42285
42521
|
- If MULTIPLE plans: show list with timestamps, ask user to select
|
|
42286
42522
|
|
|
42287
|
-
4. **
|
|
42523
|
+
4. **Worktree Setup** (when \`worktree_path\` not already set in boulder.json):
|
|
42524
|
+
1. \`git worktree list --porcelain\` \u2014 see available worktrees
|
|
42525
|
+
2. Create: \`git worktree add <absolute-path> <branch-or-HEAD>\`
|
|
42526
|
+
3. Update boulder.json to add \`"worktree_path": "<absolute-path>"\`
|
|
42527
|
+
4. All work happens inside that worktree directory
|
|
42528
|
+
|
|
42529
|
+
5. **Create/Update boulder.json**:
|
|
42288
42530
|
\`\`\`json
|
|
42289
42531
|
{
|
|
42290
42532
|
"active_plan": "/absolute/path/to/plan.md",
|
|
42291
42533
|
"started_at": "ISO_TIMESTAMP",
|
|
42292
42534
|
"session_ids": ["session_id_1", "session_id_2"],
|
|
42293
|
-
"plan_name": "plan-name"
|
|
42535
|
+
"plan_name": "plan-name",
|
|
42536
|
+
"worktree_path": "/absolute/path/to/git/worktree"
|
|
42294
42537
|
}
|
|
42295
42538
|
\`\`\`
|
|
42296
42539
|
|
|
42297
|
-
|
|
42540
|
+
6. **Read the plan file** and start executing tasks according to atlas workflow
|
|
42298
42541
|
|
|
42299
42542
|
## OUTPUT FORMAT
|
|
42300
42543
|
|
|
@@ -42318,6 +42561,7 @@ Resuming Work Session
|
|
|
42318
42561
|
Active Plan: {plan-name}
|
|
42319
42562
|
Progress: {completed}/{total} tasks
|
|
42320
42563
|
Sessions: {count} (appending current session)
|
|
42564
|
+
Worktree: {worktree_path}
|
|
42321
42565
|
|
|
42322
42566
|
Reading plan and continuing from last incomplete task...
|
|
42323
42567
|
\`\`\`
|
|
@@ -42329,6 +42573,7 @@ Starting Work Session
|
|
|
42329
42573
|
Plan: {plan-name}
|
|
42330
42574
|
Session ID: {session_id}
|
|
42331
42575
|
Started: {timestamp}
|
|
42576
|
+
Worktree: {worktree_path}
|
|
42332
42577
|
|
|
42333
42578
|
Reading plan and beginning execution...
|
|
42334
42579
|
\`\`\`
|
|
@@ -42337,6 +42582,7 @@ Reading plan and beginning execution...
|
|
|
42337
42582
|
|
|
42338
42583
|
- The session_id is injected by the hook - use it directly
|
|
42339
42584
|
- Always update boulder.json BEFORE starting work
|
|
42585
|
+
- Always set worktree_path in boulder.json before executing any tasks
|
|
42340
42586
|
- Read the FULL plan file before delegating any tasks
|
|
42341
42587
|
- Follow atlas delegation protocols (7-section format)`;
|
|
42342
42588
|
|
|
@@ -45838,8 +46084,8 @@ function getPlanProgress(planPath) {
|
|
|
45838
46084
|
}
|
|
45839
46085
|
try {
|
|
45840
46086
|
const content = readFileSync35(planPath, "utf-8");
|
|
45841
|
-
const uncheckedMatches = content.match(
|
|
45842
|
-
const checkedMatches = content.match(
|
|
46087
|
+
const uncheckedMatches = content.match(/^\s*[-*]\s*\[\s*\]/gm) || [];
|
|
46088
|
+
const checkedMatches = content.match(/^\s*[-*]\s*\[[xX]\]/gm) || [];
|
|
45843
46089
|
const total = uncheckedMatches.length + checkedMatches.length;
|
|
45844
46090
|
const completed = checkedMatches.length;
|
|
45845
46091
|
return {
|
|
@@ -45854,13 +46100,14 @@ function getPlanProgress(planPath) {
|
|
|
45854
46100
|
function getPlanName(planPath) {
|
|
45855
46101
|
return basename3(planPath, ".md");
|
|
45856
46102
|
}
|
|
45857
|
-
function createBoulderState(planPath, sessionId, agent) {
|
|
46103
|
+
function createBoulderState(planPath, sessionId, agent, worktreePath) {
|
|
45858
46104
|
return {
|
|
45859
46105
|
active_plan: planPath,
|
|
45860
46106
|
started_at: new Date().toISOString(),
|
|
45861
46107
|
session_ids: [sessionId],
|
|
45862
46108
|
plan_name: getPlanName(planPath),
|
|
45863
|
-
...agent !== undefined ? { agent } : {}
|
|
46109
|
+
...agent !== undefined ? { agent } : {},
|
|
46110
|
+
...worktreePath !== undefined ? { worktree_path: worktreePath } : {}
|
|
45864
46111
|
};
|
|
45865
46112
|
}
|
|
45866
46113
|
// src/hooks/prometheus-md-only/agent-resolution.ts
|
|
@@ -46060,19 +46307,48 @@ to continue: task(session_id="${sessionId}", prompt="...")`;
|
|
|
46060
46307
|
};
|
|
46061
46308
|
}
|
|
46062
46309
|
// src/hooks/start-work/start-work-hook.ts
|
|
46310
|
+
import { statSync as statSync6 } from "fs";
|
|
46063
46311
|
init_logger();
|
|
46064
|
-
|
|
46065
|
-
|
|
46066
|
-
|
|
46067
|
-
|
|
46068
|
-
|
|
46312
|
+
|
|
46313
|
+
// src/hooks/start-work/worktree-detector.ts
|
|
46314
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
46315
|
+
function detectWorktreePath(directory) {
|
|
46316
|
+
try {
|
|
46317
|
+
return execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
46318
|
+
cwd: directory,
|
|
46319
|
+
encoding: "utf-8",
|
|
46320
|
+
timeout: 5000,
|
|
46321
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
46322
|
+
}).trim();
|
|
46323
|
+
} catch {
|
|
46069
46324
|
return null;
|
|
46070
|
-
|
|
46325
|
+
}
|
|
46326
|
+
}
|
|
46327
|
+
|
|
46328
|
+
// src/hooks/start-work/parse-user-request.ts
|
|
46329
|
+
var KEYWORD_PATTERN = /\b(ultrawork|ulw)\b/gi;
|
|
46330
|
+
var WORKTREE_FLAG_PATTERN = /--worktree(?:\s+(\S+))?/;
|
|
46331
|
+
function parseUserRequest(promptText) {
|
|
46332
|
+
const match = promptText.match(/<user-request>\s*([\s\S]*?)\s*<\/user-request>/i);
|
|
46333
|
+
if (!match)
|
|
46334
|
+
return { planName: null, explicitWorktreePath: null };
|
|
46335
|
+
let rawArg = match[1].trim();
|
|
46071
46336
|
if (!rawArg)
|
|
46072
|
-
return null;
|
|
46337
|
+
return { planName: null, explicitWorktreePath: null };
|
|
46338
|
+
const worktreeMatch = rawArg.match(WORKTREE_FLAG_PATTERN);
|
|
46339
|
+
const explicitWorktreePath = worktreeMatch ? worktreeMatch[1] ?? null : null;
|
|
46340
|
+
if (worktreeMatch) {
|
|
46341
|
+
rawArg = rawArg.replace(worktreeMatch[0], "").trim();
|
|
46342
|
+
}
|
|
46073
46343
|
const cleanedArg = rawArg.replace(KEYWORD_PATTERN, "").trim();
|
|
46074
|
-
return
|
|
46344
|
+
return {
|
|
46345
|
+
planName: cleanedArg || null,
|
|
46346
|
+
explicitWorktreePath
|
|
46347
|
+
};
|
|
46075
46348
|
}
|
|
46349
|
+
|
|
46350
|
+
// src/hooks/start-work/start-work-hook.ts
|
|
46351
|
+
var HOOK_NAME6 = "start-work";
|
|
46076
46352
|
function findPlanByName(plans, requestedName) {
|
|
46077
46353
|
const lowerName = requestedName.toLowerCase();
|
|
46078
46354
|
const exactMatch = plans.find((p) => getPlanName(p).toLowerCase() === lowerName);
|
|
@@ -46081,29 +46357,48 @@ function findPlanByName(plans, requestedName) {
|
|
|
46081
46357
|
const partialMatch = plans.find((p) => getPlanName(p).toLowerCase().includes(lowerName));
|
|
46082
46358
|
return partialMatch || null;
|
|
46083
46359
|
}
|
|
46360
|
+
var MODEL_DECIDES_WORKTREE_BLOCK = `
|
|
46361
|
+
## Worktree Setup Required
|
|
46362
|
+
|
|
46363
|
+
No worktree specified. Before starting work, you MUST choose or create one:
|
|
46364
|
+
|
|
46365
|
+
1. \`git worktree list --porcelain\` \u2014 list existing worktrees
|
|
46366
|
+
2. Create if needed: \`git worktree add <absolute-path> <branch-or-HEAD>\`
|
|
46367
|
+
3. Update \`.sisyphus/boulder.json\` \u2014 add \`"worktree_path": "<absolute-path>"\`
|
|
46368
|
+
4. Work exclusively inside that worktree directory`;
|
|
46369
|
+
function resolveWorktreeContext(explicitWorktreePath) {
|
|
46370
|
+
if (explicitWorktreePath === null) {
|
|
46371
|
+
return { worktreePath: undefined, block: MODEL_DECIDES_WORKTREE_BLOCK };
|
|
46372
|
+
}
|
|
46373
|
+
const validatedPath = detectWorktreePath(explicitWorktreePath);
|
|
46374
|
+
if (validatedPath) {
|
|
46375
|
+
return { worktreePath: validatedPath, block: `
|
|
46376
|
+
**Worktree**: ${validatedPath}` };
|
|
46377
|
+
}
|
|
46378
|
+
return {
|
|
46379
|
+
worktreePath: undefined,
|
|
46380
|
+
block: `
|
|
46381
|
+
**Worktree** (needs setup): \`git worktree add ${explicitWorktreePath} <branch>\`, then add \`"worktree_path"\` to boulder.json`
|
|
46382
|
+
};
|
|
46383
|
+
}
|
|
46084
46384
|
function createStartWorkHook(ctx) {
|
|
46085
46385
|
return {
|
|
46086
46386
|
"chat.message": async (input, output) => {
|
|
46087
46387
|
const parts = output.parts;
|
|
46088
46388
|
const promptText = parts?.filter((p) => p.type === "text" && p.text).map((p) => p.text).join(`
|
|
46089
46389
|
`).trim() || "";
|
|
46090
|
-
|
|
46091
|
-
if (!isStartWorkCommand) {
|
|
46390
|
+
if (!promptText.includes("<session-context>"))
|
|
46092
46391
|
return;
|
|
46093
|
-
}
|
|
46094
|
-
log(`[${HOOK_NAME6}] Processing start-work command`, {
|
|
46095
|
-
sessionID: input.sessionID
|
|
46096
|
-
});
|
|
46392
|
+
log(`[${HOOK_NAME6}] Processing start-work command`, { sessionID: input.sessionID });
|
|
46097
46393
|
updateSessionAgent(input.sessionID, "atlas");
|
|
46098
46394
|
const existingState = readBoulderState(ctx.directory);
|
|
46099
46395
|
const sessionId = input.sessionID;
|
|
46100
46396
|
const timestamp2 = new Date().toISOString();
|
|
46397
|
+
const { planName: explicitPlanName, explicitWorktreePath } = parseUserRequest(promptText);
|
|
46398
|
+
const { worktreePath, block: worktreeBlock } = resolveWorktreeContext(explicitWorktreePath);
|
|
46101
46399
|
let contextInfo = "";
|
|
46102
|
-
const explicitPlanName = extractUserRequestPlanName(promptText);
|
|
46103
46400
|
if (explicitPlanName) {
|
|
46104
|
-
log(`[${HOOK_NAME6}] Explicit plan name requested: ${explicitPlanName}`, {
|
|
46105
|
-
sessionID: input.sessionID
|
|
46106
|
-
});
|
|
46401
|
+
log(`[${HOOK_NAME6}] Explicit plan name requested: ${explicitPlanName}`, { sessionID: input.sessionID });
|
|
46107
46402
|
const allPlans = findPrometheusPlans(ctx.directory);
|
|
46108
46403
|
const matchedPlan = findPlanByName(allPlans, explicitPlanName);
|
|
46109
46404
|
if (matchedPlan) {
|
|
@@ -46115,10 +46410,9 @@ function createStartWorkHook(ctx) {
|
|
|
46115
46410
|
The requested plan "${getPlanName(matchedPlan)}" has been completed.
|
|
46116
46411
|
All ${progress.total} tasks are done. Create a new plan with: /plan "your task"`;
|
|
46117
46412
|
} else {
|
|
46118
|
-
if (existingState)
|
|
46413
|
+
if (existingState)
|
|
46119
46414
|
clearBoulderState(ctx.directory);
|
|
46120
|
-
|
|
46121
|
-
const newState = createBoulderState(matchedPlan, sessionId, "atlas");
|
|
46415
|
+
const newState = createBoulderState(matchedPlan, sessionId, "atlas", worktreePath);
|
|
46122
46416
|
writeBoulderState(ctx.directory, newState);
|
|
46123
46417
|
contextInfo = `
|
|
46124
46418
|
## Auto-Selected Plan
|
|
@@ -46128,6 +46422,7 @@ All ${progress.total} tasks are done. Create a new plan with: /plan "your task"`
|
|
|
46128
46422
|
**Progress**: ${progress.completed}/${progress.total} tasks
|
|
46129
46423
|
**Session ID**: ${sessionId}
|
|
46130
46424
|
**Started**: ${timestamp2}
|
|
46425
|
+
${worktreeBlock}
|
|
46131
46426
|
|
|
46132
46427
|
boulder.json has been created. Read the plan and begin execution.`;
|
|
46133
46428
|
}
|
|
@@ -46159,7 +46454,19 @@ No incomplete plans available. Create a new plan with: /plan "your task"`;
|
|
|
46159
46454
|
} else if (existingState) {
|
|
46160
46455
|
const progress = getPlanProgress(existingState.active_plan);
|
|
46161
46456
|
if (!progress.isComplete) {
|
|
46162
|
-
|
|
46457
|
+
const effectiveWorktree = worktreePath ?? existingState.worktree_path;
|
|
46458
|
+
if (worktreePath !== undefined) {
|
|
46459
|
+
const updatedSessions = existingState.session_ids.includes(sessionId) ? existingState.session_ids : [...existingState.session_ids, sessionId];
|
|
46460
|
+
writeBoulderState(ctx.directory, {
|
|
46461
|
+
...existingState,
|
|
46462
|
+
worktree_path: worktreePath,
|
|
46463
|
+
session_ids: updatedSessions
|
|
46464
|
+
});
|
|
46465
|
+
} else {
|
|
46466
|
+
appendSessionId(ctx.directory, sessionId);
|
|
46467
|
+
}
|
|
46468
|
+
const worktreeDisplay = effectiveWorktree ? `
|
|
46469
|
+
**Worktree**: ${effectiveWorktree}` : worktreeBlock;
|
|
46163
46470
|
contextInfo = `
|
|
46164
46471
|
## Active Work Session Found
|
|
46165
46472
|
|
|
@@ -46169,6 +46476,7 @@ No incomplete plans available. Create a new plan with: /plan "your task"`;
|
|
|
46169
46476
|
**Progress**: ${progress.completed}/${progress.total} tasks completed
|
|
46170
46477
|
**Sessions**: ${existingState.session_ids.length + 1} (current session appended)
|
|
46171
46478
|
**Started**: ${existingState.started_at}
|
|
46479
|
+
${worktreeDisplay}
|
|
46172
46480
|
|
|
46173
46481
|
The current session (${sessionId}) has been added to session_ids.
|
|
46174
46482
|
Read the plan file and continue from the first unchecked task.`;
|
|
@@ -46185,7 +46493,6 @@ Looking for new plans...`;
|
|
|
46185
46493
|
const incompletePlans = plans.filter((p) => !getPlanProgress(p).isComplete);
|
|
46186
46494
|
if (plans.length === 0) {
|
|
46187
46495
|
contextInfo += `
|
|
46188
|
-
|
|
46189
46496
|
## No Plans Found
|
|
46190
46497
|
|
|
46191
46498
|
No Prometheus plan files found at .sisyphus/plans/
|
|
@@ -46199,7 +46506,7 @@ All ${plans.length} plan(s) are complete. Create a new plan with: /plan "your ta
|
|
|
46199
46506
|
} else if (incompletePlans.length === 1) {
|
|
46200
46507
|
const planPath = incompletePlans[0];
|
|
46201
46508
|
const progress = getPlanProgress(planPath);
|
|
46202
|
-
const newState = createBoulderState(planPath, sessionId, "atlas");
|
|
46509
|
+
const newState = createBoulderState(planPath, sessionId, "atlas", worktreePath);
|
|
46203
46510
|
writeBoulderState(ctx.directory, newState);
|
|
46204
46511
|
contextInfo += `
|
|
46205
46512
|
|
|
@@ -46210,13 +46517,13 @@ All ${plans.length} plan(s) are complete. Create a new plan with: /plan "your ta
|
|
|
46210
46517
|
**Progress**: ${progress.completed}/${progress.total} tasks
|
|
46211
46518
|
**Session ID**: ${sessionId}
|
|
46212
46519
|
**Started**: ${timestamp2}
|
|
46520
|
+
${worktreeBlock}
|
|
46213
46521
|
|
|
46214
46522
|
boulder.json has been created. Read the plan and begin execution.`;
|
|
46215
46523
|
} else {
|
|
46216
46524
|
const planList = incompletePlans.map((p, i2) => {
|
|
46217
46525
|
const progress = getPlanProgress(p);
|
|
46218
|
-
const
|
|
46219
|
-
const modified = new Date(stat.mtimeMs).toISOString();
|
|
46526
|
+
const modified = new Date(statSync6(p).mtimeMs).toISOString();
|
|
46220
46527
|
return `${i2 + 1}. [${getPlanName(p)}] - Modified: ${modified} - Progress: ${progress.completed}/${progress.total}`;
|
|
46221
46528
|
}).join(`
|
|
46222
46529
|
`);
|
|
@@ -46231,6 +46538,7 @@ Session ID: ${sessionId}
|
|
|
46231
46538
|
${planList}
|
|
46232
46539
|
|
|
46233
46540
|
Ask the user which plan to work on. Present the options above and wait for their response.
|
|
46541
|
+
${worktreeBlock}
|
|
46234
46542
|
</system-reminder>`;
|
|
46235
46543
|
}
|
|
46236
46544
|
}
|
|
@@ -46244,7 +46552,8 @@ ${contextInfo}`;
|
|
|
46244
46552
|
}
|
|
46245
46553
|
log(`[${HOOK_NAME6}] Context injected`, {
|
|
46246
46554
|
sessionID: input.sessionID,
|
|
46247
|
-
hasExistingState: !!existingState
|
|
46555
|
+
hasExistingState: !!existingState,
|
|
46556
|
+
worktreePath
|
|
46248
46557
|
});
|
|
46249
46558
|
}
|
|
46250
46559
|
};
|
|
@@ -46496,6 +46805,7 @@ async function injectBoulderContinuation(input) {
|
|
|
46496
46805
|
remaining,
|
|
46497
46806
|
total,
|
|
46498
46807
|
agent,
|
|
46808
|
+
worktreePath,
|
|
46499
46809
|
backgroundManager,
|
|
46500
46810
|
sessionState
|
|
46501
46811
|
} = input;
|
|
@@ -46504,9 +46814,12 @@ async function injectBoulderContinuation(input) {
|
|
|
46504
46814
|
log(`[${HOOK_NAME7}] Skipped injection: background tasks running`, { sessionID });
|
|
46505
46815
|
return;
|
|
46506
46816
|
}
|
|
46817
|
+
const worktreeContext = worktreePath ? `
|
|
46818
|
+
|
|
46819
|
+
[Worktree: ${worktreePath}]` : "";
|
|
46507
46820
|
const prompt = BOULDER_CONTINUATION_PROMPT.replace(/{PLAN_NAME}/g, planName) + `
|
|
46508
46821
|
|
|
46509
|
-
[Status: ${total - remaining}/${total} completed, ${remaining} remaining]
|
|
46822
|
+
[Status: ${total - remaining}/${total} completed, ${remaining} remaining]` + worktreeContext;
|
|
46510
46823
|
try {
|
|
46511
46824
|
log(`[${HOOK_NAME7}] Injecting boulder continuation`, { sessionID, planName, remaining });
|
|
46512
46825
|
const promptContext = await resolveRecentPromptContextForSession(ctx, sessionID);
|
|
@@ -46525,6 +46838,7 @@ async function injectBoulderContinuation(input) {
|
|
|
46525
46838
|
log(`[${HOOK_NAME7}] Boulder continuation injected`, { sessionID });
|
|
46526
46839
|
} catch (err) {
|
|
46527
46840
|
sessionState.promptFailureCount += 1;
|
|
46841
|
+
sessionState.lastFailureAt = Date.now();
|
|
46528
46842
|
log(`[${HOOK_NAME7}] Boulder continuation failed`, {
|
|
46529
46843
|
sessionID,
|
|
46530
46844
|
error: String(err),
|
|
@@ -46549,6 +46863,7 @@ async function getLastAgentFromSession(sessionID, client) {
|
|
|
46549
46863
|
|
|
46550
46864
|
// src/hooks/atlas/event-handler.ts
|
|
46551
46865
|
var CONTINUATION_COOLDOWN_MS2 = 5000;
|
|
46866
|
+
var FAILURE_BACKOFF_MS = 5 * 60 * 1000;
|
|
46552
46867
|
function createAtlasEventHandler(input) {
|
|
46553
46868
|
const { ctx, options, sessions, getState } = input;
|
|
46554
46869
|
return async ({ event }) => {
|
|
@@ -46576,17 +46891,24 @@ function createAtlasEventHandler(input) {
|
|
|
46576
46891
|
return;
|
|
46577
46892
|
}
|
|
46578
46893
|
const state3 = getState(sessionID);
|
|
46894
|
+
const now = Date.now();
|
|
46579
46895
|
if (state3.lastEventWasAbortError) {
|
|
46580
46896
|
state3.lastEventWasAbortError = false;
|
|
46581
46897
|
log(`[${HOOK_NAME7}] Skipped: abort error immediately before idle`, { sessionID });
|
|
46582
46898
|
return;
|
|
46583
46899
|
}
|
|
46584
46900
|
if (state3.promptFailureCount >= 2) {
|
|
46585
|
-
|
|
46586
|
-
|
|
46587
|
-
|
|
46588
|
-
|
|
46589
|
-
|
|
46901
|
+
const timeSinceLastFailure = state3.lastFailureAt !== undefined ? now - state3.lastFailureAt : Number.POSITIVE_INFINITY;
|
|
46902
|
+
if (timeSinceLastFailure < FAILURE_BACKOFF_MS) {
|
|
46903
|
+
log(`[${HOOK_NAME7}] Skipped: continuation in backoff after repeated failures`, {
|
|
46904
|
+
sessionID,
|
|
46905
|
+
promptFailureCount: state3.promptFailureCount,
|
|
46906
|
+
backoffRemaining: FAILURE_BACKOFF_MS - timeSinceLastFailure
|
|
46907
|
+
});
|
|
46908
|
+
return;
|
|
46909
|
+
}
|
|
46910
|
+
state3.promptFailureCount = 0;
|
|
46911
|
+
state3.lastFailureAt = undefined;
|
|
46590
46912
|
}
|
|
46591
46913
|
const backgroundManager = options?.backgroundManager;
|
|
46592
46914
|
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
|
|
@@ -46602,21 +46924,21 @@ function createAtlasEventHandler(input) {
|
|
|
46602
46924
|
log(`[${HOOK_NAME7}] Skipped: continuation stopped for session`, { sessionID });
|
|
46603
46925
|
return;
|
|
46604
46926
|
}
|
|
46927
|
+
const sessionAgent = getSessionAgent(sessionID);
|
|
46605
46928
|
const lastAgent = await getLastAgentFromSession(sessionID, ctx.client);
|
|
46606
|
-
const
|
|
46929
|
+
const effectiveAgent = sessionAgent ?? lastAgent;
|
|
46930
|
+
const lastAgentKey = getAgentConfigKey(effectiveAgent ?? "");
|
|
46607
46931
|
const requiredAgent = getAgentConfigKey(boulderState.agent ?? "atlas");
|
|
46608
46932
|
const lastAgentMatchesRequired = lastAgentKey === requiredAgent;
|
|
46609
|
-
const boulderAgentWasNotExplicitlySet = boulderState.agent === undefined;
|
|
46610
46933
|
const boulderAgentDefaultsToAtlas = requiredAgent === "atlas";
|
|
46611
46934
|
const lastAgentIsSisyphus = lastAgentKey === "sisyphus";
|
|
46612
|
-
const
|
|
46613
|
-
const agentMatches = lastAgentMatchesRequired ||
|
|
46935
|
+
const allowSisyphusForAtlasBoulder = boulderAgentDefaultsToAtlas && lastAgentIsSisyphus;
|
|
46936
|
+
const agentMatches = lastAgentMatchesRequired || allowSisyphusForAtlasBoulder;
|
|
46614
46937
|
if (!agentMatches) {
|
|
46615
46938
|
log(`[${HOOK_NAME7}] Skipped: last agent does not match boulder agent`, {
|
|
46616
46939
|
sessionID,
|
|
46617
|
-
lastAgent:
|
|
46618
|
-
requiredAgent
|
|
46619
|
-
boulderAgentExplicitlySet: boulderState.agent !== undefined
|
|
46940
|
+
lastAgent: effectiveAgent ?? "unknown",
|
|
46941
|
+
requiredAgent
|
|
46620
46942
|
});
|
|
46621
46943
|
return;
|
|
46622
46944
|
}
|
|
@@ -46625,7 +46947,6 @@ function createAtlasEventHandler(input) {
|
|
|
46625
46947
|
log(`[${HOOK_NAME7}] Boulder complete`, { sessionID, plan: boulderState.plan_name });
|
|
46626
46948
|
return;
|
|
46627
46949
|
}
|
|
46628
|
-
const now = Date.now();
|
|
46629
46950
|
if (state3.lastContinuationInjectedAt && now - state3.lastContinuationInjectedAt < CONTINUATION_COOLDOWN_MS2) {
|
|
46630
46951
|
log(`[${HOOK_NAME7}] Skipped: continuation cooldown active`, {
|
|
46631
46952
|
sessionID,
|
|
@@ -46643,6 +46964,7 @@ function createAtlasEventHandler(input) {
|
|
|
46643
46964
|
remaining,
|
|
46644
46965
|
total: progress.total,
|
|
46645
46966
|
agent: boulderState.agent,
|
|
46967
|
+
worktreePath: boulderState.worktree_path,
|
|
46646
46968
|
backgroundManager,
|
|
46647
46969
|
sessionState: state3
|
|
46648
46970
|
});
|
|
@@ -47125,12 +47447,36 @@ function createQuestionLabelTruncatorHook() {
|
|
|
47125
47447
|
// src/hooks/stop-continuation-guard/hook.ts
|
|
47126
47448
|
init_logger();
|
|
47127
47449
|
var HOOK_NAME8 = "stop-continuation-guard";
|
|
47128
|
-
function createStopContinuationGuardHook(ctx) {
|
|
47450
|
+
function createStopContinuationGuardHook(ctx, options) {
|
|
47129
47451
|
const stoppedSessions = new Set;
|
|
47130
47452
|
const stop = (sessionID) => {
|
|
47131
47453
|
stoppedSessions.add(sessionID);
|
|
47132
47454
|
setContinuationMarkerSource(ctx.directory, sessionID, "stop", "stopped", "continuation stopped");
|
|
47133
47455
|
log(`[${HOOK_NAME8}] Continuation stopped for session`, { sessionID });
|
|
47456
|
+
const backgroundManager = options?.backgroundManager;
|
|
47457
|
+
if (!backgroundManager) {
|
|
47458
|
+
return;
|
|
47459
|
+
}
|
|
47460
|
+
const cancellableTasks = backgroundManager.getAllDescendantTasks(sessionID).filter((task) => task.status === "running" || task.status === "pending");
|
|
47461
|
+
if (cancellableTasks.length === 0) {
|
|
47462
|
+
return;
|
|
47463
|
+
}
|
|
47464
|
+
Promise.allSettled(cancellableTasks.map(async (task) => {
|
|
47465
|
+
await backgroundManager.cancelTask(task.id, {
|
|
47466
|
+
source: "stop-continuation",
|
|
47467
|
+
reason: "Continuation stopped via /stop-continuation",
|
|
47468
|
+
abortSession: task.status === "running",
|
|
47469
|
+
skipNotification: true
|
|
47470
|
+
});
|
|
47471
|
+
})).then((results) => {
|
|
47472
|
+
const cancelledCount = results.filter((result) => result.status === "fulfilled").length;
|
|
47473
|
+
const failedCount = results.length - cancelledCount;
|
|
47474
|
+
log(`[${HOOK_NAME8}] Cancelled background tasks for stopped session`, {
|
|
47475
|
+
sessionID,
|
|
47476
|
+
cancelledCount,
|
|
47477
|
+
failedCount
|
|
47478
|
+
});
|
|
47479
|
+
});
|
|
47134
47480
|
};
|
|
47135
47481
|
const isStopped = (sessionID) => {
|
|
47136
47482
|
return stoppedSessions.has(sessionID);
|
|
@@ -47531,10 +47877,24 @@ function createUnstableAgentBabysitterHook(ctx, options) {
|
|
|
47531
47877
|
// src/hooks/preemptive-compaction.ts
|
|
47532
47878
|
init_logger();
|
|
47533
47879
|
var DEFAULT_ACTUAL_LIMIT = 200000;
|
|
47880
|
+
var PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120000;
|
|
47534
47881
|
function getAnthropicActualLimit3(modelCacheState) {
|
|
47535
47882
|
return (modelCacheState?.anthropicContext1MEnabled ?? false) || process.env.ANTHROPIC_1M_CONTEXT === "true" || process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true" ? 1e6 : DEFAULT_ACTUAL_LIMIT;
|
|
47536
47883
|
}
|
|
47537
47884
|
var PREEMPTIVE_COMPACTION_THRESHOLD = 0.78;
|
|
47885
|
+
function withTimeout2(promise2, timeoutMs, errorMessage) {
|
|
47886
|
+
let timeoutID;
|
|
47887
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
47888
|
+
timeoutID = setTimeout(() => {
|
|
47889
|
+
reject(new Error(errorMessage));
|
|
47890
|
+
}, timeoutMs);
|
|
47891
|
+
});
|
|
47892
|
+
return Promise.race([promise2, timeoutPromise]).finally(() => {
|
|
47893
|
+
if (timeoutID !== undefined) {
|
|
47894
|
+
clearTimeout(timeoutID);
|
|
47895
|
+
}
|
|
47896
|
+
});
|
|
47897
|
+
}
|
|
47538
47898
|
function isAnthropicProvider2(providerID) {
|
|
47539
47899
|
return providerID === "anthropic" || providerID === "google-vertex-anthropic";
|
|
47540
47900
|
}
|
|
@@ -47561,11 +47921,11 @@ function createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState) {
|
|
|
47561
47921
|
compactionInProgress.add(sessionID);
|
|
47562
47922
|
try {
|
|
47563
47923
|
const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel(pluginConfig, sessionID, cached2.providerID, modelID);
|
|
47564
|
-
await ctx.client.session.summarize({
|
|
47924
|
+
await withTimeout2(ctx.client.session.summarize({
|
|
47565
47925
|
path: { id: sessionID },
|
|
47566
47926
|
body: { providerID: targetProviderID, modelID: targetModelID, auto: true },
|
|
47567
47927
|
query: { directory: ctx.directory }
|
|
47568
|
-
});
|
|
47928
|
+
}), PREEMPTIVE_COMPACTION_TIMEOUT_MS, `Compaction summarize timed out after ${PREEMPTIVE_COMPACTION_TIMEOUT_MS}ms`);
|
|
47569
47929
|
compactedSessions.add(sessionID);
|
|
47570
47930
|
} catch (error45) {
|
|
47571
47931
|
log("[preemptive-compaction] Compaction failed", { sessionID, error: String(error45) });
|
|
@@ -47773,7 +48133,9 @@ var AgentOverridesSchema = exports_external.object({
|
|
|
47773
48133
|
build: AgentOverrideConfigSchema.optional(),
|
|
47774
48134
|
plan: AgentOverrideConfigSchema.optional(),
|
|
47775
48135
|
sisyphus: AgentOverrideConfigSchema.optional(),
|
|
47776
|
-
hephaestus: AgentOverrideConfigSchema.
|
|
48136
|
+
hephaestus: AgentOverrideConfigSchema.extend({
|
|
48137
|
+
allow_non_gpt_model: exports_external.boolean().optional()
|
|
48138
|
+
}).optional(),
|
|
47777
48139
|
"sisyphus-junior": AgentOverrideConfigSchema.optional(),
|
|
47778
48140
|
"OpenCode-Builder": AgentOverrideConfigSchema.optional(),
|
|
47779
48141
|
prometheus: AgentOverrideConfigSchema.optional(),
|
|
@@ -47824,6 +48186,7 @@ var CategoryConfigSchema = exports_external.object({
|
|
|
47824
48186
|
textVerbosity: exports_external.enum(["low", "medium", "high"]).optional(),
|
|
47825
48187
|
tools: exports_external.record(exports_external.string(), exports_external.boolean()).optional(),
|
|
47826
48188
|
prompt_append: exports_external.string().optional(),
|
|
48189
|
+
max_prompt_tokens: exports_external.number().int().positive().optional(),
|
|
47827
48190
|
is_unstable_agent: exports_external.boolean().optional(),
|
|
47828
48191
|
disable: exports_external.boolean().optional()
|
|
47829
48192
|
});
|
|
@@ -47959,7 +48322,8 @@ var HookNameSchema = exports_external.enum([
|
|
|
47959
48322
|
"runtime-fallback",
|
|
47960
48323
|
"write-existing-file-guard",
|
|
47961
48324
|
"anthropic-effort",
|
|
47962
|
-
"hashline-read-enhancer"
|
|
48325
|
+
"hashline-read-enhancer",
|
|
48326
|
+
"read-image-resizer"
|
|
47963
48327
|
]);
|
|
47964
48328
|
// src/config/schema/notification.ts
|
|
47965
48329
|
var NotificationConfigSchema = exports_external.object({
|
|
@@ -48066,7 +48430,7 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
|
|
|
48066
48430
|
new_task_system_enabled: exports_external.boolean().optional(),
|
|
48067
48431
|
default_run_agent: exports_external.string().optional(),
|
|
48068
48432
|
disabled_mcps: exports_external.array(AnyMcpNameSchema).optional(),
|
|
48069
|
-
disabled_agents: exports_external.array(
|
|
48433
|
+
disabled_agents: exports_external.array(exports_external.string()).optional(),
|
|
48070
48434
|
disabled_skills: exports_external.array(BuiltinSkillNameSchema).optional(),
|
|
48071
48435
|
disabled_hooks: exports_external.array(exports_external.string()).optional(),
|
|
48072
48436
|
disabled_commands: exports_external.array(BuiltinCommandNameSchema).optional(),
|
|
@@ -49535,6 +49899,511 @@ ${JSON_ERROR_REMINDER}`;
|
|
|
49535
49899
|
}
|
|
49536
49900
|
};
|
|
49537
49901
|
}
|
|
49902
|
+
// src/tools/look-at/mime-type-inference.ts
|
|
49903
|
+
import { extname as extname2 } from "path";
|
|
49904
|
+
function inferMimeTypeFromBase64(base64Data) {
|
|
49905
|
+
if (base64Data.startsWith("data:")) {
|
|
49906
|
+
const match = base64Data.match(/^data:([^;]+);/);
|
|
49907
|
+
if (match)
|
|
49908
|
+
return match[1];
|
|
49909
|
+
}
|
|
49910
|
+
try {
|
|
49911
|
+
const cleanData = base64Data.replace(/^data:[^;]+;base64,/, "");
|
|
49912
|
+
const header = atob(cleanData.slice(0, 16));
|
|
49913
|
+
if (header.startsWith("\x89PNG"))
|
|
49914
|
+
return "image/png";
|
|
49915
|
+
if (header.startsWith("\xFF\xD8\xFF"))
|
|
49916
|
+
return "image/jpeg";
|
|
49917
|
+
if (header.startsWith("GIF8"))
|
|
49918
|
+
return "image/gif";
|
|
49919
|
+
if (header.startsWith("RIFF") && header.includes("WEBP"))
|
|
49920
|
+
return "image/webp";
|
|
49921
|
+
if (header.startsWith("%PDF"))
|
|
49922
|
+
return "application/pdf";
|
|
49923
|
+
} catch {}
|
|
49924
|
+
return "image/png";
|
|
49925
|
+
}
|
|
49926
|
+
function inferMimeTypeFromFilePath(filePath) {
|
|
49927
|
+
const ext = extname2(filePath).toLowerCase();
|
|
49928
|
+
const mimeTypes = {
|
|
49929
|
+
".jpg": "image/jpeg",
|
|
49930
|
+
".jpeg": "image/jpeg",
|
|
49931
|
+
".png": "image/png",
|
|
49932
|
+
".webp": "image/webp",
|
|
49933
|
+
".heic": "image/heic",
|
|
49934
|
+
".heif": "image/heif",
|
|
49935
|
+
".mp4": "video/mp4",
|
|
49936
|
+
".mpeg": "video/mpeg",
|
|
49937
|
+
".mpg": "video/mpeg",
|
|
49938
|
+
".mov": "video/mov",
|
|
49939
|
+
".avi": "video/avi",
|
|
49940
|
+
".flv": "video/x-flv",
|
|
49941
|
+
".webm": "video/webm",
|
|
49942
|
+
".wmv": "video/wmv",
|
|
49943
|
+
".3gpp": "video/3gpp",
|
|
49944
|
+
".3gp": "video/3gpp",
|
|
49945
|
+
".wav": "audio/wav",
|
|
49946
|
+
".mp3": "audio/mp3",
|
|
49947
|
+
".aiff": "audio/aiff",
|
|
49948
|
+
".aac": "audio/aac",
|
|
49949
|
+
".ogg": "audio/ogg",
|
|
49950
|
+
".flac": "audio/flac",
|
|
49951
|
+
".pdf": "application/pdf",
|
|
49952
|
+
".txt": "text/plain",
|
|
49953
|
+
".csv": "text/csv",
|
|
49954
|
+
".md": "text/md",
|
|
49955
|
+
".html": "text/html",
|
|
49956
|
+
".json": "application/json",
|
|
49957
|
+
".xml": "application/xml",
|
|
49958
|
+
".js": "text/javascript",
|
|
49959
|
+
".py": "text/x-python"
|
|
49960
|
+
};
|
|
49961
|
+
return mimeTypes[ext] || "application/octet-stream";
|
|
49962
|
+
}
|
|
49963
|
+
function extractBase64Data(imageData) {
|
|
49964
|
+
if (imageData.startsWith("data:")) {
|
|
49965
|
+
const commaIndex = imageData.indexOf(",");
|
|
49966
|
+
if (commaIndex !== -1) {
|
|
49967
|
+
return imageData.slice(commaIndex + 1);
|
|
49968
|
+
}
|
|
49969
|
+
}
|
|
49970
|
+
return imageData;
|
|
49971
|
+
}
|
|
49972
|
+
|
|
49973
|
+
// src/hooks/read-image-resizer/image-dimensions.ts
|
|
49974
|
+
var HEADER_BYTES = 32768;
|
|
49975
|
+
var HEADER_BASE64_CHARS = Math.ceil(HEADER_BYTES / 3) * 4;
|
|
49976
|
+
function toImageDimensions(width, height) {
|
|
49977
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) {
|
|
49978
|
+
return null;
|
|
49979
|
+
}
|
|
49980
|
+
if (width <= 0 || height <= 0) {
|
|
49981
|
+
return null;
|
|
49982
|
+
}
|
|
49983
|
+
return { width, height };
|
|
49984
|
+
}
|
|
49985
|
+
function parsePngDimensions(buffer) {
|
|
49986
|
+
if (buffer.length < 24) {
|
|
49987
|
+
return null;
|
|
49988
|
+
}
|
|
49989
|
+
const isPngSignature = buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71 && buffer[4] === 13 && buffer[5] === 10 && buffer[6] === 26 && buffer[7] === 10;
|
|
49990
|
+
if (!isPngSignature || buffer.toString("ascii", 12, 16) !== "IHDR") {
|
|
49991
|
+
return null;
|
|
49992
|
+
}
|
|
49993
|
+
const width = buffer.readUInt32BE(16);
|
|
49994
|
+
const height = buffer.readUInt32BE(20);
|
|
49995
|
+
return toImageDimensions(width, height);
|
|
49996
|
+
}
|
|
49997
|
+
function parseGifDimensions(buffer) {
|
|
49998
|
+
if (buffer.length < 10) {
|
|
49999
|
+
return null;
|
|
50000
|
+
}
|
|
50001
|
+
if (buffer.toString("ascii", 0, 4) !== "GIF8") {
|
|
50002
|
+
return null;
|
|
50003
|
+
}
|
|
50004
|
+
const width = buffer.readUInt16LE(6);
|
|
50005
|
+
const height = buffer.readUInt16LE(8);
|
|
50006
|
+
return toImageDimensions(width, height);
|
|
50007
|
+
}
|
|
50008
|
+
function parseJpegDimensions(buffer) {
|
|
50009
|
+
if (buffer.length < 4 || buffer[0] !== 255 || buffer[1] !== 216) {
|
|
50010
|
+
return null;
|
|
50011
|
+
}
|
|
50012
|
+
let offset = 2;
|
|
50013
|
+
while (offset < buffer.length) {
|
|
50014
|
+
if (buffer[offset] !== 255) {
|
|
50015
|
+
offset += 1;
|
|
50016
|
+
continue;
|
|
50017
|
+
}
|
|
50018
|
+
while (offset < buffer.length && buffer[offset] === 255) {
|
|
50019
|
+
offset += 1;
|
|
50020
|
+
}
|
|
50021
|
+
if (offset >= buffer.length) {
|
|
50022
|
+
return null;
|
|
50023
|
+
}
|
|
50024
|
+
const marker = buffer[offset];
|
|
50025
|
+
offset += 1;
|
|
50026
|
+
if (marker === 217 || marker === 218) {
|
|
50027
|
+
break;
|
|
50028
|
+
}
|
|
50029
|
+
if (offset + 1 >= buffer.length) {
|
|
50030
|
+
return null;
|
|
50031
|
+
}
|
|
50032
|
+
const segmentLength = buffer.readUInt16BE(offset);
|
|
50033
|
+
if (segmentLength < 2) {
|
|
50034
|
+
return null;
|
|
50035
|
+
}
|
|
50036
|
+
if ((marker === 192 || marker === 194) && offset + 7 < buffer.length) {
|
|
50037
|
+
const height = buffer.readUInt16BE(offset + 3);
|
|
50038
|
+
const width = buffer.readUInt16BE(offset + 5);
|
|
50039
|
+
return toImageDimensions(width, height);
|
|
50040
|
+
}
|
|
50041
|
+
offset += segmentLength;
|
|
50042
|
+
}
|
|
50043
|
+
return null;
|
|
50044
|
+
}
|
|
50045
|
+
function readUInt24LE(buffer, offset) {
|
|
50046
|
+
return buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16;
|
|
50047
|
+
}
|
|
50048
|
+
function parseWebpDimensions(buffer) {
|
|
50049
|
+
if (buffer.length < 16) {
|
|
50050
|
+
return null;
|
|
50051
|
+
}
|
|
50052
|
+
if (buffer.toString("ascii", 0, 4) !== "RIFF" || buffer.toString("ascii", 8, 12) !== "WEBP") {
|
|
50053
|
+
return null;
|
|
50054
|
+
}
|
|
50055
|
+
const chunkType = buffer.toString("ascii", 12, 16);
|
|
50056
|
+
if (chunkType === "VP8 ") {
|
|
50057
|
+
if (buffer[23] !== 157 || buffer[24] !== 1 || buffer[25] !== 42) {
|
|
50058
|
+
return null;
|
|
50059
|
+
}
|
|
50060
|
+
const width = buffer.readUInt16LE(26) & 16383;
|
|
50061
|
+
const height = buffer.readUInt16LE(28) & 16383;
|
|
50062
|
+
return toImageDimensions(width, height);
|
|
50063
|
+
}
|
|
50064
|
+
if (chunkType === "VP8L") {
|
|
50065
|
+
if (buffer.length < 25 || buffer[20] !== 47) {
|
|
50066
|
+
return null;
|
|
50067
|
+
}
|
|
50068
|
+
const bits = buffer.readUInt32LE(21);
|
|
50069
|
+
const width = (bits & 16383) + 1;
|
|
50070
|
+
const height = (bits >>> 14 & 16383) + 1;
|
|
50071
|
+
return toImageDimensions(width, height);
|
|
50072
|
+
}
|
|
50073
|
+
if (chunkType === "VP8X") {
|
|
50074
|
+
const width = readUInt24LE(buffer, 24) + 1;
|
|
50075
|
+
const height = readUInt24LE(buffer, 27) + 1;
|
|
50076
|
+
return toImageDimensions(width, height);
|
|
50077
|
+
}
|
|
50078
|
+
return null;
|
|
50079
|
+
}
|
|
50080
|
+
function parseImageDimensions(base64DataUrl, mimeType) {
|
|
50081
|
+
try {
|
|
50082
|
+
if (!base64DataUrl || !mimeType) {
|
|
50083
|
+
return null;
|
|
50084
|
+
}
|
|
50085
|
+
const rawBase64 = extractBase64Data(base64DataUrl);
|
|
50086
|
+
if (!rawBase64) {
|
|
50087
|
+
return null;
|
|
50088
|
+
}
|
|
50089
|
+
const headerBase64 = rawBase64.length > HEADER_BASE64_CHARS ? rawBase64.slice(0, HEADER_BASE64_CHARS) : rawBase64;
|
|
50090
|
+
const buffer = Buffer.from(headerBase64, "base64");
|
|
50091
|
+
if (buffer.length === 0) {
|
|
50092
|
+
return null;
|
|
50093
|
+
}
|
|
50094
|
+
const normalizedMime = mimeType.toLowerCase();
|
|
50095
|
+
if (normalizedMime === "image/png") {
|
|
50096
|
+
return parsePngDimensions(buffer);
|
|
50097
|
+
}
|
|
50098
|
+
if (normalizedMime === "image/gif") {
|
|
50099
|
+
return parseGifDimensions(buffer);
|
|
50100
|
+
}
|
|
50101
|
+
if (normalizedMime === "image/jpeg" || normalizedMime === "image/jpg") {
|
|
50102
|
+
return parseJpegDimensions(buffer);
|
|
50103
|
+
}
|
|
50104
|
+
if (normalizedMime === "image/webp") {
|
|
50105
|
+
return parseWebpDimensions(buffer);
|
|
50106
|
+
}
|
|
50107
|
+
return null;
|
|
50108
|
+
} catch {
|
|
50109
|
+
return null;
|
|
50110
|
+
}
|
|
50111
|
+
}
|
|
50112
|
+
|
|
50113
|
+
// src/hooks/read-image-resizer/image-resizer.ts
|
|
50114
|
+
var ANTHROPIC_MAX_LONG_EDGE = 1568;
|
|
50115
|
+
var ANTHROPIC_MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
50116
|
+
function resolveSharpFactory(sharpModule) {
|
|
50117
|
+
if (typeof sharpModule === "function") {
|
|
50118
|
+
return sharpModule;
|
|
50119
|
+
}
|
|
50120
|
+
if (!sharpModule || typeof sharpModule !== "object") {
|
|
50121
|
+
return null;
|
|
50122
|
+
}
|
|
50123
|
+
const defaultExport = Reflect.get(sharpModule, "default");
|
|
50124
|
+
return typeof defaultExport === "function" ? defaultExport : null;
|
|
50125
|
+
}
|
|
50126
|
+
function resolveSharpFormat(mimeType) {
|
|
50127
|
+
const normalizedMime = mimeType.toLowerCase();
|
|
50128
|
+
if (normalizedMime === "image/png") {
|
|
50129
|
+
return "png";
|
|
50130
|
+
}
|
|
50131
|
+
if (normalizedMime === "image/gif") {
|
|
50132
|
+
return "gif";
|
|
50133
|
+
}
|
|
50134
|
+
if (normalizedMime === "image/webp") {
|
|
50135
|
+
return "webp";
|
|
50136
|
+
}
|
|
50137
|
+
return "jpeg";
|
|
50138
|
+
}
|
|
50139
|
+
function canAdjustQuality(format2) {
|
|
50140
|
+
return format2 === "jpeg" || format2 === "webp";
|
|
50141
|
+
}
|
|
50142
|
+
function toDimensions(metadata) {
|
|
50143
|
+
const { width, height } = metadata;
|
|
50144
|
+
if (!width || !height) {
|
|
50145
|
+
return null;
|
|
50146
|
+
}
|
|
50147
|
+
return { width, height };
|
|
50148
|
+
}
|
|
50149
|
+
async function renderResizedBuffer(args) {
|
|
50150
|
+
const { sharpFactory, inputBuffer, target, format: format2, quality } = args;
|
|
50151
|
+
return sharpFactory(inputBuffer).resize(target.width, target.height, { fit: "inside" }).toFormat(format2, quality ? { quality } : undefined).toBuffer();
|
|
50152
|
+
}
|
|
50153
|
+
function getErrorMessage3(error45) {
|
|
50154
|
+
return error45 instanceof Error ? error45.message : String(error45);
|
|
50155
|
+
}
|
|
50156
|
+
function calculateTargetDimensions(width, height, maxLongEdge = ANTHROPIC_MAX_LONG_EDGE) {
|
|
50157
|
+
if (width <= 0 || height <= 0 || maxLongEdge <= 0) {
|
|
50158
|
+
return null;
|
|
50159
|
+
}
|
|
50160
|
+
const longEdge = Math.max(width, height);
|
|
50161
|
+
if (longEdge <= maxLongEdge) {
|
|
50162
|
+
return null;
|
|
50163
|
+
}
|
|
50164
|
+
if (width >= height) {
|
|
50165
|
+
return {
|
|
50166
|
+
width: maxLongEdge,
|
|
50167
|
+
height: Math.max(1, Math.floor(height * maxLongEdge / width))
|
|
50168
|
+
};
|
|
50169
|
+
}
|
|
50170
|
+
return {
|
|
50171
|
+
width: Math.max(1, Math.floor(width * maxLongEdge / height)),
|
|
50172
|
+
height: maxLongEdge
|
|
50173
|
+
};
|
|
50174
|
+
}
|
|
50175
|
+
async function resizeImage(base64DataUrl, mimeType, target) {
|
|
50176
|
+
try {
|
|
50177
|
+
const sharpModuleName = "sharp";
|
|
50178
|
+
const sharpModule = await import(sharpModuleName).catch(() => null);
|
|
50179
|
+
if (!sharpModule) {
|
|
50180
|
+
log("[read-image-resizer] sharp unavailable, skipping resize");
|
|
50181
|
+
return null;
|
|
50182
|
+
}
|
|
50183
|
+
const sharpFactory = resolveSharpFactory(sharpModule);
|
|
50184
|
+
if (!sharpFactory) {
|
|
50185
|
+
log("[read-image-resizer] sharp import has unexpected shape");
|
|
50186
|
+
return null;
|
|
50187
|
+
}
|
|
50188
|
+
const rawBase64 = extractBase64Data(base64DataUrl);
|
|
50189
|
+
if (!rawBase64) {
|
|
50190
|
+
return null;
|
|
50191
|
+
}
|
|
50192
|
+
const inputBuffer = Buffer.from(rawBase64, "base64");
|
|
50193
|
+
if (inputBuffer.length === 0) {
|
|
50194
|
+
return null;
|
|
50195
|
+
}
|
|
50196
|
+
const original = toDimensions(await sharpFactory(inputBuffer).metadata());
|
|
50197
|
+
if (!original) {
|
|
50198
|
+
return null;
|
|
50199
|
+
}
|
|
50200
|
+
const format2 = resolveSharpFormat(mimeType);
|
|
50201
|
+
let resizedBuffer = await renderResizedBuffer({
|
|
50202
|
+
sharpFactory,
|
|
50203
|
+
inputBuffer,
|
|
50204
|
+
target,
|
|
50205
|
+
format: format2
|
|
50206
|
+
});
|
|
50207
|
+
if (resizedBuffer.length > ANTHROPIC_MAX_FILE_SIZE && canAdjustQuality(format2)) {
|
|
50208
|
+
for (const quality of [80, 60, 40]) {
|
|
50209
|
+
resizedBuffer = await renderResizedBuffer({
|
|
50210
|
+
sharpFactory,
|
|
50211
|
+
inputBuffer,
|
|
50212
|
+
target,
|
|
50213
|
+
format: format2,
|
|
50214
|
+
quality
|
|
50215
|
+
});
|
|
50216
|
+
if (resizedBuffer.length <= ANTHROPIC_MAX_FILE_SIZE) {
|
|
50217
|
+
break;
|
|
50218
|
+
}
|
|
50219
|
+
}
|
|
50220
|
+
}
|
|
50221
|
+
const resized = toDimensions(await sharpFactory(resizedBuffer).metadata());
|
|
50222
|
+
if (!resized) {
|
|
50223
|
+
return null;
|
|
50224
|
+
}
|
|
50225
|
+
return {
|
|
50226
|
+
resizedDataUrl: `data:${mimeType};base64,${resizedBuffer.toString("base64")}`,
|
|
50227
|
+
original,
|
|
50228
|
+
resized
|
|
50229
|
+
};
|
|
50230
|
+
} catch (error45) {
|
|
50231
|
+
log("[read-image-resizer] resize failed", {
|
|
50232
|
+
error: getErrorMessage3(error45),
|
|
50233
|
+
mimeType,
|
|
50234
|
+
target
|
|
50235
|
+
});
|
|
50236
|
+
return null;
|
|
50237
|
+
}
|
|
50238
|
+
}
|
|
50239
|
+
|
|
50240
|
+
// src/shared/session-model-state.ts
|
|
50241
|
+
var sessionModels = new Map;
|
|
50242
|
+
function setSessionModel(sessionID, model) {
|
|
50243
|
+
sessionModels.set(sessionID, model);
|
|
50244
|
+
}
|
|
50245
|
+
function getSessionModel(sessionID) {
|
|
50246
|
+
return sessionModels.get(sessionID);
|
|
50247
|
+
}
|
|
50248
|
+
function clearSessionModel(sessionID) {
|
|
50249
|
+
sessionModels.delete(sessionID);
|
|
50250
|
+
}
|
|
50251
|
+
|
|
50252
|
+
// src/hooks/read-image-resizer/hook.ts
|
|
50253
|
+
var SUPPORTED_IMAGE_MIMES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
50254
|
+
var TOKEN_DIVISOR = 750;
|
|
50255
|
+
function isReadTool2(toolName) {
|
|
50256
|
+
return toolName.toLowerCase() === "read";
|
|
50257
|
+
}
|
|
50258
|
+
function asRecord2(value) {
|
|
50259
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
50260
|
+
return null;
|
|
50261
|
+
}
|
|
50262
|
+
return value;
|
|
50263
|
+
}
|
|
50264
|
+
function isImageAttachmentRecord(value) {
|
|
50265
|
+
const filename = value.filename;
|
|
50266
|
+
return typeof value.mime === "string" && typeof value.url === "string" && (typeof filename === "undefined" || typeof filename === "string");
|
|
50267
|
+
}
|
|
50268
|
+
function extractImageAttachments(output) {
|
|
50269
|
+
const attachmentsValue = output.attachments;
|
|
50270
|
+
if (!Array.isArray(attachmentsValue)) {
|
|
50271
|
+
return [];
|
|
50272
|
+
}
|
|
50273
|
+
const attachments = [];
|
|
50274
|
+
for (const attachmentValue of attachmentsValue) {
|
|
50275
|
+
const attachmentRecord = asRecord2(attachmentValue);
|
|
50276
|
+
if (!attachmentRecord) {
|
|
50277
|
+
continue;
|
|
50278
|
+
}
|
|
50279
|
+
const mime = attachmentRecord.mime;
|
|
50280
|
+
const url2 = attachmentRecord.url;
|
|
50281
|
+
if (typeof mime !== "string" || typeof url2 !== "string") {
|
|
50282
|
+
continue;
|
|
50283
|
+
}
|
|
50284
|
+
const normalizedMime = mime.toLowerCase();
|
|
50285
|
+
if (!SUPPORTED_IMAGE_MIMES.has(normalizedMime)) {
|
|
50286
|
+
continue;
|
|
50287
|
+
}
|
|
50288
|
+
attachmentRecord.mime = normalizedMime;
|
|
50289
|
+
attachmentRecord.url = url2;
|
|
50290
|
+
if (isImageAttachmentRecord(attachmentRecord)) {
|
|
50291
|
+
attachments.push(attachmentRecord);
|
|
50292
|
+
}
|
|
50293
|
+
}
|
|
50294
|
+
return attachments;
|
|
50295
|
+
}
|
|
50296
|
+
function calculateTokens(width, height) {
|
|
50297
|
+
return Math.ceil(width * height / TOKEN_DIVISOR);
|
|
50298
|
+
}
|
|
50299
|
+
function formatResizeAppendix(entries) {
|
|
50300
|
+
const header = entries.some((entry) => entry.status === "resized") ? "[Image Resize Info]" : "[Image Info]";
|
|
50301
|
+
const lines = [`
|
|
50302
|
+
|
|
50303
|
+
${header}`];
|
|
50304
|
+
for (const entry of entries) {
|
|
50305
|
+
if (entry.status === "unknown-dims" || !entry.originalDims) {
|
|
50306
|
+
lines.push(`- ${entry.filename}: dimensions could not be parsed`);
|
|
50307
|
+
continue;
|
|
50308
|
+
}
|
|
50309
|
+
const original = entry.originalDims;
|
|
50310
|
+
const originalText = `${original.width}x${original.height}`;
|
|
50311
|
+
const originalTokens = calculateTokens(original.width, original.height);
|
|
50312
|
+
if (entry.status === "within-limits") {
|
|
50313
|
+
lines.push(`- ${entry.filename}: ${originalText} (within limits, tokens: ${originalTokens})`);
|
|
50314
|
+
continue;
|
|
50315
|
+
}
|
|
50316
|
+
if (entry.status === "resize-skipped") {
|
|
50317
|
+
lines.push(`- ${entry.filename}: ${originalText} (resize skipped, tokens: ${originalTokens})`);
|
|
50318
|
+
continue;
|
|
50319
|
+
}
|
|
50320
|
+
if (!entry.resizedDims) {
|
|
50321
|
+
lines.push(`- ${entry.filename}: ${originalText} (resize skipped, tokens: ${originalTokens})`);
|
|
50322
|
+
continue;
|
|
50323
|
+
}
|
|
50324
|
+
const resized = entry.resizedDims;
|
|
50325
|
+
const resizedText = `${resized.width}x${resized.height}`;
|
|
50326
|
+
const resizedTokens = calculateTokens(resized.width, resized.height);
|
|
50327
|
+
lines.push(`- ${entry.filename}: ${originalText} -> ${resizedText} (resized, tokens: ${originalTokens} -> ${resizedTokens})`);
|
|
50328
|
+
}
|
|
50329
|
+
return lines.join(`
|
|
50330
|
+
`);
|
|
50331
|
+
}
|
|
50332
|
+
function resolveFilename(attachment, index) {
|
|
50333
|
+
if (attachment.filename && attachment.filename.trim().length > 0) {
|
|
50334
|
+
return attachment.filename;
|
|
50335
|
+
}
|
|
50336
|
+
return `image-${index + 1}`;
|
|
50337
|
+
}
|
|
50338
|
+
function createReadImageResizerHook(_ctx) {
|
|
50339
|
+
return {
|
|
50340
|
+
"tool.execute.after": async (input, output) => {
|
|
50341
|
+
if (!isReadTool2(input.tool)) {
|
|
50342
|
+
return;
|
|
50343
|
+
}
|
|
50344
|
+
const sessionModel = getSessionModel(input.sessionID);
|
|
50345
|
+
if (sessionModel?.providerID !== "anthropic") {
|
|
50346
|
+
return;
|
|
50347
|
+
}
|
|
50348
|
+
if (typeof output.output !== "string") {
|
|
50349
|
+
return;
|
|
50350
|
+
}
|
|
50351
|
+
const outputRecord = output;
|
|
50352
|
+
const attachments = extractImageAttachments(outputRecord);
|
|
50353
|
+
if (attachments.length === 0) {
|
|
50354
|
+
return;
|
|
50355
|
+
}
|
|
50356
|
+
const entries = [];
|
|
50357
|
+
for (const [index, attachment] of attachments.entries()) {
|
|
50358
|
+
const filename = resolveFilename(attachment, index);
|
|
50359
|
+
try {
|
|
50360
|
+
const originalDims = parseImageDimensions(attachment.url, attachment.mime);
|
|
50361
|
+
if (!originalDims) {
|
|
50362
|
+
entries.push({ filename, originalDims: null, resizedDims: null, status: "unknown-dims" });
|
|
50363
|
+
continue;
|
|
50364
|
+
}
|
|
50365
|
+
const targetDims = calculateTargetDimensions(originalDims.width, originalDims.height);
|
|
50366
|
+
if (!targetDims) {
|
|
50367
|
+
entries.push({
|
|
50368
|
+
filename,
|
|
50369
|
+
originalDims,
|
|
50370
|
+
resizedDims: null,
|
|
50371
|
+
status: "within-limits"
|
|
50372
|
+
});
|
|
50373
|
+
continue;
|
|
50374
|
+
}
|
|
50375
|
+
const resizedResult = await resizeImage(attachment.url, attachment.mime, targetDims);
|
|
50376
|
+
if (!resizedResult) {
|
|
50377
|
+
entries.push({
|
|
50378
|
+
filename,
|
|
50379
|
+
originalDims,
|
|
50380
|
+
resizedDims: null,
|
|
50381
|
+
status: "resize-skipped"
|
|
50382
|
+
});
|
|
50383
|
+
continue;
|
|
50384
|
+
}
|
|
50385
|
+
attachment.url = resizedResult.resizedDataUrl;
|
|
50386
|
+
entries.push({
|
|
50387
|
+
filename,
|
|
50388
|
+
originalDims: resizedResult.original,
|
|
50389
|
+
resizedDims: resizedResult.resized,
|
|
50390
|
+
status: "resized"
|
|
50391
|
+
});
|
|
50392
|
+
} catch (error45) {
|
|
50393
|
+
log("[read-image-resizer] attachment processing failed", {
|
|
50394
|
+
error: error45 instanceof Error ? error45.message : String(error45),
|
|
50395
|
+
filename
|
|
50396
|
+
});
|
|
50397
|
+
entries.push({ filename, originalDims: null, resizedDims: null, status: "unknown-dims" });
|
|
50398
|
+
}
|
|
50399
|
+
}
|
|
50400
|
+
if (entries.length === 0) {
|
|
50401
|
+
return;
|
|
50402
|
+
}
|
|
50403
|
+
output.output += formatResizeAppendix(entries);
|
|
50404
|
+
}
|
|
50405
|
+
};
|
|
50406
|
+
}
|
|
49538
50407
|
// src/hooks/anthropic-effort/hook.ts
|
|
49539
50408
|
var OPUS_4_6_PATTERN = /claude-opus-4[-.]6/i;
|
|
49540
50409
|
function normalizeModelID2(modelID) {
|
|
@@ -50019,9 +50888,9 @@ function getLanguageId(ext) {
|
|
|
50019
50888
|
}
|
|
50020
50889
|
// src/tools/lsp/lsp-process.ts
|
|
50021
50890
|
init_logger();
|
|
50022
|
-
var {spawn:
|
|
50023
|
-
import { spawn as
|
|
50024
|
-
import { existsSync as existsSync51, statSync as
|
|
50891
|
+
var {spawn: bunSpawn2 } = globalThis.Bun;
|
|
50892
|
+
import { spawn as nodeSpawn2 } from "child_process";
|
|
50893
|
+
import { existsSync as existsSync51, statSync as statSync7 } from "fs";
|
|
50025
50894
|
function shouldUseNodeSpawn() {
|
|
50026
50895
|
return process.platform === "win32";
|
|
50027
50896
|
}
|
|
@@ -50030,7 +50899,7 @@ function validateCwd(cwd) {
|
|
|
50030
50899
|
if (!existsSync51(cwd)) {
|
|
50031
50900
|
return { valid: false, error: `Working directory does not exist: ${cwd}` };
|
|
50032
50901
|
}
|
|
50033
|
-
const stats =
|
|
50902
|
+
const stats = statSync7(cwd);
|
|
50034
50903
|
if (!stats.isDirectory()) {
|
|
50035
50904
|
return { valid: false, error: `Path is not a directory: ${cwd}` };
|
|
50036
50905
|
}
|
|
@@ -50039,7 +50908,7 @@ function validateCwd(cwd) {
|
|
|
50039
50908
|
return { valid: false, error: `Cannot access working directory: ${cwd} (${err instanceof Error ? err.message : String(err)})` };
|
|
50040
50909
|
}
|
|
50041
50910
|
}
|
|
50042
|
-
function
|
|
50911
|
+
function wrapNodeProcess2(proc) {
|
|
50043
50912
|
let resolveExited;
|
|
50044
50913
|
let exitCode = null;
|
|
50045
50914
|
const exitedPromise = new Promise((resolve8) => {
|
|
@@ -50140,16 +51009,16 @@ function spawnProcess(command, options) {
|
|
|
50140
51009
|
if (shouldUseNodeSpawn()) {
|
|
50141
51010
|
const [cmd, ...args] = command;
|
|
50142
51011
|
log("[LSP] Using Node.js child_process on Windows to avoid Bun spawn segfault");
|
|
50143
|
-
const proc2 =
|
|
51012
|
+
const proc2 = nodeSpawn2(cmd, args, {
|
|
50144
51013
|
cwd: options.cwd,
|
|
50145
51014
|
env: options.env,
|
|
50146
51015
|
stdio: ["pipe", "pipe", "pipe"],
|
|
50147
51016
|
windowsHide: true,
|
|
50148
51017
|
shell: true
|
|
50149
51018
|
});
|
|
50150
|
-
return
|
|
51019
|
+
return wrapNodeProcess2(proc2);
|
|
50151
51020
|
}
|
|
50152
|
-
const proc =
|
|
51021
|
+
const proc = bunSpawn2(command, {
|
|
50153
51022
|
stdin: "pipe",
|
|
50154
51023
|
stdout: "pipe",
|
|
50155
51024
|
stderr: "pipe",
|
|
@@ -50160,7 +51029,7 @@ function spawnProcess(command, options) {
|
|
|
50160
51029
|
}
|
|
50161
51030
|
// src/tools/lsp/lsp-client.ts
|
|
50162
51031
|
import { readFileSync as readFileSync38 } from "fs";
|
|
50163
|
-
import { extname as
|
|
51032
|
+
import { extname as extname3, resolve as resolve8 } from "path";
|
|
50164
51033
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
50165
51034
|
|
|
50166
51035
|
// src/tools/lsp/lsp-client-connection.ts
|
|
@@ -50168,7 +51037,7 @@ import { pathToFileURL } from "url";
|
|
|
50168
51037
|
|
|
50169
51038
|
// src/tools/lsp/lsp-client-transport.ts
|
|
50170
51039
|
var import_node = __toESM(require_main(), 1);
|
|
50171
|
-
import { Readable, Writable } from "stream";
|
|
51040
|
+
import { Readable as Readable2, Writable } from "stream";
|
|
50172
51041
|
init_logger();
|
|
50173
51042
|
|
|
50174
51043
|
class LSPClientTransport {
|
|
@@ -50204,7 +51073,7 @@ class LSPClientTransport {
|
|
|
50204
51073
|
stderr: ${stderr}` : ""));
|
|
50205
51074
|
}
|
|
50206
51075
|
const stdoutReader = this.proc.stdout.getReader();
|
|
50207
|
-
const nodeReadable = new
|
|
51076
|
+
const nodeReadable = new Readable2({
|
|
50208
51077
|
async read() {
|
|
50209
51078
|
try {
|
|
50210
51079
|
const { done, value } = await stdoutReader.read();
|
|
@@ -50425,7 +51294,7 @@ class LSPClient extends LSPClientConnection {
|
|
|
50425
51294
|
const uri = pathToFileURL2(absPath).href;
|
|
50426
51295
|
const text = readFileSync38(absPath, "utf-8");
|
|
50427
51296
|
if (!this.openedFiles.has(absPath)) {
|
|
50428
|
-
const ext =
|
|
51297
|
+
const ext = extname3(absPath);
|
|
50429
51298
|
const languageId = getLanguageId(ext);
|
|
50430
51299
|
const version2 = 1;
|
|
50431
51300
|
this.sendNotification("textDocument/didOpen", {
|
|
@@ -50762,7 +51631,7 @@ class LSPServerManager {
|
|
|
50762
51631
|
}
|
|
50763
51632
|
var lspManager = LSPServerManager.getInstance();
|
|
50764
51633
|
// src/tools/lsp/lsp-client-wrapper.ts
|
|
50765
|
-
import { extname as
|
|
51634
|
+
import { extname as extname4, resolve as resolve9 } from "path";
|
|
50766
51635
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
50767
51636
|
import { existsSync as existsSync52 } from "fs";
|
|
50768
51637
|
function findWorkspaceRoot(filePath) {
|
|
@@ -50823,7 +51692,7 @@ function formatServerLookupError(result) {
|
|
|
50823
51692
|
}
|
|
50824
51693
|
async function withLspClient(filePath, fn) {
|
|
50825
51694
|
const absPath = resolve9(filePath);
|
|
50826
|
-
const ext =
|
|
51695
|
+
const ext = extname4(absPath);
|
|
50827
51696
|
const result = findServerForExtension(ext);
|
|
50828
51697
|
if (result.status !== "found") {
|
|
50829
51698
|
throw new Error(formatServerLookupError(result));
|
|
@@ -51301,7 +52170,7 @@ var DEFAULT_MAX_MATCHES = 500;
|
|
|
51301
52170
|
// src/tools/ast-grep/sg-cli-path.ts
|
|
51302
52171
|
import { createRequire as createRequire4 } from "module";
|
|
51303
52172
|
import { dirname as dirname16, join as join63 } from "path";
|
|
51304
|
-
import { existsSync as existsSync54, statSync as
|
|
52173
|
+
import { existsSync as existsSync54, statSync as statSync8 } from "fs";
|
|
51305
52174
|
|
|
51306
52175
|
// src/tools/ast-grep/downloader.ts
|
|
51307
52176
|
import { existsSync as existsSync53 } from "fs";
|
|
@@ -51388,7 +52257,7 @@ async function ensureAstGrepBinary() {
|
|
|
51388
52257
|
// src/tools/ast-grep/sg-cli-path.ts
|
|
51389
52258
|
function isValidBinary(filePath) {
|
|
51390
52259
|
try {
|
|
51391
|
-
return
|
|
52260
|
+
return statSync8(filePath).size > 1e4;
|
|
51392
52261
|
} catch {
|
|
51393
52262
|
return false;
|
|
51394
52263
|
}
|
|
@@ -51823,6 +52692,9 @@ ${hint}`;
|
|
|
51823
52692
|
});
|
|
51824
52693
|
return { ast_grep_search, ast_grep_replace };
|
|
51825
52694
|
}
|
|
52695
|
+
// src/tools/grep/tools.ts
|
|
52696
|
+
import { resolve as resolve10 } from "path";
|
|
52697
|
+
|
|
51826
52698
|
// src/tools/grep/cli.ts
|
|
51827
52699
|
var {spawn: spawn11 } = globalThis.Bun;
|
|
51828
52700
|
|
|
@@ -52333,10 +53205,12 @@ function createGrepTools(ctx) {
|
|
|
52333
53205
|
output_mode: tool.schema.enum(["content", "files_with_matches", "count"]).optional().describe('Output mode: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts per file.'),
|
|
52334
53206
|
head_limit: tool.schema.number().optional().describe("Limit output to first N entries. 0 or omitted means no limit.")
|
|
52335
53207
|
},
|
|
52336
|
-
execute: async (args) => {
|
|
53208
|
+
execute: async (args, context) => {
|
|
52337
53209
|
try {
|
|
52338
53210
|
const globs = args.include ? [args.include] : undefined;
|
|
52339
|
-
const
|
|
53211
|
+
const runtimeCtx = context;
|
|
53212
|
+
const dir = typeof runtimeCtx.directory === "string" ? runtimeCtx.directory : ctx.directory;
|
|
53213
|
+
const searchPath = args.path ? resolve10(dir, args.path) : dir;
|
|
52340
53214
|
const paths = [searchPath];
|
|
52341
53215
|
const outputMode = args.output_mode ?? "files_with_matches";
|
|
52342
53216
|
const headLimit = args.head_limit ?? 0;
|
|
@@ -52365,7 +53239,11 @@ function createGrepTools(ctx) {
|
|
|
52365
53239
|
});
|
|
52366
53240
|
return { grep };
|
|
52367
53241
|
}
|
|
53242
|
+
// src/tools/glob/tools.ts
|
|
53243
|
+
import { resolve as resolve12 } from "path";
|
|
53244
|
+
|
|
52368
53245
|
// src/tools/glob/cli.ts
|
|
53246
|
+
import { resolve as resolve11 } from "path";
|
|
52369
53247
|
var {spawn: spawn12 } = globalThis.Bun;
|
|
52370
53248
|
|
|
52371
53249
|
// src/tools/glob/constants.ts
|
|
@@ -52450,10 +53328,9 @@ async function runRgFilesInternal(options, resolvedCli) {
|
|
|
52450
53328
|
let cwd;
|
|
52451
53329
|
if (isRg) {
|
|
52452
53330
|
const args = buildRgArgs2(options);
|
|
52453
|
-
|
|
52454
|
-
args.push(
|
|
53331
|
+
cwd = options.paths?.[0] || ".";
|
|
53332
|
+
args.push(".");
|
|
52455
53333
|
command = [cli.path, ...args];
|
|
52456
|
-
cwd = undefined;
|
|
52457
53334
|
} else if (isWindows2) {
|
|
52458
53335
|
command = buildPowerShellCommand(options);
|
|
52459
53336
|
cwd = undefined;
|
|
@@ -52500,7 +53377,7 @@ async function runRgFilesInternal(options, resolvedCli) {
|
|
|
52500
53377
|
}
|
|
52501
53378
|
let filePath;
|
|
52502
53379
|
if (isRg) {
|
|
52503
|
-
filePath = line;
|
|
53380
|
+
filePath = cwd ? resolve11(cwd, line) : line;
|
|
52504
53381
|
} else if (isWindows2) {
|
|
52505
53382
|
filePath = line.trim();
|
|
52506
53383
|
} else {
|
|
@@ -52555,14 +53432,15 @@ function createGlobTools(ctx) {
|
|
|
52555
53432
|
pattern: tool.schema.string().describe("The glob pattern to match files against"),
|
|
52556
53433
|
path: tool.schema.string().optional().describe("The directory to search in. If not specified, the current working directory will be used. " + 'IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - ' + "simply omit it for the default behavior. Must be a valid directory path if provided.")
|
|
52557
53434
|
},
|
|
52558
|
-
execute: async (args) => {
|
|
53435
|
+
execute: async (args, context) => {
|
|
52559
53436
|
try {
|
|
52560
53437
|
const cli = await resolveGrepCliWithAutoInstall();
|
|
52561
|
-
const
|
|
52562
|
-
const
|
|
53438
|
+
const runtimeCtx = context;
|
|
53439
|
+
const dir = typeof runtimeCtx.directory === "string" ? runtimeCtx.directory : ctx.directory;
|
|
53440
|
+
const searchPath = args.path ? resolve12(dir, args.path) : dir;
|
|
52563
53441
|
const result = await runRgFiles({
|
|
52564
53442
|
pattern: args.pattern,
|
|
52565
|
-
paths
|
|
53443
|
+
paths: [searchPath]
|
|
52566
53444
|
}, cli);
|
|
52567
53445
|
return formatGlobResult(result);
|
|
52568
53446
|
} catch (e) {
|
|
@@ -53470,7 +54348,7 @@ async function searchInSession(sessionID, query, caseSensitive = false, maxResul
|
|
|
53470
54348
|
// src/tools/session-manager/tools.ts
|
|
53471
54349
|
var SEARCH_TIMEOUT_MS = 60000;
|
|
53472
54350
|
var MAX_SESSIONS_TO_SCAN = 50;
|
|
53473
|
-
function
|
|
54351
|
+
function withTimeout3(promise2, ms, operation) {
|
|
53474
54352
|
return Promise.race([
|
|
53475
54353
|
promise2,
|
|
53476
54354
|
new Promise((_, reject) => setTimeout(() => reject(new Error(`${operation} timed out after ${ms}ms`)), ms))
|
|
@@ -53557,7 +54435,7 @@ function createSessionManagerTools(ctx) {
|
|
|
53557
54435
|
}
|
|
53558
54436
|
return allResults.slice(0, resultLimit);
|
|
53559
54437
|
};
|
|
53560
|
-
const results = await
|
|
54438
|
+
const results = await withTimeout3(searchOperation(), SEARCH_TIMEOUT_MS, "Search");
|
|
53561
54439
|
return formatSearchResults(results);
|
|
53562
54440
|
} catch (e) {
|
|
53563
54441
|
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
@@ -53675,7 +54553,7 @@ tmux capture-pane -p -t ${sessionName} -S -1000
|
|
|
53675
54553
|
|
|
53676
54554
|
The Bash tool can execute these commands directly. Do NOT retry with interactive_bash.`;
|
|
53677
54555
|
}
|
|
53678
|
-
const proc =
|
|
54556
|
+
const proc = spawnWithWindowsHide([tmuxPath2, ...parts], {
|
|
53679
54557
|
stdout: "pipe",
|
|
53680
54558
|
stderr: "pipe"
|
|
53681
54559
|
});
|
|
@@ -53893,10 +54771,10 @@ init_logger();
|
|
|
53893
54771
|
|
|
53894
54772
|
// src/tools/background-task/delay.ts
|
|
53895
54773
|
function delay3(ms) {
|
|
53896
|
-
return new Promise((
|
|
54774
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
53897
54775
|
}
|
|
53898
54776
|
// src/tools/background-task/session-messages.ts
|
|
53899
|
-
function
|
|
54777
|
+
function getErrorMessage4(value) {
|
|
53900
54778
|
if (Array.isArray(value))
|
|
53901
54779
|
return null;
|
|
53902
54780
|
if (value.error === undefined || value.error === null)
|
|
@@ -54049,7 +54927,7 @@ async function formatFullSession(task, client2, options) {
|
|
|
54049
54927
|
const messagesResult = await client2.session.messages({
|
|
54050
54928
|
path: { id: task.sessionID }
|
|
54051
54929
|
});
|
|
54052
|
-
const errorMessage =
|
|
54930
|
+
const errorMessage = getErrorMessage4(messagesResult);
|
|
54053
54931
|
if (errorMessage) {
|
|
54054
54932
|
return `Error fetching messages: ${errorMessage}`;
|
|
54055
54933
|
}
|
|
@@ -54147,7 +55025,7 @@ async function formatTaskResult(task, client2) {
|
|
|
54147
55025
|
const messagesResult = await client2.session.messages({
|
|
54148
55026
|
path: { id: task.sessionID }
|
|
54149
55027
|
});
|
|
54150
|
-
const errorMessage =
|
|
55028
|
+
const errorMessage = getErrorMessage4(messagesResult);
|
|
54151
55029
|
if (errorMessage) {
|
|
54152
55030
|
return `Error fetching messages: ${errorMessage}`;
|
|
54153
55031
|
}
|
|
@@ -54250,6 +55128,14 @@ function formatResolvedTitle(task) {
|
|
|
54250
55128
|
const label = task.agent === SISYPHUS_JUNIOR_AGENT && task.category ? task.category : task.agent;
|
|
54251
55129
|
return `${label} - ${task.description}`;
|
|
54252
55130
|
}
|
|
55131
|
+
function isTaskActiveStatus(status) {
|
|
55132
|
+
return status === "pending" || status === "running";
|
|
55133
|
+
}
|
|
55134
|
+
function appendTimeoutNote(output, timeoutMs) {
|
|
55135
|
+
return `${output}
|
|
55136
|
+
|
|
55137
|
+
> **Timed out waiting** after ${timeoutMs}ms. Task is still running; showing latest available output.`;
|
|
55138
|
+
}
|
|
54253
55139
|
function createBackgroundOutput(manager, client2) {
|
|
54254
55140
|
return tool({
|
|
54255
55141
|
description: BACKGROUND_OUTPUT_DESCRIPTION,
|
|
@@ -54290,7 +55176,8 @@ function createBackgroundOutput(manager, client2) {
|
|
|
54290
55176
|
const timeoutMs = Math.min(args.timeout ?? 60000, 600000);
|
|
54291
55177
|
const fullSession = args.full_session ?? true;
|
|
54292
55178
|
let resolvedTask = task;
|
|
54293
|
-
|
|
55179
|
+
let didTimeoutWhileActive = false;
|
|
55180
|
+
if (shouldBlock && isTaskActiveStatus(task.status)) {
|
|
54294
55181
|
const startTime = Date.now();
|
|
54295
55182
|
while (Date.now() - startTime < timeoutMs) {
|
|
54296
55183
|
await delay3(1000);
|
|
@@ -54298,27 +55185,33 @@ function createBackgroundOutput(manager, client2) {
|
|
|
54298
55185
|
if (!currentTask) {
|
|
54299
55186
|
return `Task was deleted: ${args.task_id}`;
|
|
54300
55187
|
}
|
|
54301
|
-
|
|
54302
|
-
|
|
55188
|
+
resolvedTask = currentTask;
|
|
55189
|
+
if (!isTaskActiveStatus(currentTask.status)) {
|
|
54303
55190
|
break;
|
|
54304
55191
|
}
|
|
54305
55192
|
}
|
|
54306
|
-
|
|
54307
|
-
|
|
54308
|
-
|
|
55193
|
+
if (isTaskActiveStatus(resolvedTask.status)) {
|
|
55194
|
+
const finalCheck = manager.getTask(args.task_id);
|
|
55195
|
+
if (finalCheck) {
|
|
55196
|
+
resolvedTask = finalCheck;
|
|
55197
|
+
}
|
|
55198
|
+
}
|
|
55199
|
+
if (isTaskActiveStatus(resolvedTask.status)) {
|
|
55200
|
+
didTimeoutWhileActive = true;
|
|
54309
55201
|
}
|
|
54310
55202
|
}
|
|
54311
|
-
const isActive = resolvedTask.status
|
|
55203
|
+
const isActive = isTaskActiveStatus(resolvedTask.status);
|
|
54312
55204
|
const includeThinking = isActive || (args.include_thinking ?? false);
|
|
54313
55205
|
const includeToolResults = isActive || (args.include_tool_results ?? false);
|
|
54314
55206
|
if (fullSession) {
|
|
54315
|
-
|
|
55207
|
+
const output = await formatFullSession(resolvedTask, client2, {
|
|
54316
55208
|
includeThinking,
|
|
54317
55209
|
messageLimit: args.message_limit,
|
|
54318
55210
|
sinceMessageId: args.since_message_id,
|
|
54319
55211
|
includeToolResults,
|
|
54320
55212
|
thinkingMaxChars: args.thinking_max_chars
|
|
54321
55213
|
});
|
|
55214
|
+
return didTimeoutWhileActive ? appendTimeoutNote(output, timeoutMs) : output;
|
|
54322
55215
|
}
|
|
54323
55216
|
if (resolvedTask.status === "completed") {
|
|
54324
55217
|
return await formatTaskResult(resolvedTask, client2);
|
|
@@ -54326,7 +55219,8 @@ function createBackgroundOutput(manager, client2) {
|
|
|
54326
55219
|
if (resolvedTask.status === "error" || resolvedTask.status === "cancelled" || resolvedTask.status === "interrupt") {
|
|
54327
55220
|
return formatTaskStatus(resolvedTask);
|
|
54328
55221
|
}
|
|
54329
|
-
|
|
55222
|
+
const statusOutput = formatTaskStatus(resolvedTask);
|
|
55223
|
+
return didTimeoutWhileActive ? appendTimeoutNote(statusOutput, timeoutMs) : statusOutput;
|
|
54330
55224
|
} catch (error45) {
|
|
54331
55225
|
return `Error getting output: ${error45 instanceof Error ? error45.message : String(error45)}`;
|
|
54332
55226
|
}
|
|
@@ -54482,7 +55376,7 @@ Task ID: ${task.id}`;
|
|
|
54482
55376
|
|
|
54483
55377
|
Task ID: ${task.id}`;
|
|
54484
55378
|
}
|
|
54485
|
-
await new Promise((
|
|
55379
|
+
await new Promise((resolve13) => setTimeout(resolve13, WAIT_FOR_SESSION_INTERVAL_MS));
|
|
54486
55380
|
sessionId = manager.getTask(task.id)?.sessionID;
|
|
54487
55381
|
}
|
|
54488
55382
|
await toolContext.metadata?.({
|
|
@@ -54575,7 +55469,7 @@ async function waitForCompletion(sessionID, toolContext, ctx) {
|
|
|
54575
55469
|
log(`[call_omo_agent] Aborted by user`);
|
|
54576
55470
|
throw new Error("Task aborted.");
|
|
54577
55471
|
}
|
|
54578
|
-
await new Promise((
|
|
55472
|
+
await new Promise((resolve13) => setTimeout(resolve13, POLL_INTERVAL_MS));
|
|
54579
55473
|
const statusResult = await ctx.client.session.status();
|
|
54580
55474
|
const allStatuses = normalizeSDKResponse(statusResult, {});
|
|
54581
55475
|
const sessionStatus = allStatuses[sessionID];
|
|
@@ -54822,77 +55716,6 @@ function validateArgs(args) {
|
|
|
54822
55716
|
return null;
|
|
54823
55717
|
}
|
|
54824
55718
|
|
|
54825
|
-
// src/tools/look-at/mime-type-inference.ts
|
|
54826
|
-
import { extname as extname4 } from "path";
|
|
54827
|
-
function inferMimeTypeFromBase64(base64Data) {
|
|
54828
|
-
if (base64Data.startsWith("data:")) {
|
|
54829
|
-
const match = base64Data.match(/^data:([^;]+);/);
|
|
54830
|
-
if (match)
|
|
54831
|
-
return match[1];
|
|
54832
|
-
}
|
|
54833
|
-
try {
|
|
54834
|
-
const cleanData = base64Data.replace(/^data:[^;]+;base64,/, "");
|
|
54835
|
-
const header = atob(cleanData.slice(0, 16));
|
|
54836
|
-
if (header.startsWith("\x89PNG"))
|
|
54837
|
-
return "image/png";
|
|
54838
|
-
if (header.startsWith("\xFF\xD8\xFF"))
|
|
54839
|
-
return "image/jpeg";
|
|
54840
|
-
if (header.startsWith("GIF8"))
|
|
54841
|
-
return "image/gif";
|
|
54842
|
-
if (header.startsWith("RIFF") && header.includes("WEBP"))
|
|
54843
|
-
return "image/webp";
|
|
54844
|
-
if (header.startsWith("%PDF"))
|
|
54845
|
-
return "application/pdf";
|
|
54846
|
-
} catch {}
|
|
54847
|
-
return "image/png";
|
|
54848
|
-
}
|
|
54849
|
-
function inferMimeTypeFromFilePath(filePath) {
|
|
54850
|
-
const ext = extname4(filePath).toLowerCase();
|
|
54851
|
-
const mimeTypes = {
|
|
54852
|
-
".jpg": "image/jpeg",
|
|
54853
|
-
".jpeg": "image/jpeg",
|
|
54854
|
-
".png": "image/png",
|
|
54855
|
-
".webp": "image/webp",
|
|
54856
|
-
".heic": "image/heic",
|
|
54857
|
-
".heif": "image/heif",
|
|
54858
|
-
".mp4": "video/mp4",
|
|
54859
|
-
".mpeg": "video/mpeg",
|
|
54860
|
-
".mpg": "video/mpeg",
|
|
54861
|
-
".mov": "video/mov",
|
|
54862
|
-
".avi": "video/avi",
|
|
54863
|
-
".flv": "video/x-flv",
|
|
54864
|
-
".webm": "video/webm",
|
|
54865
|
-
".wmv": "video/wmv",
|
|
54866
|
-
".3gpp": "video/3gpp",
|
|
54867
|
-
".3gp": "video/3gpp",
|
|
54868
|
-
".wav": "audio/wav",
|
|
54869
|
-
".mp3": "audio/mp3",
|
|
54870
|
-
".aiff": "audio/aiff",
|
|
54871
|
-
".aac": "audio/aac",
|
|
54872
|
-
".ogg": "audio/ogg",
|
|
54873
|
-
".flac": "audio/flac",
|
|
54874
|
-
".pdf": "application/pdf",
|
|
54875
|
-
".txt": "text/plain",
|
|
54876
|
-
".csv": "text/csv",
|
|
54877
|
-
".md": "text/md",
|
|
54878
|
-
".html": "text/html",
|
|
54879
|
-
".json": "application/json",
|
|
54880
|
-
".xml": "application/xml",
|
|
54881
|
-
".js": "text/javascript",
|
|
54882
|
-
".py": "text/x-python"
|
|
54883
|
-
};
|
|
54884
|
-
return mimeTypes[ext] || "application/octet-stream";
|
|
54885
|
-
}
|
|
54886
|
-
function extractBase64Data(imageData) {
|
|
54887
|
-
if (imageData.startsWith("data:")) {
|
|
54888
|
-
const commaIndex = imageData.indexOf(",");
|
|
54889
|
-
if (commaIndex !== -1) {
|
|
54890
|
-
return imageData.slice(commaIndex + 1);
|
|
54891
|
-
}
|
|
54892
|
-
}
|
|
54893
|
-
return imageData;
|
|
54894
|
-
}
|
|
54895
|
-
|
|
54896
55719
|
// src/tools/look-at/multimodal-agent-metadata.ts
|
|
54897
55720
|
function isObject4(value) {
|
|
54898
55721
|
return typeof value === "object" && value !== null;
|
|
@@ -55062,47 +55885,153 @@ init_logger();
|
|
|
55062
55885
|
|
|
55063
55886
|
// src/tools/delegate-task/prompt-builder.ts
|
|
55064
55887
|
init_constants();
|
|
55888
|
+
|
|
55889
|
+
// src/tools/delegate-task/token-limiter.ts
|
|
55890
|
+
var CHARACTERS_PER_TOKEN = 4;
|
|
55891
|
+
function estimateTokenCount(text) {
|
|
55892
|
+
if (!text) {
|
|
55893
|
+
return 0;
|
|
55894
|
+
}
|
|
55895
|
+
return Math.ceil(text.length / CHARACTERS_PER_TOKEN);
|
|
55896
|
+
}
|
|
55897
|
+
function truncateToTokenBudget(content, maxTokens) {
|
|
55898
|
+
if (!content || maxTokens <= 0) {
|
|
55899
|
+
return "";
|
|
55900
|
+
}
|
|
55901
|
+
const maxCharacters = maxTokens * CHARACTERS_PER_TOKEN;
|
|
55902
|
+
if (content.length <= maxCharacters) {
|
|
55903
|
+
return content;
|
|
55904
|
+
}
|
|
55905
|
+
const sliced = content.slice(0, maxCharacters);
|
|
55906
|
+
const lastNewline = sliced.lastIndexOf(`
|
|
55907
|
+
`);
|
|
55908
|
+
if (lastNewline > 0) {
|
|
55909
|
+
return `${sliced.slice(0, lastNewline)}
|
|
55910
|
+
[TRUNCATED]`;
|
|
55911
|
+
}
|
|
55912
|
+
return `${sliced}
|
|
55913
|
+
[TRUNCATED]`;
|
|
55914
|
+
}
|
|
55915
|
+
function joinSystemParts(parts) {
|
|
55916
|
+
const filtered = parts.filter((part) => part.trim().length > 0);
|
|
55917
|
+
if (filtered.length === 0) {
|
|
55918
|
+
return;
|
|
55919
|
+
}
|
|
55920
|
+
return filtered.join(`
|
|
55921
|
+
|
|
55922
|
+
`);
|
|
55923
|
+
}
|
|
55924
|
+
function reduceSegmentToFitBudget(content, overflowTokens) {
|
|
55925
|
+
if (overflowTokens <= 0 || !content) {
|
|
55926
|
+
return content;
|
|
55927
|
+
}
|
|
55928
|
+
const currentTokens = estimateTokenCount(content);
|
|
55929
|
+
const nextBudget = Math.max(0, currentTokens - overflowTokens);
|
|
55930
|
+
return truncateToTokenBudget(content, nextBudget);
|
|
55931
|
+
}
|
|
55932
|
+
function buildSystemContentWithTokenLimit(input, maxTokens) {
|
|
55933
|
+
const skillParts = input.skillContents?.length ? [...input.skillContents] : input.skillContent ? [input.skillContent] : [];
|
|
55934
|
+
const categoryPromptAppend = input.categoryPromptAppend ?? "";
|
|
55935
|
+
const agentsContext = input.agentsContext ?? input.planAgentPrepend ?? "";
|
|
55936
|
+
if (maxTokens === undefined) {
|
|
55937
|
+
return joinSystemParts([agentsContext, ...skillParts, categoryPromptAppend]);
|
|
55938
|
+
}
|
|
55939
|
+
let nextSkills = [...skillParts];
|
|
55940
|
+
let nextCategoryPromptAppend = categoryPromptAppend;
|
|
55941
|
+
let nextAgentsContext = agentsContext;
|
|
55942
|
+
const buildCurrentContent = () => joinSystemParts([nextAgentsContext, ...nextSkills, nextCategoryPromptAppend]);
|
|
55943
|
+
let systemContent = buildCurrentContent();
|
|
55944
|
+
if (!systemContent) {
|
|
55945
|
+
return;
|
|
55946
|
+
}
|
|
55947
|
+
let overflowTokens = estimateTokenCount(systemContent) - maxTokens;
|
|
55948
|
+
if (overflowTokens > 0) {
|
|
55949
|
+
for (let index = 0;index < nextSkills.length && overflowTokens > 0; index += 1) {
|
|
55950
|
+
const skill2 = nextSkills[index];
|
|
55951
|
+
const reducedSkill = reduceSegmentToFitBudget(skill2, overflowTokens);
|
|
55952
|
+
nextSkills[index] = reducedSkill;
|
|
55953
|
+
systemContent = buildCurrentContent();
|
|
55954
|
+
if (!systemContent) {
|
|
55955
|
+
return;
|
|
55956
|
+
}
|
|
55957
|
+
overflowTokens = estimateTokenCount(systemContent) - maxTokens;
|
|
55958
|
+
}
|
|
55959
|
+
nextSkills = nextSkills.filter((skill2) => skill2.trim().length > 0);
|
|
55960
|
+
systemContent = buildCurrentContent();
|
|
55961
|
+
if (!systemContent) {
|
|
55962
|
+
return;
|
|
55963
|
+
}
|
|
55964
|
+
overflowTokens = estimateTokenCount(systemContent) - maxTokens;
|
|
55965
|
+
}
|
|
55966
|
+
if (overflowTokens > 0 && nextCategoryPromptAppend) {
|
|
55967
|
+
nextCategoryPromptAppend = reduceSegmentToFitBudget(nextCategoryPromptAppend, overflowTokens);
|
|
55968
|
+
systemContent = buildCurrentContent();
|
|
55969
|
+
if (!systemContent) {
|
|
55970
|
+
return;
|
|
55971
|
+
}
|
|
55972
|
+
overflowTokens = estimateTokenCount(systemContent) - maxTokens;
|
|
55973
|
+
}
|
|
55974
|
+
if (overflowTokens > 0 && nextAgentsContext) {
|
|
55975
|
+
nextAgentsContext = reduceSegmentToFitBudget(nextAgentsContext, overflowTokens);
|
|
55976
|
+
systemContent = buildCurrentContent();
|
|
55977
|
+
if (!systemContent) {
|
|
55978
|
+
return;
|
|
55979
|
+
}
|
|
55980
|
+
}
|
|
55981
|
+
if (!systemContent) {
|
|
55982
|
+
return;
|
|
55983
|
+
}
|
|
55984
|
+
return truncateToTokenBudget(systemContent, maxTokens);
|
|
55985
|
+
}
|
|
55986
|
+
|
|
55987
|
+
// src/tools/delegate-task/prompt-builder.ts
|
|
55988
|
+
var FREE_OR_LOCAL_PROMPT_TOKEN_LIMIT = 24000;
|
|
55989
|
+
function usesFreeOrLocalModel(model) {
|
|
55990
|
+
if (!model) {
|
|
55991
|
+
return false;
|
|
55992
|
+
}
|
|
55993
|
+
const provider = model.providerID.toLowerCase();
|
|
55994
|
+
const modelId = model.modelID.toLowerCase();
|
|
55995
|
+
return provider.includes("local") || provider === "ollama" || provider === "lmstudio" || modelId.includes("free");
|
|
55996
|
+
}
|
|
55065
55997
|
function buildSystemContent(input) {
|
|
55066
55998
|
const {
|
|
55067
55999
|
skillContent,
|
|
56000
|
+
skillContents,
|
|
55068
56001
|
categoryPromptAppend,
|
|
56002
|
+
agentsContext,
|
|
56003
|
+
maxPromptTokens,
|
|
56004
|
+
model,
|
|
55069
56005
|
agentName,
|
|
55070
56006
|
availableCategories,
|
|
55071
56007
|
availableSkills
|
|
55072
56008
|
} = input;
|
|
55073
56009
|
const planAgentPrepend = isPlanAgent(agentName) ? buildPlanAgentSystemPrepend(availableCategories, availableSkills) : "";
|
|
55074
|
-
|
|
55075
|
-
|
|
55076
|
-
|
|
55077
|
-
|
|
55078
|
-
|
|
55079
|
-
|
|
55080
|
-
|
|
55081
|
-
|
|
55082
|
-
parts.push(skillContent);
|
|
55083
|
-
}
|
|
55084
|
-
if (categoryPromptAppend) {
|
|
55085
|
-
parts.push(categoryPromptAppend);
|
|
55086
|
-
}
|
|
55087
|
-
return parts.join(`
|
|
55088
|
-
|
|
55089
|
-
`) || undefined;
|
|
56010
|
+
const effectiveMaxPromptTokens = maxPromptTokens ?? (usesFreeOrLocalModel(model) ? FREE_OR_LOCAL_PROMPT_TOKEN_LIMIT : undefined);
|
|
56011
|
+
return buildSystemContentWithTokenLimit({
|
|
56012
|
+
skillContent,
|
|
56013
|
+
skillContents,
|
|
56014
|
+
categoryPromptAppend,
|
|
56015
|
+
agentsContext: agentsContext ?? planAgentPrepend,
|
|
56016
|
+
planAgentPrepend
|
|
56017
|
+
}, effectiveMaxPromptTokens);
|
|
55090
56018
|
}
|
|
55091
56019
|
|
|
55092
56020
|
// src/tools/delegate-task/skill-resolver.ts
|
|
55093
56021
|
async function resolveSkillContent2(skills2, options) {
|
|
55094
56022
|
if (skills2.length === 0) {
|
|
55095
|
-
return { content: undefined, error: null };
|
|
56023
|
+
return { content: undefined, contents: [], error: null };
|
|
55096
56024
|
}
|
|
55097
56025
|
const { resolved, notFound } = await resolveMultipleSkillsAsync(skills2, options);
|
|
55098
56026
|
if (notFound.length > 0) {
|
|
55099
56027
|
const allSkills = await discoverSkills({ includeClaudeCodePaths: true, directory: options?.directory });
|
|
55100
56028
|
const available = allSkills.map((s) => s.name).join(", ");
|
|
55101
|
-
return { content: undefined, error: `Skills not found: ${notFound.join(", ")}. Available: ${available}` };
|
|
56029
|
+
return { content: undefined, contents: [], error: `Skills not found: ${notFound.join(", ")}. Available: ${available}` };
|
|
55102
56030
|
}
|
|
55103
|
-
|
|
56031
|
+
const contents = Array.from(resolved.values());
|
|
56032
|
+
return { content: contents.join(`
|
|
55104
56033
|
|
|
55105
|
-
`), error: null };
|
|
56034
|
+
`), contents, error: null };
|
|
55106
56035
|
}
|
|
55107
56036
|
// src/tools/delegate-task/parent-context-resolver.ts
|
|
55108
56037
|
init_logger();
|
|
@@ -55292,7 +56221,7 @@ async function pollSyncSession(ctx, client2, input) {
|
|
|
55292
56221
|
|
|
55293
56222
|
Session ID: ${input.sessionID}`;
|
|
55294
56223
|
}
|
|
55295
|
-
await new Promise((
|
|
56224
|
+
await new Promise((resolve13) => setTimeout(resolve13, syncTiming.POLL_INTERVAL_MS));
|
|
55296
56225
|
pollCount++;
|
|
55297
56226
|
let statusResult;
|
|
55298
56227
|
try {
|
|
@@ -55554,7 +56483,7 @@ async function executeUnstableAgentTask(args, ctx, executorCtx, parentContext, a
|
|
|
55554
56483
|
|
|
55555
56484
|
Task ID: ${task.id}`;
|
|
55556
56485
|
}
|
|
55557
|
-
await new Promise((
|
|
56486
|
+
await new Promise((resolve13) => setTimeout(resolve13, timing.WAIT_FOR_SESSION_INTERVAL_MS));
|
|
55558
56487
|
const updated = manager.getTask(task.id);
|
|
55559
56488
|
sessionID = updated?.sessionID;
|
|
55560
56489
|
}
|
|
@@ -55595,7 +56524,7 @@ Task ID: ${task.id}`;
|
|
|
55595
56524
|
|
|
55596
56525
|
Session ID: ${sessionID}`;
|
|
55597
56526
|
}
|
|
55598
|
-
await new Promise((
|
|
56527
|
+
await new Promise((resolve13) => setTimeout(resolve13, timingCfg.POLL_INTERVAL_MS));
|
|
55599
56528
|
const currentTask = manager.getTask(task.id);
|
|
55600
56529
|
if (currentTask && (currentTask.status === "interrupt" || currentTask.status === "error" || currentTask.status === "cancelled")) {
|
|
55601
56530
|
terminalStatus = { status: currentTask.status, error: currentTask.error };
|
|
@@ -55724,7 +56653,7 @@ async function executeBackgroundTask(args, ctx, executorCtx, parentContext, agen
|
|
|
55724
56653
|
|
|
55725
56654
|
Task ID: ${task.id}`;
|
|
55726
56655
|
}
|
|
55727
|
-
await new Promise((
|
|
56656
|
+
await new Promise((resolve13) => setTimeout(resolve13, timing.WAIT_FOR_SESSION_INTERVAL_MS));
|
|
55728
56657
|
const updated = manager.getTask(task.id);
|
|
55729
56658
|
sessionId = updated?.sessionID;
|
|
55730
56659
|
}
|
|
@@ -56173,6 +57102,7 @@ async function resolveCategoryExecution(args, executorCtx, inheritedModel, syste
|
|
|
56173
57102
|
agentToUse: "",
|
|
56174
57103
|
categoryModel: undefined,
|
|
56175
57104
|
categoryPromptAppend: undefined,
|
|
57105
|
+
maxPromptTokens: undefined,
|
|
56176
57106
|
modelInfo: undefined,
|
|
56177
57107
|
actualModel: undefined,
|
|
56178
57108
|
isUnstableAgent: false,
|
|
@@ -56189,6 +57119,7 @@ Available categories: ${allCategoryNames}`
|
|
|
56189
57119
|
agentToUse: "",
|
|
56190
57120
|
categoryModel: undefined,
|
|
56191
57121
|
categoryPromptAppend: undefined,
|
|
57122
|
+
maxPromptTokens: undefined,
|
|
56192
57123
|
modelInfo: undefined,
|
|
56193
57124
|
actualModel: undefined,
|
|
56194
57125
|
isUnstableAgent: false,
|
|
@@ -56222,6 +57153,7 @@ Available categories: ${allCategoryNames}`
|
|
|
56222
57153
|
agentToUse: "",
|
|
56223
57154
|
categoryModel: undefined,
|
|
56224
57155
|
categoryPromptAppend: undefined,
|
|
57156
|
+
maxPromptTokens: undefined,
|
|
56225
57157
|
modelInfo: undefined,
|
|
56226
57158
|
actualModel: undefined,
|
|
56227
57159
|
isUnstableAgent: false,
|
|
@@ -56247,6 +57179,7 @@ Available categories: ${allCategoryNames}`
|
|
|
56247
57179
|
agentToUse: "",
|
|
56248
57180
|
categoryModel: undefined,
|
|
56249
57181
|
categoryPromptAppend: undefined,
|
|
57182
|
+
maxPromptTokens: undefined,
|
|
56250
57183
|
modelInfo: undefined,
|
|
56251
57184
|
actualModel: undefined,
|
|
56252
57185
|
isUnstableAgent: false,
|
|
@@ -56268,6 +57201,7 @@ Available categories: ${categoryNames.join(", ")}`
|
|
|
56268
57201
|
agentToUse: SISYPHUS_JUNIOR_AGENT2,
|
|
56269
57202
|
categoryModel,
|
|
56270
57203
|
categoryPromptAppend,
|
|
57204
|
+
maxPromptTokens: resolved.config.max_prompt_tokens,
|
|
56271
57205
|
modelInfo,
|
|
56272
57206
|
actualModel,
|
|
56273
57207
|
isUnstableAgent,
|
|
@@ -56477,7 +57411,7 @@ function createDelegateTask(options) {
|
|
|
56477
57411
|
throw new Error(`Invalid arguments: load_skills=null is not allowed. Pass [] if no skills needed.`);
|
|
56478
57412
|
}
|
|
56479
57413
|
const runInBackground = args.run_in_background === true;
|
|
56480
|
-
const { content: skillContent, error: skillError } = await resolveSkillContent2(args.load_skills, {
|
|
57414
|
+
const { content: skillContent, contents: skillContents, error: skillError } = await resolveSkillContent2(args.load_skills, {
|
|
56481
57415
|
gitMasterConfig: options.gitMasterConfig,
|
|
56482
57416
|
browserProvider: options.browserProvider,
|
|
56483
57417
|
disabledSkills: options.disabledSkills,
|
|
@@ -56511,6 +57445,7 @@ function createDelegateTask(options) {
|
|
|
56511
57445
|
let actualModel;
|
|
56512
57446
|
let isUnstableAgent = false;
|
|
56513
57447
|
let fallbackChain;
|
|
57448
|
+
let maxPromptTokens;
|
|
56514
57449
|
if (args.category) {
|
|
56515
57450
|
const resolution = await resolveCategoryExecution(args, options, inheritedModel, systemDefaultModel);
|
|
56516
57451
|
if (resolution.error) {
|
|
@@ -56523,6 +57458,7 @@ function createDelegateTask(options) {
|
|
|
56523
57458
|
actualModel = resolution.actualModel;
|
|
56524
57459
|
isUnstableAgent = resolution.isUnstableAgent;
|
|
56525
57460
|
fallbackChain = resolution.fallbackChain;
|
|
57461
|
+
maxPromptTokens = resolution.maxPromptTokens;
|
|
56526
57462
|
const isRunInBackgroundExplicitlyFalse = args.run_in_background === false || args.run_in_background === "false";
|
|
56527
57463
|
log("[task] unstable agent detection", {
|
|
56528
57464
|
category: args.category,
|
|
@@ -56536,8 +57472,11 @@ function createDelegateTask(options) {
|
|
|
56536
57472
|
if (isUnstableAgent && isRunInBackgroundExplicitlyFalse) {
|
|
56537
57473
|
const systemContent2 = buildSystemContent({
|
|
56538
57474
|
skillContent,
|
|
57475
|
+
skillContents,
|
|
56539
57476
|
categoryPromptAppend,
|
|
56540
57477
|
agentName: agentToUse,
|
|
57478
|
+
maxPromptTokens,
|
|
57479
|
+
model: categoryModel,
|
|
56541
57480
|
availableCategories,
|
|
56542
57481
|
availableSkills
|
|
56543
57482
|
});
|
|
@@ -56554,8 +57493,11 @@ function createDelegateTask(options) {
|
|
|
56554
57493
|
}
|
|
56555
57494
|
const systemContent = buildSystemContent({
|
|
56556
57495
|
skillContent,
|
|
57496
|
+
skillContents,
|
|
56557
57497
|
categoryPromptAppend,
|
|
56558
57498
|
agentName: agentToUse,
|
|
57499
|
+
maxPromptTokens,
|
|
57500
|
+
model: categoryModel,
|
|
56559
57501
|
availableCategories,
|
|
56560
57502
|
availableSkills
|
|
56561
57503
|
});
|
|
@@ -57356,14 +58298,19 @@ function normalizeEditPayload(payload) {
|
|
|
57356
58298
|
return toNewLines(payload).join(`
|
|
57357
58299
|
`);
|
|
57358
58300
|
}
|
|
58301
|
+
function canonicalAnchor(anchor) {
|
|
58302
|
+
if (!anchor)
|
|
58303
|
+
return "";
|
|
58304
|
+
return normalizeLineRef(anchor);
|
|
58305
|
+
}
|
|
57359
58306
|
function buildDedupeKey(edit) {
|
|
57360
58307
|
switch (edit.op) {
|
|
57361
58308
|
case "replace":
|
|
57362
|
-
return `replace|${edit.pos}|${edit.end
|
|
58309
|
+
return `replace|${canonicalAnchor(edit.pos)}|${edit.end ? canonicalAnchor(edit.end) : ""}|${normalizeEditPayload(edit.lines)}`;
|
|
57363
58310
|
case "append":
|
|
57364
|
-
return `append|${edit.pos
|
|
58311
|
+
return `append|${canonicalAnchor(edit.pos)}|${normalizeEditPayload(edit.lines)}`;
|
|
57365
58312
|
case "prepend":
|
|
57366
|
-
return `prepend|${edit.pos
|
|
58313
|
+
return `prepend|${canonicalAnchor(edit.pos)}|${normalizeEditPayload(edit.lines)}`;
|
|
57367
58314
|
default:
|
|
57368
58315
|
return JSON.stringify(edit);
|
|
57369
58316
|
}
|
|
@@ -57748,66 +58695,448 @@ function applyHashlineEditsWithReport(content, edits) {
|
|
|
57748
58695
|
deduplicatedEdits: dedupeResult.deduplicatedEdits
|
|
57749
58696
|
};
|
|
57750
58697
|
}
|
|
57751
|
-
//
|
|
57752
|
-
|
|
57753
|
-
|
|
57754
|
-
|
|
57755
|
-
|
|
58698
|
+
// node_modules/diff/libesm/diff/base.js
|
|
58699
|
+
class Diff {
|
|
58700
|
+
diff(oldStr, newStr, options = {}) {
|
|
58701
|
+
let callback;
|
|
58702
|
+
if (typeof options === "function") {
|
|
58703
|
+
callback = options;
|
|
58704
|
+
options = {};
|
|
58705
|
+
} else if ("callback" in options) {
|
|
58706
|
+
callback = options.callback;
|
|
58707
|
+
}
|
|
58708
|
+
const oldString = this.castInput(oldStr, options);
|
|
58709
|
+
const newString = this.castInput(newStr, options);
|
|
58710
|
+
const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
|
|
58711
|
+
const newTokens = this.removeEmpty(this.tokenize(newString, options));
|
|
58712
|
+
return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
|
|
58713
|
+
}
|
|
58714
|
+
diffWithOptionsObj(oldTokens, newTokens, options, callback) {
|
|
58715
|
+
var _a;
|
|
58716
|
+
const done = (value) => {
|
|
58717
|
+
value = this.postProcess(value, options);
|
|
58718
|
+
if (callback) {
|
|
58719
|
+
setTimeout(function() {
|
|
58720
|
+
callback(value);
|
|
58721
|
+
}, 0);
|
|
58722
|
+
return;
|
|
58723
|
+
} else {
|
|
58724
|
+
return value;
|
|
58725
|
+
}
|
|
58726
|
+
};
|
|
58727
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
58728
|
+
let editLength = 1;
|
|
58729
|
+
let maxEditLength = newLen + oldLen;
|
|
58730
|
+
if (options.maxEditLength != null) {
|
|
58731
|
+
maxEditLength = Math.min(maxEditLength, options.maxEditLength);
|
|
58732
|
+
}
|
|
58733
|
+
const maxExecutionTime = (_a = options.timeout) !== null && _a !== undefined ? _a : Infinity;
|
|
58734
|
+
const abortAfterTimestamp = Date.now() + maxExecutionTime;
|
|
58735
|
+
const bestPath = [{ oldPos: -1, lastComponent: undefined }];
|
|
58736
|
+
let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
|
|
58737
|
+
if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
58738
|
+
return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
|
|
58739
|
+
}
|
|
58740
|
+
let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
|
|
58741
|
+
const execEditLength = () => {
|
|
58742
|
+
for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength);diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
|
|
58743
|
+
let basePath;
|
|
58744
|
+
const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
|
|
58745
|
+
if (removePath) {
|
|
58746
|
+
bestPath[diagonalPath - 1] = undefined;
|
|
58747
|
+
}
|
|
58748
|
+
let canAdd = false;
|
|
58749
|
+
if (addPath) {
|
|
58750
|
+
const addPathNewPos = addPath.oldPos - diagonalPath;
|
|
58751
|
+
canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
|
|
58752
|
+
}
|
|
58753
|
+
const canRemove = removePath && removePath.oldPos + 1 < oldLen;
|
|
58754
|
+
if (!canAdd && !canRemove) {
|
|
58755
|
+
bestPath[diagonalPath] = undefined;
|
|
58756
|
+
continue;
|
|
58757
|
+
}
|
|
58758
|
+
if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
|
|
58759
|
+
basePath = this.addToPath(addPath, true, false, 0, options);
|
|
58760
|
+
} else {
|
|
58761
|
+
basePath = this.addToPath(removePath, false, true, 1, options);
|
|
58762
|
+
}
|
|
58763
|
+
newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
|
|
58764
|
+
if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
58765
|
+
return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
|
|
58766
|
+
} else {
|
|
58767
|
+
bestPath[diagonalPath] = basePath;
|
|
58768
|
+
if (basePath.oldPos + 1 >= oldLen) {
|
|
58769
|
+
maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
|
|
58770
|
+
}
|
|
58771
|
+
if (newPos + 1 >= newLen) {
|
|
58772
|
+
minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
|
|
58773
|
+
}
|
|
58774
|
+
}
|
|
58775
|
+
}
|
|
58776
|
+
editLength++;
|
|
58777
|
+
};
|
|
58778
|
+
if (callback) {
|
|
58779
|
+
(function exec2() {
|
|
58780
|
+
setTimeout(function() {
|
|
58781
|
+
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
|
|
58782
|
+
return callback(undefined);
|
|
58783
|
+
}
|
|
58784
|
+
if (!execEditLength()) {
|
|
58785
|
+
exec2();
|
|
58786
|
+
}
|
|
58787
|
+
}, 0);
|
|
58788
|
+
})();
|
|
58789
|
+
} else {
|
|
58790
|
+
while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
|
|
58791
|
+
const ret = execEditLength();
|
|
58792
|
+
if (ret) {
|
|
58793
|
+
return ret;
|
|
58794
|
+
}
|
|
58795
|
+
}
|
|
58796
|
+
}
|
|
58797
|
+
}
|
|
58798
|
+
addToPath(path11, added, removed, oldPosInc, options) {
|
|
58799
|
+
const last = path11.lastComponent;
|
|
58800
|
+
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
58801
|
+
return {
|
|
58802
|
+
oldPos: path11.oldPos + oldPosInc,
|
|
58803
|
+
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
58804
|
+
};
|
|
58805
|
+
} else {
|
|
58806
|
+
return {
|
|
58807
|
+
oldPos: path11.oldPos + oldPosInc,
|
|
58808
|
+
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
58809
|
+
};
|
|
58810
|
+
}
|
|
58811
|
+
}
|
|
58812
|
+
extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
|
|
58813
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
58814
|
+
let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
|
|
58815
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
|
|
58816
|
+
newPos++;
|
|
58817
|
+
oldPos++;
|
|
58818
|
+
commonCount++;
|
|
58819
|
+
if (options.oneChangePerToken) {
|
|
58820
|
+
basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
58821
|
+
}
|
|
58822
|
+
}
|
|
58823
|
+
if (commonCount && !options.oneChangePerToken) {
|
|
58824
|
+
basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
58825
|
+
}
|
|
58826
|
+
basePath.oldPos = oldPos;
|
|
58827
|
+
return newPos;
|
|
58828
|
+
}
|
|
58829
|
+
equals(left, right, options) {
|
|
58830
|
+
if (options.comparator) {
|
|
58831
|
+
return options.comparator(left, right);
|
|
58832
|
+
} else {
|
|
58833
|
+
return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
58834
|
+
}
|
|
58835
|
+
}
|
|
58836
|
+
removeEmpty(array2) {
|
|
58837
|
+
const ret = [];
|
|
58838
|
+
for (let i2 = 0;i2 < array2.length; i2++) {
|
|
58839
|
+
if (array2[i2]) {
|
|
58840
|
+
ret.push(array2[i2]);
|
|
58841
|
+
}
|
|
58842
|
+
}
|
|
58843
|
+
return ret;
|
|
58844
|
+
}
|
|
58845
|
+
castInput(value, options) {
|
|
58846
|
+
return value;
|
|
58847
|
+
}
|
|
58848
|
+
tokenize(value, options) {
|
|
58849
|
+
return Array.from(value);
|
|
58850
|
+
}
|
|
58851
|
+
join(chars) {
|
|
58852
|
+
return chars.join("");
|
|
58853
|
+
}
|
|
58854
|
+
postProcess(changeObjects, options) {
|
|
58855
|
+
return changeObjects;
|
|
58856
|
+
}
|
|
58857
|
+
get useLongestToken() {
|
|
58858
|
+
return false;
|
|
58859
|
+
}
|
|
58860
|
+
buildValues(lastComponent, newTokens, oldTokens) {
|
|
58861
|
+
const components = [];
|
|
58862
|
+
let nextComponent;
|
|
58863
|
+
while (lastComponent) {
|
|
58864
|
+
components.push(lastComponent);
|
|
58865
|
+
nextComponent = lastComponent.previousComponent;
|
|
58866
|
+
delete lastComponent.previousComponent;
|
|
58867
|
+
lastComponent = nextComponent;
|
|
58868
|
+
}
|
|
58869
|
+
components.reverse();
|
|
58870
|
+
const componentLen = components.length;
|
|
58871
|
+
let componentPos = 0, newPos = 0, oldPos = 0;
|
|
58872
|
+
for (;componentPos < componentLen; componentPos++) {
|
|
58873
|
+
const component = components[componentPos];
|
|
58874
|
+
if (!component.removed) {
|
|
58875
|
+
if (!component.added && this.useLongestToken) {
|
|
58876
|
+
let value = newTokens.slice(newPos, newPos + component.count);
|
|
58877
|
+
value = value.map(function(value2, i2) {
|
|
58878
|
+
const oldValue = oldTokens[oldPos + i2];
|
|
58879
|
+
return oldValue.length > value2.length ? oldValue : value2;
|
|
58880
|
+
});
|
|
58881
|
+
component.value = this.join(value);
|
|
58882
|
+
} else {
|
|
58883
|
+
component.value = this.join(newTokens.slice(newPos, newPos + component.count));
|
|
58884
|
+
}
|
|
58885
|
+
newPos += component.count;
|
|
58886
|
+
if (!component.added) {
|
|
58887
|
+
oldPos += component.count;
|
|
58888
|
+
}
|
|
58889
|
+
} else {
|
|
58890
|
+
component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
|
|
58891
|
+
oldPos += component.count;
|
|
58892
|
+
}
|
|
58893
|
+
}
|
|
58894
|
+
return components;
|
|
58895
|
+
}
|
|
58896
|
+
}
|
|
58897
|
+
|
|
58898
|
+
// node_modules/diff/libesm/diff/line.js
|
|
58899
|
+
class LineDiff extends Diff {
|
|
58900
|
+
constructor() {
|
|
58901
|
+
super(...arguments);
|
|
58902
|
+
this.tokenize = tokenize;
|
|
58903
|
+
}
|
|
58904
|
+
equals(left, right, options) {
|
|
58905
|
+
if (options.ignoreWhitespace) {
|
|
58906
|
+
if (!options.newlineIsToken || !left.includes(`
|
|
58907
|
+
`)) {
|
|
58908
|
+
left = left.trim();
|
|
58909
|
+
}
|
|
58910
|
+
if (!options.newlineIsToken || !right.includes(`
|
|
58911
|
+
`)) {
|
|
58912
|
+
right = right.trim();
|
|
58913
|
+
}
|
|
58914
|
+
} else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
|
|
58915
|
+
if (left.endsWith(`
|
|
58916
|
+
`)) {
|
|
58917
|
+
left = left.slice(0, -1);
|
|
58918
|
+
}
|
|
58919
|
+
if (right.endsWith(`
|
|
58920
|
+
`)) {
|
|
58921
|
+
right = right.slice(0, -1);
|
|
58922
|
+
}
|
|
58923
|
+
}
|
|
58924
|
+
return super.equals(left, right, options);
|
|
58925
|
+
}
|
|
58926
|
+
}
|
|
58927
|
+
var lineDiff = new LineDiff;
|
|
58928
|
+
function diffLines(oldStr, newStr, options) {
|
|
58929
|
+
return lineDiff.diff(oldStr, newStr, options);
|
|
58930
|
+
}
|
|
58931
|
+
function tokenize(value, options) {
|
|
58932
|
+
if (options.stripTrailingCr) {
|
|
58933
|
+
value = value.replace(/\r\n/g, `
|
|
57756
58934
|
`);
|
|
57757
|
-
|
|
57758
|
-
|
|
57759
|
-
|
|
57760
|
-
|
|
57761
|
-
|
|
57762
|
-
let
|
|
57763
|
-
|
|
57764
|
-
|
|
57765
|
-
|
|
57766
|
-
|
|
57767
|
-
|
|
57768
|
-
|
|
57769
|
-
|
|
57770
|
-
|
|
57771
|
-
|
|
57772
|
-
|
|
57773
|
-
|
|
57774
|
-
|
|
57775
|
-
|
|
57776
|
-
|
|
57777
|
-
|
|
57778
|
-
|
|
57779
|
-
|
|
57780
|
-
|
|
57781
|
-
|
|
57782
|
-
|
|
57783
|
-
|
|
57784
|
-
|
|
57785
|
-
|
|
57786
|
-
|
|
57787
|
-
|
|
57788
|
-
|
|
57789
|
-
|
|
57790
|
-
|
|
57791
|
-
|
|
57792
|
-
|
|
57793
|
-
|
|
57794
|
-
|
|
57795
|
-
|
|
57796
|
-
|
|
57797
|
-
|
|
58935
|
+
}
|
|
58936
|
+
const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
|
|
58937
|
+
if (!linesAndNewlines[linesAndNewlines.length - 1]) {
|
|
58938
|
+
linesAndNewlines.pop();
|
|
58939
|
+
}
|
|
58940
|
+
for (let i2 = 0;i2 < linesAndNewlines.length; i2++) {
|
|
58941
|
+
const line = linesAndNewlines[i2];
|
|
58942
|
+
if (i2 % 2 && !options.newlineIsToken) {
|
|
58943
|
+
retLines[retLines.length - 1] += line;
|
|
58944
|
+
} else {
|
|
58945
|
+
retLines.push(line);
|
|
58946
|
+
}
|
|
58947
|
+
}
|
|
58948
|
+
return retLines;
|
|
58949
|
+
}
|
|
58950
|
+
|
|
58951
|
+
// node_modules/diff/libesm/patch/create.js
|
|
58952
|
+
var INCLUDE_HEADERS = {
|
|
58953
|
+
includeIndex: true,
|
|
58954
|
+
includeUnderline: true,
|
|
58955
|
+
includeFileHeaders: true
|
|
58956
|
+
};
|
|
58957
|
+
function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
|
|
58958
|
+
let optionsObj;
|
|
58959
|
+
if (!options) {
|
|
58960
|
+
optionsObj = {};
|
|
58961
|
+
} else if (typeof options === "function") {
|
|
58962
|
+
optionsObj = { callback: options };
|
|
58963
|
+
} else {
|
|
58964
|
+
optionsObj = options;
|
|
58965
|
+
}
|
|
58966
|
+
if (typeof optionsObj.context === "undefined") {
|
|
58967
|
+
optionsObj.context = 4;
|
|
58968
|
+
}
|
|
58969
|
+
const context = optionsObj.context;
|
|
58970
|
+
if (optionsObj.newlineIsToken) {
|
|
58971
|
+
throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
|
|
58972
|
+
}
|
|
58973
|
+
if (!optionsObj.callback) {
|
|
58974
|
+
return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
|
|
58975
|
+
} else {
|
|
58976
|
+
const { callback } = optionsObj;
|
|
58977
|
+
diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
|
|
58978
|
+
const patch = diffLinesResultToPatch(diff);
|
|
58979
|
+
callback(patch);
|
|
58980
|
+
} }));
|
|
58981
|
+
}
|
|
58982
|
+
function diffLinesResultToPatch(diff) {
|
|
58983
|
+
if (!diff) {
|
|
58984
|
+
return;
|
|
58985
|
+
}
|
|
58986
|
+
diff.push({ value: "", lines: [] });
|
|
58987
|
+
function contextLines(lines) {
|
|
58988
|
+
return lines.map(function(entry) {
|
|
58989
|
+
return " " + entry;
|
|
58990
|
+
});
|
|
58991
|
+
}
|
|
58992
|
+
const hunks = [];
|
|
58993
|
+
let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
|
|
58994
|
+
for (let i2 = 0;i2 < diff.length; i2++) {
|
|
58995
|
+
const current = diff[i2], lines = current.lines || splitLines(current.value);
|
|
58996
|
+
current.lines = lines;
|
|
58997
|
+
if (current.added || current.removed) {
|
|
58998
|
+
if (!oldRangeStart) {
|
|
58999
|
+
const prev = diff[i2 - 1];
|
|
59000
|
+
oldRangeStart = oldLine;
|
|
59001
|
+
newRangeStart = newLine;
|
|
59002
|
+
if (prev) {
|
|
59003
|
+
curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
|
|
59004
|
+
oldRangeStart -= curRange.length;
|
|
59005
|
+
newRangeStart -= curRange.length;
|
|
59006
|
+
}
|
|
59007
|
+
}
|
|
59008
|
+
for (const line of lines) {
|
|
59009
|
+
curRange.push((current.added ? "+" : "-") + line);
|
|
59010
|
+
}
|
|
59011
|
+
if (current.added) {
|
|
59012
|
+
newLine += lines.length;
|
|
59013
|
+
} else {
|
|
59014
|
+
oldLine += lines.length;
|
|
59015
|
+
}
|
|
59016
|
+
} else {
|
|
59017
|
+
if (oldRangeStart) {
|
|
59018
|
+
if (lines.length <= context * 2 && i2 < diff.length - 2) {
|
|
59019
|
+
for (const line of contextLines(lines)) {
|
|
59020
|
+
curRange.push(line);
|
|
59021
|
+
}
|
|
59022
|
+
} else {
|
|
59023
|
+
const contextSize = Math.min(lines.length, context);
|
|
59024
|
+
for (const line of contextLines(lines.slice(0, contextSize))) {
|
|
59025
|
+
curRange.push(line);
|
|
59026
|
+
}
|
|
59027
|
+
const hunk = {
|
|
59028
|
+
oldStart: oldRangeStart,
|
|
59029
|
+
oldLines: oldLine - oldRangeStart + contextSize,
|
|
59030
|
+
newStart: newRangeStart,
|
|
59031
|
+
newLines: newLine - newRangeStart + contextSize,
|
|
59032
|
+
lines: curRange
|
|
59033
|
+
};
|
|
59034
|
+
hunks.push(hunk);
|
|
59035
|
+
oldRangeStart = 0;
|
|
59036
|
+
newRangeStart = 0;
|
|
59037
|
+
curRange = [];
|
|
59038
|
+
}
|
|
59039
|
+
}
|
|
59040
|
+
oldLine += lines.length;
|
|
59041
|
+
newLine += lines.length;
|
|
59042
|
+
}
|
|
59043
|
+
}
|
|
59044
|
+
for (const hunk of hunks) {
|
|
59045
|
+
for (let i2 = 0;i2 < hunk.lines.length; i2++) {
|
|
59046
|
+
if (hunk.lines[i2].endsWith(`
|
|
59047
|
+
`)) {
|
|
59048
|
+
hunk.lines[i2] = hunk.lines[i2].slice(0, -1);
|
|
59049
|
+
} else {
|
|
59050
|
+
hunk.lines.splice(i2 + 1, 0, "\");
|
|
59051
|
+
i2++;
|
|
59052
|
+
}
|
|
57798
59053
|
}
|
|
57799
59054
|
}
|
|
59055
|
+
return {
|
|
59056
|
+
oldFileName,
|
|
59057
|
+
newFileName,
|
|
59058
|
+
oldHeader,
|
|
59059
|
+
newHeader,
|
|
59060
|
+
hunks
|
|
59061
|
+
};
|
|
57800
59062
|
}
|
|
57801
|
-
|
|
57802
|
-
|
|
57803
|
-
|
|
57804
|
-
|
|
59063
|
+
}
|
|
59064
|
+
function formatPatch(patch, headerOptions) {
|
|
59065
|
+
if (!headerOptions) {
|
|
59066
|
+
headerOptions = INCLUDE_HEADERS;
|
|
59067
|
+
}
|
|
59068
|
+
if (Array.isArray(patch)) {
|
|
59069
|
+
if (patch.length > 1 && !headerOptions.includeFileHeaders) {
|
|
59070
|
+
throw new Error("Cannot omit file headers on a multi-file patch. " + "(The result would be unparseable; how would a tool trying to apply " + "the patch know which changes are to which file?)");
|
|
59071
|
+
}
|
|
59072
|
+
return patch.map((p) => formatPatch(p, headerOptions)).join(`
|
|
59073
|
+
`);
|
|
59074
|
+
}
|
|
59075
|
+
const ret = [];
|
|
59076
|
+
if (headerOptions.includeIndex && patch.oldFileName == patch.newFileName) {
|
|
59077
|
+
ret.push("Index: " + patch.oldFileName);
|
|
59078
|
+
}
|
|
59079
|
+
if (headerOptions.includeUnderline) {
|
|
59080
|
+
ret.push("===================================================================");
|
|
59081
|
+
}
|
|
59082
|
+
if (headerOptions.includeFileHeaders) {
|
|
59083
|
+
ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : "\t" + patch.oldHeader));
|
|
59084
|
+
ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : "\t" + patch.newHeader));
|
|
59085
|
+
}
|
|
59086
|
+
for (let i2 = 0;i2 < patch.hunks.length; i2++) {
|
|
59087
|
+
const hunk = patch.hunks[i2];
|
|
59088
|
+
if (hunk.oldLines === 0) {
|
|
59089
|
+
hunk.oldStart -= 1;
|
|
59090
|
+
}
|
|
59091
|
+
if (hunk.newLines === 0) {
|
|
59092
|
+
hunk.newStart -= 1;
|
|
59093
|
+
}
|
|
59094
|
+
ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
|
|
59095
|
+
for (const line of hunk.lines) {
|
|
59096
|
+
ret.push(line);
|
|
59097
|
+
}
|
|
59098
|
+
}
|
|
59099
|
+
return ret.join(`
|
|
57805
59100
|
`) + `
|
|
57806
59101
|
`;
|
|
59102
|
+
}
|
|
59103
|
+
function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
|
|
59104
|
+
if (typeof options === "function") {
|
|
59105
|
+
options = { callback: options };
|
|
57807
59106
|
}
|
|
57808
|
-
|
|
57809
|
-
|
|
57810
|
-
|
|
59107
|
+
if (!(options === null || options === undefined ? undefined : options.callback)) {
|
|
59108
|
+
const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
|
|
59109
|
+
if (!patchObj) {
|
|
59110
|
+
return;
|
|
59111
|
+
}
|
|
59112
|
+
return formatPatch(patchObj, options === null || options === undefined ? undefined : options.headerOptions);
|
|
59113
|
+
} else {
|
|
59114
|
+
const { callback } = options;
|
|
59115
|
+
structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
|
|
59116
|
+
if (!patchObj) {
|
|
59117
|
+
callback(undefined);
|
|
59118
|
+
} else {
|
|
59119
|
+
callback(formatPatch(patchObj, options.headerOptions));
|
|
59120
|
+
}
|
|
59121
|
+
} }));
|
|
59122
|
+
}
|
|
59123
|
+
}
|
|
59124
|
+
function splitLines(text) {
|
|
59125
|
+
const hasTrailingNl = text.endsWith(`
|
|
59126
|
+
`);
|
|
59127
|
+
const result = text.split(`
|
|
59128
|
+
`).map((line) => line + `
|
|
59129
|
+
`);
|
|
59130
|
+
if (hasTrailingNl) {
|
|
59131
|
+
result.pop();
|
|
59132
|
+
} else {
|
|
59133
|
+
result.push(result.pop().slice(0, -1));
|
|
59134
|
+
}
|
|
59135
|
+
return result;
|
|
59136
|
+
}
|
|
59137
|
+
// src/tools/hashline-edit/diff-utils.ts
|
|
59138
|
+
function generateUnifiedDiff(oldContent, newContent, filePath) {
|
|
59139
|
+
return createTwoFilesPatch(filePath, filePath, oldContent, newContent, undefined, undefined, { context: 3 });
|
|
57811
59140
|
}
|
|
57812
59141
|
function countLineDiffs(oldContent, newContent) {
|
|
57813
59142
|
const oldLines = oldContent.split(`
|
|
@@ -57979,7 +59308,7 @@ function resolveToolCallID2(ctx) {
|
|
|
57979
59308
|
function canCreateFromMissingFile(edits) {
|
|
57980
59309
|
if (edits.length === 0)
|
|
57981
59310
|
return false;
|
|
57982
|
-
return edits.every((edit) => edit.op === "append" || edit.op === "prepend");
|
|
59311
|
+
return edits.every((edit) => (edit.op === "append" || edit.op === "prepend") && !edit.pos);
|
|
57983
59312
|
}
|
|
57984
59313
|
function buildSuccessMeta(effectivePath, beforeContent, afterContent, noopEdits, deduplicatedEdits) {
|
|
57985
59314
|
const unifiedDiff = generateUnifiedDiff(beforeContent, afterContent, effectivePath);
|
|
@@ -58023,16 +59352,16 @@ async function executeHashlineEditTool(args, context) {
|
|
|
58023
59352
|
const metadataContext = context;
|
|
58024
59353
|
const filePath = args.filePath;
|
|
58025
59354
|
const { delete: deleteMode, rename } = args;
|
|
58026
|
-
if (!deleteMode && (!args.edits || !Array.isArray(args.edits) || args.edits.length === 0)) {
|
|
58027
|
-
return "Error: edits parameter must be a non-empty array";
|
|
58028
|
-
}
|
|
58029
|
-
const edits = deleteMode ? [] : normalizeHashlineEdits(args.edits);
|
|
58030
59355
|
if (deleteMode && rename) {
|
|
58031
59356
|
return "Error: delete and rename cannot be used together";
|
|
58032
59357
|
}
|
|
58033
|
-
if (deleteMode && edits.length > 0) {
|
|
59358
|
+
if (deleteMode && args.edits.length > 0) {
|
|
58034
59359
|
return "Error: delete mode requires edits to be an empty array";
|
|
58035
59360
|
}
|
|
59361
|
+
if (!deleteMode && (!args.edits || !Array.isArray(args.edits) || args.edits.length === 0)) {
|
|
59362
|
+
return "Error: edits parameter must be a non-empty array";
|
|
59363
|
+
}
|
|
59364
|
+
const edits = deleteMode ? [] : normalizeHashlineEdits(args.edits);
|
|
58036
59365
|
const file2 = Bun.file(filePath);
|
|
58037
59366
|
const exists = await file2.exists();
|
|
58038
59367
|
if (!exists && !deleteMode && !canCreateFromMissingFile(edits)) {
|
|
@@ -58097,7 +59426,7 @@ WORKFLOW:
|
|
|
58097
59426
|
VALIDATION:
|
|
58098
59427
|
Payload shape: { "filePath": string, "edits": [...], "delete"?: boolean, "rename"?: string }
|
|
58099
59428
|
Each edit must be one of: replace, append, prepend
|
|
58100
|
-
Edit shape: { "op": "replace"|"append"|"prepend", "pos"?: "LINE#ID", "end"?: "LINE#ID", "lines"
|
|
59429
|
+
Edit shape: { "op": "replace"|"append"|"prepend", "pos"?: "LINE#ID", "end"?: "LINE#ID", "lines": string|string[]|null }
|
|
58101
59430
|
lines must contain plain replacement text only (no LINE#ID prefixes, no diff + markers)
|
|
58102
59431
|
CRITICAL: all operations validate against the same pre-edit file snapshot and apply bottom-up. Refs/tags are interpreted against the last-read version of the file.
|
|
58103
59432
|
|
|
@@ -58171,7 +59500,7 @@ function createHashlineEditTool() {
|
|
|
58171
59500
|
]).describe("Hashline edit operation mode"),
|
|
58172
59501
|
pos: tool.schema.string().optional().describe("Primary anchor in LINE#ID format"),
|
|
58173
59502
|
end: tool.schema.string().optional().describe("Range end anchor in LINE#ID format"),
|
|
58174
|
-
lines: tool.schema.union([tool.schema.string(), tool.schema.array(tool.schema.string()), tool.schema.null()]).
|
|
59503
|
+
lines: tool.schema.union([tool.schema.string(), tool.schema.array(tool.schema.string()), tool.schema.null()]).describe("Replacement or inserted lines. null/[] deletes with replace")
|
|
58175
59504
|
})).describe("Array of edit operations to apply (empty when delete=true)")
|
|
58176
59505
|
},
|
|
58177
59506
|
execute: async (args, context) => executeHashlineEditTool(args, context)
|
|
@@ -58281,7 +59610,9 @@ function createSessionHooks(args) {
|
|
|
58281
59610
|
const prometheusMdOnly = isHookEnabled("prometheus-md-only") ? safeHook("prometheus-md-only", () => createPrometheusMdOnlyHook(ctx)) : null;
|
|
58282
59611
|
const sisyphusJuniorNotepad = isHookEnabled("sisyphus-junior-notepad") ? safeHook("sisyphus-junior-notepad", () => createSisyphusJuniorNotepadHook(ctx)) : null;
|
|
58283
59612
|
const noSisyphusGpt = isHookEnabled("no-sisyphus-gpt") ? safeHook("no-sisyphus-gpt", () => createNoSisyphusGptHook(ctx)) : null;
|
|
58284
|
-
const noHephaestusNonGpt = isHookEnabled("no-hephaestus-non-gpt") ? safeHook("no-hephaestus-non-gpt", () => createNoHephaestusNonGptHook(ctx
|
|
59613
|
+
const noHephaestusNonGpt = isHookEnabled("no-hephaestus-non-gpt") ? safeHook("no-hephaestus-non-gpt", () => createNoHephaestusNonGptHook(ctx, {
|
|
59614
|
+
allowNonGptModel: pluginConfig.agents?.hephaestus?.allow_non_gpt_model
|
|
59615
|
+
})) : null;
|
|
58285
59616
|
const questionLabelTruncator = isHookEnabled("question-label-truncator") ? safeHook("question-label-truncator", () => createQuestionLabelTruncatorHook()) : null;
|
|
58286
59617
|
const taskResumeInfo = isHookEnabled("task-resume-info") ? safeHook("task-resume-info", () => createTaskResumeInfoHook()) : null;
|
|
58287
59618
|
const anthropicEffort = isHookEnabled("anthropic-effort") ? safeHook("anthropic-effort", () => createAnthropicEffortHook()) : null;
|
|
@@ -58344,8 +59675,9 @@ function createToolGuardHooks(args) {
|
|
|
58344
59675
|
const rulesInjector = isHookEnabled("rules-injector") ? safeHook("rules-injector", () => createRulesInjectorHook(ctx, modelCacheState)) : null;
|
|
58345
59676
|
const tasksTodowriteDisabler = isHookEnabled("tasks-todowrite-disabler") ? safeHook("tasks-todowrite-disabler", () => createTasksTodowriteDisablerHook({ experimental: pluginConfig.experimental })) : null;
|
|
58346
59677
|
const writeExistingFileGuard = isHookEnabled("write-existing-file-guard") ? safeHook("write-existing-file-guard", () => createWriteExistingFileGuardHook(ctx)) : null;
|
|
58347
|
-
const hashlineReadEnhancer = isHookEnabled("hashline-read-enhancer") ? safeHook("hashline-read-enhancer", () => createHashlineReadEnhancerHook(ctx, { hashline_edit: { enabled: pluginConfig.hashline_edit ??
|
|
59678
|
+
const hashlineReadEnhancer = isHookEnabled("hashline-read-enhancer") ? safeHook("hashline-read-enhancer", () => createHashlineReadEnhancerHook(ctx, { hashline_edit: { enabled: pluginConfig.hashline_edit ?? false } })) : null;
|
|
58348
59679
|
const jsonErrorRecovery = isHookEnabled("json-error-recovery") ? safeHook("json-error-recovery", () => createJsonErrorRecoveryHook(ctx)) : null;
|
|
59680
|
+
const readImageResizer = isHookEnabled("read-image-resizer") ? safeHook("read-image-resizer", () => createReadImageResizerHook(ctx)) : null;
|
|
58349
59681
|
return {
|
|
58350
59682
|
commentChecker,
|
|
58351
59683
|
toolOutputTruncator,
|
|
@@ -58356,7 +59688,8 @@ function createToolGuardHooks(args) {
|
|
|
58356
59688
|
tasksTodowriteDisabler,
|
|
58357
59689
|
writeExistingFileGuard,
|
|
58358
59690
|
hashlineReadEnhancer,
|
|
58359
|
-
jsonErrorRecovery
|
|
59691
|
+
jsonErrorRecovery,
|
|
59692
|
+
readImageResizer
|
|
58360
59693
|
};
|
|
58361
59694
|
}
|
|
58362
59695
|
|
|
@@ -58372,6 +59705,7 @@ var CONTEXT_SEPARATOR = `
|
|
|
58372
59705
|
---
|
|
58373
59706
|
|
|
58374
59707
|
`;
|
|
59708
|
+
var registrationCounter = 0;
|
|
58375
59709
|
|
|
58376
59710
|
class ContextCollector {
|
|
58377
59711
|
sessions = new Map;
|
|
@@ -58386,7 +59720,7 @@ class ContextCollector {
|
|
|
58386
59720
|
source: options.source,
|
|
58387
59721
|
content: options.content,
|
|
58388
59722
|
priority: options.priority ?? "normal",
|
|
58389
|
-
|
|
59723
|
+
registrationOrder: ++registrationCounter,
|
|
58390
59724
|
metadata: options.metadata
|
|
58391
59725
|
};
|
|
58392
59726
|
sessionMap.set(key, entry);
|
|
@@ -58425,7 +59759,7 @@ class ContextCollector {
|
|
|
58425
59759
|
const priorityDiff = PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority];
|
|
58426
59760
|
if (priorityDiff !== 0)
|
|
58427
59761
|
return priorityDiff;
|
|
58428
|
-
return a.
|
|
59762
|
+
return a.registrationOrder - b.registrationOrder;
|
|
58429
59763
|
});
|
|
58430
59764
|
}
|
|
58431
59765
|
}
|
|
@@ -58486,7 +59820,7 @@ function createContextInjectorMessagesTransformHook(collector) {
|
|
|
58486
59820
|
return;
|
|
58487
59821
|
}
|
|
58488
59822
|
const syntheticPart = {
|
|
58489
|
-
id: `synthetic_hook_${
|
|
59823
|
+
id: `synthetic_hook_${sessionID}`,
|
|
58490
59824
|
messageID: lastUserMessage.info.id,
|
|
58491
59825
|
sessionID: lastUserMessage.info.sessionID ?? "",
|
|
58492
59826
|
type: "text",
|
|
@@ -58591,7 +59925,9 @@ function createContinuationHooks(args) {
|
|
|
58591
59925
|
sessionRecovery
|
|
58592
59926
|
} = args;
|
|
58593
59927
|
const safeHook = (hookName, factory) => safeCreateHook(hookName, factory, { enabled: safeHookEnabled });
|
|
58594
|
-
const stopContinuationGuard = isHookEnabled("stop-continuation-guard") ? safeHook("stop-continuation-guard", () => createStopContinuationGuardHook(ctx
|
|
59928
|
+
const stopContinuationGuard = isHookEnabled("stop-continuation-guard") ? safeHook("stop-continuation-guard", () => createStopContinuationGuardHook(ctx, {
|
|
59929
|
+
backgroundManager
|
|
59930
|
+
})) : null;
|
|
58595
59931
|
const compactionContextInjector = isHookEnabled("compaction-context-injector") ? safeHook("compaction-context-injector", () => createCompactionContextInjector(backgroundManager)) : null;
|
|
58596
59932
|
const compactionTodoPreserver = isHookEnabled("compaction-todo-preserver") ? safeHook("compaction-todo-preserver", () => createCompactionTodoPreserverHook(ctx)) : null;
|
|
58597
59933
|
const todoContinuationEnforcer = isHookEnabled("todo-continuation-enforcer") ? safeHook("todo-continuation-enforcer", () => createTodoContinuationEnforcer(ctx, {
|
|
@@ -58779,14 +60115,14 @@ class ConcurrencyManager {
|
|
|
58779
60115
|
this.counts.set(model, current + 1);
|
|
58780
60116
|
return;
|
|
58781
60117
|
}
|
|
58782
|
-
return new Promise((
|
|
60118
|
+
return new Promise((resolve13, reject) => {
|
|
58783
60119
|
const queue = this.queues.get(model) ?? [];
|
|
58784
60120
|
const entry = {
|
|
58785
60121
|
resolve: () => {
|
|
58786
60122
|
if (entry.settled)
|
|
58787
60123
|
return;
|
|
58788
60124
|
entry.settled = true;
|
|
58789
|
-
|
|
60125
|
+
resolve13();
|
|
58790
60126
|
},
|
|
58791
60127
|
rawReject: reject,
|
|
58792
60128
|
settled: false
|
|
@@ -59307,6 +60643,7 @@ async function checkAndInterruptStaleTasks(args) {
|
|
|
59307
60643
|
class BackgroundManager {
|
|
59308
60644
|
tasks;
|
|
59309
60645
|
notifications;
|
|
60646
|
+
pendingNotifications;
|
|
59310
60647
|
pendingByParent;
|
|
59311
60648
|
client;
|
|
59312
60649
|
directory;
|
|
@@ -59328,6 +60665,7 @@ class BackgroundManager {
|
|
|
59328
60665
|
constructor(ctx, config3, options) {
|
|
59329
60666
|
this.tasks = new Map;
|
|
59330
60667
|
this.notifications = new Map;
|
|
60668
|
+
this.pendingNotifications = new Map;
|
|
59331
60669
|
this.pendingByParent = new Map;
|
|
59332
60670
|
this.client = ctx.client;
|
|
59333
60671
|
this.directory = ctx.directory;
|
|
@@ -59893,6 +61231,7 @@ class BackgroundManager {
|
|
|
59893
61231
|
for (const descendant of this.getAllDescendantTasks(sessionID)) {
|
|
59894
61232
|
tasksToCancel.set(descendant.id, descendant);
|
|
59895
61233
|
}
|
|
61234
|
+
this.pendingNotifications.delete(sessionID);
|
|
59896
61235
|
if (tasksToCancel.size === 0)
|
|
59897
61236
|
return;
|
|
59898
61237
|
for (const task of tasksToCancel.values()) {
|
|
@@ -59926,6 +61265,11 @@ class BackgroundManager {
|
|
|
59926
61265
|
subagentSessions.delete(task.sessionID);
|
|
59927
61266
|
}
|
|
59928
61267
|
}
|
|
61268
|
+
for (const task of tasksToCancel.values()) {
|
|
61269
|
+
if (task.parentSessionID) {
|
|
61270
|
+
this.pendingNotifications.delete(task.parentSessionID);
|
|
61271
|
+
}
|
|
61272
|
+
}
|
|
59929
61273
|
SessionCategoryRegistry.remove(sessionID);
|
|
59930
61274
|
}
|
|
59931
61275
|
if (event.type === "session.status") {
|
|
@@ -59969,6 +61313,34 @@ class BackgroundManager {
|
|
|
59969
61313
|
clearNotifications(sessionID) {
|
|
59970
61314
|
this.notifications.delete(sessionID);
|
|
59971
61315
|
}
|
|
61316
|
+
queuePendingNotification(sessionID, notification2) {
|
|
61317
|
+
if (!sessionID)
|
|
61318
|
+
return;
|
|
61319
|
+
const existingNotifications = this.pendingNotifications.get(sessionID) ?? [];
|
|
61320
|
+
existingNotifications.push(notification2);
|
|
61321
|
+
this.pendingNotifications.set(sessionID, existingNotifications);
|
|
61322
|
+
}
|
|
61323
|
+
injectPendingNotificationsIntoChatMessage(output, sessionID) {
|
|
61324
|
+
const pendingNotifications = this.pendingNotifications.get(sessionID);
|
|
61325
|
+
if (!pendingNotifications || pendingNotifications.length === 0) {
|
|
61326
|
+
return;
|
|
61327
|
+
}
|
|
61328
|
+
this.pendingNotifications.delete(sessionID);
|
|
61329
|
+
const notificationContent = pendingNotifications.join(`
|
|
61330
|
+
|
|
61331
|
+
`);
|
|
61332
|
+
const firstTextPartIndex = output.parts.findIndex((part) => part.type === "text");
|
|
61333
|
+
if (firstTextPartIndex === -1) {
|
|
61334
|
+
output.parts.unshift(createInternalAgentTextPart(notificationContent));
|
|
61335
|
+
return;
|
|
61336
|
+
}
|
|
61337
|
+
const originalText = output.parts[firstTextPartIndex].text ?? "";
|
|
61338
|
+
output.parts[firstTextPartIndex].text = `${notificationContent}
|
|
61339
|
+
|
|
61340
|
+
---
|
|
61341
|
+
|
|
61342
|
+
${originalText}`;
|
|
61343
|
+
}
|
|
59972
61344
|
async validateSessionHasOutput(sessionID) {
|
|
59973
61345
|
try {
|
|
59974
61346
|
const response = await this.client.session.messages({
|
|
@@ -60264,6 +61636,7 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
60264
61636
|
taskId: task.id,
|
|
60265
61637
|
parentSessionID: task.parentSessionID
|
|
60266
61638
|
});
|
|
61639
|
+
this.queuePendingNotification(task.parentSessionID, notification2);
|
|
60267
61640
|
} else {
|
|
60268
61641
|
log("[background-agent] Failed to send notification:", error45);
|
|
60269
61642
|
}
|
|
@@ -60452,6 +61825,7 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
60452
61825
|
this.concurrencyManager.clear();
|
|
60453
61826
|
this.tasks.clear();
|
|
60454
61827
|
this.notifications.clear();
|
|
61828
|
+
this.pendingNotifications.clear();
|
|
60455
61829
|
this.pendingByParent.clear();
|
|
60456
61830
|
this.notificationQueueByParent.clear();
|
|
60457
61831
|
this.queuesByKey.clear();
|
|
@@ -62003,7 +63377,7 @@ class Protocol {
|
|
|
62003
63377
|
return;
|
|
62004
63378
|
}
|
|
62005
63379
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
62006
|
-
await new Promise((
|
|
63380
|
+
await new Promise((resolve13) => setTimeout(resolve13, pollInterval));
|
|
62007
63381
|
options?.signal?.throwIfAborted();
|
|
62008
63382
|
}
|
|
62009
63383
|
} catch (error45) {
|
|
@@ -62015,7 +63389,7 @@ class Protocol {
|
|
|
62015
63389
|
}
|
|
62016
63390
|
request(request, resultSchema, options) {
|
|
62017
63391
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
62018
|
-
return new Promise((
|
|
63392
|
+
return new Promise((resolve13, reject) => {
|
|
62019
63393
|
const earlyReject = (error45) => {
|
|
62020
63394
|
reject(error45);
|
|
62021
63395
|
};
|
|
@@ -62093,7 +63467,7 @@ class Protocol {
|
|
|
62093
63467
|
if (!parseResult.success) {
|
|
62094
63468
|
reject(parseResult.error);
|
|
62095
63469
|
} else {
|
|
62096
|
-
|
|
63470
|
+
resolve13(parseResult.data);
|
|
62097
63471
|
}
|
|
62098
63472
|
} catch (error45) {
|
|
62099
63473
|
reject(error45);
|
|
@@ -62284,12 +63658,12 @@ class Protocol {
|
|
|
62284
63658
|
interval = task.pollInterval;
|
|
62285
63659
|
}
|
|
62286
63660
|
} catch {}
|
|
62287
|
-
return new Promise((
|
|
63661
|
+
return new Promise((resolve13, reject) => {
|
|
62288
63662
|
if (signal.aborted) {
|
|
62289
63663
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
62290
63664
|
return;
|
|
62291
63665
|
}
|
|
62292
|
-
const timeoutId = setTimeout(
|
|
63666
|
+
const timeoutId = setTimeout(resolve13, interval);
|
|
62293
63667
|
signal.addEventListener("abort", () => {
|
|
62294
63668
|
clearTimeout(timeoutId);
|
|
62295
63669
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -63027,8 +64401,8 @@ async function random(size) {
|
|
|
63027
64401
|
const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
|
|
63028
64402
|
let result = "";
|
|
63029
64403
|
while (result.length < size) {
|
|
63030
|
-
const
|
|
63031
|
-
for (const randomByte of
|
|
64404
|
+
const randomBytes2 = await getRandomValues(size - result.length);
|
|
64405
|
+
for (const randomByte of randomBytes2) {
|
|
63032
64406
|
if (randomByte < evenDistCutoff) {
|
|
63033
64407
|
result += mask[randomByte % mask.length];
|
|
63034
64408
|
}
|
|
@@ -63834,7 +65208,7 @@ function createParser(callbacks) {
|
|
|
63834
65208
|
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks;
|
|
63835
65209
|
let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = "";
|
|
63836
65210
|
function feed(newChunk) {
|
|
63837
|
-
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] =
|
|
65211
|
+
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines2(`${incompleteLine}${chunk}`);
|
|
63838
65212
|
for (const line of complete)
|
|
63839
65213
|
parseLine(line);
|
|
63840
65214
|
incompleteLine = incomplete, isFirstChunk = false;
|
|
@@ -63893,7 +65267,7 @@ function createParser(callbacks) {
|
|
|
63893
65267
|
}
|
|
63894
65268
|
return { feed, reset };
|
|
63895
65269
|
}
|
|
63896
|
-
function
|
|
65270
|
+
function splitLines2(chunk) {
|
|
63897
65271
|
const lines = [];
|
|
63898
65272
|
let incompleteLine = "", searchIndex = 0;
|
|
63899
65273
|
for (;searchIndex < chunk.length; ) {
|
|
@@ -64533,10 +65907,10 @@ async function findAvailablePort2(startPort = DEFAULT_PORT) {
|
|
|
64533
65907
|
|
|
64534
65908
|
// src/features/mcp-oauth/oauth-authorization-flow.ts
|
|
64535
65909
|
import { spawn as spawn13 } from "child_process";
|
|
64536
|
-
import { createHash as createHash2, randomBytes } from "crypto";
|
|
65910
|
+
import { createHash as createHash2, randomBytes as randomBytes2 } from "crypto";
|
|
64537
65911
|
import { createServer } from "http";
|
|
64538
65912
|
function generateCodeVerifier() {
|
|
64539
|
-
return
|
|
65913
|
+
return randomBytes2(32).toString("base64url");
|
|
64540
65914
|
}
|
|
64541
65915
|
function generateCodeChallenge(verifier) {
|
|
64542
65916
|
return createHash2("sha256").update(verifier).digest("base64url");
|
|
@@ -64559,7 +65933,7 @@ function buildAuthorizationUrl(authorizationEndpoint, options) {
|
|
|
64559
65933
|
}
|
|
64560
65934
|
var CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
64561
65935
|
function startCallbackServer(port) {
|
|
64562
|
-
return new Promise((
|
|
65936
|
+
return new Promise((resolve13, reject) => {
|
|
64563
65937
|
let timeoutId;
|
|
64564
65938
|
const server = createServer((request, response) => {
|
|
64565
65939
|
clearTimeout(timeoutId);
|
|
@@ -64585,7 +65959,7 @@ function startCallbackServer(port) {
|
|
|
64585
65959
|
response.writeHead(200, { "content-type": "text/html" });
|
|
64586
65960
|
response.end("<html><body><h1>Authorization successful. You can close this tab.</h1></body></html>");
|
|
64587
65961
|
server.close();
|
|
64588
|
-
|
|
65962
|
+
resolve13({ code, state: state3 });
|
|
64589
65963
|
});
|
|
64590
65964
|
timeoutId = setTimeout(() => {
|
|
64591
65965
|
server.close();
|
|
@@ -64621,7 +65995,7 @@ function openBrowser(url2) {
|
|
|
64621
65995
|
async function runAuthorizationCodeRedirect(options) {
|
|
64622
65996
|
const verifier = generateCodeVerifier();
|
|
64623
65997
|
const challenge = generateCodeChallenge(verifier);
|
|
64624
|
-
const state3 =
|
|
65998
|
+
const state3 = randomBytes2(16).toString("hex");
|
|
64625
65999
|
const authorizationUrl = buildAuthorizationUrl(options.authorizationEndpoint, {
|
|
64626
66000
|
clientId: options.clientId,
|
|
64627
66001
|
redirectUri: options.redirectUri,
|
|
@@ -65037,7 +66411,7 @@ class StdioClientTransport {
|
|
|
65037
66411
|
if (this._process) {
|
|
65038
66412
|
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
65039
66413
|
}
|
|
65040
|
-
return new Promise((
|
|
66414
|
+
return new Promise((resolve13, reject) => {
|
|
65041
66415
|
this._process = import_cross_spawn.default(this._serverParams.command, this._serverParams.args ?? [], {
|
|
65042
66416
|
env: {
|
|
65043
66417
|
...getDefaultEnvironment(),
|
|
@@ -65053,7 +66427,7 @@ class StdioClientTransport {
|
|
|
65053
66427
|
this.onerror?.(error45);
|
|
65054
66428
|
});
|
|
65055
66429
|
this._process.on("spawn", () => {
|
|
65056
|
-
|
|
66430
|
+
resolve13();
|
|
65057
66431
|
});
|
|
65058
66432
|
this._process.on("close", (_code) => {
|
|
65059
66433
|
this._process = undefined;
|
|
@@ -65100,20 +66474,20 @@ class StdioClientTransport {
|
|
|
65100
66474
|
if (this._process) {
|
|
65101
66475
|
const processToClose = this._process;
|
|
65102
66476
|
this._process = undefined;
|
|
65103
|
-
const closePromise = new Promise((
|
|
66477
|
+
const closePromise = new Promise((resolve13) => {
|
|
65104
66478
|
processToClose.once("close", () => {
|
|
65105
|
-
|
|
66479
|
+
resolve13();
|
|
65106
66480
|
});
|
|
65107
66481
|
});
|
|
65108
66482
|
try {
|
|
65109
66483
|
processToClose.stdin?.end();
|
|
65110
66484
|
} catch {}
|
|
65111
|
-
await Promise.race([closePromise, new Promise((
|
|
66485
|
+
await Promise.race([closePromise, new Promise((resolve13) => setTimeout(resolve13, 2000).unref())]);
|
|
65112
66486
|
if (processToClose.exitCode === null) {
|
|
65113
66487
|
try {
|
|
65114
66488
|
processToClose.kill("SIGTERM");
|
|
65115
66489
|
} catch {}
|
|
65116
|
-
await Promise.race([closePromise, new Promise((
|
|
66490
|
+
await Promise.race([closePromise, new Promise((resolve13) => setTimeout(resolve13, 2000).unref())]);
|
|
65117
66491
|
}
|
|
65118
66492
|
if (processToClose.exitCode === null) {
|
|
65119
66493
|
try {
|
|
@@ -65124,15 +66498,15 @@ class StdioClientTransport {
|
|
|
65124
66498
|
this._readBuffer.clear();
|
|
65125
66499
|
}
|
|
65126
66500
|
send(message) {
|
|
65127
|
-
return new Promise((
|
|
66501
|
+
return new Promise((resolve13) => {
|
|
65128
66502
|
if (!this._process?.stdin) {
|
|
65129
66503
|
throw new Error("Not connected");
|
|
65130
66504
|
}
|
|
65131
66505
|
const json3 = serializeMessage(message);
|
|
65132
66506
|
if (this._process.stdin.write(json3)) {
|
|
65133
|
-
|
|
66507
|
+
resolve13();
|
|
65134
66508
|
} else {
|
|
65135
|
-
this._process.stdin.once("drain",
|
|
66509
|
+
this._process.stdin.once("drain", resolve13);
|
|
65136
66510
|
}
|
|
65137
66511
|
});
|
|
65138
66512
|
}
|
|
@@ -66225,7 +67599,7 @@ class TmuxSessionManager {
|
|
|
66225
67599
|
} catch (err) {
|
|
66226
67600
|
log("[tmux-session-manager] session status check error", { error: String(err) });
|
|
66227
67601
|
}
|
|
66228
|
-
await new Promise((
|
|
67602
|
+
await new Promise((resolve13) => setTimeout(resolve13, SESSION_READY_POLL_INTERVAL_MS));
|
|
66229
67603
|
}
|
|
66230
67604
|
log("[tmux-session-manager] session ready timeout", {
|
|
66231
67605
|
sessionId,
|
|
@@ -66480,6 +67854,134 @@ Before responding, enumerate in your head:
|
|
|
66480
67854
|
Then ACTUALLY CALL those tools using the JSON tool schema. Produce the tool_use blocks. Execute.
|
|
66481
67855
|
</TOOL_CALL_MANDATE>`;
|
|
66482
67856
|
}
|
|
67857
|
+
function buildGeminiToolGuide() {
|
|
67858
|
+
return `<GEMINI_TOOL_GUIDE>
|
|
67859
|
+
## Tool Usage Guide \u2014 WHEN and HOW to Call Each Tool
|
|
67860
|
+
|
|
67861
|
+
You have access to tools via function calling. This guide defines WHEN to call each one.
|
|
67862
|
+
**Violating these patterns = failed response.**
|
|
67863
|
+
|
|
67864
|
+
### Reading & Search (ALWAYS parallelizable \u2014 call multiple simultaneously)
|
|
67865
|
+
|
|
67866
|
+
| Tool | When to Call | Parallel? |
|
|
67867
|
+
|---|---|---|
|
|
67868
|
+
| \`Read\` | Before making ANY claim about file contents. Before editing any file. | \uFFFD Yes \u2014 read multiple files at once |
|
|
67869
|
+
| \`Grep\` | Finding patterns, imports, usages across codebase. BEFORE claiming "X is used in Y". | \u2705 Yes \u2014 run multiple greps at once |
|
|
67870
|
+
| \`Glob\` | Finding files by name/extension pattern. BEFORE claiming "file X exists". | \u2705 Yes \u2014 run multiple globs at once |
|
|
67871
|
+
| \`AstGrepSearch\` | Finding code patterns with AST awareness (structural matches). | \u2705 Yes |
|
|
67872
|
+
|
|
67873
|
+
### Code Intelligence (parallelizable on different files)
|
|
67874
|
+
|
|
67875
|
+
| Tool | When to Call | Parallel? |
|
|
67876
|
+
|---|---|---|
|
|
67877
|
+
| \`LspDiagnostics\` | **AFTER EVERY edit.** BEFORE claiming task is done. MANDATORY. | \u2705 Yes \u2014 different files |
|
|
67878
|
+
| \`LspGotoDefinition\` | Finding where a symbol is defined. | \u2705 Yes |
|
|
67879
|
+
| \`LspFindReferences\` | Finding all usages of a symbol across workspace. | \u2705 Yes |
|
|
67880
|
+
| \`LspSymbols\` | Getting file outline or searching workspace symbols. | \u2705 Yes |
|
|
67881
|
+
|
|
67882
|
+
### Editing (SEQUENTIAL \u2014 must Read first)
|
|
67883
|
+
|
|
67884
|
+
| Tool | When to Call | Parallel? |
|
|
67885
|
+
|---|---|---|
|
|
67886
|
+
| \`Edit\` | Modifying existing files. MUST Read file first to get LINE#ID anchors. | \u274C After Read |
|
|
67887
|
+
| \`Write\` | Creating NEW files only. Or full file overwrite. | \u274C Sequential |
|
|
67888
|
+
|
|
67889
|
+
### Execution & Delegation
|
|
67890
|
+
|
|
67891
|
+
| Tool | When to Call | Parallel? |
|
|
67892
|
+
|---|---|---|
|
|
67893
|
+
| \`Bash\` | Running tests, builds, git commands. | \u274C Usually sequential |
|
|
67894
|
+
| \`Task\` | ANY non-trivial implementation. Research via explore/librarian. | \u2705 Fire multiple in background |
|
|
67895
|
+
|
|
67896
|
+
### Correct Sequences (MANDATORY \u2014 follow these exactly):
|
|
67897
|
+
|
|
67898
|
+
1. **Answer about code**: Read \u2192 (analyze) \u2192 Answer
|
|
67899
|
+
2. **Edit code**: Read \u2192 Edit \u2192 LspDiagnostics \u2192 Report
|
|
67900
|
+
3. **Find something**: Grep/Glob (parallel) \u2192 Read results \u2192 Report
|
|
67901
|
+
4. **Implement feature**: Task(delegate) \u2192 Verify results \u2192 Report
|
|
67902
|
+
5. **Debug**: Read error \u2192 Read file \u2192 Grep related \u2192 Fix \u2192 LspDiagnostics
|
|
67903
|
+
|
|
67904
|
+
### PARALLEL RULES:
|
|
67905
|
+
|
|
67906
|
+
- **Independent reads/searches**: ALWAYS call simultaneously in ONE response
|
|
67907
|
+
- **Dependent operations**: Call sequentially (Edit AFTER Read, LspDiagnostics AFTER Edit)
|
|
67908
|
+
- **Background agents**: ALWAYS \`run_in_background=true\`, continue working
|
|
67909
|
+
</GEMINI_TOOL_GUIDE>`;
|
|
67910
|
+
}
|
|
67911
|
+
function buildGeminiToolCallExamples() {
|
|
67912
|
+
return `<GEMINI_TOOL_CALL_EXAMPLES>
|
|
67913
|
+
## Correct Tool Calling Patterns \u2014 Follow These Examples
|
|
67914
|
+
|
|
67915
|
+
### Example 1: User asks about code \u2192 Read FIRST, then answer
|
|
67916
|
+
**User**: "How does the auth middleware work?"
|
|
67917
|
+
**CORRECT**:
|
|
67918
|
+
\`\`\`
|
|
67919
|
+
\u2192 Call Read(filePath="/src/middleware/auth.ts")
|
|
67920
|
+
\u2192 Call Read(filePath="/src/config/auth.ts") // parallel with above
|
|
67921
|
+
\u2192 (After reading) Answer based on ACTUAL file contents
|
|
67922
|
+
\`\`\`
|
|
67923
|
+
**WRONG**:
|
|
67924
|
+
\`\`\`
|
|
67925
|
+
\u2192 "The auth middleware likely validates JWT tokens by..." \u2190 HALLUCINATION. You didn't read the file.
|
|
67926
|
+
\`\`\`
|
|
67927
|
+
|
|
67928
|
+
### Example 2: User asks to edit code \u2192 Read, Edit, Verify
|
|
67929
|
+
**User**: "Fix the type error in user.ts"
|
|
67930
|
+
**CORRECT**:
|
|
67931
|
+
\`\`\`
|
|
67932
|
+
\u2192 Call Read(filePath="/src/models/user.ts")
|
|
67933
|
+
\u2192 Call LspDiagnostics(filePath="/src/models/user.ts") // parallel with Read
|
|
67934
|
+
\u2192 (After reading) Call Edit with LINE#ID anchors
|
|
67935
|
+
\u2192 Call LspDiagnostics(filePath="/src/models/user.ts") // verify fix
|
|
67936
|
+
\u2192 Report: "Fixed. Diagnostics clean."
|
|
67937
|
+
\`\`\`
|
|
67938
|
+
**WRONG**:
|
|
67939
|
+
\`\`\`
|
|
67940
|
+
\u2192 Call Edit without reading first \u2190 No LINE#ID anchors = WILL FAIL
|
|
67941
|
+
\u2192 Skip LspDiagnostics after edit \u2190 UNVERIFIED
|
|
67942
|
+
\`\`\`
|
|
67943
|
+
|
|
67944
|
+
### Example 3: User asks to find something \u2192 Search in parallel
|
|
67945
|
+
**User**: "Where is the database connection configured?"
|
|
67946
|
+
**CORRECT**:
|
|
67947
|
+
\`\`\`
|
|
67948
|
+
\u2192 Call Grep(pattern="database|connection|pool", path="/src") // fires simultaneously
|
|
67949
|
+
\u2192 Call Glob(pattern="**/*database*") // fires simultaneously
|
|
67950
|
+
\u2192 Call Glob(pattern="**/*db*") // fires simultaneously
|
|
67951
|
+
\u2192 (After results) Read the most relevant files
|
|
67952
|
+
\u2192 Report findings with file paths
|
|
67953
|
+
\`\`\`
|
|
67954
|
+
|
|
67955
|
+
### Example 4: User asks to implement a feature \u2192 DELEGATE
|
|
67956
|
+
**User**: "Add a new /health endpoint to the API"
|
|
67957
|
+
**CORRECT**:
|
|
67958
|
+
\`\`\`
|
|
67959
|
+
\u2192 Call Task(category="quick", load_skills=["typescript-programmer"], prompt="...")
|
|
67960
|
+
\u2192 (After agent completes) Read changed files to verify
|
|
67961
|
+
\u2192 Call LspDiagnostics on changed files
|
|
67962
|
+
\u2192 Report
|
|
67963
|
+
\`\`\`
|
|
67964
|
+
**WRONG**:
|
|
67965
|
+
\`\`\`
|
|
67966
|
+
\u2192 Write the code yourself \u2190 YOU ARE AN ORCHESTRATOR, NOT AN IMPLEMENTER
|
|
67967
|
+
\`\`\`
|
|
67968
|
+
|
|
67969
|
+
### Example 5: Investigation \u2260 Implementation
|
|
67970
|
+
**User**: "Look into why the tests are failing"
|
|
67971
|
+
**CORRECT**:
|
|
67972
|
+
\`\`\`
|
|
67973
|
+
\u2192 Call Bash(command="npm test") // see actual failures
|
|
67974
|
+
\u2192 Call Read on failing test files
|
|
67975
|
+
\u2192 Call Read on source files under test
|
|
67976
|
+
\u2192 Report: "Tests fail because X. Root cause: Y. Proposed fix: Z."
|
|
67977
|
+
\u2192 STOP \u2014 wait for user to say "fix it"
|
|
67978
|
+
\`\`\`
|
|
67979
|
+
**WRONG**:
|
|
67980
|
+
\`\`\`
|
|
67981
|
+
\u2192 Start editing source files immediately \u2190 "look into" \u2260 "fix"
|
|
67982
|
+
\`\`\`
|
|
67983
|
+
</GEMINI_TOOL_CALL_EXAMPLES>`;
|
|
67984
|
+
}
|
|
66483
67985
|
function buildGeminiDelegationOverride() {
|
|
66484
67986
|
return `<GEMINI_DELEGATION_OVERRIDE>
|
|
66485
67987
|
## DELEGATION IS MANDATORY \u2014 YOU ARE NOT AN IMPLEMENTER
|
|
@@ -66781,12 +68283,11 @@ Briefly announce "Consulting Oracle for [reason]" before invocation.
|
|
|
66781
68283
|
|
|
66782
68284
|
### Oracle Background Task Policy:
|
|
66783
68285
|
|
|
66784
|
-
**
|
|
68286
|
+
**Collect Oracle results before your final answer. No exceptions.**
|
|
66785
68287
|
|
|
66786
|
-
- Oracle
|
|
66787
|
-
-
|
|
66788
|
-
-
|
|
66789
|
-
- **NEVER** cancel Oracle. **NEVER** use \`background_cancel(all=true)\` when Oracle is running. Cancel disposable tasks (explore, librarian) individually by taskId instead.
|
|
68288
|
+
- Oracle takes minutes. When done with your own work: **end your response** \u2014 wait for the \`<system-reminder>\`.
|
|
68289
|
+
- Do NOT poll \`background_output\` on a running Oracle. The notification will come.
|
|
68290
|
+
- Never cancel Oracle.
|
|
66790
68291
|
</Oracle_Usage>`;
|
|
66791
68292
|
}
|
|
66792
68293
|
function buildHardBlocksSection() {
|
|
@@ -66795,8 +68296,8 @@ function buildHardBlocksSection() {
|
|
|
66795
68296
|
"- Commit without explicit request \u2014 **Never**",
|
|
66796
68297
|
"- Speculate about unread code \u2014 **Never**",
|
|
66797
68298
|
"- Leave code in broken state after failures \u2014 **Never**",
|
|
66798
|
-
"- `background_cancel(all=true)`
|
|
66799
|
-
"- Delivering final answer before collecting Oracle result \u2014 **Never.**
|
|
68299
|
+
"- `background_cancel(all=true)` \u2014 **Never.** Always cancel individually by taskId.",
|
|
68300
|
+
"- Delivering final answer before collecting Oracle result \u2014 **Never.**"
|
|
66800
68301
|
];
|
|
66801
68302
|
return `## Hard Blocks (NEVER violate)
|
|
66802
68303
|
|
|
@@ -66810,14 +68311,29 @@ function buildAntiPatternsSection() {
|
|
|
66810
68311
|
'- **Testing**: Deleting failing tests to "pass"',
|
|
66811
68312
|
"- **Search**: Firing agents for single-line typos or obvious syntax errors",
|
|
66812
68313
|
"- **Debugging**: Shotgun debugging, random changes",
|
|
66813
|
-
"- **Background Tasks**: `
|
|
66814
|
-
"- **Oracle**:
|
|
68314
|
+
"- **Background Tasks**: Polling `background_output` on running tasks \u2014 end response and wait for notification",
|
|
68315
|
+
"- **Oracle**: Delivering answer without collecting Oracle results"
|
|
66815
68316
|
];
|
|
66816
68317
|
return `## Anti-Patterns (BLOCKING violations)
|
|
66817
68318
|
|
|
66818
68319
|
${patterns.join(`
|
|
66819
68320
|
`)}`;
|
|
66820
68321
|
}
|
|
68322
|
+
function buildNonClaudePlannerSection(model) {
|
|
68323
|
+
const isNonClaude = !model.toLowerCase().includes("claude");
|
|
68324
|
+
if (!isNonClaude)
|
|
68325
|
+
return "";
|
|
68326
|
+
return `### Plan Agent Dependency (Non-Claude)
|
|
68327
|
+
|
|
68328
|
+
Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementation without a plan.
|
|
68329
|
+
|
|
68330
|
+
- Single-file fix or trivial change \u2192 proceed directly
|
|
68331
|
+
- Anything else (2+ steps, unclear scope, architecture) \u2192 \`task(subagent_type="plan", ...)\` FIRST
|
|
68332
|
+
- Use \`session_id\` to resume the same Plan Agent \u2014 ask follow-up questions aggressively
|
|
68333
|
+
- If ANY part of the task is ambiguous, ask Plan Agent before guessing
|
|
68334
|
+
|
|
68335
|
+
Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.`;
|
|
68336
|
+
}
|
|
66821
68337
|
function buildDeepParallelSection(model, categories2) {
|
|
66822
68338
|
const isNonClaude = !model.toLowerCase().includes("claude");
|
|
66823
68339
|
const hasDeepCategory = categories2.some((c) => c.name === "deep");
|
|
@@ -66825,16 +68341,17 @@ function buildDeepParallelSection(model, categories2) {
|
|
|
66825
68341
|
return "";
|
|
66826
68342
|
return `### Deep Parallel Delegation
|
|
66827
68343
|
|
|
66828
|
-
|
|
68344
|
+
Delegate EVERY independent unit to a \`deep\` agent in parallel (\`run_in_background=true\`).
|
|
68345
|
+
If a task decomposes into 4 independent units, spawn 4 agents simultaneously \u2014 not 1 at a time.
|
|
66829
68346
|
|
|
66830
|
-
1.
|
|
66831
|
-
2.
|
|
66832
|
-
3. Give each agent a GOAL, not step-by-step instructions
|
|
66833
|
-
4. Collect results, integrate, verify coherence`;
|
|
68347
|
+
1. Decompose the implementation into independent work units
|
|
68348
|
+
2. Assign one \`deep\` agent per unit \u2014 all via \`run_in_background=true\`
|
|
68349
|
+
3. Give each agent a clear GOAL with success criteria, not step-by-step instructions
|
|
68350
|
+
4. Collect all results, integrate, verify coherence across units`;
|
|
66834
68351
|
}
|
|
66835
68352
|
|
|
66836
68353
|
// src/agents/sisyphus.ts
|
|
66837
|
-
var MODE = "
|
|
68354
|
+
var MODE = "all";
|
|
66838
68355
|
function buildTaskManagementSection(useTaskSystem) {
|
|
66839
68356
|
if (useTaskSystem) {
|
|
66840
68357
|
return `<Task_Management>
|
|
@@ -66954,6 +68471,7 @@ function buildDynamicSisyphusPrompt(model, availableAgents, availableTools = [],
|
|
|
66954
68471
|
const hardBlocks = buildHardBlocksSection();
|
|
66955
68472
|
const antiPatterns = buildAntiPatternsSection();
|
|
66956
68473
|
const deepParallelSection = buildDeepParallelSection(model, availableCategories);
|
|
68474
|
+
const nonClaudePlannerSection = buildNonClaudePlannerSection(model);
|
|
66957
68475
|
const taskManagementSection = buildTaskManagementSection(useTaskSystem);
|
|
66958
68476
|
const todoHookNote = useTaskSystem ? "YOUR TASK CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TASK CONTINUATION])" : "YOUR TODO CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TODO CONTINUATION])";
|
|
66959
68477
|
return `<Role>
|
|
@@ -67110,7 +68628,7 @@ task(subagent_type="explore", run_in_background=true, load_skills=[], descriptio
|
|
|
67110
68628
|
// Reference Grep (external)
|
|
67111
68629
|
task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find JWT security docs", prompt="I'm implementing JWT auth and need current security best practices to choose token storage (httpOnly cookies vs localStorage) and set expiration policy. Find: OWASP auth guidelines, recommended token lifetimes, refresh token rotation strategies, common JWT vulnerabilities. Skip 'what is JWT' tutorials \u2014 production security guidance only.")
|
|
67112
68630
|
task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find Express auth patterns", prompt="I'm building Express auth middleware and need production-quality patterns to structure my middleware chain. Find how established Express apps (1000+ stars) handle: middleware ordering, token refresh, role-based access control, auth error propagation. Skip basic tutorials \u2014 I need battle-tested patterns with proper error handling.")
|
|
67113
|
-
// Continue working immediately.
|
|
68631
|
+
// Continue working immediately. System notifies on completion \u2014 collect with background_output then.
|
|
67114
68632
|
|
|
67115
68633
|
// WRONG: Sequential or blocking
|
|
67116
68634
|
result = task(..., run_in_background=false) // Never wait synchronously for explore/librarian
|
|
@@ -67118,10 +68636,10 @@ result = task(..., run_in_background=false) // Never wait synchronously for exp
|
|
|
67118
68636
|
|
|
67119
68637
|
### Background Result Collection:
|
|
67120
68638
|
1. Launch parallel agents \u2192 receive task_ids
|
|
67121
|
-
2. Continue immediate work
|
|
67122
|
-
3.
|
|
67123
|
-
4.
|
|
67124
|
-
5. Cleanup: Cancel disposable tasks
|
|
68639
|
+
2. Continue immediate work
|
|
68640
|
+
3. System sends \`<system-reminder>\` on each task completion \u2014 then call \`background_output(task_id="...")\`
|
|
68641
|
+
4. Need results not yet ready? **End your response.** The notification will trigger your next turn.
|
|
68642
|
+
5. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\`
|
|
67125
68643
|
|
|
67126
68644
|
### Search Stop Conditions
|
|
67127
68645
|
|
|
@@ -67145,6 +68663,8 @@ STOP searching when:
|
|
|
67145
68663
|
|
|
67146
68664
|
${categorySkillsGuide}
|
|
67147
68665
|
|
|
68666
|
+
${nonClaudePlannerSection}
|
|
68667
|
+
|
|
67148
68668
|
${deepParallelSection}
|
|
67149
68669
|
|
|
67150
68670
|
${delegationTable}
|
|
@@ -67258,9 +68778,8 @@ If verification fails:
|
|
|
67258
68778
|
3. Report: "Done. Note: found N pre-existing lint errors unrelated to my changes."
|
|
67259
68779
|
|
|
67260
68780
|
### Before Delivering Final Answer:
|
|
67261
|
-
-
|
|
67262
|
-
- Cancel disposable background tasks
|
|
67263
|
-
- **Never use \`background_cancel(all=true)\`.**
|
|
68781
|
+
- If Oracle is running: **end your response** and wait for the completion notification first.
|
|
68782
|
+
- Cancel disposable background tasks individually via \`background_cancel(taskId="...")\`.
|
|
67264
68783
|
</Behavior_Instructions>
|
|
67265
68784
|
|
|
67266
68785
|
${oracleSection}
|
|
@@ -67333,10 +68852,16 @@ function createSisyphusAgent(model, availableAgents, availableToolNames, availab
|
|
|
67333
68852
|
${buildGeminiIntentGateEnforcement()}
|
|
67334
68853
|
|
|
67335
68854
|
${buildGeminiToolMandate()}`);
|
|
67336
|
-
prompt
|
|
67337
|
-
|
|
67338
|
-
|
|
67339
|
-
|
|
68855
|
+
prompt = prompt.replace("</tool_usage_rules>", `</tool_usage_rules>
|
|
68856
|
+
|
|
68857
|
+
${buildGeminiToolGuide()}
|
|
68858
|
+
|
|
68859
|
+
${buildGeminiToolCallExamples()}`);
|
|
68860
|
+
prompt = prompt.replace("<Constraints>", `${buildGeminiDelegationOverride()}
|
|
68861
|
+
|
|
68862
|
+
${buildGeminiVerificationOverride()}
|
|
68863
|
+
|
|
68864
|
+
<Constraints>`);
|
|
67340
68865
|
}
|
|
67341
68866
|
const permission = {
|
|
67342
68867
|
question: "allow",
|
|
@@ -69544,7 +71069,7 @@ ${agentRows.join(`
|
|
|
69544
71069
|
}
|
|
69545
71070
|
|
|
69546
71071
|
// src/agents/atlas/agent.ts
|
|
69547
|
-
var MODE7 = "
|
|
71072
|
+
var MODE7 = "all";
|
|
69548
71073
|
function getAtlasPromptSource(model) {
|
|
69549
71074
|
if (model && isGptModel(model)) {
|
|
69550
71075
|
return "gpt";
|
|
@@ -69585,18 +71110,13 @@ function buildDynamicOrchestratorPrompt(ctx) {
|
|
|
69585
71110
|
return basePrompt.replace("{CATEGORY_SECTION}", categorySection).replace("{AGENT_SECTION}", agentSection).replace("{DECISION_MATRIX}", decisionMatrix).replace("{SKILLS_SECTION}", skillsSection).replace("{{CATEGORY_SKILLS_DELEGATION_GUIDE}}", categorySkillsGuide);
|
|
69586
71111
|
}
|
|
69587
71112
|
function createAtlasAgent(ctx) {
|
|
69588
|
-
const restrictions = createAgentToolRestrictions([
|
|
69589
|
-
"task",
|
|
69590
|
-
"call_omo_agent"
|
|
69591
|
-
]);
|
|
69592
71113
|
const baseConfig = {
|
|
69593
71114
|
description: "Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Atlas - OhMyOpenCode)",
|
|
69594
71115
|
mode: MODE7,
|
|
69595
71116
|
...ctx.model ? { model: ctx.model } : {},
|
|
69596
71117
|
temperature: 0.1,
|
|
69597
71118
|
prompt: buildDynamicOrchestratorPrompt(ctx),
|
|
69598
|
-
color: "#10B981"
|
|
69599
|
-
...restrictions
|
|
71119
|
+
color: "#10B981"
|
|
69600
71120
|
};
|
|
69601
71121
|
return baseConfig;
|
|
69602
71122
|
}
|
|
@@ -69847,7 +71367,7 @@ var momusPromptMetadata = {
|
|
|
69847
71367
|
};
|
|
69848
71368
|
|
|
69849
71369
|
// src/agents/hephaestus.ts
|
|
69850
|
-
var MODE9 = "
|
|
71370
|
+
var MODE9 = "all";
|
|
69851
71371
|
function buildTodoDisciplineSection(useTaskSystem) {
|
|
69852
71372
|
if (useTaskSystem) {
|
|
69853
71373
|
return `## Task Discipline (NON-NEGOTIABLE)
|
|
@@ -70377,7 +71897,7 @@ function buildAgent(source, model, categories2, gitMasterConfig, browserProvider
|
|
|
70377
71897
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
70378
71898
|
import { existsSync as existsSync64, readFileSync as readFileSync44 } from "fs";
|
|
70379
71899
|
import { homedir as homedir13 } from "os";
|
|
70380
|
-
import { isAbsolute as isAbsolute9, resolve as
|
|
71900
|
+
import { isAbsolute as isAbsolute9, resolve as resolve13 } from "path";
|
|
70381
71901
|
function resolvePromptAppend(promptAppend, configDir) {
|
|
70382
71902
|
if (!promptAppend.startsWith("file://"))
|
|
70383
71903
|
return promptAppend;
|
|
@@ -70386,7 +71906,7 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
70386
71906
|
try {
|
|
70387
71907
|
const decoded = decodeURIComponent(encoded);
|
|
70388
71908
|
const expanded = decoded.startsWith("~/") ? decoded.replace(/^~\//, `${homedir13()}/`) : decoded;
|
|
70389
|
-
filePath = isAbsolute9(expanded) ? expanded :
|
|
71909
|
+
filePath = isAbsolute9(expanded) ? expanded : resolve13(configDir ?? process.cwd(), expanded);
|
|
70390
71910
|
} catch {
|
|
70391
71911
|
return `[WARNING: Malformed file URI (invalid percent-encoding): ${promptAppend}]`;
|
|
70392
71912
|
}
|
|
@@ -70452,25 +71972,10 @@ function applyOverrides(config3, override, mergedCategories, directory) {
|
|
|
70452
71972
|
|
|
70453
71973
|
// src/agents/env-context.ts
|
|
70454
71974
|
function createEnvContext() {
|
|
70455
|
-
const now = new Date;
|
|
70456
71975
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
70457
71976
|
const locale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
70458
|
-
const dateStr = now.toLocaleDateString(locale, {
|
|
70459
|
-
weekday: "short",
|
|
70460
|
-
year: "numeric",
|
|
70461
|
-
month: "short",
|
|
70462
|
-
day: "numeric"
|
|
70463
|
-
});
|
|
70464
|
-
const timeStr = now.toLocaleTimeString(locale, {
|
|
70465
|
-
hour: "2-digit",
|
|
70466
|
-
minute: "2-digit",
|
|
70467
|
-
second: "2-digit",
|
|
70468
|
-
hour12: true
|
|
70469
|
-
});
|
|
70470
71977
|
return `
|
|
70471
71978
|
<omo-env>
|
|
70472
|
-
Current date: ${dateStr}
|
|
70473
|
-
Current time: ${timeStr}
|
|
70474
71979
|
Timezone: ${timezone}
|
|
70475
71980
|
Locale: ${locale}
|
|
70476
71981
|
</omo-env>`;
|
|
@@ -73701,6 +75206,8 @@ async function applyAgentConfig(params) {
|
|
|
73701
75206
|
key,
|
|
73702
75207
|
value ? migrateAgentConfig(value) : value
|
|
73703
75208
|
]));
|
|
75209
|
+
const disabledAgentNames = new Set((migratedDisabledAgents ?? []).map((a) => a.toLowerCase()));
|
|
75210
|
+
const filterDisabledAgents = (agents) => Object.fromEntries(Object.entries(agents).filter(([name]) => !disabledAgentNames.has(name.toLowerCase())));
|
|
73704
75211
|
const isSisyphusEnabled = params.pluginConfig.sisyphus_agent?.disabled !== true;
|
|
73705
75212
|
const builderEnabled = params.pluginConfig.sisyphus_agent?.default_builder_enabled ?? false;
|
|
73706
75213
|
const plannerEnabled = params.pluginConfig.sisyphus_agent?.planner_enabled ?? true;
|
|
@@ -73754,9 +75261,9 @@ async function applyAgentConfig(params) {
|
|
|
73754
75261
|
params.config.agent = {
|
|
73755
75262
|
...agentConfig,
|
|
73756
75263
|
...Object.fromEntries(Object.entries(builtinAgents).filter(([key]) => key !== "sisyphus")),
|
|
73757
|
-
...userAgents,
|
|
73758
|
-
...projectAgents,
|
|
73759
|
-
...pluginAgents,
|
|
75264
|
+
...filterDisabledAgents(userAgents),
|
|
75265
|
+
...filterDisabledAgents(projectAgents),
|
|
75266
|
+
...filterDisabledAgents(pluginAgents),
|
|
73760
75267
|
...filteredConfigAgents,
|
|
73761
75268
|
build: { ...migratedBuild, mode: "subagent", hidden: true },
|
|
73762
75269
|
...planDemoteConfig ? { plan: planDemoteConfig } : {}
|
|
@@ -73764,9 +75271,9 @@ async function applyAgentConfig(params) {
|
|
|
73764
75271
|
} else {
|
|
73765
75272
|
params.config.agent = {
|
|
73766
75273
|
...builtinAgents,
|
|
73767
|
-
...userAgents,
|
|
73768
|
-
...projectAgents,
|
|
73769
|
-
...pluginAgents,
|
|
75274
|
+
...filterDisabledAgents(userAgents),
|
|
75275
|
+
...filterDisabledAgents(projectAgents),
|
|
75276
|
+
...filterDisabledAgents(pluginAgents),
|
|
73770
75277
|
...configAgent
|
|
73771
75278
|
};
|
|
73772
75279
|
}
|
|
@@ -74719,6 +76226,7 @@ function applyToolConfig(params) {
|
|
|
74719
76226
|
function createConfigHandler(deps) {
|
|
74720
76227
|
const { ctx, pluginConfig, modelCacheState } = deps;
|
|
74721
76228
|
return async (config3) => {
|
|
76229
|
+
const formatterConfig = config3.formatter;
|
|
74722
76230
|
applyProviderConfig({ config: config3, modelCacheState });
|
|
74723
76231
|
const pluginComponents = await loadPluginComponents({ pluginConfig });
|
|
74724
76232
|
const agentResult = await applyAgentConfig({
|
|
@@ -74730,6 +76238,7 @@ function createConfigHandler(deps) {
|
|
|
74730
76238
|
applyToolConfig({ config: config3, pluginConfig, agentResult });
|
|
74731
76239
|
await applyMcpConfig({ config: config3, pluginConfig, pluginComponents });
|
|
74732
76240
|
await applyCommandConfig({ config: config3, pluginConfig, ctx, pluginComponents });
|
|
76241
|
+
config3.formatter = formatterConfig;
|
|
74733
76242
|
log("[config-handler] config handler applied", {
|
|
74734
76243
|
agentCount: Object.keys(agentResult).length,
|
|
74735
76244
|
commandCount: Object.keys(config3.command ?? {}).length
|
|
@@ -74921,7 +76430,7 @@ function createToolRegistry(args) {
|
|
|
74921
76430
|
task_list: createTaskList(pluginConfig),
|
|
74922
76431
|
task_update: createTaskUpdateTool(pluginConfig, ctx)
|
|
74923
76432
|
} : {};
|
|
74924
|
-
const hashlineEnabled = pluginConfig.hashline_edit ??
|
|
76433
|
+
const hashlineEnabled = pluginConfig.hashline_edit ?? false;
|
|
74925
76434
|
const hashlineToolsRecord = hashlineEnabled ? { edit: createHashlineEditTool() } : {};
|
|
74926
76435
|
const allTools = {
|
|
74927
76436
|
...builtinTools,
|
|
@@ -75140,15 +76649,6 @@ function createChatHeadersHandler(args) {
|
|
|
75140
76649
|
};
|
|
75141
76650
|
}
|
|
75142
76651
|
|
|
75143
|
-
// src/shared/session-model-state.ts
|
|
75144
|
-
var sessionModels = new Map;
|
|
75145
|
-
function setSessionModel(sessionID, model) {
|
|
75146
|
-
sessionModels.set(sessionID, model);
|
|
75147
|
-
}
|
|
75148
|
-
function clearSessionModel(sessionID) {
|
|
75149
|
-
sessionModels.delete(sessionID);
|
|
75150
|
-
}
|
|
75151
|
-
|
|
75152
76652
|
// src/plugin/ultrawork-db-model-override.ts
|
|
75153
76653
|
import { Database } from "bun:sqlite";
|
|
75154
76654
|
import { join as join84 } from "path";
|
|
@@ -75313,11 +76813,11 @@ function applyUltraworkModelOverrideOnMessage(pluginConfig, inputAgentName, outp
|
|
|
75313
76813
|
const override = resolveUltraworkOverride(pluginConfig, inputAgentName, output, sessionID);
|
|
75314
76814
|
if (!override)
|
|
75315
76815
|
return;
|
|
76816
|
+
if (override.variant) {
|
|
76817
|
+
output.message["variant"] = override.variant;
|
|
76818
|
+
output.message["thinking"] = override.variant;
|
|
76819
|
+
}
|
|
75316
76820
|
if (!override.providerID || !override.modelID) {
|
|
75317
|
-
if (override.variant) {
|
|
75318
|
-
output.message["variant"] = override.variant;
|
|
75319
|
-
output.message["thinking"] = override.variant;
|
|
75320
|
-
}
|
|
75321
76821
|
return;
|
|
75322
76822
|
}
|
|
75323
76823
|
const targetModel = { providerID: override.providerID, modelID: override.modelID };
|
|
@@ -75329,10 +76829,6 @@ function applyUltraworkModelOverrideOnMessage(pluginConfig, inputAgentName, outp
|
|
|
75329
76829
|
if (!messageId) {
|
|
75330
76830
|
log("[ultrawork-model-override] No message ID found, falling back to direct mutation");
|
|
75331
76831
|
output.message.model = targetModel;
|
|
75332
|
-
if (override.variant) {
|
|
75333
|
-
output.message["variant"] = override.variant;
|
|
75334
|
-
output.message["thinking"] = override.variant;
|
|
75335
|
-
}
|
|
75336
76832
|
return;
|
|
75337
76833
|
}
|
|
75338
76834
|
const fromModel = output.message.model?.modelID ?? "unknown";
|
|
@@ -75404,8 +76900,10 @@ function createChatMessageHandler3(args) {
|
|
|
75404
76900
|
setSessionModel(input.sessionID, input.model);
|
|
75405
76901
|
}
|
|
75406
76902
|
await hooks2.stopContinuationGuard?.["chat.message"]?.(input);
|
|
76903
|
+
await hooks2.backgroundNotificationHook?.["chat.message"]?.(input, output);
|
|
75407
76904
|
await hooks2.runtimeFallback?.["chat.message"]?.(input, output);
|
|
75408
76905
|
await hooks2.keywordDetector?.["chat.message"]?.(input, output);
|
|
76906
|
+
await hooks2.thinkMode?.["chat.message"]?.(input, output);
|
|
75409
76907
|
await hooks2.claudeCodeHooks?.["chat.message"]?.(input, output);
|
|
75410
76908
|
await hooks2.autoSlashCommand?.["chat.message"]?.(input, output);
|
|
75411
76909
|
await hooks2.noSisyphusGpt?.["chat.message"]?.(input, output);
|
|
@@ -75856,6 +77354,7 @@ function createToolExecuteAfterHandler3(args) {
|
|
|
75856
77354
|
await hooks2.delegateTaskRetry?.["tool.execute.after"]?.(input, output);
|
|
75857
77355
|
await hooks2.atlasHook?.["tool.execute.after"]?.(input, output);
|
|
75858
77356
|
await hooks2.taskResumeInfo?.["tool.execute.after"]?.(input, output);
|
|
77357
|
+
await hooks2.readImageResizer?.["tool.execute.after"]?.(input, output);
|
|
75859
77358
|
await hooks2.hashlineReadEnhancer?.["tool.execute.after"]?.(input, output);
|
|
75860
77359
|
await hooks2.jsonErrorRecovery?.["tool.execute.after"]?.(input, output);
|
|
75861
77360
|
};
|