oh-my-opencode-slim 0.9.14 → 0.9.15
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.md +116 -56
- package/dist/agents/orchestrator.d.ts +2 -1
- package/dist/background/background-manager.d.ts +9 -1
- package/dist/background/multiplexer-session-manager.d.ts +2 -0
- package/dist/cli/index.js +49 -50
- package/dist/cli/types.d.ts +0 -1
- package/dist/config/schema.d.ts +5 -0
- package/dist/index.js +584 -310
- package/dist/multiplexer/factory.d.ts +5 -1
- package/dist/multiplexer/tmux/index.d.ts +3 -1
- package/dist/multiplexer/types.d.ts +2 -2
- package/dist/multiplexer/zellij/index.d.ts +1 -1
- package/dist/utils/agent-variant.d.ts +15 -1
- package/oh-my-opencode-slim.schema.json +12 -0
- package/package.json +3 -1
- package/src/skills/simplify/README.md +19 -0
- package/src/skills/simplify/SKILL.md +138 -0
- package/dist/background/tmux-session-manager.d.ts +0 -63
- package/dist/cli/chutes-selection.d.ts +0 -3
- package/dist/cli/dynamic-model-selection.d.ts +0 -14
- package/dist/cli/external-rankings.d.ts +0 -8
- package/dist/cli/model-selection.d.ts +0 -30
- package/dist/cli/opencode-models.d.ts +0 -18
- package/dist/cli/opencode-selection.d.ts +0 -3
- package/dist/cli/precedence-resolver.d.ts +0 -16
- package/dist/cli/scoring-v2/engine.d.ts +0 -4
- package/dist/cli/scoring-v2/features.d.ts +0 -3
- package/dist/cli/scoring-v2/index.d.ts +0 -4
- package/dist/cli/scoring-v2/types.d.ts +0 -17
- package/dist/cli/scoring-v2/weights.d.ts +0 -2
- package/dist/hooks/post-read-nudge/index.d.ts +0 -18
- package/dist/interview/store.d.ts +0 -9
- package/dist/tools/grep/cli.d.ts +0 -3
- package/dist/tools/grep/constants.d.ts +0 -18
- package/dist/tools/grep/downloader.d.ts +0 -3
- package/dist/tools/grep/index.d.ts +0 -5
- package/dist/tools/grep/tools.d.ts +0 -2
- package/dist/tools/grep/types.d.ts +0 -35
- package/dist/tools/grep/utils.d.ts +0 -2
- package/dist/tools/quota/api.d.ts +0 -5
- package/dist/tools/quota/command.d.ts +0 -1
- package/dist/tools/quota/index.d.ts +0 -21
- package/dist/tools/quota/types.d.ts +0 -41
- package/dist/utils/tmux.d.ts +0 -32
package/dist/index.js
CHANGED
|
@@ -210,9 +210,9 @@ var init_orchestrator = __esm(() => {
|
|
|
210
210
|
- Role: Fast execution specialist for well-defined tasks, which empowers orchestrator with parallel, speedy executions
|
|
211
211
|
- Stats: 2x faster code edits, 1/2 cost of orchestrator, 0.8x quality of orchestrator
|
|
212
212
|
- Tools/Constraints: Execution-focused—no research, no architectural decisions
|
|
213
|
-
- **Delegate when:** For implementation work, think and triage first. If the change is non-trivial or multi-file, hand bounded execution to @fixer • Writing or updating tests • Tasks that touch test files, fixtures, mocks, or test helpers
|
|
213
|
+
- **Delegate when:** For implementation work, think and triage first. If the change is non-trivial or multi-file, hand bounded execution to @fixer • Writing or updating tests • Tasks that touch test files, fixtures, mocks, or test helpers. Parallelization benefits: Task involves multiple folders and multiple files modificaiton, scoping work per folder and spawning parallel @fixers for each folder.
|
|
214
214
|
- **Don't delegate when:** Needs discovery/research/decisions • Single small change (<20 lines, one file) • Unclear requirements needing iteration • Explaining to fixer > doing • Tight integration with your current work • Sequential dependencies
|
|
215
|
-
- **Rule of thumb:** Explaining > doing? → yourself. Test file modifications and bounded implementation work usually go to @fixer.
|
|
215
|
+
- **Rule of thumb:** Explaining > doing? → yourself. Test file modifications and bounded implementation work usually go to @fixer. Bigger or lots of edits, splitting makes sense, parallelized by spawning @fixers per certain scope.`,
|
|
216
216
|
council: `@council
|
|
217
217
|
- Role: Multi-LLM consensus engine for high-confidence answers
|
|
218
218
|
- Stats: 3x slower than orchestrator, 3x or more cost of orchestrator
|
|
@@ -3255,7 +3255,7 @@ var require_main = __commonJS((exports) => {
|
|
|
3255
3255
|
exports.createMessageConnection = exports.createServerSocketTransport = exports.createClientSocketTransport = exports.createServerPipeTransport = exports.createClientPipeTransport = exports.generateRandomPipeName = exports.StreamMessageWriter = exports.StreamMessageReader = exports.SocketMessageWriter = exports.SocketMessageReader = exports.PortMessageWriter = exports.PortMessageReader = exports.IPCMessageWriter = exports.IPCMessageReader = undefined;
|
|
3256
3256
|
var ril_1 = require_ril();
|
|
3257
3257
|
ril_1.default.install();
|
|
3258
|
-
var
|
|
3258
|
+
var path13 = __require("path");
|
|
3259
3259
|
var os4 = __require("os");
|
|
3260
3260
|
var crypto_1 = __require("crypto");
|
|
3261
3261
|
var net_1 = __require("net");
|
|
@@ -3397,9 +3397,9 @@ var require_main = __commonJS((exports) => {
|
|
|
3397
3397
|
}
|
|
3398
3398
|
let result;
|
|
3399
3399
|
if (XDG_RUNTIME_DIR) {
|
|
3400
|
-
result =
|
|
3400
|
+
result = path13.join(XDG_RUNTIME_DIR, `vscode-ipc-${randomSuffix}.sock`);
|
|
3401
3401
|
} else {
|
|
3402
|
-
result =
|
|
3402
|
+
result = path13.join(os4.tmpdir(), `vscode-${randomSuffix}.sock`);
|
|
3403
3403
|
}
|
|
3404
3404
|
const limit = safeIpcPathLengths.get(process.platform);
|
|
3405
3405
|
if (limit !== undefined && result.length > limit) {
|
|
@@ -3629,7 +3629,7 @@ var require_index_min = __commonJS((exports) => {
|
|
|
3629
3629
|
// node_modules/which/lib/index.js
|
|
3630
3630
|
var require_lib = __commonJS((exports, module) => {
|
|
3631
3631
|
var { isexe, sync: isexeSync } = require_index_min();
|
|
3632
|
-
var { join:
|
|
3632
|
+
var { join: join13, delimiter, sep: sep2, posix } = __require("path");
|
|
3633
3633
|
var isWindows = process.platform === "win32";
|
|
3634
3634
|
var rSlash = new RegExp(`[${posix.sep}${sep2 === posix.sep ? "" : sep2}]`.replace(/(\\)/g, "\\$1"));
|
|
3635
3635
|
var rRel = new RegExp(`^\\.${rSlash.source}`);
|
|
@@ -3656,7 +3656,7 @@ var require_lib = __commonJS((exports, module) => {
|
|
|
3656
3656
|
var getPathPart = (raw, cmd) => {
|
|
3657
3657
|
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
|
|
3658
3658
|
const prefix2 = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : "";
|
|
3659
|
-
return prefix2 +
|
|
3659
|
+
return prefix2 + join13(pathPart, cmd);
|
|
3660
3660
|
};
|
|
3661
3661
|
var which = async (cmd, opt = {}) => {
|
|
3662
3662
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
@@ -3762,8 +3762,8 @@ var require_Readability = __commonJS((exports, module) => {
|
|
|
3762
3762
|
args.unshift("Reader: (Readability)");
|
|
3763
3763
|
console.log(...args);
|
|
3764
3764
|
} else if (typeof dump !== "undefined") {
|
|
3765
|
-
var msg = Array.prototype.map.call(arguments, function(
|
|
3766
|
-
return
|
|
3765
|
+
var msg = Array.prototype.map.call(arguments, function(x) {
|
|
3766
|
+
return x && x.nodeName ? logNode(x) : x;
|
|
3767
3767
|
}).join(" ");
|
|
3768
3768
|
dump("Reader: (Readability) " + msg + `
|
|
3769
3769
|
`);
|
|
@@ -5181,8 +5181,8 @@ var require_Readability = __commonJS((exports, module) => {
|
|
|
5181
5181
|
};
|
|
5182
5182
|
var haveToRemove = shouldRemoveNode();
|
|
5183
5183
|
if (isList && haveToRemove) {
|
|
5184
|
-
for (var
|
|
5185
|
-
let child = node.children[
|
|
5184
|
+
for (var x = 0;x < node.children.length; x++) {
|
|
5185
|
+
let child = node.children[x];
|
|
5186
5186
|
if (child.children.length > 1) {
|
|
5187
5187
|
return haveToRemove;
|
|
5188
5188
|
}
|
|
@@ -8378,7 +8378,7 @@ var require_Element = __commonJS((exports, module) => {
|
|
|
8378
8378
|
getElementsByName: { value: function getElementsByName(name) {
|
|
8379
8379
|
return new FilteredElementList(this, elementNameFilter(String(name)));
|
|
8380
8380
|
} },
|
|
8381
|
-
clone: { value: function
|
|
8381
|
+
clone: { value: function clone2() {
|
|
8382
8382
|
var e;
|
|
8383
8383
|
if (this.namespaceURI !== NAMESPACE.HTML || this.prefix || !this.ownerDocument.isHTML) {
|
|
8384
8384
|
e = this.ownerDocument.createElementNS(this.namespaceURI, this.prefix !== null ? this.prefix + ":" + this.localName : this.localName);
|
|
@@ -9173,7 +9173,7 @@ var require_Text = __commonJS((exports, module) => {
|
|
|
9173
9173
|
return result;
|
|
9174
9174
|
} },
|
|
9175
9175
|
replaceWholeText: { value: utils.nyi },
|
|
9176
|
-
clone: { value: function
|
|
9176
|
+
clone: { value: function clone2() {
|
|
9177
9177
|
return new Text(this.ownerDocument, this._data);
|
|
9178
9178
|
} }
|
|
9179
9179
|
});
|
|
@@ -9216,7 +9216,7 @@ var require_Comment = __commonJS((exports, module) => {
|
|
|
9216
9216
|
nodeValue.set.call(this, v === null ? "" : String(v));
|
|
9217
9217
|
}
|
|
9218
9218
|
},
|
|
9219
|
-
clone: { value: function
|
|
9219
|
+
clone: { value: function clone2() {
|
|
9220
9220
|
return new Comment(this.ownerDocument, this._data);
|
|
9221
9221
|
} }
|
|
9222
9222
|
});
|
|
@@ -9258,7 +9258,7 @@ var require_DocumentFragment = __commonJS((exports, module) => {
|
|
|
9258
9258
|
var nodes = select(selector, context);
|
|
9259
9259
|
return nodes.item ? nodes : new NodeList(nodes);
|
|
9260
9260
|
} },
|
|
9261
|
-
clone: { value: function
|
|
9261
|
+
clone: { value: function clone2() {
|
|
9262
9262
|
return new DocumentFragment(this.ownerDocument);
|
|
9263
9263
|
} },
|
|
9264
9264
|
isEqual: { value: function isEqual(n) {
|
|
@@ -9319,7 +9319,7 @@ var require_ProcessingInstruction = __commonJS((exports, module) => {
|
|
|
9319
9319
|
nodeValue.set.call(this, v === null ? "" : String(v));
|
|
9320
9320
|
}
|
|
9321
9321
|
},
|
|
9322
|
-
clone: { value: function
|
|
9322
|
+
clone: { value: function clone2() {
|
|
9323
9323
|
return new ProcessingInstruction(this.ownerDocument, this.target, this._data);
|
|
9324
9324
|
} },
|
|
9325
9325
|
isEqual: { value: function isEqual(n) {
|
|
@@ -9924,33 +9924,33 @@ var require_URL = __commonJS((exports, module) => {
|
|
|
9924
9924
|
else
|
|
9925
9925
|
return basepath.substring(0, lastslash + 1) + refpath;
|
|
9926
9926
|
}
|
|
9927
|
-
function remove_dot_segments(
|
|
9928
|
-
if (!
|
|
9929
|
-
return
|
|
9927
|
+
function remove_dot_segments(path14) {
|
|
9928
|
+
if (!path14)
|
|
9929
|
+
return path14;
|
|
9930
9930
|
var output = "";
|
|
9931
|
-
while (
|
|
9932
|
-
if (
|
|
9933
|
-
|
|
9931
|
+
while (path14.length > 0) {
|
|
9932
|
+
if (path14 === "." || path14 === "..") {
|
|
9933
|
+
path14 = "";
|
|
9934
9934
|
break;
|
|
9935
9935
|
}
|
|
9936
|
-
var twochars =
|
|
9937
|
-
var threechars =
|
|
9938
|
-
var fourchars =
|
|
9936
|
+
var twochars = path14.substring(0, 2);
|
|
9937
|
+
var threechars = path14.substring(0, 3);
|
|
9938
|
+
var fourchars = path14.substring(0, 4);
|
|
9939
9939
|
if (threechars === "../") {
|
|
9940
|
-
|
|
9940
|
+
path14 = path14.substring(3);
|
|
9941
9941
|
} else if (twochars === "./") {
|
|
9942
|
-
|
|
9942
|
+
path14 = path14.substring(2);
|
|
9943
9943
|
} else if (threechars === "/./") {
|
|
9944
|
-
|
|
9945
|
-
} else if (twochars === "/." &&
|
|
9946
|
-
|
|
9947
|
-
} else if (fourchars === "/../" || threechars === "/.." &&
|
|
9948
|
-
|
|
9944
|
+
path14 = "/" + path14.substring(3);
|
|
9945
|
+
} else if (twochars === "/." && path14.length === 2) {
|
|
9946
|
+
path14 = "/";
|
|
9947
|
+
} else if (fourchars === "/../" || threechars === "/.." && path14.length === 3) {
|
|
9948
|
+
path14 = "/" + path14.substring(4);
|
|
9949
9949
|
output = output.replace(/\/?[^\/]*$/, "");
|
|
9950
9950
|
} else {
|
|
9951
|
-
var segment =
|
|
9951
|
+
var segment = path14.match(/(\/?([^\/]*))/)[0];
|
|
9952
9952
|
output += segment;
|
|
9953
|
-
|
|
9953
|
+
path14 = path14.substring(segment.length);
|
|
9954
9954
|
}
|
|
9955
9955
|
}
|
|
9956
9956
|
return output;
|
|
@@ -10593,7 +10593,7 @@ var require_htmlelts = __commonJS((exports) => {
|
|
|
10593
10593
|
var HTMLElement = exports.HTMLElement = define({
|
|
10594
10594
|
superclass: Element,
|
|
10595
10595
|
name: "HTMLElement",
|
|
10596
|
-
ctor: function
|
|
10596
|
+
ctor: function HTMLElement2(doc2, localName, prefix2) {
|
|
10597
10597
|
Element.call(this, doc2, localName, utils.NAMESPACE.HTML, prefix2);
|
|
10598
10598
|
},
|
|
10599
10599
|
props: {
|
|
@@ -10730,7 +10730,7 @@ var require_htmlelts = __commonJS((exports) => {
|
|
|
10730
10730
|
});
|
|
10731
10731
|
var HTMLUnknownElement = define({
|
|
10732
10732
|
name: "HTMLUnknownElement",
|
|
10733
|
-
ctor: function
|
|
10733
|
+
ctor: function HTMLUnknownElement2(doc2, localName, prefix2) {
|
|
10734
10734
|
HTMLElement.call(this, doc2, localName, prefix2);
|
|
10735
10735
|
}
|
|
10736
10736
|
});
|
|
@@ -10945,7 +10945,7 @@ var require_htmlelts = __commonJS((exports) => {
|
|
|
10945
10945
|
define({
|
|
10946
10946
|
tag: "form",
|
|
10947
10947
|
name: "HTMLFormElement",
|
|
10948
|
-
ctor: function
|
|
10948
|
+
ctor: function HTMLFormElement2(doc2, localName, prefix2) {
|
|
10949
10949
|
HTMLElement.call(this, doc2, localName, prefix2);
|
|
10950
10950
|
},
|
|
10951
10951
|
attributes: {
|
|
@@ -12002,7 +12002,7 @@ var require_svg = __commonJS((exports) => {
|
|
|
12002
12002
|
var SVGElement = define({
|
|
12003
12003
|
superclass: Element,
|
|
12004
12004
|
name: "SVGElement",
|
|
12005
|
-
ctor: function
|
|
12005
|
+
ctor: function SVGElement2(doc2, localName, prefix2) {
|
|
12006
12006
|
Element.call(this, doc2, localName, utils.NAMESPACE.SVG, prefix2);
|
|
12007
12007
|
},
|
|
12008
12008
|
props: {
|
|
@@ -12421,7 +12421,7 @@ var require_Document = __commonJS((exports, module) => {
|
|
|
12421
12421
|
contentType: { get: function contentType() {
|
|
12422
12422
|
return this._contentType;
|
|
12423
12423
|
} },
|
|
12424
|
-
URL: { get: function
|
|
12424
|
+
URL: { get: function URL5() {
|
|
12425
12425
|
return this._address;
|
|
12426
12426
|
} },
|
|
12427
12427
|
domain: { get: utils.nyi, set: utils.nyi },
|
|
@@ -12549,7 +12549,7 @@ var require_Document = __commonJS((exports, module) => {
|
|
|
12549
12549
|
this.defaultView._dispatchEvent(new Event("load"), true);
|
|
12550
12550
|
}
|
|
12551
12551
|
} },
|
|
12552
|
-
clone: { value: function
|
|
12552
|
+
clone: { value: function clone2() {
|
|
12553
12553
|
var d = new Document(this.isHTML, this._address);
|
|
12554
12554
|
d._quirks = this._quirks;
|
|
12555
12555
|
d._contentType = this._contentType;
|
|
@@ -12858,7 +12858,7 @@ var require_DocumentType = __commonJS((exports, module) => {
|
|
|
12858
12858
|
},
|
|
12859
12859
|
set: function() {}
|
|
12860
12860
|
},
|
|
12861
|
-
clone: { value: function
|
|
12861
|
+
clone: { value: function clone2() {
|
|
12862
12862
|
return new DocumentType(this.ownerDocument, this.name, this.publicId, this.systemId);
|
|
12863
12863
|
} },
|
|
12864
12864
|
isEqual: { value: function isEqual(n) {
|
|
@@ -16259,7 +16259,7 @@ var require_HTMLParser = __commonJS((exports, module) => {
|
|
|
16259
16259
|
parser(EOF);
|
|
16260
16260
|
doc2.modclock = 1;
|
|
16261
16261
|
}
|
|
16262
|
-
var insertToken = htmlparser.insertToken = function
|
|
16262
|
+
var insertToken = htmlparser.insertToken = function insertToken2(t, value, arg3, arg4) {
|
|
16263
16263
|
flushText();
|
|
16264
16264
|
var current = stack.top;
|
|
16265
16265
|
if (!current || current.namespaceURI === NAMESPACE.HTML) {
|
|
@@ -21828,14 +21828,14 @@ var require_turndown_cjs = __commonJS((exports, module) => {
|
|
|
21828
21828
|
} else if (node.nodeType === 1) {
|
|
21829
21829
|
replacement = replacementForNode.call(self, node);
|
|
21830
21830
|
}
|
|
21831
|
-
return
|
|
21831
|
+
return join15(output, replacement);
|
|
21832
21832
|
}, "");
|
|
21833
21833
|
}
|
|
21834
21834
|
function postProcess(output) {
|
|
21835
21835
|
var self = this;
|
|
21836
21836
|
this.rules.forEach(function(rule) {
|
|
21837
21837
|
if (typeof rule.append === "function") {
|
|
21838
|
-
output =
|
|
21838
|
+
output = join15(output, rule.append(self.options));
|
|
21839
21839
|
}
|
|
21840
21840
|
});
|
|
21841
21841
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -21848,7 +21848,7 @@ var require_turndown_cjs = __commonJS((exports, module) => {
|
|
|
21848
21848
|
content = content.trim();
|
|
21849
21849
|
return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
|
|
21850
21850
|
}
|
|
21851
|
-
function
|
|
21851
|
+
function join15(output, replacement) {
|
|
21852
21852
|
var s1 = trimTrailingNewlines(output);
|
|
21853
21853
|
var s2 = trimLeadingNewlines(replacement);
|
|
21854
21854
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -21887,6 +21887,12 @@ function getOpenCodeConfigPaths() {
|
|
|
21887
21887
|
|
|
21888
21888
|
// src/cli/custom-skills.ts
|
|
21889
21889
|
var CUSTOM_SKILLS = [
|
|
21890
|
+
{
|
|
21891
|
+
name: "simplify",
|
|
21892
|
+
description: "Code simplification and readability-focused refactoring",
|
|
21893
|
+
allowedAgents: ["oracle"],
|
|
21894
|
+
sourcePath: "src/skills/simplify"
|
|
21895
|
+
},
|
|
21890
21896
|
{
|
|
21891
21897
|
name: "cartography",
|
|
21892
21898
|
description: "Repository understanding and hierarchical codemap generation",
|
|
@@ -21897,13 +21903,6 @@ var CUSTOM_SKILLS = [
|
|
|
21897
21903
|
|
|
21898
21904
|
// src/cli/skills.ts
|
|
21899
21905
|
var RECOMMENDED_SKILLS = [
|
|
21900
|
-
{
|
|
21901
|
-
name: "simplify",
|
|
21902
|
-
repo: "https://github.com/brianlovin/claude-config",
|
|
21903
|
-
skillName: "simplify",
|
|
21904
|
-
allowedAgents: ["oracle"],
|
|
21905
|
-
description: "YAGNI code simplification expert"
|
|
21906
|
-
},
|
|
21907
21906
|
{
|
|
21908
21907
|
name: "agent-browser",
|
|
21909
21908
|
repo: "https://github.com/vercel-labs/agent-browser",
|
|
@@ -35624,7 +35623,7 @@ import * as path from "node:path";
|
|
|
35624
35623
|
|
|
35625
35624
|
// src/config/agent-mcps.ts
|
|
35626
35625
|
var DEFAULT_AGENT_MCPS = {
|
|
35627
|
-
orchestrator: ["*"],
|
|
35626
|
+
orchestrator: ["*", "!context7"],
|
|
35628
35627
|
designer: [],
|
|
35629
35628
|
oracle: [],
|
|
35630
35629
|
librarian: ["websearch", "context7", "grep_app"],
|
|
@@ -35718,7 +35717,8 @@ var AgentOverrideConfigSchema = exports_external.object({
|
|
|
35718
35717
|
variant: exports_external.string().optional().catch(undefined),
|
|
35719
35718
|
skills: exports_external.array(exports_external.string()).optional(),
|
|
35720
35719
|
mcps: exports_external.array(exports_external.string()).optional(),
|
|
35721
|
-
options: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
35720
|
+
options: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
35721
|
+
displayName: exports_external.string().min(1).optional()
|
|
35722
35722
|
});
|
|
35723
35723
|
var MultiplexerTypeSchema = exports_external.enum(["auto", "tmux", "zellij", "none"]);
|
|
35724
35724
|
var MultiplexerLayoutSchema = exports_external.enum([
|
|
@@ -35772,6 +35772,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
35772
35772
|
setDefaultAgent: exports_external.boolean().optional(),
|
|
35773
35773
|
scoringEngineVersion: exports_external.enum(["v1", "v2-shadow", "v2"]).optional(),
|
|
35774
35774
|
balanceProviderUsage: exports_external.boolean().optional(),
|
|
35775
|
+
showStartupToast: exports_external.boolean().optional().describe("Show the startup activation toast when OpenCode starts. Defaults to true."),
|
|
35775
35776
|
manualPlan: ManualPlanSchema.optional(),
|
|
35776
35777
|
presets: exports_external.record(exports_external.string(), PresetSchema).optional(),
|
|
35777
35778
|
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
@@ -36494,6 +36495,10 @@ ${customAppendPrompt}`;
|
|
|
36494
36495
|
|
|
36495
36496
|
// src/agents/index.ts
|
|
36496
36497
|
init_orchestrator();
|
|
36498
|
+
function normalizeDisplayName(displayName) {
|
|
36499
|
+
const trimmed = displayName.trim();
|
|
36500
|
+
return trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
36501
|
+
}
|
|
36497
36502
|
function applyOverrides(agent, override) {
|
|
36498
36503
|
if (override.model) {
|
|
36499
36504
|
if (Array.isArray(override.model)) {
|
|
@@ -36513,6 +36518,20 @@ function applyOverrides(agent, override) {
|
|
|
36513
36518
|
...override.options
|
|
36514
36519
|
};
|
|
36515
36520
|
}
|
|
36521
|
+
if (override.displayName) {
|
|
36522
|
+
agent.displayName = override.displayName;
|
|
36523
|
+
}
|
|
36524
|
+
}
|
|
36525
|
+
function injectDisplayNames(orchestrator, nameMap) {
|
|
36526
|
+
if (nameMap.size === 0)
|
|
36527
|
+
return;
|
|
36528
|
+
let prompt = orchestrator.config.prompt;
|
|
36529
|
+
if (!prompt)
|
|
36530
|
+
return;
|
|
36531
|
+
for (const [internalName, displayName] of nameMap) {
|
|
36532
|
+
prompt = prompt.replace(new RegExp(`@${internalName}\\b`, "g"), `@${normalizeDisplayName(displayName)}`);
|
|
36533
|
+
}
|
|
36534
|
+
orchestrator.config.prompt = prompt;
|
|
36516
36535
|
}
|
|
36517
36536
|
function applyDefaultPermissions(agent, configuredSkills) {
|
|
36518
36537
|
const existing = agent.config.permission ?? {};
|
|
@@ -36580,28 +36599,66 @@ function createAgents(config2) {
|
|
|
36580
36599
|
if (orchestratorOverride) {
|
|
36581
36600
|
applyOverrides(orchestrator, orchestratorOverride);
|
|
36582
36601
|
}
|
|
36602
|
+
const displayNameMap = new Map;
|
|
36603
|
+
if (orchestrator.displayName) {
|
|
36604
|
+
displayNameMap.set("orchestrator", orchestrator.displayName);
|
|
36605
|
+
}
|
|
36606
|
+
for (const agent of allSubAgents) {
|
|
36607
|
+
if (agent.displayName) {
|
|
36608
|
+
displayNameMap.set(agent.name, agent.displayName);
|
|
36609
|
+
}
|
|
36610
|
+
}
|
|
36611
|
+
const usedDisplayNames = new Set;
|
|
36612
|
+
for (const [, displayName] of displayNameMap) {
|
|
36613
|
+
const normalizedDisplayName = normalizeDisplayName(displayName);
|
|
36614
|
+
if (usedDisplayNames.has(normalizedDisplayName)) {
|
|
36615
|
+
throw new Error(`Duplicate displayName '${normalizedDisplayName}' assigned to multiple agents`);
|
|
36616
|
+
}
|
|
36617
|
+
usedDisplayNames.add(normalizedDisplayName);
|
|
36618
|
+
}
|
|
36619
|
+
for (const displayName of usedDisplayNames) {
|
|
36620
|
+
if (ALL_AGENT_NAMES.includes(displayName)) {
|
|
36621
|
+
throw new Error(`displayName '${displayName}' conflicts with internal agent name`);
|
|
36622
|
+
}
|
|
36623
|
+
}
|
|
36624
|
+
injectDisplayNames(orchestrator, displayNameMap);
|
|
36583
36625
|
return [orchestrator, ...allSubAgents];
|
|
36584
36626
|
}
|
|
36585
36627
|
function getAgentConfigs(config2) {
|
|
36586
36628
|
const agents = createAgents(config2);
|
|
36587
|
-
|
|
36588
|
-
|
|
36589
|
-
...a.config,
|
|
36590
|
-
description: a.description,
|
|
36591
|
-
mcps: getAgentMcpList(a.name, config2)
|
|
36592
|
-
};
|
|
36593
|
-
if (a.name === "council") {
|
|
36629
|
+
const applyClassification = (name, sdkConfig) => {
|
|
36630
|
+
if (name === "council") {
|
|
36594
36631
|
sdkConfig.mode = "all";
|
|
36595
|
-
} else if (
|
|
36632
|
+
} else if (name === "councillor" || name === "council-master") {
|
|
36596
36633
|
sdkConfig.mode = "subagent";
|
|
36597
36634
|
sdkConfig.hidden = true;
|
|
36598
|
-
} else if (isSubagent(
|
|
36635
|
+
} else if (isSubagent(name)) {
|
|
36599
36636
|
sdkConfig.mode = "subagent";
|
|
36600
|
-
} else if (
|
|
36637
|
+
} else if (name === "orchestrator") {
|
|
36601
36638
|
sdkConfig.mode = "primary";
|
|
36602
36639
|
}
|
|
36603
|
-
|
|
36604
|
-
|
|
36640
|
+
};
|
|
36641
|
+
const isInternalOnly = (name) => name === "councillor" || name === "council-master";
|
|
36642
|
+
const entries = [];
|
|
36643
|
+
for (const a of agents) {
|
|
36644
|
+
const sdkConfig = {
|
|
36645
|
+
...a.config,
|
|
36646
|
+
description: a.description,
|
|
36647
|
+
mcps: getAgentMcpList(a.name, config2)
|
|
36648
|
+
};
|
|
36649
|
+
if (a.displayName) {
|
|
36650
|
+
sdkConfig.displayName = a.displayName;
|
|
36651
|
+
}
|
|
36652
|
+
applyClassification(a.name, sdkConfig);
|
|
36653
|
+
const normalizedDisplayName = a.displayName ? normalizeDisplayName(a.displayName) : undefined;
|
|
36654
|
+
if (normalizedDisplayName && !isInternalOnly(a.name)) {
|
|
36655
|
+
entries.push([normalizedDisplayName, sdkConfig]);
|
|
36656
|
+
entries.push([a.name, { ...sdkConfig, hidden: true }]);
|
|
36657
|
+
continue;
|
|
36658
|
+
}
|
|
36659
|
+
entries.push([a.name, sdkConfig]);
|
|
36660
|
+
}
|
|
36661
|
+
return Object.fromEntries(entries);
|
|
36605
36662
|
}
|
|
36606
36663
|
function getDisabledAgents(config2) {
|
|
36607
36664
|
const userDisabled = config2?.disabled_agents;
|
|
@@ -36615,6 +36672,10 @@ function getDisabledAgents(config2) {
|
|
|
36615
36672
|
return disabled;
|
|
36616
36673
|
}
|
|
36617
36674
|
|
|
36675
|
+
// src/background/background-manager.ts
|
|
36676
|
+
import * as fs3 from "node:fs";
|
|
36677
|
+
import * as path3 from "node:path";
|
|
36678
|
+
|
|
36618
36679
|
// src/utils/logger.ts
|
|
36619
36680
|
import * as fs2 from "node:fs";
|
|
36620
36681
|
import * as os from "node:os";
|
|
@@ -36642,6 +36703,22 @@ function cleanupOldLogs(logDir) {
|
|
|
36642
36703
|
}
|
|
36643
36704
|
}
|
|
36644
36705
|
} catch {}
|
|
36706
|
+
try {
|
|
36707
|
+
const bgTaskDir = path2.join(logDir, "bg-tasks");
|
|
36708
|
+
const taskFiles = fs2.readdirSync(bgTaskDir);
|
|
36709
|
+
const now = Date.now();
|
|
36710
|
+
for (const entry of taskFiles) {
|
|
36711
|
+
if (!entry.endsWith(".json"))
|
|
36712
|
+
continue;
|
|
36713
|
+
const filePath = path2.join(bgTaskDir, entry);
|
|
36714
|
+
try {
|
|
36715
|
+
const stat = fs2.statSync(filePath);
|
|
36716
|
+
if (now - stat.mtimeMs > RETENTION_MS) {
|
|
36717
|
+
fs2.unlinkSync(filePath);
|
|
36718
|
+
}
|
|
36719
|
+
} catch {}
|
|
36720
|
+
}
|
|
36721
|
+
} catch {}
|
|
36645
36722
|
}
|
|
36646
36723
|
function initLogger(sessionId) {
|
|
36647
36724
|
const dir = getLogDir();
|
|
@@ -36727,6 +36804,7 @@ class TmuxMultiplexer {
|
|
|
36727
36804
|
hasChecked = false;
|
|
36728
36805
|
storedLayout;
|
|
36729
36806
|
storedMainPaneSize;
|
|
36807
|
+
targetPane = process.env.TMUX_PANE;
|
|
36730
36808
|
constructor(layout = "main-vertical", mainPaneSize = 60) {
|
|
36731
36809
|
this.storedLayout = layout;
|
|
36732
36810
|
this.storedMainPaneSize = mainPaneSize;
|
|
@@ -36742,14 +36820,25 @@ class TmuxMultiplexer {
|
|
|
36742
36820
|
isInsideSession() {
|
|
36743
36821
|
return !!process.env.TMUX;
|
|
36744
36822
|
}
|
|
36745
|
-
async spawnPane(sessionId, description, serverUrl) {
|
|
36823
|
+
async spawnPane(sessionId, description, serverUrl, directory) {
|
|
36746
36824
|
const tmux = await this.getBinary();
|
|
36747
36825
|
if (!tmux) {
|
|
36748
36826
|
log("[tmux] spawnPane: tmux binary not found");
|
|
36749
36827
|
return { success: false };
|
|
36750
36828
|
}
|
|
36751
36829
|
try {
|
|
36752
|
-
const
|
|
36830
|
+
const quotedDirectory = quoteShellArg(directory);
|
|
36831
|
+
const quotedUrl = quoteShellArg(serverUrl);
|
|
36832
|
+
const quotedSessionId = quoteShellArg(sessionId);
|
|
36833
|
+
const opencodeCmd = [
|
|
36834
|
+
"opencode",
|
|
36835
|
+
"attach",
|
|
36836
|
+
quotedUrl,
|
|
36837
|
+
"--session",
|
|
36838
|
+
quotedSessionId,
|
|
36839
|
+
"--dir",
|
|
36840
|
+
quotedDirectory
|
|
36841
|
+
].join(" ");
|
|
36753
36842
|
const args = [
|
|
36754
36843
|
"split-window",
|
|
36755
36844
|
"-h",
|
|
@@ -36757,6 +36846,7 @@ class TmuxMultiplexer {
|
|
|
36757
36846
|
"-P",
|
|
36758
36847
|
"-F",
|
|
36759
36848
|
"#{pane_id}",
|
|
36849
|
+
...this.targetArgs(),
|
|
36760
36850
|
opencodeCmd
|
|
36761
36851
|
];
|
|
36762
36852
|
log("[tmux] spawnPane: executing", { tmux, args });
|
|
@@ -36830,19 +36920,25 @@ class TmuxMultiplexer {
|
|
|
36830
36920
|
this.storedLayout = layout;
|
|
36831
36921
|
this.storedMainPaneSize = mainPaneSize;
|
|
36832
36922
|
try {
|
|
36833
|
-
const layoutProc = crossSpawn([tmux, "select-layout", layout], {
|
|
36923
|
+
const layoutProc = crossSpawn([tmux, "select-layout", ...this.targetArgs(), layout], {
|
|
36834
36924
|
stdout: "pipe",
|
|
36835
36925
|
stderr: "pipe"
|
|
36836
36926
|
});
|
|
36837
36927
|
await layoutProc.exited;
|
|
36838
36928
|
if (layout === "main-horizontal" || layout === "main-vertical") {
|
|
36839
36929
|
const sizeOption = layout === "main-horizontal" ? "main-pane-height" : "main-pane-width";
|
|
36840
|
-
const sizeProc = crossSpawn([
|
|
36930
|
+
const sizeProc = crossSpawn([
|
|
36931
|
+
tmux,
|
|
36932
|
+
"set-window-option",
|
|
36933
|
+
...this.targetArgs(),
|
|
36934
|
+
sizeOption,
|
|
36935
|
+
`${mainPaneSize}%`
|
|
36936
|
+
], {
|
|
36841
36937
|
stdout: "pipe",
|
|
36842
36938
|
stderr: "pipe"
|
|
36843
36939
|
});
|
|
36844
36940
|
await sizeProc.exited;
|
|
36845
|
-
const reapplyProc = crossSpawn([tmux, "select-layout", layout], {
|
|
36941
|
+
const reapplyProc = crossSpawn([tmux, "select-layout", ...this.targetArgs(), layout], {
|
|
36846
36942
|
stdout: "pipe",
|
|
36847
36943
|
stderr: "pipe"
|
|
36848
36944
|
});
|
|
@@ -36857,6 +36953,9 @@ class TmuxMultiplexer {
|
|
|
36857
36953
|
await this.isAvailable();
|
|
36858
36954
|
return this.binaryPath;
|
|
36859
36955
|
}
|
|
36956
|
+
targetArgs() {
|
|
36957
|
+
return this.targetPane ? ["-t", this.targetPane] : [];
|
|
36958
|
+
}
|
|
36860
36959
|
async findBinary() {
|
|
36861
36960
|
const isWindows = process.platform === "win32";
|
|
36862
36961
|
const cmd = isWindows ? "where" : "which";
|
|
@@ -36894,6 +36993,9 @@ class TmuxMultiplexer {
|
|
|
36894
36993
|
}
|
|
36895
36994
|
}
|
|
36896
36995
|
}
|
|
36996
|
+
function quoteShellArg(value) {
|
|
36997
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
36998
|
+
}
|
|
36897
36999
|
|
|
36898
37000
|
// src/multiplexer/zellij/index.ts
|
|
36899
37001
|
class ZellijMultiplexer {
|
|
@@ -36915,7 +37017,7 @@ class ZellijMultiplexer {
|
|
|
36915
37017
|
isInsideSession() {
|
|
36916
37018
|
return !!process.env.ZELLIJ;
|
|
36917
37019
|
}
|
|
36918
|
-
async spawnPane(sessionId, description, serverUrl) {
|
|
37020
|
+
async spawnPane(sessionId, description, serverUrl, directory) {
|
|
36919
37021
|
const zellij = await this.getBinary();
|
|
36920
37022
|
if (!zellij)
|
|
36921
37023
|
return { success: false };
|
|
@@ -36928,19 +37030,19 @@ class ZellijMultiplexer {
|
|
|
36928
37030
|
this.firstPaneId = result.firstPaneId;
|
|
36929
37031
|
}
|
|
36930
37032
|
if (!this.firstPaneUsed && this.firstPaneId) {
|
|
36931
|
-
const success2 = await this.runInPane(zellij, this.firstPaneId, sessionId, serverUrl, description);
|
|
37033
|
+
const success2 = await this.runInPane(zellij, this.firstPaneId, sessionId, serverUrl, directory, description);
|
|
36932
37034
|
if (success2) {
|
|
36933
37035
|
this.firstPaneUsed = true;
|
|
36934
37036
|
return { success: true, paneId: this.firstPaneId };
|
|
36935
37037
|
}
|
|
36936
37038
|
}
|
|
36937
|
-
return await this.createPaneInAgentTab(zellij, sessionId, serverUrl, description);
|
|
37039
|
+
return await this.createPaneInAgentTab(zellij, sessionId, serverUrl, directory, description);
|
|
36938
37040
|
} catch {
|
|
36939
37041
|
return { success: false };
|
|
36940
37042
|
}
|
|
36941
37043
|
}
|
|
36942
|
-
async createPaneInAgentTab(zellij, sessionId, serverUrl, description) {
|
|
36943
|
-
const opencodeCmd =
|
|
37044
|
+
async createPaneInAgentTab(zellij, sessionId, serverUrl, directory, description) {
|
|
37045
|
+
const opencodeCmd = buildOpencodeAttachCommand(sessionId, serverUrl, directory);
|
|
36944
37046
|
const paneName = description.slice(0, 30).replace(/"/g, "\\\"");
|
|
36945
37047
|
const currentTabId = await this.getCurrentTabId(zellij);
|
|
36946
37048
|
const inAgentTab = currentTabId === this.agentTabId;
|
|
@@ -36953,7 +37055,7 @@ class ZellijMultiplexer {
|
|
|
36953
37055
|
"--close-on-exit",
|
|
36954
37056
|
"--",
|
|
36955
37057
|
"sh",
|
|
36956
|
-
"-
|
|
37058
|
+
"-lc",
|
|
36957
37059
|
opencodeCmd
|
|
36958
37060
|
];
|
|
36959
37061
|
const proc2 = crossSpawn([zellij, ...args2], {
|
|
@@ -36984,7 +37086,7 @@ class ZellijMultiplexer {
|
|
|
36984
37086
|
"--close-on-exit",
|
|
36985
37087
|
"--",
|
|
36986
37088
|
"sh",
|
|
36987
|
-
"-
|
|
37089
|
+
"-lc",
|
|
36988
37090
|
opencodeCmd
|
|
36989
37091
|
];
|
|
36990
37092
|
const proc = crossSpawn([zellij, ...args], {
|
|
@@ -37005,15 +37107,15 @@ class ZellijMultiplexer {
|
|
|
37005
37107
|
}
|
|
37006
37108
|
return { success: false };
|
|
37007
37109
|
}
|
|
37008
|
-
async runInPane(zellij, paneId, sessionId, serverUrl, description) {
|
|
37110
|
+
async runInPane(zellij, paneId, sessionId, serverUrl, directory, description) {
|
|
37009
37111
|
try {
|
|
37010
|
-
const opencodeCmd =
|
|
37112
|
+
const opencodeCmd = buildOpencodeAttachCommand(sessionId, serverUrl, directory);
|
|
37011
37113
|
await crossSpawn([zellij, "action", "focus-pane", "--pane-id", paneId], {
|
|
37012
37114
|
stdout: "ignore",
|
|
37013
37115
|
stderr: "ignore"
|
|
37014
37116
|
}).exited;
|
|
37015
37117
|
await crossSpawn([zellij, "action", "rename-pane", "--name", description.slice(0, 30)], { stdout: "ignore", stderr: "ignore" }).exited;
|
|
37016
|
-
await crossSpawn([zellij, "action", "write-chars", opencodeCmd], {
|
|
37118
|
+
await crossSpawn([zellij, "action", "write-chars", buildShellLaunchCommand(opencodeCmd)], {
|
|
37017
37119
|
stdout: "ignore",
|
|
37018
37120
|
stderr: "ignore"
|
|
37019
37121
|
}).exited;
|
|
@@ -37192,18 +37294,30 @@ class ZellijMultiplexer {
|
|
|
37192
37294
|
}
|
|
37193
37295
|
}
|
|
37194
37296
|
}
|
|
37297
|
+
function buildOpencodeAttachCommand(sessionId, serverUrl, directory) {
|
|
37298
|
+
return [
|
|
37299
|
+
"opencode",
|
|
37300
|
+
"attach",
|
|
37301
|
+
quoteShellArg2(serverUrl),
|
|
37302
|
+
"--session",
|
|
37303
|
+
quoteShellArg2(sessionId),
|
|
37304
|
+
"--dir",
|
|
37305
|
+
quoteShellArg2(directory)
|
|
37306
|
+
].join(" ");
|
|
37307
|
+
}
|
|
37308
|
+
function buildShellLaunchCommand(command) {
|
|
37309
|
+
return ["sh", "-lc", quoteShellArg2(command)].join(" ");
|
|
37310
|
+
}
|
|
37311
|
+
function quoteShellArg2(value) {
|
|
37312
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
37313
|
+
}
|
|
37195
37314
|
|
|
37196
37315
|
// src/multiplexer/factory.ts
|
|
37197
|
-
var multiplexerCache = new Map;
|
|
37198
37316
|
function getMultiplexer(config2) {
|
|
37199
37317
|
const { type } = config2;
|
|
37200
37318
|
if (type === "none") {
|
|
37201
37319
|
return null;
|
|
37202
37320
|
}
|
|
37203
|
-
const cached2 = multiplexerCache.get(type);
|
|
37204
|
-
if (cached2) {
|
|
37205
|
-
return cached2;
|
|
37206
|
-
}
|
|
37207
37321
|
let multiplexer;
|
|
37208
37322
|
let actualType;
|
|
37209
37323
|
switch (type) {
|
|
@@ -37232,7 +37346,6 @@ function getMultiplexer(config2) {
|
|
|
37232
37346
|
log(`[multiplexer] Unknown type: ${type}`);
|
|
37233
37347
|
return null;
|
|
37234
37348
|
}
|
|
37235
|
-
multiplexerCache.set(actualType, multiplexer);
|
|
37236
37349
|
log(`[multiplexer] Created ${actualType} instance`);
|
|
37237
37350
|
return multiplexer;
|
|
37238
37351
|
}
|
|
@@ -37269,8 +37382,8 @@ function normalizeAgentName(agentName) {
|
|
|
37269
37382
|
return trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
37270
37383
|
}
|
|
37271
37384
|
function resolveAgentVariant(config2, agentName) {
|
|
37272
|
-
const normalized =
|
|
37273
|
-
const rawVariant = config2
|
|
37385
|
+
const normalized = resolveRuntimeAgentName(config2, agentName);
|
|
37386
|
+
const rawVariant = getAgentOverride(config2, normalized)?.variant;
|
|
37274
37387
|
if (typeof rawVariant !== "string") {
|
|
37275
37388
|
return;
|
|
37276
37389
|
}
|
|
@@ -37281,6 +37394,46 @@ function resolveAgentVariant(config2, agentName) {
|
|
|
37281
37394
|
log(`[variant] resolved variant="${trimmed}" for agent "${normalized}"`);
|
|
37282
37395
|
return trimmed;
|
|
37283
37396
|
}
|
|
37397
|
+
function resolveRuntimeAgentName(config2, agentName) {
|
|
37398
|
+
const normalized = normalizeAgentName(agentName);
|
|
37399
|
+
if (!normalized) {
|
|
37400
|
+
return normalized;
|
|
37401
|
+
}
|
|
37402
|
+
if (ALL_AGENT_NAMES.includes(normalized)) {
|
|
37403
|
+
return normalized;
|
|
37404
|
+
}
|
|
37405
|
+
for (const internalName of ALL_AGENT_NAMES) {
|
|
37406
|
+
const displayName = getAgentOverride(config2, internalName)?.displayName;
|
|
37407
|
+
if (!displayName) {
|
|
37408
|
+
continue;
|
|
37409
|
+
}
|
|
37410
|
+
if (normalizeAgentName(displayName) === normalized) {
|
|
37411
|
+
return internalName;
|
|
37412
|
+
}
|
|
37413
|
+
}
|
|
37414
|
+
return normalized;
|
|
37415
|
+
}
|
|
37416
|
+
function escapeRegExp(value) {
|
|
37417
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
37418
|
+
}
|
|
37419
|
+
function rewriteDisplayNameMentions(config2, text) {
|
|
37420
|
+
if (!text.includes("@")) {
|
|
37421
|
+
return text;
|
|
37422
|
+
}
|
|
37423
|
+
let rewritten = text;
|
|
37424
|
+
for (const internalName of ALL_AGENT_NAMES) {
|
|
37425
|
+
const displayName = getAgentOverride(config2, internalName)?.displayName;
|
|
37426
|
+
if (!displayName) {
|
|
37427
|
+
continue;
|
|
37428
|
+
}
|
|
37429
|
+
const normalizedDisplayName = normalizeAgentName(displayName);
|
|
37430
|
+
if (!normalizedDisplayName || normalizedDisplayName === internalName) {
|
|
37431
|
+
continue;
|
|
37432
|
+
}
|
|
37433
|
+
rewritten = rewritten.replace(new RegExp(`(^|[^\\w.])@${escapeRegExp(normalizedDisplayName)}\\b`, "g"), `$1@${internalName}`);
|
|
37434
|
+
}
|
|
37435
|
+
return rewritten;
|
|
37436
|
+
}
|
|
37284
37437
|
function applyAgentVariant(variant, body) {
|
|
37285
37438
|
if (!variant) {
|
|
37286
37439
|
return body;
|
|
@@ -37433,6 +37586,51 @@ class SubagentDepthTracker {
|
|
|
37433
37586
|
}
|
|
37434
37587
|
|
|
37435
37588
|
// src/background/background-manager.ts
|
|
37589
|
+
function persistTask(task) {
|
|
37590
|
+
try {
|
|
37591
|
+
const dir = path3.join(getLogDir(), "bg-tasks");
|
|
37592
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
37593
|
+
const data = {
|
|
37594
|
+
id: task.id,
|
|
37595
|
+
sessionId: task.sessionId,
|
|
37596
|
+
parentSessionId: task.parentSessionId,
|
|
37597
|
+
description: task.description,
|
|
37598
|
+
agent: task.agent,
|
|
37599
|
+
prompt: task.prompt,
|
|
37600
|
+
config: task.config,
|
|
37601
|
+
status: task.status,
|
|
37602
|
+
result: task.result,
|
|
37603
|
+
error: task.error,
|
|
37604
|
+
startedAt: task.startedAt.toISOString(),
|
|
37605
|
+
completedAt: task.completedAt?.toISOString()
|
|
37606
|
+
};
|
|
37607
|
+
fs3.writeFileSync(path3.join(dir, `${task.id}.json`), JSON.stringify(data), "utf-8");
|
|
37608
|
+
} catch (e) {
|
|
37609
|
+
log(`[background-manager] failed to persist task ${task.id}: ${e}`);
|
|
37610
|
+
}
|
|
37611
|
+
}
|
|
37612
|
+
function loadPersistedTask(taskId) {
|
|
37613
|
+
try {
|
|
37614
|
+
const file2 = path3.join(getLogDir(), "bg-tasks", `${taskId}.json`);
|
|
37615
|
+
const data = JSON.parse(fs3.readFileSync(file2, "utf-8"));
|
|
37616
|
+
return {
|
|
37617
|
+
id: data.id,
|
|
37618
|
+
sessionId: data.sessionId,
|
|
37619
|
+
parentSessionId: data.parentSessionId,
|
|
37620
|
+
description: data.description,
|
|
37621
|
+
agent: data.agent,
|
|
37622
|
+
status: data.status,
|
|
37623
|
+
result: data.result,
|
|
37624
|
+
error: data.error,
|
|
37625
|
+
startedAt: new Date(data.startedAt),
|
|
37626
|
+
completedAt: data.completedAt ? new Date(data.completedAt) : undefined,
|
|
37627
|
+
prompt: data.prompt,
|
|
37628
|
+
config: data.config
|
|
37629
|
+
};
|
|
37630
|
+
} catch {
|
|
37631
|
+
return null;
|
|
37632
|
+
}
|
|
37633
|
+
}
|
|
37436
37634
|
function generateTaskId() {
|
|
37437
37635
|
return `bg_${Math.random().toString(36).substring(2, 10)}`;
|
|
37438
37636
|
}
|
|
@@ -37467,6 +37665,9 @@ class BackgroundTaskManager {
|
|
|
37467
37665
|
getSubagentRules(agentName) {
|
|
37468
37666
|
return SUBAGENT_DELEGATION_RULES[agentName] ?? ["explorer"];
|
|
37469
37667
|
}
|
|
37668
|
+
getSessionAgent(sessionId) {
|
|
37669
|
+
return this.agentBySessionId.get(sessionId) ?? "orchestrator";
|
|
37670
|
+
}
|
|
37470
37671
|
isAgentAllowed(parentSessionId, requestedAgent) {
|
|
37471
37672
|
if (this.disabledAgents.has(requestedAgent)) {
|
|
37472
37673
|
return false;
|
|
@@ -37483,11 +37684,12 @@ class BackgroundTaskManager {
|
|
|
37483
37684
|
return allowedSubagents.filter((name) => !this.disabledAgents.has(name));
|
|
37484
37685
|
}
|
|
37485
37686
|
launch(opts) {
|
|
37687
|
+
const resolvedAgent = resolveRuntimeAgentName(this.config, opts.agent);
|
|
37486
37688
|
const task = {
|
|
37487
37689
|
id: generateTaskId(),
|
|
37488
37690
|
sessionId: undefined,
|
|
37489
37691
|
description: opts.description,
|
|
37490
|
-
agent:
|
|
37692
|
+
agent: resolvedAgent,
|
|
37491
37693
|
status: "pending",
|
|
37492
37694
|
startedAt: new Date,
|
|
37493
37695
|
config: {
|
|
@@ -37499,7 +37701,7 @@ class BackgroundTaskManager {
|
|
|
37499
37701
|
this.tasks.set(task.id, task);
|
|
37500
37702
|
this.enqueueStart(task);
|
|
37501
37703
|
log(`[background-manager] task launched: ${task.id}`, {
|
|
37502
|
-
agent:
|
|
37704
|
+
agent: resolvedAgent,
|
|
37503
37705
|
description: opts.description
|
|
37504
37706
|
});
|
|
37505
37707
|
return task;
|
|
@@ -37750,18 +37952,29 @@ class BackgroundTaskManager {
|
|
|
37750
37952
|
log(`[background-manager] task ${status}: ${task.id}`, {
|
|
37751
37953
|
description: task.description
|
|
37752
37954
|
});
|
|
37955
|
+
persistTask(task);
|
|
37753
37956
|
}
|
|
37754
37957
|
async sendCompletionNotification(task) {
|
|
37958
|
+
const parentAgent = this.getSessionAgent(task.parentSessionId);
|
|
37755
37959
|
const message = task.status === "completed" ? `[Background task "${task.description}" completed]` : `[Background task "${task.description}" failed: ${task.error}]`;
|
|
37756
37960
|
await this.client.session.prompt({
|
|
37757
37961
|
path: { id: task.parentSessionId },
|
|
37758
37962
|
body: {
|
|
37963
|
+
agent: parentAgent,
|
|
37759
37964
|
parts: [createInternalAgentTextPart(message)]
|
|
37760
37965
|
}
|
|
37761
37966
|
});
|
|
37762
37967
|
}
|
|
37763
37968
|
getResult(taskId) {
|
|
37764
|
-
|
|
37969
|
+
const inMemory = this.tasks.get(taskId);
|
|
37970
|
+
if (inMemory)
|
|
37971
|
+
return inMemory;
|
|
37972
|
+
const fromDisk = loadPersistedTask(taskId);
|
|
37973
|
+
if (fromDisk) {
|
|
37974
|
+
this.tasks.set(taskId, fromDisk);
|
|
37975
|
+
log(`[background-manager] restored task from disk: ${taskId}`);
|
|
37976
|
+
}
|
|
37977
|
+
return fromDisk;
|
|
37765
37978
|
}
|
|
37766
37979
|
async waitForCompletion(taskId, timeout = 0) {
|
|
37767
37980
|
const task = this.tasks.get(taskId);
|
|
@@ -37836,12 +38049,14 @@ var SESSION_MISSING_GRACE_MS = POLL_INTERVAL_BACKGROUND_MS * 3;
|
|
|
37836
38049
|
class MultiplexerSessionManager {
|
|
37837
38050
|
client;
|
|
37838
38051
|
serverUrl;
|
|
38052
|
+
directory;
|
|
37839
38053
|
multiplexer = null;
|
|
37840
38054
|
sessions = new Map;
|
|
37841
38055
|
pollInterval;
|
|
37842
38056
|
enabled = false;
|
|
37843
38057
|
constructor(ctx, config2) {
|
|
37844
38058
|
this.client = ctx.client;
|
|
38059
|
+
this.directory = ctx.directory;
|
|
37845
38060
|
const defaultPort = process.env.OPENCODE_PORT ?? "4096";
|
|
37846
38061
|
this.serverUrl = ctx.serverUrl?.toString() ?? `http://localhost:${defaultPort}`;
|
|
37847
38062
|
this.multiplexer = getMultiplexer(config2);
|
|
@@ -37864,6 +38079,7 @@ class MultiplexerSessionManager {
|
|
|
37864
38079
|
const sessionId = info.id;
|
|
37865
38080
|
const parentId = info.parentID;
|
|
37866
38081
|
const title = info.title ?? "Subagent";
|
|
38082
|
+
const directory = info.directory ?? this.directory;
|
|
37867
38083
|
if (this.sessions.has(sessionId)) {
|
|
37868
38084
|
log("[multiplexer-session-manager] session already tracked", {
|
|
37869
38085
|
sessionId
|
|
@@ -37882,7 +38098,7 @@ class MultiplexerSessionManager {
|
|
|
37882
38098
|
parentId,
|
|
37883
38099
|
title
|
|
37884
38100
|
});
|
|
37885
|
-
const paneResult = await this.multiplexer.spawnPane(sessionId, title, this.serverUrl).catch((err) => {
|
|
38101
|
+
const paneResult = await this.multiplexer.spawnPane(sessionId, title, this.serverUrl, directory).catch((err) => {
|
|
37886
38102
|
log("[multiplexer-session-manager] failed to spawn pane", {
|
|
37887
38103
|
error: String(err)
|
|
37888
38104
|
});
|
|
@@ -38392,8 +38608,8 @@ function ensureApplyPatchError(error48, context) {
|
|
|
38392
38608
|
}
|
|
38393
38609
|
|
|
38394
38610
|
// src/hooks/apply-patch/execution-context.ts
|
|
38395
|
-
import * as
|
|
38396
|
-
import
|
|
38611
|
+
import * as fs4 from "node:fs/promises";
|
|
38612
|
+
import path4 from "node:path";
|
|
38397
38613
|
|
|
38398
38614
|
// src/hooks/apply-patch/codec.ts
|
|
38399
38615
|
function normalizeLineEndings(text) {
|
|
@@ -39179,28 +39395,28 @@ function isMissingPathError(error48) {
|
|
|
39179
39395
|
}
|
|
39180
39396
|
async function real(target) {
|
|
39181
39397
|
const parts = [];
|
|
39182
|
-
let current =
|
|
39398
|
+
let current = path4.resolve(target);
|
|
39183
39399
|
while (true) {
|
|
39184
|
-
const exact = await
|
|
39400
|
+
const exact = await fs4.realpath(current).catch((error48) => {
|
|
39185
39401
|
if (isMissingPathError(error48)) {
|
|
39186
39402
|
return null;
|
|
39187
39403
|
}
|
|
39188
39404
|
throw createApplyPatchInternalError(`Failed to resolve real path: ${current}`, error48);
|
|
39189
39405
|
});
|
|
39190
39406
|
if (exact) {
|
|
39191
|
-
return parts.length === 0 ? exact :
|
|
39407
|
+
return parts.length === 0 ? exact : path4.join(exact, ...parts.reverse());
|
|
39192
39408
|
}
|
|
39193
|
-
const parent =
|
|
39409
|
+
const parent = path4.dirname(current);
|
|
39194
39410
|
if (parent === current) {
|
|
39195
|
-
return parts.length === 0 ? current :
|
|
39411
|
+
return parts.length === 0 ? current : path4.join(current, ...parts.reverse());
|
|
39196
39412
|
}
|
|
39197
|
-
parts.push(
|
|
39413
|
+
parts.push(path4.basename(current));
|
|
39198
39414
|
current = parent;
|
|
39199
39415
|
}
|
|
39200
39416
|
}
|
|
39201
39417
|
function inside(root, target) {
|
|
39202
|
-
const rel =
|
|
39203
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
39418
|
+
const rel = path4.relative(root, target);
|
|
39419
|
+
return rel === "" || !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
39204
39420
|
}
|
|
39205
39421
|
function createPathGuardContext(root, worktree) {
|
|
39206
39422
|
return {
|
|
@@ -39210,7 +39426,7 @@ function createPathGuardContext(root, worktree) {
|
|
|
39210
39426
|
};
|
|
39211
39427
|
}
|
|
39212
39428
|
async function realCached(ctx, target) {
|
|
39213
|
-
const resolvedTarget =
|
|
39429
|
+
const resolvedTarget = path4.resolve(target);
|
|
39214
39430
|
let pending = ctx.realCache.get(resolvedTarget);
|
|
39215
39431
|
if (!pending) {
|
|
39216
39432
|
pending = real(resolvedTarget);
|
|
@@ -39241,7 +39457,7 @@ function createFileCacheContext() {
|
|
|
39241
39457
|
async function statCached(ctx, filePath) {
|
|
39242
39458
|
let pending = ctx.stats.get(filePath);
|
|
39243
39459
|
if (!pending) {
|
|
39244
|
-
const nextPending =
|
|
39460
|
+
const nextPending = fs4.stat(filePath).catch((error48) => {
|
|
39245
39461
|
if (isMissingPathError(error48)) {
|
|
39246
39462
|
return null;
|
|
39247
39463
|
}
|
|
@@ -39261,22 +39477,22 @@ async function assertRegularFile(ctx, filePath, verb) {
|
|
|
39261
39477
|
function collectPatchTargets(root, hunks) {
|
|
39262
39478
|
const targets = new Set;
|
|
39263
39479
|
for (const hunk of hunks) {
|
|
39264
|
-
targets.add(
|
|
39480
|
+
targets.add(path4.resolve(root, hunk.path));
|
|
39265
39481
|
if (hunk.type === "update" && hunk.move_path) {
|
|
39266
|
-
targets.add(
|
|
39482
|
+
targets.add(path4.resolve(root, hunk.move_path));
|
|
39267
39483
|
}
|
|
39268
39484
|
}
|
|
39269
39485
|
return [...targets];
|
|
39270
39486
|
}
|
|
39271
39487
|
function toRelativePatchPath(root, target) {
|
|
39272
|
-
const relative =
|
|
39488
|
+
const relative = path4.relative(root, target);
|
|
39273
39489
|
return (relative.length === 0 ? "." : relative).replaceAll("\\", "/");
|
|
39274
39490
|
}
|
|
39275
39491
|
function normalizePatchPath(root, value) {
|
|
39276
|
-
return
|
|
39492
|
+
return path4.isAbsolute(value) ? toRelativePatchPath(root, path4.resolve(value)) : value;
|
|
39277
39493
|
}
|
|
39278
39494
|
function normalizePatchPaths(root, hunks) {
|
|
39279
|
-
const resolvedRoot =
|
|
39495
|
+
const resolvedRoot = path4.resolve(root);
|
|
39280
39496
|
const normalized = [];
|
|
39281
39497
|
let changed = false;
|
|
39282
39498
|
for (const hunk of hunks) {
|
|
@@ -39327,7 +39543,7 @@ function parseValidatedPatch(patchText) {
|
|
|
39327
39543
|
}
|
|
39328
39544
|
async function readPreparedFileText(filePath, verb) {
|
|
39329
39545
|
try {
|
|
39330
|
-
return await
|
|
39546
|
+
return await fs4.readFile(filePath, "utf-8");
|
|
39331
39547
|
} catch (error48) {
|
|
39332
39548
|
if (isMissingPathError(error48)) {
|
|
39333
39549
|
throw createApplyPatchVerificationError(`Failed to read file to ${verb}: ${filePath}`);
|
|
@@ -39400,7 +39616,7 @@ function stageAddedText(contents) {
|
|
|
39400
39616
|
`;
|
|
39401
39617
|
}
|
|
39402
39618
|
// src/hooks/apply-patch/rewrite.ts
|
|
39403
|
-
import
|
|
39619
|
+
import path5 from "node:path";
|
|
39404
39620
|
function normalizeTextLineEndings(text) {
|
|
39405
39621
|
return text.replace(/\r\n/g, `
|
|
39406
39622
|
`).replace(/\r/g, `
|
|
@@ -39572,7 +39788,7 @@ async function rewritePatch(root, patchText, cfg, worktree) {
|
|
|
39572
39788
|
const dependencyGroups = new Map;
|
|
39573
39789
|
for (const hunk of hunks) {
|
|
39574
39790
|
if (hunk.type === "add") {
|
|
39575
|
-
const filePath2 =
|
|
39791
|
+
const filePath2 = path5.resolve(root, hunk.path);
|
|
39576
39792
|
await assertPreparedPathMissing(filePath2, "add");
|
|
39577
39793
|
rewritten.push(hunk);
|
|
39578
39794
|
clearDependencyGroup(filePath2);
|
|
@@ -39594,20 +39810,20 @@ async function rewritePatch(root, patchText, cfg, worktree) {
|
|
|
39594
39810
|
continue;
|
|
39595
39811
|
}
|
|
39596
39812
|
if (hunk.type === "delete") {
|
|
39597
|
-
const filePath2 =
|
|
39813
|
+
const filePath2 = path5.resolve(root, hunk.path);
|
|
39598
39814
|
await getPreparedFileState(filePath2, "delete");
|
|
39599
39815
|
clearDependencyGroup(filePath2);
|
|
39600
39816
|
rewritten.push(hunk);
|
|
39601
39817
|
staged.set(filePath2, { exists: false, derived: true });
|
|
39602
39818
|
continue;
|
|
39603
39819
|
}
|
|
39604
|
-
const filePath =
|
|
39820
|
+
const filePath = path5.resolve(root, hunk.path);
|
|
39605
39821
|
const currentDependency = dependencyGroups.get(filePath);
|
|
39606
39822
|
const current = await getPreparedFileState(filePath, "update");
|
|
39607
39823
|
if (!current.exists) {
|
|
39608
39824
|
throw createApplyPatchVerificationError(`Failed to read file to update: ${filePath}`);
|
|
39609
39825
|
}
|
|
39610
|
-
const movePath = hunk.move_path ?
|
|
39826
|
+
const movePath = hunk.move_path ? path5.resolve(root, hunk.move_path) : undefined;
|
|
39611
39827
|
if (movePath && movePath !== filePath) {
|
|
39612
39828
|
await assertPreparedPathMissing(movePath, "move");
|
|
39613
39829
|
}
|
|
@@ -39771,27 +39987,27 @@ function createApplyPatchHook(ctx) {
|
|
|
39771
39987
|
};
|
|
39772
39988
|
}
|
|
39773
39989
|
// src/hooks/auto-update-checker/cache.ts
|
|
39990
|
+
import * as fs6 from "node:fs";
|
|
39991
|
+
import * as path8 from "node:path";
|
|
39992
|
+
// src/hooks/auto-update-checker/checker.ts
|
|
39774
39993
|
import * as fs5 from "node:fs";
|
|
39775
39994
|
import * as path7 from "node:path";
|
|
39776
|
-
// src/hooks/auto-update-checker/checker.ts
|
|
39777
|
-
import * as fs4 from "node:fs";
|
|
39778
|
-
import * as path6 from "node:path";
|
|
39779
39995
|
import { fileURLToPath } from "node:url";
|
|
39780
39996
|
|
|
39781
39997
|
// src/hooks/auto-update-checker/constants.ts
|
|
39782
39998
|
import * as os2 from "node:os";
|
|
39783
|
-
import * as
|
|
39999
|
+
import * as path6 from "node:path";
|
|
39784
40000
|
var PACKAGE_NAME = "oh-my-opencode-slim";
|
|
39785
40001
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
|
|
39786
40002
|
var NPM_FETCH_TIMEOUT = 5000;
|
|
39787
40003
|
function getCacheDir() {
|
|
39788
40004
|
if (process.platform === "win32") {
|
|
39789
|
-
return
|
|
40005
|
+
return path6.join(process.env.LOCALAPPDATA ?? os2.homedir(), "opencode");
|
|
39790
40006
|
}
|
|
39791
|
-
return
|
|
40007
|
+
return path6.join(os2.homedir(), ".cache", "opencode");
|
|
39792
40008
|
}
|
|
39793
40009
|
var CACHE_DIR = getCacheDir();
|
|
39794
|
-
var INSTALLED_PACKAGE_JSON =
|
|
40010
|
+
var INSTALLED_PACKAGE_JSON = path6.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
|
|
39795
40011
|
var configPaths = getOpenCodeConfigPaths();
|
|
39796
40012
|
var USER_OPENCODE_CONFIG = configPaths[0];
|
|
39797
40013
|
var USER_OPENCODE_CONFIG_JSONC = configPaths[1];
|
|
@@ -39820,8 +40036,8 @@ function extractChannel(version2) {
|
|
|
39820
40036
|
}
|
|
39821
40037
|
function getConfigPaths(directory) {
|
|
39822
40038
|
return [
|
|
39823
|
-
|
|
39824
|
-
|
|
40039
|
+
path7.join(directory, ".opencode", "opencode.json"),
|
|
40040
|
+
path7.join(directory, ".opencode", "opencode.jsonc"),
|
|
39825
40041
|
USER_OPENCODE_CONFIG,
|
|
39826
40042
|
USER_OPENCODE_CONFIG_JSONC
|
|
39827
40043
|
];
|
|
@@ -39829,9 +40045,9 @@ function getConfigPaths(directory) {
|
|
|
39829
40045
|
function getLocalDevPath(directory) {
|
|
39830
40046
|
for (const configPath of getConfigPaths(directory)) {
|
|
39831
40047
|
try {
|
|
39832
|
-
if (!
|
|
40048
|
+
if (!fs5.existsSync(configPath))
|
|
39833
40049
|
continue;
|
|
39834
|
-
const content =
|
|
40050
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
39835
40051
|
const config2 = JSON.parse(stripJsonComments(content));
|
|
39836
40052
|
const plugins = config2.plugin ?? [];
|
|
39837
40053
|
for (const entry of plugins) {
|
|
@@ -39849,19 +40065,19 @@ function getLocalDevPath(directory) {
|
|
|
39849
40065
|
}
|
|
39850
40066
|
function findPackageJsonUp(startPath) {
|
|
39851
40067
|
try {
|
|
39852
|
-
const stat2 =
|
|
39853
|
-
let dir = stat2.isDirectory() ? startPath :
|
|
40068
|
+
const stat2 = fs5.statSync(startPath);
|
|
40069
|
+
let dir = stat2.isDirectory() ? startPath : path7.dirname(startPath);
|
|
39854
40070
|
for (let i = 0;i < 10; i++) {
|
|
39855
|
-
const pkgPath =
|
|
39856
|
-
if (
|
|
40071
|
+
const pkgPath = path7.join(dir, "package.json");
|
|
40072
|
+
if (fs5.existsSync(pkgPath)) {
|
|
39857
40073
|
try {
|
|
39858
|
-
const content =
|
|
40074
|
+
const content = fs5.readFileSync(pkgPath, "utf-8");
|
|
39859
40075
|
const pkg = JSON.parse(content);
|
|
39860
40076
|
if (pkg.name === PACKAGE_NAME)
|
|
39861
40077
|
return pkgPath;
|
|
39862
40078
|
} catch {}
|
|
39863
40079
|
}
|
|
39864
|
-
const parent =
|
|
40080
|
+
const parent = path7.dirname(dir);
|
|
39865
40081
|
if (parent === dir)
|
|
39866
40082
|
break;
|
|
39867
40083
|
dir = parent;
|
|
@@ -39877,7 +40093,7 @@ function getLocalDevVersion(directory) {
|
|
|
39877
40093
|
const pkgPath = findPackageJsonUp(localPath);
|
|
39878
40094
|
if (!pkgPath)
|
|
39879
40095
|
return null;
|
|
39880
|
-
const content =
|
|
40096
|
+
const content = fs5.readFileSync(pkgPath, "utf-8");
|
|
39881
40097
|
const pkg = JSON.parse(content);
|
|
39882
40098
|
return pkg.version ?? null;
|
|
39883
40099
|
} catch {
|
|
@@ -39886,7 +40102,7 @@ function getLocalDevVersion(directory) {
|
|
|
39886
40102
|
}
|
|
39887
40103
|
function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
|
|
39888
40104
|
try {
|
|
39889
|
-
const currentDir =
|
|
40105
|
+
const currentDir = path7.dirname(fileURLToPath(currentModuleUrl));
|
|
39890
40106
|
return findPackageJsonUp(currentDir);
|
|
39891
40107
|
} catch (err) {
|
|
39892
40108
|
log("[auto-update-checker] Failed to resolve runtime package path:", err);
|
|
@@ -39896,9 +40112,9 @@ function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
|
|
|
39896
40112
|
function findPluginEntry(directory) {
|
|
39897
40113
|
for (const configPath of getConfigPaths(directory)) {
|
|
39898
40114
|
try {
|
|
39899
|
-
if (!
|
|
40115
|
+
if (!fs5.existsSync(configPath))
|
|
39900
40116
|
continue;
|
|
39901
|
-
const content =
|
|
40117
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
39902
40118
|
const config2 = JSON.parse(stripJsonComments(content));
|
|
39903
40119
|
const plugins = config2.plugin ?? [];
|
|
39904
40120
|
for (const entry of plugins) {
|
|
@@ -39926,8 +40142,8 @@ function getCachedVersion() {
|
|
|
39926
40142
|
return cachedPackageVersion;
|
|
39927
40143
|
try {
|
|
39928
40144
|
const runtimePackageJsonPath = getCurrentRuntimePackageJsonPath();
|
|
39929
|
-
if (runtimePackageJsonPath &&
|
|
39930
|
-
const content =
|
|
40145
|
+
if (runtimePackageJsonPath && fs5.existsSync(runtimePackageJsonPath)) {
|
|
40146
|
+
const content = fs5.readFileSync(runtimePackageJsonPath, "utf-8");
|
|
39931
40147
|
const pkg = JSON.parse(content);
|
|
39932
40148
|
if (pkg.version) {
|
|
39933
40149
|
cachedPackageVersion = pkg.version;
|
|
@@ -39936,8 +40152,8 @@ function getCachedVersion() {
|
|
|
39936
40152
|
}
|
|
39937
40153
|
} catch {}
|
|
39938
40154
|
try {
|
|
39939
|
-
if (
|
|
39940
|
-
const content =
|
|
40155
|
+
if (fs5.existsSync(INSTALLED_PACKAGE_JSON)) {
|
|
40156
|
+
const content = fs5.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
|
|
39941
40157
|
const pkg = JSON.parse(content);
|
|
39942
40158
|
if (pkg.version) {
|
|
39943
40159
|
cachedPackageVersion = pkg.version;
|
|
@@ -39970,11 +40186,11 @@ async function getLatestVersion(channel = "latest") {
|
|
|
39970
40186
|
|
|
39971
40187
|
// src/hooks/auto-update-checker/cache.ts
|
|
39972
40188
|
function removeFromBunLock(installDir, packageName) {
|
|
39973
|
-
const lockPath =
|
|
39974
|
-
if (!
|
|
40189
|
+
const lockPath = path8.join(installDir, "bun.lock");
|
|
40190
|
+
if (!fs6.existsSync(lockPath))
|
|
39975
40191
|
return false;
|
|
39976
40192
|
try {
|
|
39977
|
-
const content =
|
|
40193
|
+
const content = fs6.readFileSync(lockPath, "utf-8");
|
|
39978
40194
|
let lock;
|
|
39979
40195
|
try {
|
|
39980
40196
|
lock = JSON.parse(stripJsonComments(content));
|
|
@@ -39991,7 +40207,7 @@ function removeFromBunLock(installDir, packageName) {
|
|
|
39991
40207
|
modified = true;
|
|
39992
40208
|
}
|
|
39993
40209
|
if (modified) {
|
|
39994
|
-
|
|
40210
|
+
fs6.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
|
|
39995
40211
|
log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
|
|
39996
40212
|
}
|
|
39997
40213
|
return modified;
|
|
@@ -40001,10 +40217,10 @@ function removeFromBunLock(installDir, packageName) {
|
|
|
40001
40217
|
}
|
|
40002
40218
|
}
|
|
40003
40219
|
function ensureDependencyVersion(packageJsonPath, packageName, version2) {
|
|
40004
|
-
if (!
|
|
40220
|
+
if (!fs6.existsSync(packageJsonPath))
|
|
40005
40221
|
return false;
|
|
40006
40222
|
try {
|
|
40007
|
-
const content =
|
|
40223
|
+
const content = fs6.readFileSync(packageJsonPath, "utf-8");
|
|
40008
40224
|
const pkgJson = JSON.parse(stripJsonComments(content));
|
|
40009
40225
|
const dependencies = { ...pkgJson.dependencies ?? {} };
|
|
40010
40226
|
if (dependencies[packageName] === version2) {
|
|
@@ -40012,7 +40228,7 @@ function ensureDependencyVersion(packageJsonPath, packageName, version2) {
|
|
|
40012
40228
|
}
|
|
40013
40229
|
dependencies[packageName] = version2;
|
|
40014
40230
|
pkgJson.dependencies = dependencies;
|
|
40015
|
-
|
|
40231
|
+
fs6.writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
40016
40232
|
log(`[auto-update-checker] Updated dependency in package.json: ${packageName} → ${version2}`);
|
|
40017
40233
|
return true;
|
|
40018
40234
|
} catch (err) {
|
|
@@ -40021,28 +40237,28 @@ function ensureDependencyVersion(packageJsonPath, packageName, version2) {
|
|
|
40021
40237
|
}
|
|
40022
40238
|
}
|
|
40023
40239
|
function removeInstalledPackage(installDir, packageName) {
|
|
40024
|
-
const pkgDir =
|
|
40025
|
-
if (!
|
|
40240
|
+
const pkgDir = path8.join(installDir, "node_modules", packageName);
|
|
40241
|
+
if (!fs6.existsSync(pkgDir))
|
|
40026
40242
|
return false;
|
|
40027
|
-
|
|
40243
|
+
fs6.rmSync(pkgDir, { recursive: true, force: true });
|
|
40028
40244
|
log(`[auto-update-checker] Package removed: ${pkgDir}`);
|
|
40029
40245
|
return true;
|
|
40030
40246
|
}
|
|
40031
40247
|
function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
40032
40248
|
if (runtimePackageJsonPath) {
|
|
40033
|
-
const packageDir =
|
|
40034
|
-
const nodeModulesDir =
|
|
40035
|
-
if (
|
|
40036
|
-
const installDir =
|
|
40037
|
-
const packageJsonPath =
|
|
40038
|
-
if (
|
|
40249
|
+
const packageDir = path8.dirname(runtimePackageJsonPath);
|
|
40250
|
+
const nodeModulesDir = path8.dirname(packageDir);
|
|
40251
|
+
if (path8.basename(packageDir) === PACKAGE_NAME && path8.basename(nodeModulesDir) === "node_modules") {
|
|
40252
|
+
const installDir = path8.dirname(nodeModulesDir);
|
|
40253
|
+
const packageJsonPath = path8.join(installDir, "package.json");
|
|
40254
|
+
if (fs6.existsSync(packageJsonPath)) {
|
|
40039
40255
|
return { installDir, packageJsonPath };
|
|
40040
40256
|
}
|
|
40041
40257
|
}
|
|
40042
40258
|
return null;
|
|
40043
40259
|
}
|
|
40044
|
-
const legacyPackageJsonPath =
|
|
40045
|
-
if (
|
|
40260
|
+
const legacyPackageJsonPath = path8.join(CACHE_DIR, "package.json");
|
|
40261
|
+
if (fs6.existsSync(legacyPackageJsonPath)) {
|
|
40046
40262
|
return { installDir: CACHE_DIR, packageJsonPath: legacyPackageJsonPath };
|
|
40047
40263
|
}
|
|
40048
40264
|
return null;
|
|
@@ -40627,14 +40843,15 @@ class ForegroundFallbackManager {
|
|
|
40627
40843
|
import { createHash } from "node:crypto";
|
|
40628
40844
|
import {
|
|
40629
40845
|
existsSync as existsSync4,
|
|
40630
|
-
mkdirSync as
|
|
40846
|
+
mkdirSync as mkdirSync3,
|
|
40631
40847
|
readdirSync as readdirSync2,
|
|
40848
|
+
rmdirSync,
|
|
40632
40849
|
statSync as statSync3,
|
|
40633
40850
|
unlinkSync as unlinkSync2,
|
|
40634
|
-
writeFileSync as
|
|
40851
|
+
writeFileSync as writeFileSync4
|
|
40635
40852
|
} from "node:fs";
|
|
40636
|
-
import { join as
|
|
40637
|
-
var
|
|
40853
|
+
import { basename as basename2, extname, join as join8 } from "node:path";
|
|
40854
|
+
var lastCleanupByDir = new Map;
|
|
40638
40855
|
var CLEANUP_INTERVAL = 10 * 60 * 1000;
|
|
40639
40856
|
function isImagePart(p) {
|
|
40640
40857
|
if (p.type === "image")
|
|
@@ -40668,41 +40885,84 @@ function extFromMime(mime) {
|
|
|
40668
40885
|
};
|
|
40669
40886
|
return map2[mime] ?? ".png";
|
|
40670
40887
|
}
|
|
40888
|
+
function sanitizeFilename(name) {
|
|
40889
|
+
return name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
40890
|
+
}
|
|
40891
|
+
function cleanupOldImages(dir, saveDir) {
|
|
40892
|
+
const now = Date.now();
|
|
40893
|
+
const lastCleanup = lastCleanupByDir.get(dir) ?? 0;
|
|
40894
|
+
if (now - lastCleanup < CLEANUP_INTERVAL)
|
|
40895
|
+
return;
|
|
40896
|
+
lastCleanupByDir.set(dir, now);
|
|
40897
|
+
try {
|
|
40898
|
+
const maxAge = 60 * 60 * 1000;
|
|
40899
|
+
for (const f of readdirSync2(dir)) {
|
|
40900
|
+
const fp = join8(dir, f);
|
|
40901
|
+
try {
|
|
40902
|
+
if (now - statSync3(fp).mtimeMs > maxAge)
|
|
40903
|
+
unlinkSync2(fp);
|
|
40904
|
+
} catch {}
|
|
40905
|
+
}
|
|
40906
|
+
if (dir !== saveDir) {
|
|
40907
|
+
try {
|
|
40908
|
+
rmdirSync(dir);
|
|
40909
|
+
lastCleanupByDir.delete(dir);
|
|
40910
|
+
} catch {}
|
|
40911
|
+
}
|
|
40912
|
+
} catch {}
|
|
40913
|
+
}
|
|
40914
|
+
function writeUniqueFile(dir, name, data, log2) {
|
|
40915
|
+
const ext = extname(name);
|
|
40916
|
+
const base = basename2(name, ext) || name;
|
|
40917
|
+
let candidate = join8(dir, name);
|
|
40918
|
+
let counter = 0;
|
|
40919
|
+
const MAX_ATTEMPTS = 1000;
|
|
40920
|
+
for (let attempt = 0;attempt < MAX_ATTEMPTS; attempt++) {
|
|
40921
|
+
try {
|
|
40922
|
+
writeFileSync4(candidate, data, { flag: "wx" });
|
|
40923
|
+
return candidate;
|
|
40924
|
+
} catch (e) {
|
|
40925
|
+
if (e instanceof Error && e.code === "EEXIST") {
|
|
40926
|
+
counter += 1;
|
|
40927
|
+
candidate = join8(dir, `${base}-${counter}${ext}`);
|
|
40928
|
+
continue;
|
|
40929
|
+
}
|
|
40930
|
+
log2(`[image-hook] failed to save image: ${e}`);
|
|
40931
|
+
return null;
|
|
40932
|
+
}
|
|
40933
|
+
}
|
|
40934
|
+
log2(`[image-hook] failed to save image: max attempts (${MAX_ATTEMPTS}) reached`);
|
|
40935
|
+
return null;
|
|
40936
|
+
}
|
|
40671
40937
|
function processImageAttachments(args) {
|
|
40672
40938
|
const { messages, workDir, disabledAgents, log: log2 } = args;
|
|
40673
40939
|
const observerEnabled = !disabledAgents.has("observer");
|
|
40674
40940
|
if (!observerEnabled)
|
|
40675
40941
|
return;
|
|
40676
|
-
const saveDir =
|
|
40677
|
-
const gitignorePath =
|
|
40942
|
+
const saveDir = join8(workDir, ".opencode", "images");
|
|
40943
|
+
const gitignorePath = join8(workDir, ".opencode", ".gitignore");
|
|
40678
40944
|
try {
|
|
40679
|
-
|
|
40945
|
+
mkdirSync3(saveDir, { recursive: true });
|
|
40680
40946
|
if (!existsSync4(gitignorePath))
|
|
40681
|
-
|
|
40947
|
+
writeFileSync4(gitignorePath, `*
|
|
40682
40948
|
`);
|
|
40683
40949
|
} catch (e) {
|
|
40684
40950
|
log2(`[image-hook] failed to create image directory: ${e}`);
|
|
40685
40951
|
}
|
|
40686
|
-
const now = Date.now();
|
|
40687
|
-
if (now - lastCleanup > CLEANUP_INTERVAL) {
|
|
40688
|
-
lastCleanup = now;
|
|
40689
|
-
try {
|
|
40690
|
-
const maxAge = 60 * 60 * 1000;
|
|
40691
|
-
for (const f of readdirSync2(saveDir)) {
|
|
40692
|
-
const fp = join7(saveDir, f);
|
|
40693
|
-
try {
|
|
40694
|
-
if (now - statSync3(fp).mtimeMs > maxAge)
|
|
40695
|
-
unlinkSync2(fp);
|
|
40696
|
-
} catch {}
|
|
40697
|
-
}
|
|
40698
|
-
} catch {}
|
|
40699
|
-
}
|
|
40700
40952
|
for (const msg of messages) {
|
|
40701
40953
|
if (msg.info.role !== "user")
|
|
40702
40954
|
continue;
|
|
40703
40955
|
const imageParts = msg.parts.filter(isImagePart);
|
|
40704
40956
|
if (imageParts.length === 0)
|
|
40705
40957
|
continue;
|
|
40958
|
+
const sessionSubdir = msg.info.sessionID ? sanitizeFilename(msg.info.sessionID) : undefined;
|
|
40959
|
+
const targetDir = sessionSubdir ? join8(saveDir, sessionSubdir) : saveDir;
|
|
40960
|
+
try {
|
|
40961
|
+
mkdirSync3(targetDir, { recursive: true });
|
|
40962
|
+
} catch (e) {
|
|
40963
|
+
log2(`[image-hook] failed to create target image directory: ${e}`);
|
|
40964
|
+
}
|
|
40965
|
+
cleanupOldImages(targetDir, saveDir);
|
|
40706
40966
|
const savedPaths = [];
|
|
40707
40967
|
for (const p of imageParts) {
|
|
40708
40968
|
const url2 = p.url;
|
|
@@ -40711,14 +40971,13 @@ function processImageAttachments(args) {
|
|
|
40711
40971
|
const decoded = decodeDataUrl(url2);
|
|
40712
40972
|
if (decoded) {
|
|
40713
40973
|
const hash2 = createHash("sha1").update(decoded.data).digest("hex").slice(0, 8);
|
|
40714
|
-
const
|
|
40715
|
-
const
|
|
40716
|
-
|
|
40717
|
-
|
|
40974
|
+
const sanitizedFilename = filename ? sanitizeFilename(filename) : undefined;
|
|
40975
|
+
const baseName = sanitizedFilename ? sanitizedFilename.replace(/\.[^.]+$/, "") || "image" : "image";
|
|
40976
|
+
const ext = sanitizedFilename ? extname(sanitizedFilename) || extFromMime(decoded.mime) : extFromMime(decoded.mime);
|
|
40977
|
+
const name = `${baseName}-${hash2}${ext}`;
|
|
40978
|
+
const filePath = writeUniqueFile(targetDir, name, decoded.data, log2);
|
|
40979
|
+
if (filePath)
|
|
40718
40980
|
savedPaths.push(filePath);
|
|
40719
|
-
} catch (e) {
|
|
40720
|
-
log2(`[image-hook] failed to save image: ${e}`);
|
|
40721
|
-
}
|
|
40722
40981
|
}
|
|
40723
40982
|
}
|
|
40724
40983
|
}
|
|
@@ -41525,37 +41784,37 @@ function createTodoContinuationHook(ctx, config2) {
|
|
|
41525
41784
|
};
|
|
41526
41785
|
}
|
|
41527
41786
|
// src/interview/manager.ts
|
|
41528
|
-
import
|
|
41787
|
+
import path12 from "node:path";
|
|
41529
41788
|
|
|
41530
41789
|
// src/interview/dashboard.ts
|
|
41531
41790
|
import crypto from "node:crypto";
|
|
41532
41791
|
import * as fsSync2 from "node:fs";
|
|
41533
|
-
import
|
|
41792
|
+
import fs8 from "node:fs/promises";
|
|
41534
41793
|
import {
|
|
41535
41794
|
createServer
|
|
41536
41795
|
} from "node:http";
|
|
41537
41796
|
import os3 from "node:os";
|
|
41538
|
-
import
|
|
41797
|
+
import path10 from "node:path";
|
|
41539
41798
|
import { URL as URL2 } from "node:url";
|
|
41540
41799
|
|
|
41541
41800
|
// src/interview/document.ts
|
|
41542
41801
|
import * as fsSync from "node:fs";
|
|
41543
|
-
import * as
|
|
41544
|
-
import * as
|
|
41802
|
+
import * as fs7 from "node:fs/promises";
|
|
41803
|
+
import * as path9 from "node:path";
|
|
41545
41804
|
var DEFAULT_OUTPUT_FOLDER = "interview";
|
|
41546
41805
|
function normalizeOutputFolder(outputFolder) {
|
|
41547
41806
|
const normalized = outputFolder.trim().replace(/^\/+|\/+$/g, "");
|
|
41548
41807
|
return normalized || DEFAULT_OUTPUT_FOLDER;
|
|
41549
41808
|
}
|
|
41550
41809
|
function createInterviewDirectoryPath(directory, outputFolder) {
|
|
41551
|
-
return
|
|
41810
|
+
return path9.join(directory, normalizeOutputFolder(outputFolder));
|
|
41552
41811
|
}
|
|
41553
41812
|
function createInterviewFilePath(directory, outputFolder, idea) {
|
|
41554
41813
|
const fileName = `${slugify2(idea) || "interview"}.md`;
|
|
41555
|
-
return
|
|
41814
|
+
return path9.join(createInterviewDirectoryPath(directory, outputFolder), fileName);
|
|
41556
41815
|
}
|
|
41557
41816
|
function relativeInterviewPath(directory, filePath) {
|
|
41558
|
-
return
|
|
41817
|
+
return path9.relative(directory, filePath) || path9.basename(filePath);
|
|
41559
41818
|
}
|
|
41560
41819
|
function resolveExistingInterviewPath(directory, outputFolder, value) {
|
|
41561
41820
|
const trimmed = value.trim();
|
|
@@ -41564,22 +41823,22 @@ function resolveExistingInterviewPath(directory, outputFolder, value) {
|
|
|
41564
41823
|
}
|
|
41565
41824
|
const outputDir = createInterviewDirectoryPath(directory, outputFolder);
|
|
41566
41825
|
const candidates = new Set;
|
|
41567
|
-
const resolvedRoot =
|
|
41568
|
-
if (
|
|
41826
|
+
const resolvedRoot = path9.resolve(directory);
|
|
41827
|
+
if (path9.isAbsolute(trimmed)) {
|
|
41569
41828
|
candidates.add(trimmed);
|
|
41570
41829
|
} else {
|
|
41571
|
-
candidates.add(
|
|
41572
|
-
candidates.add(
|
|
41830
|
+
candidates.add(path9.resolve(directory, trimmed));
|
|
41831
|
+
candidates.add(path9.join(outputDir, trimmed));
|
|
41573
41832
|
if (!trimmed.endsWith(".md")) {
|
|
41574
|
-
candidates.add(
|
|
41833
|
+
candidates.add(path9.join(outputDir, `${trimmed}.md`));
|
|
41575
41834
|
}
|
|
41576
41835
|
}
|
|
41577
41836
|
for (const candidate of candidates) {
|
|
41578
|
-
if (
|
|
41837
|
+
if (path9.extname(candidate) !== ".md") {
|
|
41579
41838
|
continue;
|
|
41580
41839
|
}
|
|
41581
|
-
const resolved =
|
|
41582
|
-
if (!resolved.startsWith(resolvedRoot +
|
|
41840
|
+
const resolved = path9.resolve(candidate);
|
|
41841
|
+
if (!resolved.startsWith(resolvedRoot + path9.sep) && resolved !== resolvedRoot) {
|
|
41583
41842
|
continue;
|
|
41584
41843
|
}
|
|
41585
41844
|
if (fsSync.existsSync(candidate)) {
|
|
@@ -41659,11 +41918,11 @@ function parseFrontmatter(content) {
|
|
|
41659
41918
|
return result;
|
|
41660
41919
|
}
|
|
41661
41920
|
async function ensureInterviewFile(record2) {
|
|
41662
|
-
await
|
|
41921
|
+
await fs7.mkdir(path9.dirname(record2.markdownPath), { recursive: true });
|
|
41663
41922
|
try {
|
|
41664
|
-
await
|
|
41923
|
+
await fs7.access(record2.markdownPath);
|
|
41665
41924
|
} catch {
|
|
41666
|
-
await
|
|
41925
|
+
await fs7.writeFile(record2.markdownPath, buildInterviewDocument(record2.idea, "", "", {
|
|
41667
41926
|
sessionID: record2.sessionID,
|
|
41668
41927
|
baseMessageCount: record2.baseMessageCount
|
|
41669
41928
|
}), "utf8");
|
|
@@ -41671,10 +41930,10 @@ async function ensureInterviewFile(record2) {
|
|
|
41671
41930
|
}
|
|
41672
41931
|
async function readInterviewDocument(record2) {
|
|
41673
41932
|
try {
|
|
41674
|
-
return await
|
|
41933
|
+
return await fs7.readFile(record2.markdownPath, "utf8");
|
|
41675
41934
|
} catch {}
|
|
41676
41935
|
await ensureInterviewFile(record2);
|
|
41677
|
-
return
|
|
41936
|
+
return fs7.readFile(record2.markdownPath, "utf8");
|
|
41678
41937
|
}
|
|
41679
41938
|
async function rewriteInterviewDocument(record2, summary) {
|
|
41680
41939
|
const existing = await readInterviewDocument(record2);
|
|
@@ -41683,7 +41942,7 @@ async function rewriteInterviewDocument(record2, summary) {
|
|
|
41683
41942
|
sessionID: record2.sessionID,
|
|
41684
41943
|
baseMessageCount: record2.baseMessageCount
|
|
41685
41944
|
});
|
|
41686
|
-
await
|
|
41945
|
+
await fs7.writeFile(record2.markdownPath, next, "utf8");
|
|
41687
41946
|
return next;
|
|
41688
41947
|
}
|
|
41689
41948
|
async function appendInterviewAnswers(record2, questions, answers) {
|
|
@@ -41701,7 +41960,7 @@ A: ${answer.answer.trim()}` : null;
|
|
|
41701
41960
|
const nextHistory = [history === "No answers yet." ? "" : history, appended].filter(Boolean).join(`
|
|
41702
41961
|
|
|
41703
41962
|
`);
|
|
41704
|
-
await
|
|
41963
|
+
await fs7.writeFile(record2.markdownPath, buildInterviewDocument(record2.idea, summary, nextHistory, {
|
|
41705
41964
|
sessionID: record2.sessionID,
|
|
41706
41965
|
baseMessageCount: record2.baseMessageCount
|
|
41707
41966
|
}), "utf8");
|
|
@@ -43181,12 +43440,12 @@ function renderInterviewPage(interviewId, resumeSlug) {
|
|
|
43181
43440
|
|
|
43182
43441
|
// src/interview/dashboard.ts
|
|
43183
43442
|
function getAuthFilePath(port) {
|
|
43184
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
43185
|
-
return
|
|
43443
|
+
const dataHome = process.env.XDG_DATA_HOME || path10.join(os3.homedir(), ".local", "share");
|
|
43444
|
+
return path10.join(dataHome, "opencode", `.dashboard-${port}.json`);
|
|
43186
43445
|
}
|
|
43187
43446
|
function writeAuthFile(port, token) {
|
|
43188
43447
|
const filePath = getAuthFilePath(port);
|
|
43189
|
-
const dir =
|
|
43448
|
+
const dir = path10.dirname(filePath);
|
|
43190
43449
|
try {
|
|
43191
43450
|
fsSync2.mkdirSync(dir, { recursive: true });
|
|
43192
43451
|
} catch {}
|
|
@@ -43203,7 +43462,7 @@ function removeAuthFile(port) {
|
|
|
43203
43462
|
}
|
|
43204
43463
|
async function readDashboardAuthFile(port) {
|
|
43205
43464
|
try {
|
|
43206
|
-
const content = await
|
|
43465
|
+
const content = await fs8.readFile(getAuthFilePath(port), "utf8");
|
|
43207
43466
|
const data = JSON.parse(content);
|
|
43208
43467
|
try {
|
|
43209
43468
|
process.kill(data.pid, 0);
|
|
@@ -43323,10 +43582,10 @@ function createDashboardServer(config2) {
|
|
|
43323
43582
|
const directories = getKnownDirectories();
|
|
43324
43583
|
const items = [];
|
|
43325
43584
|
for (const dir of directories) {
|
|
43326
|
-
const interviewDir =
|
|
43585
|
+
const interviewDir = path10.join(dir, config2.outputFolder);
|
|
43327
43586
|
let entries;
|
|
43328
43587
|
try {
|
|
43329
|
-
entries = await
|
|
43588
|
+
entries = await fs8.readdir(interviewDir);
|
|
43330
43589
|
} catch {
|
|
43331
43590
|
continue;
|
|
43332
43591
|
}
|
|
@@ -43335,7 +43594,7 @@ function createDashboardServer(config2) {
|
|
|
43335
43594
|
continue;
|
|
43336
43595
|
let content;
|
|
43337
43596
|
try {
|
|
43338
|
-
content = await
|
|
43597
|
+
content = await fs8.readFile(path10.join(interviewDir, entry), "utf8");
|
|
43339
43598
|
} catch {
|
|
43340
43599
|
continue;
|
|
43341
43600
|
}
|
|
@@ -43361,10 +43620,10 @@ function createDashboardServer(config2) {
|
|
|
43361
43620
|
const directories = getKnownDirectories();
|
|
43362
43621
|
let rebuilt = 0;
|
|
43363
43622
|
for (const dir of directories) {
|
|
43364
|
-
const interviewDir =
|
|
43623
|
+
const interviewDir = path10.join(dir, config2.outputFolder);
|
|
43365
43624
|
let entries;
|
|
43366
43625
|
try {
|
|
43367
|
-
entries = await
|
|
43626
|
+
entries = await fs8.readdir(interviewDir);
|
|
43368
43627
|
} catch {
|
|
43369
43628
|
continue;
|
|
43370
43629
|
}
|
|
@@ -43373,7 +43632,7 @@ function createDashboardServer(config2) {
|
|
|
43373
43632
|
continue;
|
|
43374
43633
|
let content;
|
|
43375
43634
|
try {
|
|
43376
|
-
content = await
|
|
43635
|
+
content = await fs8.readFile(path10.join(interviewDir, entry), "utf8");
|
|
43377
43636
|
} catch {
|
|
43378
43637
|
continue;
|
|
43379
43638
|
}
|
|
@@ -43399,7 +43658,7 @@ function createDashboardServer(config2) {
|
|
|
43399
43658
|
questions: [],
|
|
43400
43659
|
pendingAnswers: null,
|
|
43401
43660
|
lastUpdatedAt: fm.updatedAt ? new Date(fm.updatedAt).getTime() : Date.now(),
|
|
43402
|
-
filePath:
|
|
43661
|
+
filePath: path10.join(interviewDir, entry),
|
|
43403
43662
|
nudgeAction: null
|
|
43404
43663
|
});
|
|
43405
43664
|
if (!sessions.has(fm.sessionID)) {
|
|
@@ -43657,15 +43916,15 @@ function createDashboardServer(config2) {
|
|
|
43657
43916
|
let markdownPath = entry.filePath;
|
|
43658
43917
|
if (entry.filePath) {
|
|
43659
43918
|
try {
|
|
43660
|
-
document = await
|
|
43919
|
+
document = await fs8.readFile(entry.filePath, "utf8");
|
|
43661
43920
|
} catch {}
|
|
43662
43921
|
} else {
|
|
43663
43922
|
const dirs = getKnownDirectories();
|
|
43664
43923
|
for (const dir of dirs) {
|
|
43665
43924
|
const slug = extractResumeSlug(interviewId);
|
|
43666
|
-
const candidate =
|
|
43925
|
+
const candidate = path10.join(dir, config2.outputFolder, `${slug}.md`);
|
|
43667
43926
|
try {
|
|
43668
|
-
document = await
|
|
43927
|
+
document = await fs8.readFile(candidate, "utf8");
|
|
43669
43928
|
markdownPath = candidate;
|
|
43670
43929
|
entry.filePath = candidate;
|
|
43671
43930
|
break;
|
|
@@ -44190,8 +44449,8 @@ function createInterviewServer(deps) {
|
|
|
44190
44449
|
|
|
44191
44450
|
// src/interview/service.ts
|
|
44192
44451
|
import { spawn } from "node:child_process";
|
|
44193
|
-
import * as
|
|
44194
|
-
import * as
|
|
44452
|
+
import * as fs9 from "node:fs/promises";
|
|
44453
|
+
import * as path11 from "node:path";
|
|
44195
44454
|
|
|
44196
44455
|
// src/interview/types.ts
|
|
44197
44456
|
var RawQuestionSchema = exports_external.object({
|
|
@@ -44444,18 +44703,18 @@ function createInterviewService(ctx, config2, deps) {
|
|
|
44444
44703
|
if (!newSlug) {
|
|
44445
44704
|
return;
|
|
44446
44705
|
}
|
|
44447
|
-
const currentFileName =
|
|
44706
|
+
const currentFileName = path11.basename(interview.markdownPath, ".md");
|
|
44448
44707
|
if (currentFileName === newSlug) {
|
|
44449
44708
|
return;
|
|
44450
44709
|
}
|
|
44451
|
-
const dir =
|
|
44452
|
-
const newPath =
|
|
44710
|
+
const dir = path11.dirname(interview.markdownPath);
|
|
44711
|
+
const newPath = path11.join(dir, `${newSlug}.md`);
|
|
44453
44712
|
try {
|
|
44454
|
-
await
|
|
44713
|
+
await fs9.access(newPath);
|
|
44455
44714
|
return;
|
|
44456
44715
|
} catch {}
|
|
44457
44716
|
try {
|
|
44458
|
-
await
|
|
44717
|
+
await fs9.rename(interview.markdownPath, newPath);
|
|
44459
44718
|
interview.markdownPath = newPath;
|
|
44460
44719
|
log("[interview] renamed file with assistant title:", {
|
|
44461
44720
|
from: currentFileName,
|
|
@@ -44521,13 +44780,13 @@ function createInterviewService(ctx, config2, deps) {
|
|
|
44521
44780
|
active.status = "abandoned";
|
|
44522
44781
|
}
|
|
44523
44782
|
}
|
|
44524
|
-
const document = await
|
|
44783
|
+
const document = await fs9.readFile(markdownPath, "utf8");
|
|
44525
44784
|
const messages = await loadMessages(sessionID);
|
|
44526
44785
|
const title = extractTitle(document);
|
|
44527
44786
|
const record2 = {
|
|
44528
|
-
id: `${Date.now()}-${++idCounter}-${slugify2(
|
|
44787
|
+
id: `${Date.now()}-${++idCounter}-${slugify2(path11.basename(markdownPath, ".md")) || "interview"}`,
|
|
44529
44788
|
sessionID,
|
|
44530
|
-
idea: title ||
|
|
44789
|
+
idea: title || path11.basename(markdownPath, ".md"),
|
|
44531
44790
|
markdownPath,
|
|
44532
44791
|
createdAt: nowIso(),
|
|
44533
44792
|
status: "active",
|
|
@@ -44691,7 +44950,7 @@ function createInterviewService(ctx, config2, deps) {
|
|
|
44691
44950
|
const resumePath = resolveExistingInterviewPath(ctx.directory, outputFolder, idea);
|
|
44692
44951
|
if (resumePath) {
|
|
44693
44952
|
const interview2 = await resumeInterview(input.sessionID, resumePath);
|
|
44694
|
-
const document = await
|
|
44953
|
+
const document = await fs9.readFile(interview2.markdownPath, "utf8");
|
|
44695
44954
|
await notifyInterviewUrl(input.sessionID, interview2);
|
|
44696
44955
|
output.parts.push(createInternalAgentTextPart(buildResumePrompt(document, maxQuestions)));
|
|
44697
44956
|
return;
|
|
@@ -44741,10 +45000,10 @@ function createInterviewService(ctx, config2, deps) {
|
|
|
44741
45000
|
return fileCache.items;
|
|
44742
45001
|
}
|
|
44743
45002
|
const outputDir = createInterviewDirectoryPath(ctx.directory, outputFolder);
|
|
44744
|
-
const activePaths = new Set([...interviewsById.values()].filter((i) => i.status === "active").map((i) =>
|
|
45003
|
+
const activePaths = new Set([...interviewsById.values()].filter((i) => i.status === "active").map((i) => path11.resolve(i.markdownPath)));
|
|
44745
45004
|
let entries;
|
|
44746
45005
|
try {
|
|
44747
|
-
entries = await
|
|
45006
|
+
entries = await fs9.readdir(outputDir);
|
|
44748
45007
|
} catch {
|
|
44749
45008
|
return [];
|
|
44750
45009
|
}
|
|
@@ -44752,12 +45011,12 @@ function createInterviewService(ctx, config2, deps) {
|
|
|
44752
45011
|
for (const entry of entries) {
|
|
44753
45012
|
if (!entry.endsWith(".md"))
|
|
44754
45013
|
continue;
|
|
44755
|
-
const fullPath =
|
|
44756
|
-
if (activePaths.has(
|
|
45014
|
+
const fullPath = path11.join(outputDir, entry);
|
|
45015
|
+
if (activePaths.has(path11.resolve(fullPath)))
|
|
44757
45016
|
continue;
|
|
44758
45017
|
let content;
|
|
44759
45018
|
try {
|
|
44760
|
-
content = await
|
|
45019
|
+
content = await fs9.readFile(fullPath, "utf8");
|
|
44761
45020
|
} catch {
|
|
44762
45021
|
continue;
|
|
44763
45022
|
}
|
|
@@ -44850,7 +45109,7 @@ function createInterviewManager(ctx, config2) {
|
|
|
44850
45109
|
const outputFolder = interviewConfig?.outputFolder ?? "interview";
|
|
44851
45110
|
if (!dashboardEnabled) {
|
|
44852
45111
|
const service2 = createInterviewService(ctx, interviewConfig);
|
|
44853
|
-
const resolvedOutputPath =
|
|
45112
|
+
const resolvedOutputPath = path12.join(ctx.directory, outputFolder);
|
|
44854
45113
|
const server = createInterviewServer({
|
|
44855
45114
|
getState: async (interviewId) => service2.getInterviewState(interviewId),
|
|
44856
45115
|
listInterviewFiles: async () => service2.listInterviewFiles(),
|
|
@@ -44955,7 +45214,7 @@ function createInterviewManager(ctx, config2) {
|
|
|
44955
45214
|
listInterviews: () => service.listInterviews(),
|
|
44956
45215
|
submitAnswers: async (interviewId, answers) => service.submitAnswers(interviewId, answers),
|
|
44957
45216
|
handleNudgeAction: async (interviewId, action) => service.handleNudgeAction(interviewId, action),
|
|
44958
|
-
outputFolder:
|
|
45217
|
+
outputFolder: path12.join(ctx.directory, outputFolder),
|
|
44959
45218
|
port: 0
|
|
44960
45219
|
});
|
|
44961
45220
|
service.setBaseUrlResolver(() => perSessionServer.ensureStarted());
|
|
@@ -45231,13 +45490,13 @@ import { existsSync as existsSync8 } from "node:fs";
|
|
|
45231
45490
|
// src/tools/ast-grep/constants.ts
|
|
45232
45491
|
import { existsSync as existsSync7, statSync as statSync4 } from "node:fs";
|
|
45233
45492
|
import { createRequire as createRequire3 } from "node:module";
|
|
45234
|
-
import { dirname as dirname6, join as
|
|
45493
|
+
import { dirname as dirname6, join as join12 } from "node:path";
|
|
45235
45494
|
|
|
45236
45495
|
// src/tools/ast-grep/downloader.ts
|
|
45237
|
-
import { chmodSync, existsSync as existsSync6, mkdirSync as
|
|
45496
|
+
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "node:fs";
|
|
45238
45497
|
import { createRequire as createRequire2 } from "node:module";
|
|
45239
45498
|
import { homedir as homedir4 } from "node:os";
|
|
45240
|
-
import { join as
|
|
45499
|
+
import { join as join11 } from "node:path";
|
|
45241
45500
|
var REPO = "ast-grep/ast-grep";
|
|
45242
45501
|
var DEFAULT_VERSION = "0.40.0";
|
|
45243
45502
|
function getAstGrepVersion() {
|
|
@@ -45261,18 +45520,18 @@ var PLATFORM_MAP = {
|
|
|
45261
45520
|
function getCacheDir2() {
|
|
45262
45521
|
if (process.platform === "win32") {
|
|
45263
45522
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
45264
|
-
const base2 = localAppData ||
|
|
45265
|
-
return
|
|
45523
|
+
const base2 = localAppData || join11(homedir4(), "AppData", "Local");
|
|
45524
|
+
return join11(base2, "oh-my-opencode-slim", "bin");
|
|
45266
45525
|
}
|
|
45267
45526
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
45268
|
-
const base = xdgCache ||
|
|
45269
|
-
return
|
|
45527
|
+
const base = xdgCache || join11(homedir4(), ".cache");
|
|
45528
|
+
return join11(base, "oh-my-opencode-slim", "bin");
|
|
45270
45529
|
}
|
|
45271
45530
|
function getBinaryName() {
|
|
45272
45531
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
45273
45532
|
}
|
|
45274
45533
|
function getCachedBinaryPath() {
|
|
45275
|
-
const binaryPath =
|
|
45534
|
+
const binaryPath = join11(getCacheDir2(), getBinaryName());
|
|
45276
45535
|
return existsSync6(binaryPath) ? binaryPath : null;
|
|
45277
45536
|
}
|
|
45278
45537
|
async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
@@ -45284,7 +45543,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
45284
45543
|
}
|
|
45285
45544
|
const cacheDir = getCacheDir2();
|
|
45286
45545
|
const binaryName = getBinaryName();
|
|
45287
|
-
const binaryPath =
|
|
45546
|
+
const binaryPath = join11(cacheDir, binaryName);
|
|
45288
45547
|
if (existsSync6(binaryPath)) {
|
|
45289
45548
|
return binaryPath;
|
|
45290
45549
|
}
|
|
@@ -45294,13 +45553,13 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
45294
45553
|
console.log(`[oh-my-opencode-slim] Downloading ast-grep binary...`);
|
|
45295
45554
|
try {
|
|
45296
45555
|
if (!existsSync6(cacheDir)) {
|
|
45297
|
-
|
|
45556
|
+
mkdirSync5(cacheDir, { recursive: true });
|
|
45298
45557
|
}
|
|
45299
45558
|
const response = await fetch(downloadUrl, { redirect: "follow" });
|
|
45300
45559
|
if (!response.ok) {
|
|
45301
45560
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
45302
45561
|
}
|
|
45303
|
-
const archivePath =
|
|
45562
|
+
const archivePath = join11(cacheDir, assetName);
|
|
45304
45563
|
const arrayBuffer = await response.arrayBuffer();
|
|
45305
45564
|
await crossWrite(archivePath, arrayBuffer);
|
|
45306
45565
|
await extractZip(archivePath, cacheDir);
|
|
@@ -45389,7 +45648,7 @@ function findSgCliPathSync() {
|
|
|
45389
45648
|
const require2 = createRequire3(import.meta.url);
|
|
45390
45649
|
const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
|
|
45391
45650
|
const cliDir = dirname6(cliPkgPath);
|
|
45392
|
-
const sgPath =
|
|
45651
|
+
const sgPath = join12(cliDir, binaryName);
|
|
45393
45652
|
if (existsSync7(sgPath) && isValidBinary(sgPath)) {
|
|
45394
45653
|
return sgPath;
|
|
45395
45654
|
}
|
|
@@ -45401,7 +45660,7 @@ function findSgCliPathSync() {
|
|
|
45401
45660
|
const pkgPath = require2.resolve(`${platformPkg}/package.json`);
|
|
45402
45661
|
const pkgDir = dirname6(pkgPath);
|
|
45403
45662
|
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
45404
|
-
const binaryPath =
|
|
45663
|
+
const binaryPath = join12(pkgDir, astGrepName);
|
|
45405
45664
|
if (existsSync7(binaryPath) && isValidBinary(binaryPath)) {
|
|
45406
45665
|
return binaryPath;
|
|
45407
45666
|
}
|
|
@@ -45409,9 +45668,9 @@ function findSgCliPathSync() {
|
|
|
45409
45668
|
}
|
|
45410
45669
|
if (process.platform === "darwin") {
|
|
45411
45670
|
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
|
|
45412
|
-
for (const
|
|
45413
|
-
if (existsSync7(
|
|
45414
|
-
return
|
|
45671
|
+
for (const path13 of homebrewPaths) {
|
|
45672
|
+
if (existsSync7(path13) && isValidBinary(path13)) {
|
|
45673
|
+
return path13;
|
|
45415
45674
|
}
|
|
45416
45675
|
}
|
|
45417
45676
|
}
|
|
@@ -45428,8 +45687,8 @@ function getSgCliPath() {
|
|
|
45428
45687
|
}
|
|
45429
45688
|
return "sg";
|
|
45430
45689
|
}
|
|
45431
|
-
function setSgCliPath(
|
|
45432
|
-
resolvedCliPath =
|
|
45690
|
+
function setSgCliPath(path13) {
|
|
45691
|
+
resolvedCliPath = path13;
|
|
45433
45692
|
}
|
|
45434
45693
|
var DEFAULT_TIMEOUT_MS2 = 300000;
|
|
45435
45694
|
var DEFAULT_MAX_OUTPUT_BYTES = 1 * 1024 * 1024;
|
|
@@ -45794,7 +46053,7 @@ Key behaviors:
|
|
|
45794
46053
|
if (!toolContext || typeof toolContext !== "object" || !("sessionID" in toolContext)) {
|
|
45795
46054
|
throw new Error("Invalid toolContext: missing sessionID");
|
|
45796
46055
|
}
|
|
45797
|
-
const agent = String(args.agent);
|
|
46056
|
+
const agent = resolveRuntimeAgentName(_pluginConfig, String(args.agent));
|
|
45798
46057
|
const prompt = String(args.prompt);
|
|
45799
46058
|
const description = String(args.description);
|
|
45800
46059
|
const parentSessionId = toolContext.sessionID;
|
|
@@ -45947,15 +46206,15 @@ Returns the synthesized result with councillor summary.`,
|
|
|
45947
46206
|
// src/tools/lsp/client.ts
|
|
45948
46207
|
var import_node = __toESM(require_main(), 1);
|
|
45949
46208
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
45950
|
-
import { readFileSync as
|
|
45951
|
-
import { extname as
|
|
46209
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
46210
|
+
import { extname as extname3, resolve as resolve5 } from "node:path";
|
|
45952
46211
|
import { pathToFileURL } from "node:url";
|
|
45953
46212
|
|
|
45954
46213
|
// src/tools/lsp/config.ts
|
|
45955
46214
|
var import_which = __toESM(require_lib(), 1);
|
|
45956
46215
|
import { existsSync as existsSync10 } from "node:fs";
|
|
45957
46216
|
import { homedir as homedir5 } from "node:os";
|
|
45958
|
-
import { dirname as dirname8, join as
|
|
46217
|
+
import { dirname as dirname8, join as join13, resolve as resolve4 } from "node:path";
|
|
45959
46218
|
|
|
45960
46219
|
// src/tools/lsp/config-store.ts
|
|
45961
46220
|
var userConfig = new Map;
|
|
@@ -46634,7 +46893,7 @@ function resolveServerCommand(command, cwd) {
|
|
|
46634
46893
|
}
|
|
46635
46894
|
const isWindows = process.platform === "win32";
|
|
46636
46895
|
const ext = isWindows ? ".exe" : "";
|
|
46637
|
-
const opencodeBin =
|
|
46896
|
+
const opencodeBin = join13(homedir5(), ".config", "opencode", "bin");
|
|
46638
46897
|
const searchPath = (process.env.PATH ?? "") + (isWindows ? ";" : ":") + opencodeBin;
|
|
46639
46898
|
const result = import_which.default.sync(cmd, {
|
|
46640
46899
|
path: searchPath,
|
|
@@ -46645,7 +46904,7 @@ function resolveServerCommand(command, cwd) {
|
|
|
46645
46904
|
return [result, ...args];
|
|
46646
46905
|
}
|
|
46647
46906
|
const localBinRoot = cwd ?? process.cwd();
|
|
46648
|
-
const localBin =
|
|
46907
|
+
const localBin = join13(localBinRoot, "node_modules", ".bin", cmd);
|
|
46649
46908
|
if (existsSync10(localBin)) {
|
|
46650
46909
|
return [localBin, ...args];
|
|
46651
46910
|
}
|
|
@@ -47066,8 +47325,8 @@ stderr: ${stderr}` : ""));
|
|
|
47066
47325
|
async ensureDocumentSynced(filePath) {
|
|
47067
47326
|
const absPath = resolve5(filePath);
|
|
47068
47327
|
const uri = pathToFileURL(absPath).href;
|
|
47069
|
-
const text =
|
|
47070
|
-
const ext =
|
|
47328
|
+
const text = readFileSync5(absPath, "utf-8");
|
|
47329
|
+
const ext = extname3(absPath);
|
|
47071
47330
|
const languageId = getLanguageId(ext);
|
|
47072
47331
|
const existing = this.documents.get(uri);
|
|
47073
47332
|
if (!existing) {
|
|
@@ -47221,12 +47480,12 @@ import { tool as tool5 } from "@opencode-ai/plugin/tool";
|
|
|
47221
47480
|
// src/tools/lsp/utils.ts
|
|
47222
47481
|
import {
|
|
47223
47482
|
existsSync as existsSync11,
|
|
47224
|
-
readFileSync as
|
|
47483
|
+
readFileSync as readFileSync6,
|
|
47225
47484
|
statSync as statSync6,
|
|
47226
47485
|
unlinkSync as unlinkSync5,
|
|
47227
|
-
writeFileSync as
|
|
47486
|
+
writeFileSync as writeFileSync6
|
|
47228
47487
|
} from "node:fs";
|
|
47229
|
-
import { dirname as dirname9, extname as
|
|
47488
|
+
import { dirname as dirname9, extname as extname4, join as join14, resolve as resolve6 } from "node:path";
|
|
47230
47489
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
47231
47490
|
function findServerProjectRoot(filePath, server) {
|
|
47232
47491
|
if (server.root) {
|
|
@@ -47252,7 +47511,7 @@ function formatServerLookupError(result) {
|
|
|
47252
47511
|
}
|
|
47253
47512
|
async function withLspClient(filePath, fn) {
|
|
47254
47513
|
const absPath = resolve6(filePath);
|
|
47255
|
-
const ext =
|
|
47514
|
+
const ext = extname4(absPath);
|
|
47256
47515
|
const result = findServerForExtension(ext, absPath);
|
|
47257
47516
|
if (result.status !== "found") {
|
|
47258
47517
|
log("[lsp] withLspClient: server not found", {
|
|
@@ -47339,7 +47598,7 @@ function filterDiagnosticsBySeverity(diagnostics, severityFilter) {
|
|
|
47339
47598
|
}
|
|
47340
47599
|
function applyTextEditsToFile(filePath, edits) {
|
|
47341
47600
|
try {
|
|
47342
|
-
const content =
|
|
47601
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
47343
47602
|
const lines = content.split(`
|
|
47344
47603
|
`);
|
|
47345
47604
|
const sortedEdits = [...edits].sort((a, b) => {
|
|
@@ -47364,7 +47623,7 @@ function applyTextEditsToFile(filePath, edits) {
|
|
|
47364
47623
|
`));
|
|
47365
47624
|
}
|
|
47366
47625
|
}
|
|
47367
|
-
|
|
47626
|
+
writeFileSync6(filePath, lines.join(`
|
|
47368
47627
|
`), "utf-8");
|
|
47369
47628
|
return { success: true, editCount: edits.length };
|
|
47370
47629
|
} catch (err) {
|
|
@@ -47412,7 +47671,7 @@ function applyWorkspaceEdit(edit) {
|
|
|
47412
47671
|
if (change.kind === "create") {
|
|
47413
47672
|
try {
|
|
47414
47673
|
const filePath = uriToPath(change.uri);
|
|
47415
|
-
|
|
47674
|
+
writeFileSync6(filePath, "", "utf-8");
|
|
47416
47675
|
result.filesModified.push(filePath);
|
|
47417
47676
|
} catch (err) {
|
|
47418
47677
|
result.success = false;
|
|
@@ -47422,8 +47681,8 @@ function applyWorkspaceEdit(edit) {
|
|
|
47422
47681
|
try {
|
|
47423
47682
|
const oldPath = uriToPath(change.oldUri);
|
|
47424
47683
|
const newPath = uriToPath(change.newUri);
|
|
47425
|
-
const content =
|
|
47426
|
-
|
|
47684
|
+
const content = readFileSync6(oldPath, "utf-8");
|
|
47685
|
+
writeFileSync6(newPath, content, "utf-8");
|
|
47427
47686
|
unlinkSync5(oldPath);
|
|
47428
47687
|
result.filesModified.push(newPath);
|
|
47429
47688
|
} catch (err) {
|
|
@@ -47625,14 +47884,14 @@ var BINARY_PREFIXES = [
|
|
|
47625
47884
|
var WEBFETCH_DESCRIPTION = "Fetch a URL with better extraction for static/docs pages. Supports llms.txt probing, content-focused HTML extraction, metadata, redirects, and an optional prompt processed by a cheap secondary model.";
|
|
47626
47885
|
// src/tools/smartfetch/tool.ts
|
|
47627
47886
|
import os4 from "node:os";
|
|
47628
|
-
import
|
|
47887
|
+
import path16 from "node:path";
|
|
47629
47888
|
import {
|
|
47630
47889
|
tool as tool6
|
|
47631
47890
|
} from "@opencode-ai/plugin";
|
|
47632
47891
|
|
|
47633
47892
|
// src/tools/smartfetch/binary.ts
|
|
47634
47893
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
47635
|
-
import
|
|
47894
|
+
import path13 from "node:path";
|
|
47636
47895
|
function extensionForMime(contentType) {
|
|
47637
47896
|
const mime = contentType.split(";")[0]?.trim().toLowerCase();
|
|
47638
47897
|
const map2 = {
|
|
@@ -47653,10 +47912,10 @@ function buildBinaryResultMessage(fetchResult, savedPath) {
|
|
|
47653
47912
|
async function saveBinary(binaryDir, data, contentType, filename) {
|
|
47654
47913
|
await mkdir2(binaryDir, { recursive: true });
|
|
47655
47914
|
const initialName = filename || `webfetch-${Date.now()}.${extensionForMime(contentType)}`;
|
|
47656
|
-
const parsed =
|
|
47915
|
+
const parsed = path13.parse(initialName);
|
|
47657
47916
|
for (let attempt = 0;attempt < 1000; attempt++) {
|
|
47658
47917
|
const candidateName = attempt === 0 ? initialName : `${parsed.name}-${attempt}${parsed.ext || `.${extensionForMime(contentType)}`}`;
|
|
47659
|
-
const file2 =
|
|
47918
|
+
const file2 = path13.join(binaryDir, candidateName);
|
|
47660
47919
|
try {
|
|
47661
47920
|
await writeFile2(file2, data, { flag: "wx" });
|
|
47662
47921
|
return file2;
|
|
@@ -47674,7 +47933,7 @@ async function saveBinary(binaryDir, data, contentType, filename) {
|
|
|
47674
47933
|
import { tracingChannel as j, channel as I } from "node:diagnostics_channel";
|
|
47675
47934
|
var S = I("lru-cache:metrics");
|
|
47676
47935
|
var W = j("lru-cache");
|
|
47677
|
-
var
|
|
47936
|
+
var D = () => S.hasSubscribers || W.hasSubscribers;
|
|
47678
47937
|
var G = typeof performance == "object" && performance && typeof performance.now == "function" ? performance : Date;
|
|
47679
47938
|
var M = new Set;
|
|
47680
47939
|
var C = typeof process == "object" && process ? process : {};
|
|
@@ -47718,7 +47977,7 @@ var L = class u2 {
|
|
|
47718
47977
|
#o;
|
|
47719
47978
|
#u;
|
|
47720
47979
|
#w;
|
|
47721
|
-
#
|
|
47980
|
+
#D;
|
|
47722
47981
|
#S;
|
|
47723
47982
|
#M;
|
|
47724
47983
|
#U;
|
|
@@ -47789,16 +48048,16 @@ var L = class u2 {
|
|
|
47789
48048
|
return this.#w;
|
|
47790
48049
|
}
|
|
47791
48050
|
get onInsert() {
|
|
47792
|
-
return this.#
|
|
48051
|
+
return this.#D;
|
|
47793
48052
|
}
|
|
47794
48053
|
get disposeAfter() {
|
|
47795
48054
|
return this.#S;
|
|
47796
48055
|
}
|
|
47797
48056
|
constructor(e) {
|
|
47798
|
-
let { max: t = 0, ttl: i, ttlResolution: s = 1, ttlAutopurge: n, updateAgeOnGet: o, updateAgeOnHas: r, allowStale: h, dispose: l, onInsert: c, disposeAfter: f, noDisposeOnSet: g, noUpdateTTL: p, maxSize: T = 0, maxEntrySize: w = 0, sizeCalculation: y, fetchMethod: a, memoMethod: m, noDeleteOnFetchRejection: _, noDeleteOnStaleGet: b, allowStaleOnFetchRejection: d, allowStaleOnFetchAbort: A, ignoreFetchAbort: z4, perf:
|
|
47799
|
-
if (
|
|
48057
|
+
let { max: t = 0, ttl: i, ttlResolution: s = 1, ttlAutopurge: n, updateAgeOnGet: o, updateAgeOnHas: r, allowStale: h, dispose: l, onInsert: c, disposeAfter: f, noDisposeOnSet: g, noUpdateTTL: p, maxSize: T = 0, maxEntrySize: w = 0, sizeCalculation: y, fetchMethod: a, memoMethod: m, noDeleteOnFetchRejection: _, noDeleteOnStaleGet: b, allowStaleOnFetchRejection: d, allowStaleOnFetchAbort: A, ignoreFetchAbort: z4, perf: x } = e;
|
|
48058
|
+
if (x !== undefined && typeof x?.now != "function")
|
|
47800
48059
|
throw new TypeError("perf option must have a now() method if specified");
|
|
47801
|
-
if (this.#m =
|
|
48060
|
+
if (this.#m = x ?? G, t !== 0 && !F(t))
|
|
47802
48061
|
throw new TypeError("max option must be a nonnegative integer");
|
|
47803
48062
|
let v = t ? U(t) : Array;
|
|
47804
48063
|
if (!v)
|
|
@@ -47813,7 +48072,7 @@ var L = class u2 {
|
|
|
47813
48072
|
throw new TypeError("memoMethod must be a function if defined");
|
|
47814
48073
|
if (this.#U = m, a !== undefined && typeof a != "function")
|
|
47815
48074
|
throw new TypeError("fetchMethod must be a function if specified");
|
|
47816
|
-
if (this.#M = a, this.#W = !!a, this.#s = new Map, this.#i = Array.from({ length: t }).fill(undefined), this.#t = Array.from({ length: t }).fill(undefined), this.#a = new v(t), this.#c = new v(t), this.#l = 0, this.#h = 0, this.#y = R.create(t), this.#n = 0, this.#b = 0, typeof l == "function" && (this.#w = l), typeof c == "function" && (this.#
|
|
48075
|
+
if (this.#M = a, this.#W = !!a, this.#s = new Map, this.#i = Array.from({ length: t }).fill(undefined), this.#t = Array.from({ length: t }).fill(undefined), this.#a = new v(t), this.#c = new v(t), this.#l = 0, this.#h = 0, this.#y = R.create(t), this.#n = 0, this.#b = 0, typeof l == "function" && (this.#w = l), typeof c == "function" && (this.#D = c), typeof f == "function" ? (this.#S = f, this.#r = []) : (this.#S = undefined, this.#r = undefined), this.#T = !!this.#w, this.#j = !!this.#D, this.#f = !!this.#S, this.noDisposeOnSet = !!g, this.noUpdateTTL = !!p, this.noDeleteOnFetchRejection = !!_, this.allowStaleOnFetchRejection = !!d, this.allowStaleOnFetchAbort = !!A, this.ignoreFetchAbort = !!z4, this.maxEntrySize !== 0) {
|
|
47817
48076
|
if (this.#u !== 0 && !F(this.#u))
|
|
47818
48077
|
throw new TypeError("maxSize must be a positive integer if specified");
|
|
47819
48078
|
if (!F(this.maxEntrySize))
|
|
@@ -47841,7 +48100,7 @@ var L = class u2 {
|
|
|
47841
48100
|
let i = this.ttlAutopurge ? Array.from({ length: this.#o }) : undefined;
|
|
47842
48101
|
this.#g = i, this.#N = (r, h, l = this.#m.now()) => {
|
|
47843
48102
|
t[r] = h !== 0 ? l : 0, e[r] = h, s(r, h);
|
|
47844
|
-
}, this.#
|
|
48103
|
+
}, this.#x = (r) => {
|
|
47845
48104
|
t[r] = e[r] !== 0 ? this.#m.now() : 0, s(r, e[r]);
|
|
47846
48105
|
};
|
|
47847
48106
|
let s = this.ttlAutopurge ? (r, h) => {
|
|
@@ -47885,7 +48144,7 @@ var L = class u2 {
|
|
|
47885
48144
|
return !!l && !!h && (n || o()) - h > l;
|
|
47886
48145
|
};
|
|
47887
48146
|
}
|
|
47888
|
-
#
|
|
48147
|
+
#x = () => {};
|
|
47889
48148
|
#E = () => {};
|
|
47890
48149
|
#N = () => {};
|
|
47891
48150
|
#p = () => false;
|
|
@@ -48051,7 +48310,7 @@ var L = class u2 {
|
|
|
48051
48310
|
return this.#v(e, "set"), h && (h.set = "miss", h.maxEntrySizeExceeded = true), this;
|
|
48052
48311
|
let f = this.#n === 0 ? undefined : this.#s.get(e);
|
|
48053
48312
|
if (f === undefined)
|
|
48054
|
-
f = this.#n === 0 ? this.#h : this.#y.length !== 0 ? this.#y.pop() : this.#n === this.#o ? this.#G(false) : this.#n, this.#i[f] = e, this.#t[f] = t, this.#s.set(e, f), this.#a[this.#h] = f, this.#c[f] = this.#h, this.#h = f, this.#n++, this.#I(f, c, h), h && (h.set = "add"), l = false, this.#j && this.#
|
|
48313
|
+
f = this.#n === 0 ? this.#h : this.#y.length !== 0 ? this.#y.pop() : this.#n === this.#o ? this.#G(false) : this.#n, this.#i[f] = e, this.#t[f] = t, this.#s.set(e, f), this.#a[this.#h] = f, this.#c[f] = this.#h, this.#h = f, this.#n++, this.#I(f, c, h), h && (h.set = "add"), l = false, this.#j && this.#D?.(t, e, "add");
|
|
48055
48314
|
else {
|
|
48056
48315
|
this.#L(f);
|
|
48057
48316
|
let g = this.#t[f];
|
|
@@ -48115,13 +48374,13 @@ var L = class u2 {
|
|
|
48115
48374
|
if (this.#p(n))
|
|
48116
48375
|
s && (s.has = "stale", this.#E(s, n));
|
|
48117
48376
|
else
|
|
48118
|
-
return i && this.#
|
|
48377
|
+
return i && this.#x(n), s && (s.has = "hit", this.#E(s, n)), true;
|
|
48119
48378
|
} else
|
|
48120
48379
|
s && (s.has = "miss");
|
|
48121
48380
|
return false;
|
|
48122
48381
|
}
|
|
48123
48382
|
peek(e, t = {}) {
|
|
48124
|
-
let { status: i =
|
|
48383
|
+
let { status: i = D() ? {} : undefined } = t;
|
|
48125
48384
|
i && (i.op = "peek", i.key = e), t.status = i;
|
|
48126
48385
|
let s = this.#J(e, t);
|
|
48127
48386
|
return S.hasSubscribers && S.publish(i), s;
|
|
@@ -48170,10 +48429,10 @@ var L = class u2 {
|
|
|
48170
48429
|
return !!t && t instanceof Promise && t.hasOwnProperty("__staleWhileFetching") && t.__abortController instanceof AbortController;
|
|
48171
48430
|
}
|
|
48172
48431
|
fetch(e, t = {}) {
|
|
48173
|
-
let i = W.hasSubscribers, { status: s =
|
|
48432
|
+
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } = t;
|
|
48174
48433
|
t.status = s, s && t.context && (s.context = t.context);
|
|
48175
48434
|
let n = this.#B(e, t);
|
|
48176
|
-
return s &&
|
|
48435
|
+
return s && D() && i && (s.trace = true, W.tracePromise(() => n, s).catch(() => {})), n;
|
|
48177
48436
|
}
|
|
48178
48437
|
async#B(e, t = {}) {
|
|
48179
48438
|
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, ttl: o = this.ttl, noDisposeOnSet: r = this.noDisposeOnSet, size: h = 0, sizeCalculation: l = this.sizeCalculation, noUpdateTTL: c = this.noUpdateTTL, noDeleteOnFetchRejection: f = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection: g = this.allowStaleOnFetchRejection, ignoreFetchAbort: p = this.ignoreFetchAbort, allowStaleOnFetchAbort: T = this.allowStaleOnFetchAbort, context: w, forceRefresh: y = false, status: a, signal: m } = t;
|
|
@@ -48192,16 +48451,16 @@ var L = class u2 {
|
|
|
48192
48451
|
}
|
|
48193
48452
|
let A = this.#p(b);
|
|
48194
48453
|
if (!y && !A)
|
|
48195
|
-
return a && (a.fetch = "hit"), this.#L(b), s && this.#
|
|
48454
|
+
return a && (a.fetch = "hit"), this.#L(b), s && this.#x(b), a && this.#E(a, b), d;
|
|
48196
48455
|
let z4 = this.#P(e, b, _, w), v = z4.__staleWhileFetching !== undefined && i;
|
|
48197
48456
|
return a && (a.fetch = A ? "stale" : "refresh", v && A && (a.returnedStale = true)), v ? z4.__staleWhileFetching : z4.__returned = z4;
|
|
48198
48457
|
}
|
|
48199
48458
|
}
|
|
48200
48459
|
forceFetch(e, t = {}) {
|
|
48201
|
-
let i = W.hasSubscribers, { status: s =
|
|
48460
|
+
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } = t;
|
|
48202
48461
|
t.status = s, s && t.context && (s.context = t.context);
|
|
48203
48462
|
let n = this.#K(e, t);
|
|
48204
|
-
return s &&
|
|
48463
|
+
return s && D() && i && (s.trace = true, W.tracePromise(() => n, s).catch(() => {})), n;
|
|
48205
48464
|
}
|
|
48206
48465
|
async#K(e, t = {}) {
|
|
48207
48466
|
let i = await this.#B(e, t);
|
|
@@ -48240,7 +48499,7 @@ var L = class u2 {
|
|
|
48240
48499
|
return;
|
|
48241
48500
|
}
|
|
48242
48501
|
let h = this.#t[r], l = this.#e(h);
|
|
48243
|
-
return o && this.#E(o, r), this.#p(r) ? l ? (o && (o.get = "stale-fetching"), i && h.__staleWhileFetching !== undefined ? (o && (o.returnedStale = true), h.__staleWhileFetching) : undefined) : (n || this.#v(e, "expire"), o && (o.get = "stale"), i ? (o && (o.returnedStale = true), h) : undefined) : (o && (o.get = l ? "fetching" : "hit"), this.#L(r), s && this.#
|
|
48502
|
+
return o && this.#E(o, r), this.#p(r) ? l ? (o && (o.get = "stale-fetching"), i && h.__staleWhileFetching !== undefined ? (o && (o.returnedStale = true), h.__staleWhileFetching) : undefined) : (n || this.#v(e, "expire"), o && (o.get = "stale"), i ? (o && (o.returnedStale = true), h) : undefined) : (o && (o.get = l ? "fetching" : "hit"), this.#L(r), s && this.#x(r), l ? h.__staleWhileFetching : h);
|
|
48244
48503
|
}
|
|
48245
48504
|
#$(e, t) {
|
|
48246
48505
|
this.#c[t] = e, this.#a[e] = t;
|
|
@@ -48310,7 +48569,7 @@ var L = class u2 {
|
|
|
48310
48569
|
};
|
|
48311
48570
|
|
|
48312
48571
|
// src/tools/smartfetch/network.ts
|
|
48313
|
-
import
|
|
48572
|
+
import path14 from "node:path";
|
|
48314
48573
|
|
|
48315
48574
|
// src/tools/smartfetch/utils.ts
|
|
48316
48575
|
var import_readability = __toESM(require_readability(), 1);
|
|
@@ -49035,12 +49294,12 @@ function inferFilenameFromUrl(url2) {
|
|
|
49035
49294
|
function truncateFilename(name, maxLength = 180) {
|
|
49036
49295
|
if (name.length <= maxLength)
|
|
49037
49296
|
return name;
|
|
49038
|
-
const parsed =
|
|
49297
|
+
const parsed = path14.parse(name);
|
|
49039
49298
|
const ext = parsed.ext || "";
|
|
49040
49299
|
const baseLimit = Math.max(1, maxLength - ext.length);
|
|
49041
49300
|
return `${parsed.name.slice(0, baseLimit)}${ext}`;
|
|
49042
49301
|
}
|
|
49043
|
-
function
|
|
49302
|
+
function sanitizeFilename2(name) {
|
|
49044
49303
|
let sanitized = Array.from(name, (char) => {
|
|
49045
49304
|
const code = char.charCodeAt(0);
|
|
49046
49305
|
if (code < 32 || '<>:"/\\|?*'.includes(char))
|
|
@@ -49065,7 +49324,7 @@ function extractHeaderMetadata(headers, finalUrl) {
|
|
|
49065
49324
|
etag: headers.get("etag") || undefined,
|
|
49066
49325
|
lastModified: headers.get("last-modified") || undefined,
|
|
49067
49326
|
contentLength: parseContentLength(headers),
|
|
49068
|
-
filename: filename ?
|
|
49327
|
+
filename: filename ? sanitizeFilename2(filename) : undefined
|
|
49069
49328
|
};
|
|
49070
49329
|
}
|
|
49071
49330
|
function buildConditionalHeaders(cached2) {
|
|
@@ -49207,7 +49466,7 @@ function isInvalidLlmsResult(fetchResult) {
|
|
|
49207
49466
|
// src/tools/smartfetch/secondary-model.ts
|
|
49208
49467
|
import { existsSync as existsSync12 } from "node:fs";
|
|
49209
49468
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
49210
|
-
import
|
|
49469
|
+
import path15 from "node:path";
|
|
49211
49470
|
function parseModelRef(value) {
|
|
49212
49471
|
if (!value)
|
|
49213
49472
|
return;
|
|
@@ -49233,7 +49492,7 @@ function pickAgentModelRef(value) {
|
|
|
49233
49492
|
}
|
|
49234
49493
|
function findPreferredOpenCodeConfigPath(baseDir) {
|
|
49235
49494
|
for (const file2 of ["opencode.jsonc", "opencode.json"]) {
|
|
49236
|
-
const fullPath =
|
|
49495
|
+
const fullPath = path15.join(baseDir, file2);
|
|
49237
49496
|
if (existsSync12(fullPath))
|
|
49238
49497
|
return fullPath;
|
|
49239
49498
|
}
|
|
@@ -49250,7 +49509,7 @@ async function readOpenCodeConfigFile(configPath) {
|
|
|
49250
49509
|
}
|
|
49251
49510
|
}
|
|
49252
49511
|
async function readEffectiveOpenCodeConfig(directory) {
|
|
49253
|
-
const projectDir =
|
|
49512
|
+
const projectDir = path15.join(directory, ".opencode");
|
|
49254
49513
|
const userDirs = getConfigSearchDirs();
|
|
49255
49514
|
const projectPath = findPreferredOpenCodeConfigPath(projectDir);
|
|
49256
49515
|
const userPath = userDirs.map((configDir) => findPreferredOpenCodeConfigPath(configDir)).find(Boolean);
|
|
@@ -49411,7 +49670,7 @@ async function runSecondaryModelWithFallback(client, directory, models, prompt,
|
|
|
49411
49670
|
// src/tools/smartfetch/tool.ts
|
|
49412
49671
|
var z4 = tool6.schema;
|
|
49413
49672
|
function createWebfetchTool(pluginCtx, options = {}) {
|
|
49414
|
-
const binaryDir = options.binaryDir ||
|
|
49673
|
+
const binaryDir = options.binaryDir || path16.join(os4.tmpdir(), "opencode-smartfetch");
|
|
49415
49674
|
return tool6({
|
|
49416
49675
|
description: WEBFETCH_DESCRIPTION,
|
|
49417
49676
|
args: {
|
|
@@ -49949,7 +50208,7 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
49949
50208
|
const webfetch = createWebfetchTool(ctx);
|
|
49950
50209
|
const multiplexerSessionManager = new MultiplexerSessionManager(ctx, multiplexerConfig);
|
|
49951
50210
|
const autoUpdateChecker = createAutoUpdateCheckerHook(ctx, {
|
|
49952
|
-
showStartupToast: true,
|
|
50211
|
+
showStartupToast: config2.showStartupToast ?? true,
|
|
49953
50212
|
autoUpdate: true
|
|
49954
50213
|
});
|
|
49955
50214
|
const phaseReminderHook = createPhaseReminderHook();
|
|
@@ -50124,7 +50383,11 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
50124
50383
|
},
|
|
50125
50384
|
"chat.headers": chatHeadersHook["chat.headers"],
|
|
50126
50385
|
"chat.message": async (input, output) => {
|
|
50127
|
-
const
|
|
50386
|
+
const rawAgent = input.agent ?? output?.message?.agent;
|
|
50387
|
+
const agent = rawAgent ? resolveRuntimeAgentName(config2, rawAgent) : undefined;
|
|
50388
|
+
if (agent && output?.message && typeof output.message.agent === "string") {
|
|
50389
|
+
output.message.agent = agent;
|
|
50390
|
+
}
|
|
50128
50391
|
if (agent) {
|
|
50129
50392
|
sessionAgentMap.set(input.sessionID, agent);
|
|
50130
50393
|
}
|
|
@@ -50151,6 +50414,17 @@ ${output.system[0]}` : "");
|
|
|
50151
50414
|
},
|
|
50152
50415
|
"experimental.chat.messages.transform": async (input, output) => {
|
|
50153
50416
|
const typedOutput = output;
|
|
50417
|
+
for (const message of typedOutput.messages) {
|
|
50418
|
+
if (message.info.role !== "user") {
|
|
50419
|
+
continue;
|
|
50420
|
+
}
|
|
50421
|
+
for (const part of message.parts) {
|
|
50422
|
+
if (part.type !== "text" || typeof part.text !== "string") {
|
|
50423
|
+
continue;
|
|
50424
|
+
}
|
|
50425
|
+
part.text = rewriteDisplayNameMentions(config2, part.text);
|
|
50426
|
+
}
|
|
50427
|
+
}
|
|
50154
50428
|
processImageAttachments({
|
|
50155
50429
|
messages: typedOutput.messages,
|
|
50156
50430
|
workDir: ctx.directory,
|