@hiai-gg/hiai-opencode 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -8
- package/AGENTS.md +19 -8
- package/ARCHITECTURE.md +7 -6
- package/LICENSE.md +0 -1
- package/README.md +48 -17
- package/assets/cli/hiai-opencode.mjs +590 -7
- package/assets/mcp/mempalace.mjs +159 -25
- package/config/hiai-opencode.schema.json +82 -148
- package/dist/agents/dynamic-agent-core-sections.d.ts +4 -1
- package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -1
- package/dist/config/defaults.d.ts +1 -0
- package/dist/config/platform-schema.d.ts +275 -10
- package/dist/config/schema/categories.d.ts +2 -2
- package/dist/config/schema/commands.d.ts +1 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +1 -3
- package/dist/config/types.d.ts +22 -5
- package/dist/create-tools.d.ts +2 -0
- package/dist/features/builtin-commands/templates/doctor.d.ts +1 -0
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/features/builtin-skills/skills/hiai-opencode-setup.d.ts +2 -0
- package/dist/features/builtin-skills/skills/index.d.ts +1 -0
- package/dist/index.js +870 -1711
- package/dist/mcp/types.d.ts +1 -1
- package/dist/plugin/tool-registry.d.ts +2 -0
- package/dist/shared/mcp-static-export.d.ts +22 -0
- package/dist/tools/ast-grep/constants.d.ts +1 -1
- package/dist/tools/ast-grep/environment-check.d.ts +1 -5
- package/dist/tools/ast-grep/language-support.d.ts +0 -1
- package/dist/tools/ast-grep/types.d.ts +1 -2
- package/dist/tools/skill-mcp/tools.d.ts +2 -0
- package/hiai-opencode.json +39 -171
- package/package.json +6 -4
- package/src/agents/bob/default.ts +6 -1
- package/src/agents/bob/gpt-pro.ts +1 -0
- package/src/agents/bob.ts +1 -0
- package/src/agents/coder/gpt-codex.ts +1 -0
- package/src/agents/coder/gpt-pro.ts +1 -0
- package/src/agents/coder/gpt.ts +1 -0
- package/src/agents/dynamic-agent-core-sections.ts +36 -0
- package/src/agents/dynamic-agent-prompt-builder.ts +1 -0
- package/src/config/defaults.ts +171 -28
- package/src/config/loader.test.ts +16 -1
- package/src/config/loader.ts +4 -2
- package/src/config/model-slots-and-export.test.ts +55 -0
- package/src/config/platform-schema.ts +37 -5
- package/src/config/schema/commands.ts +1 -0
- package/src/config/schema/oh-my-opencode-config.ts +0 -3
- package/src/config/types.ts +34 -5
- package/src/create-tools.ts +4 -1
- package/src/features/builtin-commands/commands.ts +7 -0
- package/src/features/builtin-commands/templates/doctor.ts +43 -0
- package/src/features/builtin-commands/types.ts +1 -1
- package/src/features/builtin-skills/skills/hiai-opencode-setup.ts +69 -0
- package/src/features/builtin-skills/skills/index.ts +1 -0
- package/src/features/builtin-skills/skills.ts +10 -1
- package/src/index.ts +4 -38
- package/src/lsp/index.ts +1 -0
- package/src/mcp/registry.ts +6 -1
- package/src/plugin/tool-registry.ts +4 -0
- package/src/shared/mcp-static-export.ts +121 -0
- package/src/tools/ast-grep/constants.ts +1 -1
- package/src/tools/ast-grep/environment-check.ts +2 -32
- package/src/tools/ast-grep/language-support.ts +0 -3
- package/src/tools/ast-grep/types.ts +1 -2
- package/src/tools/skill-mcp/tools.test.ts +44 -0
- package/src/tools/skill-mcp/tools.ts +45 -7
- package/dist/ast-grep-napi.win32-x64-msvc-67c0y8nc.node +0 -0
- package/dist/config/loader.test.d.ts +0 -1
- package/dist/config/models.d.ts +0 -13
- package/dist/internals/plugins/websearch-cited/google.d.ts +0 -38
- package/dist/internals/plugins/websearch-cited/index.d.ts +0 -11
- package/dist/internals/plugins/websearch-cited/openai.d.ts +0 -9
- package/dist/internals/plugins/websearch-cited/openrouter.d.ts +0 -2
- package/dist/internals/plugins/websearch-cited/types.d.ts +0 -5
- package/src/internals/plugins/websearch-cited/LICENSE +0 -214
- package/src/internals/plugins/websearch-cited/codex_prompt.txt +0 -79
- package/src/internals/plugins/websearch-cited/google.ts +0 -749
- package/src/internals/plugins/websearch-cited/index.ts +0 -301
- package/src/internals/plugins/websearch-cited/openai.ts +0 -407
- package/src/internals/plugins/websearch-cited/openrouter.ts +0 -190
- package/src/internals/plugins/websearch-cited/types.ts +0 -7
package/dist/index.js
CHANGED
|
@@ -32523,1267 +32523,6 @@ var require_dist2 = __commonJS((exports) => {
|
|
|
32523
32523
|
exports.visitAsync = visit2.visitAsync;
|
|
32524
32524
|
});
|
|
32525
32525
|
|
|
32526
|
-
// src/internals/plugins/websearch-cited/google.ts
|
|
32527
|
-
function buildGeminiUrl(model) {
|
|
32528
|
-
const encoded = encodeURIComponent(model);
|
|
32529
|
-
return `${GEMINI_API_BASE}/models/${encoded}:generateContent`;
|
|
32530
|
-
}
|
|
32531
|
-
async function runGeminiWebSearch(options) {
|
|
32532
|
-
const response = await fetch(buildGeminiUrl(options.model), {
|
|
32533
|
-
method: "POST",
|
|
32534
|
-
headers: {
|
|
32535
|
-
"Content-Type": "application/json",
|
|
32536
|
-
"x-goog-api-key": options.apiKey,
|
|
32537
|
-
"User-Agent": CODE_ASSIST_HEADERS["User-Agent"],
|
|
32538
|
-
"X-Goog-Api-Client": CODE_ASSIST_HEADERS["X-Goog-Api-Client"],
|
|
32539
|
-
"Client-Metadata": CODE_ASSIST_HEADERS["Client-Metadata"]
|
|
32540
|
-
},
|
|
32541
|
-
body: JSON.stringify({
|
|
32542
|
-
contents: [
|
|
32543
|
-
{
|
|
32544
|
-
role: "user",
|
|
32545
|
-
parts: [{ text: options.query }]
|
|
32546
|
-
}
|
|
32547
|
-
],
|
|
32548
|
-
tools: [{ googleSearch: {} }]
|
|
32549
|
-
}),
|
|
32550
|
-
signal: options.abortSignal
|
|
32551
|
-
});
|
|
32552
|
-
if (!response.ok) {
|
|
32553
|
-
const message = await readErrorMessage(response);
|
|
32554
|
-
throw new Error(message ?? `Request failed with status ${response.status}`);
|
|
32555
|
-
}
|
|
32556
|
-
return await response.json();
|
|
32557
|
-
}
|
|
32558
|
-
function formatWebSearchResponse(response, query) {
|
|
32559
|
-
const responseText = extractResponseText(response);
|
|
32560
|
-
if (!responseText || !responseText.trim()) {
|
|
32561
|
-
return `No search results or information found for query: "${query}"`;
|
|
32562
|
-
}
|
|
32563
|
-
const metadata = extractGroundingMetadata(response);
|
|
32564
|
-
const sources = metadata?.groundingChunks;
|
|
32565
|
-
const hasSources = Boolean(sources && sources.length > 0);
|
|
32566
|
-
let modifiedText = responseText;
|
|
32567
|
-
if (hasSources && metadata) {
|
|
32568
|
-
const insertions = buildCitationInsertions(metadata);
|
|
32569
|
-
if (insertions.length > 0) {
|
|
32570
|
-
modifiedText = insertMarkersByUtf8Index(modifiedText, insertions);
|
|
32571
|
-
}
|
|
32572
|
-
}
|
|
32573
|
-
if (hasSources && sources) {
|
|
32574
|
-
const sourceLines = sources.map((source, index) => {
|
|
32575
|
-
const title = source.web?.title || "Untitled";
|
|
32576
|
-
const uri = source.web?.uri || "No URI";
|
|
32577
|
-
return `[${index + 1}] ${title} (${uri})`;
|
|
32578
|
-
});
|
|
32579
|
-
modifiedText += `
|
|
32580
|
-
|
|
32581
|
-
Sources:
|
|
32582
|
-
${sourceLines.join(`
|
|
32583
|
-
`)}`;
|
|
32584
|
-
}
|
|
32585
|
-
return modifiedText;
|
|
32586
|
-
}
|
|
32587
|
-
function extractResponseText(response) {
|
|
32588
|
-
const parts = response.candidates?.[0]?.content?.parts;
|
|
32589
|
-
if (!parts || parts.length === 0) {
|
|
32590
|
-
return;
|
|
32591
|
-
}
|
|
32592
|
-
let combined = "";
|
|
32593
|
-
for (const part of parts) {
|
|
32594
|
-
if (part.thought) {
|
|
32595
|
-
continue;
|
|
32596
|
-
}
|
|
32597
|
-
if (typeof part.text === "string") {
|
|
32598
|
-
combined += part.text;
|
|
32599
|
-
}
|
|
32600
|
-
}
|
|
32601
|
-
return combined || undefined;
|
|
32602
|
-
}
|
|
32603
|
-
function extractGroundingMetadata(response) {
|
|
32604
|
-
return response.candidates?.[0]?.groundingMetadata;
|
|
32605
|
-
}
|
|
32606
|
-
function buildCitationInsertions(metadata) {
|
|
32607
|
-
const supports = metadata?.groundingSupports;
|
|
32608
|
-
if (!supports || supports.length === 0) {
|
|
32609
|
-
return [];
|
|
32610
|
-
}
|
|
32611
|
-
const insertions = [];
|
|
32612
|
-
for (const support of supports) {
|
|
32613
|
-
const segment = support.segment;
|
|
32614
|
-
const indices = support.groundingChunkIndices;
|
|
32615
|
-
if (!segment || segment.endIndex == null || !indices || indices.length === 0) {
|
|
32616
|
-
continue;
|
|
32617
|
-
}
|
|
32618
|
-
const uniqueSorted = Array.from(new Set(indices)).sort((a, b) => a - b);
|
|
32619
|
-
const marker = uniqueSorted.map((idx) => `[${idx + 1}]`).join("");
|
|
32620
|
-
insertions.push({
|
|
32621
|
-
index: segment.endIndex,
|
|
32622
|
-
marker
|
|
32623
|
-
});
|
|
32624
|
-
}
|
|
32625
|
-
insertions.sort((a, b) => b.index - a.index);
|
|
32626
|
-
return insertions;
|
|
32627
|
-
}
|
|
32628
|
-
function insertMarkersByUtf8Index(text, insertions) {
|
|
32629
|
-
if (insertions.length === 0) {
|
|
32630
|
-
return text;
|
|
32631
|
-
}
|
|
32632
|
-
const encoder = new TextEncoder;
|
|
32633
|
-
const responseBytes = encoder.encode(text);
|
|
32634
|
-
const parts = [];
|
|
32635
|
-
let lastIndex = responseBytes.length;
|
|
32636
|
-
for (const insertion of insertions) {
|
|
32637
|
-
const position = Math.min(insertion.index, lastIndex);
|
|
32638
|
-
parts.unshift(responseBytes.subarray(position, lastIndex));
|
|
32639
|
-
parts.unshift(encoder.encode(insertion.marker));
|
|
32640
|
-
lastIndex = position;
|
|
32641
|
-
}
|
|
32642
|
-
parts.unshift(responseBytes.subarray(0, lastIndex));
|
|
32643
|
-
const totalLength = parts.reduce((sum, part) => sum + part.length, 0);
|
|
32644
|
-
const finalBytes = new Uint8Array(totalLength);
|
|
32645
|
-
let offset = 0;
|
|
32646
|
-
for (const part of parts) {
|
|
32647
|
-
finalBytes.set(part, offset);
|
|
32648
|
-
offset += part.length;
|
|
32649
|
-
}
|
|
32650
|
-
return new TextDecoder().decode(finalBytes);
|
|
32651
|
-
}
|
|
32652
|
-
|
|
32653
|
-
class GeminiApiKeyClient {
|
|
32654
|
-
apiKey;
|
|
32655
|
-
model;
|
|
32656
|
-
constructor(apiKey, model) {
|
|
32657
|
-
const normalizedKey = apiKey.trim();
|
|
32658
|
-
const normalizedModel = model.trim();
|
|
32659
|
-
if (!normalizedKey || !normalizedModel) {
|
|
32660
|
-
throw new Error("Invalid Google API configuration");
|
|
32661
|
-
}
|
|
32662
|
-
this.apiKey = normalizedKey;
|
|
32663
|
-
this.model = normalizedModel;
|
|
32664
|
-
}
|
|
32665
|
-
async search(query, abortSignal) {
|
|
32666
|
-
const normalizedQuery = query.trim();
|
|
32667
|
-
const response = await runGeminiWebSearch({
|
|
32668
|
-
apiKey: this.apiKey,
|
|
32669
|
-
model: this.model,
|
|
32670
|
-
query: normalizedQuery,
|
|
32671
|
-
abortSignal
|
|
32672
|
-
});
|
|
32673
|
-
return formatWebSearchResponse(response, normalizedQuery);
|
|
32674
|
-
}
|
|
32675
|
-
}
|
|
32676
|
-
function parseRefresh(refresh) {
|
|
32677
|
-
const normalized = refresh.trim();
|
|
32678
|
-
if (!normalized) {
|
|
32679
|
-
return { refreshToken: "" };
|
|
32680
|
-
}
|
|
32681
|
-
const [token, project, managed] = normalized.split("|");
|
|
32682
|
-
const refreshToken = token?.trim() ?? "";
|
|
32683
|
-
const projectId = project?.trim() ?? "";
|
|
32684
|
-
const managedProjectId = managed?.trim() ?? "";
|
|
32685
|
-
return {
|
|
32686
|
-
refreshToken,
|
|
32687
|
-
projectId: projectId || undefined,
|
|
32688
|
-
managedProjectId: managedProjectId || undefined
|
|
32689
|
-
};
|
|
32690
|
-
}
|
|
32691
|
-
function getCachedAccess(refreshToken) {
|
|
32692
|
-
const cached3 = tokenCache.get(refreshToken);
|
|
32693
|
-
if (!cached3) {
|
|
32694
|
-
return;
|
|
32695
|
-
}
|
|
32696
|
-
if (cached3.expiresAt <= Date.now() + REFRESH_BUFFER_MS) {
|
|
32697
|
-
tokenCache.delete(refreshToken);
|
|
32698
|
-
return;
|
|
32699
|
-
}
|
|
32700
|
-
return cached3;
|
|
32701
|
-
}
|
|
32702
|
-
function cacheToken(refreshToken, accessToken, expiresAt) {
|
|
32703
|
-
if (!refreshToken || !accessToken) {
|
|
32704
|
-
return;
|
|
32705
|
-
}
|
|
32706
|
-
if (typeof expiresAt === "number" && Number.isFinite(expiresAt)) {
|
|
32707
|
-
tokenCache.set(refreshToken, { accessToken, expiresAt });
|
|
32708
|
-
}
|
|
32709
|
-
}
|
|
32710
|
-
async function requestToken(refreshToken) {
|
|
32711
|
-
const requestTime = Date.now();
|
|
32712
|
-
const response = await fetch(OAUTH_TOKEN_ENDPOINT, {
|
|
32713
|
-
method: "POST",
|
|
32714
|
-
headers: {
|
|
32715
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
32716
|
-
},
|
|
32717
|
-
body: new URLSearchParams({
|
|
32718
|
-
grant_type: "refresh_token",
|
|
32719
|
-
refresh_token: refreshToken,
|
|
32720
|
-
client_id: ANTIGRAVITY_CLIENT_ID,
|
|
32721
|
-
client_secret: ANTIGRAVITY_CLIENT_SECRET
|
|
32722
|
-
})
|
|
32723
|
-
});
|
|
32724
|
-
if (!response.ok) {
|
|
32725
|
-
const message = await readErrorMessage(response);
|
|
32726
|
-
throw new Error(message ?? `Request failed with status ${response.status}`);
|
|
32727
|
-
}
|
|
32728
|
-
const payload = await response.json();
|
|
32729
|
-
if (!payload.access_token) {
|
|
32730
|
-
throw new Error("Token refresh response missing access_token");
|
|
32731
|
-
}
|
|
32732
|
-
const expiresIn = typeof payload.expires_in === "number" && Number.isFinite(payload.expires_in) ? payload.expires_in : 3600;
|
|
32733
|
-
const expiresAt = expiresIn > 0 ? requestTime + expiresIn * 1000 : requestTime;
|
|
32734
|
-
return {
|
|
32735
|
-
accessToken: payload.access_token,
|
|
32736
|
-
expiresAt
|
|
32737
|
-
};
|
|
32738
|
-
}
|
|
32739
|
-
async function refreshAccessToken(refreshToken) {
|
|
32740
|
-
const result = await requestToken(refreshToken);
|
|
32741
|
-
cacheToken(refreshToken, result.accessToken, result.expiresAt);
|
|
32742
|
-
return result;
|
|
32743
|
-
}
|
|
32744
|
-
function buildMetadata(projectId) {
|
|
32745
|
-
const metadata = {
|
|
32746
|
-
ideType: "IDE_UNSPECIFIED",
|
|
32747
|
-
platform: "PLATFORM_UNSPECIFIED",
|
|
32748
|
-
pluginType: "GEMINI"
|
|
32749
|
-
};
|
|
32750
|
-
if (projectId) {
|
|
32751
|
-
metadata.duetProject = projectId;
|
|
32752
|
-
}
|
|
32753
|
-
return metadata;
|
|
32754
|
-
}
|
|
32755
|
-
async function loadManagedProject(accessToken, projectId, abortSignal) {
|
|
32756
|
-
const loadHeaders = {
|
|
32757
|
-
"Content-Type": "application/json",
|
|
32758
|
-
Authorization: `Bearer ${accessToken}`,
|
|
32759
|
-
"User-Agent": "google-api-nodejs-client/9.15.1",
|
|
32760
|
-
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
32761
|
-
"Client-Metadata": CODE_ASSIST_HEADERS["Client-Metadata"]
|
|
32762
|
-
};
|
|
32763
|
-
const requestBody = {
|
|
32764
|
-
metadata: buildMetadata(projectId)
|
|
32765
|
-
};
|
|
32766
|
-
const loadEndpoints = Array.from(new Set([...CODE_ASSIST_LOAD_ENDPOINTS, ...CODE_ASSIST_GENERATE_ENDPOINTS]));
|
|
32767
|
-
for (const baseEndpoint of loadEndpoints) {
|
|
32768
|
-
try {
|
|
32769
|
-
const response = await fetch(`${baseEndpoint}${GEMINI_CODE_ASSIST_LOAD_PATH}`, {
|
|
32770
|
-
method: "POST",
|
|
32771
|
-
headers: loadHeaders,
|
|
32772
|
-
body: JSON.stringify(requestBody),
|
|
32773
|
-
signal: abortSignal
|
|
32774
|
-
});
|
|
32775
|
-
if (!response.ok) {
|
|
32776
|
-
continue;
|
|
32777
|
-
}
|
|
32778
|
-
return await response.json();
|
|
32779
|
-
} catch {}
|
|
32780
|
-
}
|
|
32781
|
-
return null;
|
|
32782
|
-
}
|
|
32783
|
-
function extractManagedProjectId(payload) {
|
|
32784
|
-
if (!payload) {
|
|
32785
|
-
return;
|
|
32786
|
-
}
|
|
32787
|
-
const project = payload.cloudaicompanionProject;
|
|
32788
|
-
if (typeof project === "string" && project.trim() !== "") {
|
|
32789
|
-
return project;
|
|
32790
|
-
}
|
|
32791
|
-
if (project && typeof project === "object" && project.id) {
|
|
32792
|
-
const id = project.id;
|
|
32793
|
-
if (typeof id === "string" && id.trim() !== "") {
|
|
32794
|
-
return id;
|
|
32795
|
-
}
|
|
32796
|
-
}
|
|
32797
|
-
return;
|
|
32798
|
-
}
|
|
32799
|
-
async function resolveProjectId(accessToken, refreshToken, refreshParts, abortSignal) {
|
|
32800
|
-
if (refreshParts.managedProjectId) {
|
|
32801
|
-
return refreshParts.managedProjectId;
|
|
32802
|
-
}
|
|
32803
|
-
const cached3 = projectCache.get(refreshToken);
|
|
32804
|
-
if (cached3) {
|
|
32805
|
-
return cached3;
|
|
32806
|
-
}
|
|
32807
|
-
const fallbackProjectId = ANTIGRAVITY_DEFAULT_PROJECT_ID;
|
|
32808
|
-
const desiredProjectId = refreshParts.projectId ?? fallbackProjectId;
|
|
32809
|
-
const loadPayload = await loadManagedProject(accessToken, desiredProjectId, abortSignal);
|
|
32810
|
-
const resolvedManagedProjectId = extractManagedProjectId(loadPayload);
|
|
32811
|
-
if (resolvedManagedProjectId) {
|
|
32812
|
-
projectCache.set(refreshToken, resolvedManagedProjectId);
|
|
32813
|
-
return resolvedManagedProjectId;
|
|
32814
|
-
}
|
|
32815
|
-
if (refreshParts.projectId) {
|
|
32816
|
-
return refreshParts.projectId;
|
|
32817
|
-
}
|
|
32818
|
-
return fallbackProjectId;
|
|
32819
|
-
}
|
|
32820
|
-
function parseExpires(expires) {
|
|
32821
|
-
if (typeof expires === "number" && Number.isFinite(expires)) {
|
|
32822
|
-
return expires;
|
|
32823
|
-
}
|
|
32824
|
-
return;
|
|
32825
|
-
}
|
|
32826
|
-
function accessTokenExpired(accessToken, expiresAt) {
|
|
32827
|
-
if (!accessToken || typeof expiresAt !== "number") {
|
|
32828
|
-
return true;
|
|
32829
|
-
}
|
|
32830
|
-
return expiresAt <= Date.now() + REFRESH_BUFFER_MS;
|
|
32831
|
-
}
|
|
32832
|
-
async function requestGenerateContent(accessToken, projectId, model, query, abortSignal) {
|
|
32833
|
-
const requestPayload = {
|
|
32834
|
-
contents: [
|
|
32835
|
-
{
|
|
32836
|
-
role: "user",
|
|
32837
|
-
parts: [{ text: query }]
|
|
32838
|
-
}
|
|
32839
|
-
],
|
|
32840
|
-
tools: [{ googleSearch: {} }]
|
|
32841
|
-
};
|
|
32842
|
-
const body = JSON.stringify({
|
|
32843
|
-
project: projectId,
|
|
32844
|
-
model,
|
|
32845
|
-
request: requestPayload,
|
|
32846
|
-
requestType: "agent",
|
|
32847
|
-
userAgent: "antigravity",
|
|
32848
|
-
requestId: `agent-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`
|
|
32849
|
-
});
|
|
32850
|
-
const headers = {
|
|
32851
|
-
"Content-Type": "application/json",
|
|
32852
|
-
Authorization: `Bearer ${accessToken}`,
|
|
32853
|
-
"User-Agent": CODE_ASSIST_HEADERS["User-Agent"],
|
|
32854
|
-
"X-Goog-Api-Client": CODE_ASSIST_HEADERS["X-Goog-Api-Client"],
|
|
32855
|
-
"Client-Metadata": CODE_ASSIST_HEADERS["Client-Metadata"]
|
|
32856
|
-
};
|
|
32857
|
-
let lastError;
|
|
32858
|
-
for (const baseUrl of CODE_ASSIST_GENERATE_ENDPOINTS) {
|
|
32859
|
-
const response = await fetch(`${baseUrl}${GEMINI_CODE_ASSIST_GENERATE_PATH}`, {
|
|
32860
|
-
method: "POST",
|
|
32861
|
-
headers,
|
|
32862
|
-
body,
|
|
32863
|
-
signal: abortSignal
|
|
32864
|
-
});
|
|
32865
|
-
if (!response.ok) {
|
|
32866
|
-
const message = await readErrorMessage(response);
|
|
32867
|
-
if (response.status === 401 || response.status === 403) {
|
|
32868
|
-
return { ok: false, status: response.status, message };
|
|
32869
|
-
}
|
|
32870
|
-
lastError = { status: response.status, message };
|
|
32871
|
-
continue;
|
|
32872
|
-
}
|
|
32873
|
-
const text = await response.text();
|
|
32874
|
-
if (!text) {
|
|
32875
|
-
throw new Error("Empty response from Google Code Assist");
|
|
32876
|
-
}
|
|
32877
|
-
let parsed;
|
|
32878
|
-
try {
|
|
32879
|
-
parsed = JSON.parse(text);
|
|
32880
|
-
} catch {
|
|
32881
|
-
throw new Error("Invalid JSON response from Google Code Assist");
|
|
32882
|
-
}
|
|
32883
|
-
const effectiveResponse = extractGenerateContentResponse(parsed);
|
|
32884
|
-
if (!effectiveResponse) {
|
|
32885
|
-
throw new Error("Google Code Assist response did not include a valid response payload");
|
|
32886
|
-
}
|
|
32887
|
-
return { ok: true, body: effectiveResponse };
|
|
32888
|
-
}
|
|
32889
|
-
if (lastError) {
|
|
32890
|
-
return { ok: false, status: lastError.status, message: lastError.message };
|
|
32891
|
-
}
|
|
32892
|
-
return {
|
|
32893
|
-
ok: false,
|
|
32894
|
-
status: 502,
|
|
32895
|
-
message: "Request failed for all Google Code Assist endpoints."
|
|
32896
|
-
};
|
|
32897
|
-
}
|
|
32898
|
-
function createGeminiOAuthWebSearchClient(authDetails, model) {
|
|
32899
|
-
const refreshParts = parseRefresh(authDetails.refresh ?? "");
|
|
32900
|
-
const refreshToken = refreshParts.refreshToken;
|
|
32901
|
-
if (!refreshToken) {
|
|
32902
|
-
throw new Error("Missing Google OAuth refresh token");
|
|
32903
|
-
}
|
|
32904
|
-
const initialAccess = authDetails.access?.trim() ?? "";
|
|
32905
|
-
const initialExpires = parseExpires(authDetails.expires);
|
|
32906
|
-
return {
|
|
32907
|
-
async search(query, abortSignal) {
|
|
32908
|
-
const normalizedQuery = query.trim();
|
|
32909
|
-
const cached3 = getCachedAccess(refreshToken);
|
|
32910
|
-
let accessToken = cached3?.accessToken ?? initialAccess;
|
|
32911
|
-
let expiresAt = cached3?.expiresAt ?? initialExpires;
|
|
32912
|
-
let refreshedThisRequest = false;
|
|
32913
|
-
if (accessTokenExpired(accessToken, expiresAt)) {
|
|
32914
|
-
const refreshed2 = await refreshAccessToken(refreshToken);
|
|
32915
|
-
accessToken = refreshed2.accessToken;
|
|
32916
|
-
expiresAt = refreshed2.expiresAt;
|
|
32917
|
-
refreshedThisRequest = true;
|
|
32918
|
-
}
|
|
32919
|
-
if (!accessToken) {
|
|
32920
|
-
throw new Error("Missing Google OAuth access token");
|
|
32921
|
-
}
|
|
32922
|
-
if (typeof expiresAt === "number") {
|
|
32923
|
-
cacheToken(refreshToken, accessToken, expiresAt);
|
|
32924
|
-
}
|
|
32925
|
-
const effectiveProjectId = await resolveProjectId(accessToken, refreshToken, refreshParts, abortSignal);
|
|
32926
|
-
const firstAttempt = await requestGenerateContent(accessToken, effectiveProjectId, model, normalizedQuery, abortSignal);
|
|
32927
|
-
if (firstAttempt.ok) {
|
|
32928
|
-
return formatWebSearchResponse(firstAttempt.body, normalizedQuery);
|
|
32929
|
-
}
|
|
32930
|
-
const shouldRetry = (firstAttempt.status === 401 || firstAttempt.status === 403) && !refreshedThisRequest;
|
|
32931
|
-
if (!shouldRetry) {
|
|
32932
|
-
throw new Error(firstAttempt.message ?? `Request failed with status ${firstAttempt.status}`);
|
|
32933
|
-
}
|
|
32934
|
-
tokenCache.delete(refreshToken);
|
|
32935
|
-
const refreshed = await refreshAccessToken(refreshToken);
|
|
32936
|
-
accessToken = refreshed.accessToken;
|
|
32937
|
-
expiresAt = refreshed.expiresAt;
|
|
32938
|
-
refreshedThisRequest = true;
|
|
32939
|
-
cacheToken(refreshToken, accessToken, expiresAt);
|
|
32940
|
-
const retry = await requestGenerateContent(accessToken, effectiveProjectId, model, normalizedQuery, abortSignal);
|
|
32941
|
-
if (retry.ok) {
|
|
32942
|
-
return formatWebSearchResponse(retry.body, normalizedQuery);
|
|
32943
|
-
}
|
|
32944
|
-
throw new Error(retry.message ?? `Request failed with status ${retry.status}`);
|
|
32945
|
-
}
|
|
32946
|
-
};
|
|
32947
|
-
}
|
|
32948
|
-
function extractGenerateContentResponse(payload) {
|
|
32949
|
-
const candidateObject = (() => {
|
|
32950
|
-
if (Array.isArray(payload)) {
|
|
32951
|
-
for (const item of payload) {
|
|
32952
|
-
if (item && typeof item === "object") {
|
|
32953
|
-
return item;
|
|
32954
|
-
}
|
|
32955
|
-
}
|
|
32956
|
-
return;
|
|
32957
|
-
}
|
|
32958
|
-
if (payload && typeof payload === "object") {
|
|
32959
|
-
return payload;
|
|
32960
|
-
}
|
|
32961
|
-
return;
|
|
32962
|
-
})();
|
|
32963
|
-
if (!candidateObject) {
|
|
32964
|
-
return;
|
|
32965
|
-
}
|
|
32966
|
-
const withResponse = candidateObject;
|
|
32967
|
-
if (withResponse.response && typeof withResponse.response === "object") {
|
|
32968
|
-
return withResponse.response;
|
|
32969
|
-
}
|
|
32970
|
-
if (withResponse.candidates) {
|
|
32971
|
-
return candidateObject;
|
|
32972
|
-
}
|
|
32973
|
-
return;
|
|
32974
|
-
}
|
|
32975
|
-
async function readErrorMessage(response) {
|
|
32976
|
-
try {
|
|
32977
|
-
const text = await response.text();
|
|
32978
|
-
const trimmed = text.trim();
|
|
32979
|
-
return trimmed === "" ? undefined : trimmed;
|
|
32980
|
-
} catch {
|
|
32981
|
-
return;
|
|
32982
|
-
}
|
|
32983
|
-
}
|
|
32984
|
-
function createGeminiWebSearchClient(config4) {
|
|
32985
|
-
return new GeminiApiKeyClient(config4.apiKey, config4.model);
|
|
32986
|
-
}
|
|
32987
|
-
function createWebSearchClientForGoogle(authDetails, model) {
|
|
32988
|
-
if (authDetails.type === "api") {
|
|
32989
|
-
const apiKey = extractApiKey(authDetails);
|
|
32990
|
-
if (!apiKey) {
|
|
32991
|
-
throw new Error("Missing Google API key");
|
|
32992
|
-
}
|
|
32993
|
-
return createGeminiWebSearchClient({
|
|
32994
|
-
mode: "api",
|
|
32995
|
-
apiKey,
|
|
32996
|
-
model
|
|
32997
|
-
});
|
|
32998
|
-
}
|
|
32999
|
-
if (authDetails.type === "oauth") {
|
|
33000
|
-
const oauthAuth = authDetails;
|
|
33001
|
-
return createGeminiOAuthWebSearchClient(oauthAuth, model);
|
|
33002
|
-
}
|
|
33003
|
-
throw new Error("Unsupported auth type for Google web search");
|
|
33004
|
-
}
|
|
33005
|
-
function extractApiKey(authDetails) {
|
|
33006
|
-
if (!authDetails || authDetails.type !== "api") {
|
|
33007
|
-
return;
|
|
33008
|
-
}
|
|
33009
|
-
const normalized = authDetails.key.trim();
|
|
33010
|
-
return normalized === "" ? undefined : normalized;
|
|
33011
|
-
}
|
|
33012
|
-
function createGoogleWebsearchClient(model) {
|
|
33013
|
-
const normalizedModel = model.trim();
|
|
33014
|
-
if (!normalizedModel) {
|
|
33015
|
-
throw new Error("Invalid Google web search model");
|
|
33016
|
-
}
|
|
33017
|
-
return {
|
|
33018
|
-
async search(query, abortSignal, getAuth) {
|
|
33019
|
-
const normalizedQuery = query.trim();
|
|
33020
|
-
if (!normalizedQuery) {
|
|
33021
|
-
throw new Error("Query must not be empty");
|
|
33022
|
-
}
|
|
33023
|
-
const auth2 = await getAuth();
|
|
33024
|
-
if (!auth2) {
|
|
33025
|
-
throw new Error('Missing auth for provider "google"');
|
|
33026
|
-
}
|
|
33027
|
-
const client3 = createWebSearchClientForGoogle(auth2, normalizedModel);
|
|
33028
|
-
return client3.search(normalizedQuery, abortSignal);
|
|
33029
|
-
}
|
|
33030
|
-
};
|
|
33031
|
-
}
|
|
33032
|
-
var GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta", ANTIGRAVITY_ENDPOINT_DAILY = "https://daily-cloudcode-pa.sandbox.googleapis.com", ANTIGRAVITY_ENDPOINT_AUTOPUSH = "https://autopush-cloudcode-pa.sandbox.googleapis.com", ANTIGRAVITY_ENDPOINT_PROD = "https://cloudcode-pa.googleapis.com", GEMINI_CODE_ASSIST_GENERATE_PATH = "/v1internal:generateContent", GEMINI_CODE_ASSIST_LOAD_PATH = "/v1internal:loadCodeAssist", CODE_ASSIST_GENERATE_ENDPOINTS, CODE_ASSIST_LOAD_ENDPOINTS, ANTIGRAVITY_DEFAULT_PROJECT_ID = "rising-fact-p41fc", OAUTH_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token", ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com", ANTIGRAVITY_CLIENT_SECRET = "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", REFRESH_BUFFER_MS = 60000, CODE_ASSIST_HEADERS, tokenCache, projectCache;
|
|
33033
|
-
var init_google = __esm(() => {
|
|
33034
|
-
CODE_ASSIST_GENERATE_ENDPOINTS = [
|
|
33035
|
-
ANTIGRAVITY_ENDPOINT_DAILY,
|
|
33036
|
-
ANTIGRAVITY_ENDPOINT_AUTOPUSH,
|
|
33037
|
-
ANTIGRAVITY_ENDPOINT_PROD
|
|
33038
|
-
];
|
|
33039
|
-
CODE_ASSIST_LOAD_ENDPOINTS = [
|
|
33040
|
-
ANTIGRAVITY_ENDPOINT_PROD,
|
|
33041
|
-
ANTIGRAVITY_ENDPOINT_DAILY,
|
|
33042
|
-
ANTIGRAVITY_ENDPOINT_AUTOPUSH
|
|
33043
|
-
];
|
|
33044
|
-
CODE_ASSIST_HEADERS = {
|
|
33045
|
-
"User-Agent": "antigravity/1.11.5 windows/amd64",
|
|
33046
|
-
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
33047
|
-
"Client-Metadata": '{"ideType":"IDE_UNSPECIFIED","platform":"PLATFORM_UNSPECIFIED","pluginType":"GEMINI"}'
|
|
33048
|
-
};
|
|
33049
|
-
tokenCache = new Map;
|
|
33050
|
-
projectCache = new Map;
|
|
33051
|
-
});
|
|
33052
|
-
|
|
33053
|
-
// src/internals/plugins/websearch-cited/codex_prompt.txt
|
|
33054
|
-
var codex_prompt_default = `You are OpenCode, the best coding agent on the planet.
|
|
33055
|
-
|
|
33056
|
-
You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
33057
|
-
|
|
33058
|
-
## Editing constraints
|
|
33059
|
-
- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.
|
|
33060
|
-
- Only add comments if they are necessary to make a non-obvious block easier to understand.
|
|
33061
|
-
- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).
|
|
33062
|
-
|
|
33063
|
-
## Tool usage
|
|
33064
|
-
- Prefer specialized tools over shell for file operations:
|
|
33065
|
-
- Use Read to view files, Edit to modify files, and Write only when needed.
|
|
33066
|
-
- Use Glob to find files by name and Grep to search file contents.
|
|
33067
|
-
- Use Bash for terminal operations (git, bun, builds, tests, running scripts).
|
|
33068
|
-
- Run tool calls in parallel when neither call needs the other\u2019s output; otherwise run sequentially.
|
|
33069
|
-
|
|
33070
|
-
## Git and workspace hygiene
|
|
33071
|
-
- You may be in a dirty git worktree.
|
|
33072
|
-
* NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.
|
|
33073
|
-
* If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.
|
|
33074
|
-
* If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.
|
|
33075
|
-
* If the changes are in unrelated files, just ignore them and don't revert them.
|
|
33076
|
-
- Do not amend commits unless explicitly requested.
|
|
33077
|
-
- **NEVER** use destructive commands like \`git reset --hard\` or \`git checkout --\` unless specifically requested or approved by the user.
|
|
33078
|
-
|
|
33079
|
-
## Frontend tasks
|
|
33080
|
-
When doing frontend design tasks, avoid collapsing into bland, generic layouts.
|
|
33081
|
-
Aim for interfaces that feel intentional and deliberate.
|
|
33082
|
-
- Typography: Use expressive, purposeful fonts and avoid default stacks (Inter, Roboto, Arial, system).
|
|
33083
|
-
- Color & Look: Choose a clear visual direction; define CSS variables; avoid purple-on-white defaults. No purple bias or dark mode bias.
|
|
33084
|
-
- Motion: Use a few meaningful animations (page-load, staggered reveals) instead of generic micro-motions.
|
|
33085
|
-
- Background: Don't rely on flat, single-color backgrounds; use gradients, shapes, or subtle patterns to build atmosphere.
|
|
33086
|
-
- Overall: Avoid boilerplate layouts and interchangeable UI patterns. Vary themes, type families, and visual languages across outputs.
|
|
33087
|
-
- Ensure the page loads properly on both desktop and mobile.
|
|
33088
|
-
|
|
33089
|
-
Exception: If working within an existing website or design system, preserve the established patterns, structure, and visual language.
|
|
33090
|
-
|
|
33091
|
-
## Presenting your work and final message
|
|
33092
|
-
|
|
33093
|
-
You are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.
|
|
33094
|
-
|
|
33095
|
-
- Default: be very concise; friendly coding teammate tone.
|
|
33096
|
-
- Default: do the work without asking questions. Treat short tasks as sufficient direction; infer missing details by reading the codebase and following existing conventions.
|
|
33097
|
-
- Questions: only ask when you are truly blocked after checking relevant context AND you cannot safely pick a reasonable default. This usually means one of:
|
|
33098
|
-
* The request is ambiguous in a way that materially changes the result and you cannot disambiguate by reading the repo.
|
|
33099
|
-
* The action is destructive/irreversible, touches production, or changes billing/security posture.
|
|
33100
|
-
* You need a secret/credential/value that cannot be inferred (API key, account id, etc.).
|
|
33101
|
-
- If you must ask: do all non-blocked work first, then ask exactly one targeted question, include your recommended default, and state what would change based on the answer.
|
|
33102
|
-
- Never ask permission questions like "Should I proceed?" or "Do you want me to run tests?"; proceed with the most reasonable option and mention what you did.
|
|
33103
|
-
- For substantial work, summarize clearly; follow final\u2011answer formatting.
|
|
33104
|
-
- Skip heavy formatting for simple confirmations.
|
|
33105
|
-
- Don't dump large files you've written; reference paths only.
|
|
33106
|
-
- No "save/copy this file" - User is on the same machine.
|
|
33107
|
-
- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something.
|
|
33108
|
-
- For code changes:
|
|
33109
|
-
* Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in.
|
|
33110
|
-
* If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.
|
|
33111
|
-
* When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.
|
|
33112
|
-
- The user does not command execution outputs. When asked to show the output of a command (e.g. \`git show\`), relay the important details in your answer or summarize the key lines so the user understands the result.
|
|
33113
|
-
|
|
33114
|
-
## Final answer structure and style guidelines
|
|
33115
|
-
|
|
33116
|
-
- Plain text; CLI handles styling. Use structure only when it helps scannability.
|
|
33117
|
-
- Headers: optional; short Title Case (1-3 words) wrapped in **\u2026**; no blank line before the first bullet; add only if they truly help.
|
|
33118
|
-
- Bullets: use - ; merge related points; keep to one line when possible; 4\u20136 per list ordered by importance; keep phrasing consistent.
|
|
33119
|
-
- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.
|
|
33120
|
-
- Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.
|
|
33121
|
-
- Structure: group related bullets; order sections general \u2192 specific \u2192 supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.
|
|
33122
|
-
- Tone: collaborative, concise, factual; present tense, active voice; self\u2011contained; no "above/below"; parallel wording.
|
|
33123
|
-
- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short\u2014wrap/reformat if long; avoid naming formatting styles in answers.
|
|
33124
|
-
- Adaptation: code explanations \u2192 precise, structured with code refs; simple tasks \u2192 lead with outcome; big changes \u2192 logical walkthrough + rationale + next actions; casual one-offs \u2192 plain sentences, no headers/bullets.
|
|
33125
|
-
- File References: When referencing files in your response follow the below rules:
|
|
33126
|
-
* Use inline code to make file paths clickable.
|
|
33127
|
-
* Each reference should have a stand alone path. Even if it's the same file.
|
|
33128
|
-
* Accepted: absolute, workspace\u2011relative, a/ or b/ diff prefixes, or bare filename/suffix.
|
|
33129
|
-
* Optionally include line/column (1\u2011based): :line[:column] or #Lline[Ccolumn] (column defaults to 1).
|
|
33130
|
-
* Do not use URIs like file://, vscode://, or https://.
|
|
33131
|
-
* Do not provide range of lines
|
|
33132
|
-
* Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5
|
|
33133
|
-
`;
|
|
33134
|
-
var init_codex_prompt = () => {};
|
|
33135
|
-
|
|
33136
|
-
// src/internals/plugins/websearch-cited/openai.ts
|
|
33137
|
-
function buildWebSearchUserPrompt(query) {
|
|
33138
|
-
const normalized = query.trim();
|
|
33139
|
-
return `perform web search on "${normalized}". Return results with inline citations (**only** source index like [1], no URL in the answer) and end with a Sources list of URLs.`;
|
|
33140
|
-
}
|
|
33141
|
-
function getAccessToken(auth2) {
|
|
33142
|
-
if (auth2.type === "oauth") {
|
|
33143
|
-
const access = auth2.access.trim();
|
|
33144
|
-
if (!access) {
|
|
33145
|
-
throw new Error("Missing OpenAI OAuth access token");
|
|
33146
|
-
}
|
|
33147
|
-
return access;
|
|
33148
|
-
}
|
|
33149
|
-
if (auth2.type === "api") {
|
|
33150
|
-
const key = auth2.key.trim();
|
|
33151
|
-
if (!key) {
|
|
33152
|
-
throw new Error("Missing OpenAI API key");
|
|
33153
|
-
}
|
|
33154
|
-
return key;
|
|
33155
|
-
}
|
|
33156
|
-
const token = auth2.token.trim();
|
|
33157
|
-
if (!token) {
|
|
33158
|
-
throw new Error("Missing OpenAI token");
|
|
33159
|
-
}
|
|
33160
|
-
return token;
|
|
33161
|
-
}
|
|
33162
|
-
function extractChatGPTAccountId(auth2) {
|
|
33163
|
-
if (auth2.type !== "oauth") {
|
|
33164
|
-
return;
|
|
33165
|
-
}
|
|
33166
|
-
const access = auth2.access.trim();
|
|
33167
|
-
if (!access) {
|
|
33168
|
-
return;
|
|
33169
|
-
}
|
|
33170
|
-
const parts = access.split(".");
|
|
33171
|
-
if (parts.length !== 3) {
|
|
33172
|
-
return;
|
|
33173
|
-
}
|
|
33174
|
-
try {
|
|
33175
|
-
const payload = parts[1];
|
|
33176
|
-
if (!payload) {
|
|
33177
|
-
return;
|
|
33178
|
-
}
|
|
33179
|
-
const decoded = Buffer.from(payload, "base64").toString("utf8");
|
|
33180
|
-
const parsed = JSON.parse(decoded);
|
|
33181
|
-
if (!parsed || typeof parsed !== "object") {
|
|
33182
|
-
return;
|
|
33183
|
-
}
|
|
33184
|
-
const root = parsed;
|
|
33185
|
-
const claim = root["https://api.openai.com/auth"];
|
|
33186
|
-
if (!claim || typeof claim !== "object") {
|
|
33187
|
-
return;
|
|
33188
|
-
}
|
|
33189
|
-
const accountId = claim.chatgpt_account_id;
|
|
33190
|
-
if (typeof accountId !== "string") {
|
|
33191
|
-
return;
|
|
33192
|
-
}
|
|
33193
|
-
const trimmed = accountId.trim();
|
|
33194
|
-
return trimmed === "" ? undefined : trimmed;
|
|
33195
|
-
} catch {
|
|
33196
|
-
return;
|
|
33197
|
-
}
|
|
33198
|
-
}
|
|
33199
|
-
async function runOpenAIWebSearch(options) {
|
|
33200
|
-
const normalizedModel = options.model.trim();
|
|
33201
|
-
if (!normalizedModel) {
|
|
33202
|
-
throw new Error("Invalid OpenAI web search model");
|
|
33203
|
-
}
|
|
33204
|
-
const normalizedQuery = options.query.trim();
|
|
33205
|
-
if (!normalizedQuery) {
|
|
33206
|
-
throw new Error("Query must not be empty");
|
|
33207
|
-
}
|
|
33208
|
-
const accessToken = getAccessToken(options.auth);
|
|
33209
|
-
const isOAuth = options.auth.type === "oauth";
|
|
33210
|
-
const body = {
|
|
33211
|
-
model: normalizedModel,
|
|
33212
|
-
instructions: "",
|
|
33213
|
-
input: [
|
|
33214
|
-
{
|
|
33215
|
-
role: "user",
|
|
33216
|
-
content: [
|
|
33217
|
-
{
|
|
33218
|
-
type: "input_text",
|
|
33219
|
-
text: buildWebSearchUserPrompt(normalizedQuery)
|
|
33220
|
-
}
|
|
33221
|
-
]
|
|
33222
|
-
}
|
|
33223
|
-
],
|
|
33224
|
-
tools: [{ type: "web_search" }],
|
|
33225
|
-
include: ["web_search_call.action.sources"]
|
|
33226
|
-
};
|
|
33227
|
-
if (options.reasoningEffort || options.reasoningSummary) {
|
|
33228
|
-
body.reasoning = {
|
|
33229
|
-
effort: options.reasoningEffort,
|
|
33230
|
-
summary: options.reasoningSummary
|
|
33231
|
-
};
|
|
33232
|
-
}
|
|
33233
|
-
body.store = false;
|
|
33234
|
-
if (options.textVerbosity) {
|
|
33235
|
-
body.text = {
|
|
33236
|
-
verbosity: options.textVerbosity
|
|
33237
|
-
};
|
|
33238
|
-
}
|
|
33239
|
-
if (Array.isArray(options.include) && options.include.length > 0) {
|
|
33240
|
-
const filtered = options.include.filter((value) => typeof value === "string" && value.trim() !== "");
|
|
33241
|
-
if (filtered.length > 0) {
|
|
33242
|
-
body.include = filtered;
|
|
33243
|
-
}
|
|
33244
|
-
}
|
|
33245
|
-
body.stream = true;
|
|
33246
|
-
body.tool_choice = "auto";
|
|
33247
|
-
body.parallel_tool_calls = true;
|
|
33248
|
-
if (isOAuth) {
|
|
33249
|
-
body.instructions = codex_prompt_default;
|
|
33250
|
-
} else {
|
|
33251
|
-
body.instructions = "You are an AI assistant answering a single web search query for the user.";
|
|
33252
|
-
}
|
|
33253
|
-
const url3 = isOAuth ? "https://chatgpt.com/backend-api/codex/responses" : "https://api.openai.com/v1/responses";
|
|
33254
|
-
const headers = {
|
|
33255
|
-
Authorization: `Bearer ${accessToken}`,
|
|
33256
|
-
"Content-Type": "application/json",
|
|
33257
|
-
"OpenAI-Beta": "responses=experimental"
|
|
33258
|
-
};
|
|
33259
|
-
if (isOAuth) {
|
|
33260
|
-
const accountId = extractChatGPTAccountId(options.auth);
|
|
33261
|
-
if (accountId) {
|
|
33262
|
-
headers["chatgpt-account-id"] = accountId;
|
|
33263
|
-
}
|
|
33264
|
-
headers.originator = "codex_cli_rs";
|
|
33265
|
-
}
|
|
33266
|
-
const response = await fetch(url3, {
|
|
33267
|
-
method: "POST",
|
|
33268
|
-
headers,
|
|
33269
|
-
body: JSON.stringify(body),
|
|
33270
|
-
signal: options.abortSignal
|
|
33271
|
-
});
|
|
33272
|
-
if (!response.ok) {
|
|
33273
|
-
const message = await buildErrorDetails(response, url3, body);
|
|
33274
|
-
throw new Error(message);
|
|
33275
|
-
}
|
|
33276
|
-
const payload = await readOpenAIResponsePayload(response);
|
|
33277
|
-
const text = extractOpenAIText(payload);
|
|
33278
|
-
if (!text || !text.trim()) {
|
|
33279
|
-
return `Web search completed for "${normalizedQuery}", but no results were returned.`;
|
|
33280
|
-
}
|
|
33281
|
-
return text;
|
|
33282
|
-
}
|
|
33283
|
-
function createOpenAIWebsearchClient(model, config4) {
|
|
33284
|
-
const normalizedModel = model.trim();
|
|
33285
|
-
if (!normalizedModel) {
|
|
33286
|
-
throw new Error("Invalid OpenAI web search model");
|
|
33287
|
-
}
|
|
33288
|
-
return {
|
|
33289
|
-
async search(query, abortSignal, getAuth) {
|
|
33290
|
-
const normalizedQuery = query.trim();
|
|
33291
|
-
if (!normalizedQuery) {
|
|
33292
|
-
throw new Error("Query must not be empty");
|
|
33293
|
-
}
|
|
33294
|
-
const auth2 = await getAuth();
|
|
33295
|
-
if (!auth2) {
|
|
33296
|
-
throw new Error('Missing auth for provider "openai"');
|
|
33297
|
-
}
|
|
33298
|
-
return runOpenAIWebSearch({
|
|
33299
|
-
model: normalizedModel,
|
|
33300
|
-
query: normalizedQuery,
|
|
33301
|
-
abortSignal,
|
|
33302
|
-
auth: auth2,
|
|
33303
|
-
reasoningEffort: config4.reasoningEffort,
|
|
33304
|
-
reasoningSummary: config4.reasoningSummary,
|
|
33305
|
-
textVerbosity: config4.textVerbosity,
|
|
33306
|
-
store: config4.store,
|
|
33307
|
-
include: config4.include
|
|
33308
|
-
});
|
|
33309
|
-
}
|
|
33310
|
-
};
|
|
33311
|
-
}
|
|
33312
|
-
function extractOpenAIText(payload) {
|
|
33313
|
-
if (!payload || typeof payload !== "object") {
|
|
33314
|
-
return;
|
|
33315
|
-
}
|
|
33316
|
-
const root = payload;
|
|
33317
|
-
const output = root.output;
|
|
33318
|
-
if (!Array.isArray(output) || output.length === 0) {
|
|
33319
|
-
return;
|
|
33320
|
-
}
|
|
33321
|
-
let combined = "";
|
|
33322
|
-
for (const item of output) {
|
|
33323
|
-
if (!item || typeof item !== "object") {
|
|
33324
|
-
continue;
|
|
33325
|
-
}
|
|
33326
|
-
const content = item.content;
|
|
33327
|
-
if (!Array.isArray(content)) {
|
|
33328
|
-
continue;
|
|
33329
|
-
}
|
|
33330
|
-
for (const part of content) {
|
|
33331
|
-
if (!part || typeof part !== "object") {
|
|
33332
|
-
continue;
|
|
33333
|
-
}
|
|
33334
|
-
const kind = part.type;
|
|
33335
|
-
if (kind !== "output_text") {
|
|
33336
|
-
continue;
|
|
33337
|
-
}
|
|
33338
|
-
const textField = part.text;
|
|
33339
|
-
if (typeof textField === "string") {
|
|
33340
|
-
combined += textField;
|
|
33341
|
-
} else if (textField && typeof textField === "object") {
|
|
33342
|
-
const obj = textField;
|
|
33343
|
-
if (typeof obj.value === "string") {
|
|
33344
|
-
combined += obj.value;
|
|
33345
|
-
}
|
|
33346
|
-
}
|
|
33347
|
-
}
|
|
33348
|
-
}
|
|
33349
|
-
return combined || undefined;
|
|
33350
|
-
}
|
|
33351
|
-
async function buildErrorDetails(response, url3, body) {
|
|
33352
|
-
const parts = [];
|
|
33353
|
-
parts.push(`status=${response.status}`);
|
|
33354
|
-
parts.push(`url=${url3}`);
|
|
33355
|
-
const safeBody = { ...body };
|
|
33356
|
-
if (typeof safeBody.instructions === "string") {
|
|
33357
|
-
const value = safeBody.instructions;
|
|
33358
|
-
const maxLength = 512;
|
|
33359
|
-
if (value.length > maxLength) {
|
|
33360
|
-
const headLength = 256;
|
|
33361
|
-
const tailLength = 128;
|
|
33362
|
-
const head = value.slice(0, headLength);
|
|
33363
|
-
const tail = value.slice(-tailLength);
|
|
33364
|
-
const omitted = value.length - headLength - tailLength;
|
|
33365
|
-
safeBody.instructions = `${head} ... [${omitted} chars truncated] ... ${tail}`;
|
|
33366
|
-
}
|
|
33367
|
-
}
|
|
33368
|
-
parts.push(`requestBody=${JSON.stringify(safeBody)}`);
|
|
33369
|
-
let rawText;
|
|
33370
|
-
try {
|
|
33371
|
-
rawText = await response.text();
|
|
33372
|
-
} catch {}
|
|
33373
|
-
if (rawText) {
|
|
33374
|
-
let parsedMessage;
|
|
33375
|
-
try {
|
|
33376
|
-
const parsed = JSON.parse(rawText);
|
|
33377
|
-
const message = parsed.error?.message;
|
|
33378
|
-
if (typeof message === "string" && message.trim() !== "") {
|
|
33379
|
-
parsedMessage = message.trim();
|
|
33380
|
-
}
|
|
33381
|
-
} catch {}
|
|
33382
|
-
if (parsedMessage) {
|
|
33383
|
-
parts.unshift(`error=${parsedMessage}`);
|
|
33384
|
-
}
|
|
33385
|
-
parts.push(`responseBody=${rawText}`);
|
|
33386
|
-
}
|
|
33387
|
-
return parts.join(" | ");
|
|
33388
|
-
}
|
|
33389
|
-
async function readOpenAIResponsePayload(response) {
|
|
33390
|
-
const text = await response.text();
|
|
33391
|
-
const trimmed = text.trim();
|
|
33392
|
-
if (trimmed === "") {
|
|
33393
|
-
return {};
|
|
33394
|
-
}
|
|
33395
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
33396
|
-
try {
|
|
33397
|
-
const parsed = JSON.parse(trimmed);
|
|
33398
|
-
return parsed;
|
|
33399
|
-
} catch {}
|
|
33400
|
-
}
|
|
33401
|
-
const extracted = extractOpenAIResponseFromSse(text);
|
|
33402
|
-
if (extracted !== undefined) {
|
|
33403
|
-
return extracted;
|
|
33404
|
-
}
|
|
33405
|
-
throw new Error("Failed to parse JSON");
|
|
33406
|
-
}
|
|
33407
|
-
function extractOpenAIResponseFromSse(sseText) {
|
|
33408
|
-
const lines = sseText.split(`
|
|
33409
|
-
`);
|
|
33410
|
-
for (const line of lines) {
|
|
33411
|
-
if (!line.startsWith("data: ")) {
|
|
33412
|
-
continue;
|
|
33413
|
-
}
|
|
33414
|
-
const payload = line.slice(6).trim();
|
|
33415
|
-
if (!payload || payload === "[DONE]") {
|
|
33416
|
-
continue;
|
|
33417
|
-
}
|
|
33418
|
-
try {
|
|
33419
|
-
const parsed = JSON.parse(payload);
|
|
33420
|
-
const kind = parsed.type ?? "";
|
|
33421
|
-
if (kind === "response.done" || kind === "response.completed") {
|
|
33422
|
-
return parsed.response;
|
|
33423
|
-
}
|
|
33424
|
-
} catch {}
|
|
33425
|
-
}
|
|
33426
|
-
return;
|
|
33427
|
-
}
|
|
33428
|
-
var init_openai = __esm(() => {
|
|
33429
|
-
init_codex_prompt();
|
|
33430
|
-
});
|
|
33431
|
-
|
|
33432
|
-
// src/internals/plugins/websearch-cited/openrouter.ts
|
|
33433
|
-
function buildWebSearchUserPrompt2(query) {
|
|
33434
|
-
const normalized = query.trim();
|
|
33435
|
-
return `perform web search on "${normalized}". Return results with inline citations (**only** source index like [1], no URL in the answer) and end with a Sources list of URLs.`;
|
|
33436
|
-
}
|
|
33437
|
-
function getApiKey(auth2) {
|
|
33438
|
-
if (auth2.type !== "api") {
|
|
33439
|
-
throw new Error("OpenRouter only supports API key authentication");
|
|
33440
|
-
}
|
|
33441
|
-
const key = auth2.key.trim();
|
|
33442
|
-
if (!key) {
|
|
33443
|
-
throw new Error("Missing OpenRouter API key");
|
|
33444
|
-
}
|
|
33445
|
-
return key;
|
|
33446
|
-
}
|
|
33447
|
-
function extractOutputText(payload) {
|
|
33448
|
-
if (!payload || typeof payload !== "object") {
|
|
33449
|
-
return;
|
|
33450
|
-
}
|
|
33451
|
-
const root = payload;
|
|
33452
|
-
const direct = root.output_text;
|
|
33453
|
-
if (typeof direct === "string" && direct.trim() !== "") {
|
|
33454
|
-
return direct;
|
|
33455
|
-
}
|
|
33456
|
-
const output = root.output;
|
|
33457
|
-
if (!Array.isArray(output) || output.length === 0) {
|
|
33458
|
-
return;
|
|
33459
|
-
}
|
|
33460
|
-
let combined = "";
|
|
33461
|
-
for (const item of output) {
|
|
33462
|
-
if (item.type !== "message") {
|
|
33463
|
-
continue;
|
|
33464
|
-
}
|
|
33465
|
-
const content = item.content;
|
|
33466
|
-
if (!Array.isArray(content)) {
|
|
33467
|
-
continue;
|
|
33468
|
-
}
|
|
33469
|
-
for (const part of content) {
|
|
33470
|
-
if (part.type !== "output_text") {
|
|
33471
|
-
continue;
|
|
33472
|
-
}
|
|
33473
|
-
const text = part.text;
|
|
33474
|
-
if (typeof text === "string") {
|
|
33475
|
-
combined += text;
|
|
33476
|
-
}
|
|
33477
|
-
}
|
|
33478
|
-
}
|
|
33479
|
-
return combined || undefined;
|
|
33480
|
-
}
|
|
33481
|
-
async function runOpenRouterWebSearch(options) {
|
|
33482
|
-
const normalizedModel = options.model.trim();
|
|
33483
|
-
if (!normalizedModel) {
|
|
33484
|
-
throw new Error("Invalid OpenRouter web search model");
|
|
33485
|
-
}
|
|
33486
|
-
const normalizedQuery = options.query.trim();
|
|
33487
|
-
if (!normalizedQuery) {
|
|
33488
|
-
throw new Error("Query must not be empty");
|
|
33489
|
-
}
|
|
33490
|
-
const apiKey = getApiKey(options.auth);
|
|
33491
|
-
const body = {
|
|
33492
|
-
model: normalizedModel,
|
|
33493
|
-
input: buildWebSearchUserPrompt2(normalizedQuery),
|
|
33494
|
-
plugins: [
|
|
33495
|
-
{
|
|
33496
|
-
id: "web",
|
|
33497
|
-
search_prompt: buildWebSearchUserPrompt2(normalizedQuery)
|
|
33498
|
-
}
|
|
33499
|
-
],
|
|
33500
|
-
store: false,
|
|
33501
|
-
stream: false
|
|
33502
|
-
};
|
|
33503
|
-
const response = await fetch(OPENROUTER_RESPONSES_ENDPOINT, {
|
|
33504
|
-
method: "POST",
|
|
33505
|
-
headers: {
|
|
33506
|
-
Authorization: `Bearer ${apiKey}`,
|
|
33507
|
-
"Content-Type": "application/json"
|
|
33508
|
-
},
|
|
33509
|
-
body: JSON.stringify(body),
|
|
33510
|
-
signal: options.abortSignal
|
|
33511
|
-
});
|
|
33512
|
-
if (!response.ok) {
|
|
33513
|
-
const text = await response.text().catch(() => "");
|
|
33514
|
-
const details = text.trim() !== "" ? ` | responseBody=${text}` : "";
|
|
33515
|
-
throw new Error(`status=${response.status} | url=${OPENROUTER_RESPONSES_ENDPOINT} | requestBody=${JSON.stringify(body)}${details}`);
|
|
33516
|
-
}
|
|
33517
|
-
const payload = await response.json();
|
|
33518
|
-
const outputText = extractOutputText(payload);
|
|
33519
|
-
if (!outputText || !outputText.trim()) {
|
|
33520
|
-
return `Web search completed for "${normalizedQuery}", but no results were returned.`;
|
|
33521
|
-
}
|
|
33522
|
-
return outputText;
|
|
33523
|
-
}
|
|
33524
|
-
function createOpenRouterWebsearchClient(model) {
|
|
33525
|
-
const normalizedModel = model.trim();
|
|
33526
|
-
if (!normalizedModel) {
|
|
33527
|
-
throw new Error("Invalid OpenRouter web search model");
|
|
33528
|
-
}
|
|
33529
|
-
return {
|
|
33530
|
-
async search(query, abortSignal, getAuth) {
|
|
33531
|
-
const normalizedQuery = query.trim();
|
|
33532
|
-
if (!normalizedQuery) {
|
|
33533
|
-
throw new Error("Query must not be empty");
|
|
33534
|
-
}
|
|
33535
|
-
const auth2 = await getAuth();
|
|
33536
|
-
if (!auth2) {
|
|
33537
|
-
throw new Error('Missing auth for provider "openrouter"');
|
|
33538
|
-
}
|
|
33539
|
-
return runOpenRouterWebSearch({
|
|
33540
|
-
model: normalizedModel,
|
|
33541
|
-
query: normalizedQuery,
|
|
33542
|
-
abortSignal,
|
|
33543
|
-
auth: auth2
|
|
33544
|
-
});
|
|
33545
|
-
}
|
|
33546
|
-
};
|
|
33547
|
-
}
|
|
33548
|
-
var OPENROUTER_RESPONSES_ENDPOINT = "https://openrouter.ai/api/v1/responses";
|
|
33549
|
-
|
|
33550
|
-
// src/internals/plugins/websearch-cited/index.ts
|
|
33551
|
-
var exports_websearch_cited = {};
|
|
33552
|
-
__export(exports_websearch_cited, {
|
|
33553
|
-
resolveGetAuth: () => resolveGetAuth,
|
|
33554
|
-
registerGetAuth: () => registerGetAuth,
|
|
33555
|
-
default: () => websearch_cited_default,
|
|
33556
|
-
WebsearchCitedOpenAIPlugin: () => WebsearchCitedOpenAIPlugin,
|
|
33557
|
-
WebsearchCitedGooglePlugin: () => WebsearchCitedGooglePlugin,
|
|
33558
|
-
OPENROUTER_PROVIDER_ID: () => OPENROUTER_PROVIDER_ID,
|
|
33559
|
-
OPENAI_PROVIDER_ID: () => OPENAI_PROVIDER_ID,
|
|
33560
|
-
GOOGLE_PROVIDER_ID: () => GOOGLE_PROVIDER_ID
|
|
33561
|
-
});
|
|
33562
|
-
function isRecord17(value) {
|
|
33563
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
33564
|
-
}
|
|
33565
|
-
function registerGetAuth(providerID, getAuth) {
|
|
33566
|
-
authRegistry.set(providerID, getAuth);
|
|
33567
|
-
}
|
|
33568
|
-
function resolveGetAuth(providerID) {
|
|
33569
|
-
return authRegistry.get(providerID);
|
|
33570
|
-
}
|
|
33571
|
-
function findFirstWebsearchCitedConfig(config4) {
|
|
33572
|
-
const providers = config4.provider;
|
|
33573
|
-
if (!providers || typeof providers !== "object") {
|
|
33574
|
-
return {};
|
|
33575
|
-
}
|
|
33576
|
-
let firstError;
|
|
33577
|
-
for (const [providerID, providerConfig] of Object.entries(providers)) {
|
|
33578
|
-
if (!providerConfig || typeof providerConfig !== "object") {
|
|
33579
|
-
continue;
|
|
33580
|
-
}
|
|
33581
|
-
const options = providerConfig.options;
|
|
33582
|
-
if (!isRecord17(options)) {
|
|
33583
|
-
continue;
|
|
33584
|
-
}
|
|
33585
|
-
if (!("websearch_cited" in options)) {
|
|
33586
|
-
continue;
|
|
33587
|
-
}
|
|
33588
|
-
const cited = options.websearch_cited;
|
|
33589
|
-
if (!isRecord17(cited)) {
|
|
33590
|
-
firstError ??= `Invalid websearch_cited configuration for provider "${providerID}".`;
|
|
33591
|
-
continue;
|
|
33592
|
-
}
|
|
33593
|
-
const candidate = cited.model;
|
|
33594
|
-
if (typeof candidate !== "string" || candidate.trim() === "") {
|
|
33595
|
-
firstError ??= `Missing websearch_cited model for provider "${providerID}".`;
|
|
33596
|
-
continue;
|
|
33597
|
-
}
|
|
33598
|
-
if (providerID !== GOOGLE_PROVIDER_ID && providerID !== OPENAI_PROVIDER_ID && providerID !== OPENROUTER_PROVIDER_ID) {
|
|
33599
|
-
firstError ??= `Unsupported provider "${providerID}" for websearch_cited.`;
|
|
33600
|
-
continue;
|
|
33601
|
-
}
|
|
33602
|
-
return {
|
|
33603
|
-
selected: {
|
|
33604
|
-
providerID,
|
|
33605
|
-
model: candidate.trim()
|
|
33606
|
-
}
|
|
33607
|
-
};
|
|
33608
|
-
}
|
|
33609
|
-
return firstError ? { error: firstError } : {};
|
|
33610
|
-
}
|
|
33611
|
-
function parseOpenAIOptions(providerConfig, model) {
|
|
33612
|
-
if (!isRecord17(providerConfig)) {
|
|
33613
|
-
return {};
|
|
33614
|
-
}
|
|
33615
|
-
const providerRecord = providerConfig;
|
|
33616
|
-
const rawOptions = providerRecord.options;
|
|
33617
|
-
const baseOptions = isRecord17(rawOptions) ? rawOptions : undefined;
|
|
33618
|
-
let modelOptions;
|
|
33619
|
-
const rawModels = providerRecord.models;
|
|
33620
|
-
if (model && isRecord17(rawModels)) {
|
|
33621
|
-
const modelsRecord = rawModels;
|
|
33622
|
-
const entry = modelsRecord[model];
|
|
33623
|
-
if (isRecord17(entry)) {
|
|
33624
|
-
const entryOptions = entry.options;
|
|
33625
|
-
if (isRecord17(entryOptions)) {
|
|
33626
|
-
modelOptions = entryOptions;
|
|
33627
|
-
}
|
|
33628
|
-
}
|
|
33629
|
-
}
|
|
33630
|
-
const merged = {
|
|
33631
|
-
...baseOptions ?? {},
|
|
33632
|
-
...modelOptions ?? {}
|
|
33633
|
-
};
|
|
33634
|
-
const result = {};
|
|
33635
|
-
const reasoningEffort = merged.reasoningEffort;
|
|
33636
|
-
if (typeof reasoningEffort === "string" && reasoningEffort.trim() !== "") {
|
|
33637
|
-
result.reasoningEffort = reasoningEffort.trim();
|
|
33638
|
-
}
|
|
33639
|
-
const reasoningSummary = merged.reasoningSummary;
|
|
33640
|
-
if (typeof reasoningSummary === "string" && reasoningSummary.trim() !== "") {
|
|
33641
|
-
result.reasoningSummary = reasoningSummary.trim();
|
|
33642
|
-
}
|
|
33643
|
-
const textVerbosity = merged.textVerbosity;
|
|
33644
|
-
if (typeof textVerbosity === "string" && textVerbosity.trim() !== "") {
|
|
33645
|
-
result.textVerbosity = textVerbosity.trim();
|
|
33646
|
-
}
|
|
33647
|
-
const store2 = merged.store;
|
|
33648
|
-
if (typeof store2 === "boolean") {
|
|
33649
|
-
result.store = store2;
|
|
33650
|
-
}
|
|
33651
|
-
const include = merged.include;
|
|
33652
|
-
if (Array.isArray(include)) {
|
|
33653
|
-
const filtered = include.filter((value) => typeof value === "string" && value.trim() !== "");
|
|
33654
|
-
if (filtered.length > 0) {
|
|
33655
|
-
result.include = filtered;
|
|
33656
|
-
}
|
|
33657
|
-
}
|
|
33658
|
-
return result;
|
|
33659
|
-
}
|
|
33660
|
-
var GOOGLE_PROVIDER_ID = "google", OPENAI_PROVIDER_ID = "openai", OPENROUTER_PROVIDER_ID = "openrouter", CITED_SEARCH_TOOL_DESCRIPTION = "Performs a Gemini-style grounded web search: returns a concise digest with inline citations and a Sources list of URLs. NOTE: for LLM rate limits, DO NOT parallel this tool > 5", WEBSEARCH_ARGS, WEBSEARCH_ALLOWED_KEYS, WEBSEARCH_ALLOWED_KEYS_DESCRIPTION, authRegistry, WebsearchCitedPlugin = () => {
|
|
33661
|
-
let selectedProvider;
|
|
33662
|
-
let selectedModel;
|
|
33663
|
-
let openaiConfig = {};
|
|
33664
|
-
let configError;
|
|
33665
|
-
return Promise.resolve({
|
|
33666
|
-
auth: {
|
|
33667
|
-
provider: OPENROUTER_PROVIDER_ID,
|
|
33668
|
-
loader(getAuth) {
|
|
33669
|
-
registerGetAuth(OPENROUTER_PROVIDER_ID, getAuth);
|
|
33670
|
-
return Promise.resolve({});
|
|
33671
|
-
},
|
|
33672
|
-
methods: [
|
|
33673
|
-
{
|
|
33674
|
-
type: "api",
|
|
33675
|
-
label: "OpenRouter API key"
|
|
33676
|
-
}
|
|
33677
|
-
]
|
|
33678
|
-
},
|
|
33679
|
-
config: (config4) => {
|
|
33680
|
-
const { selected, error: error92 } = findFirstWebsearchCitedConfig(config4);
|
|
33681
|
-
selectedProvider = undefined;
|
|
33682
|
-
selectedModel = undefined;
|
|
33683
|
-
openaiConfig = {};
|
|
33684
|
-
configError = error92;
|
|
33685
|
-
if (selected) {
|
|
33686
|
-
selectedProvider = selected.providerID;
|
|
33687
|
-
selectedModel = selected.model;
|
|
33688
|
-
if (selectedProvider === OPENAI_PROVIDER_ID) {
|
|
33689
|
-
const openaiProvider = config4.provider?.openai;
|
|
33690
|
-
openaiConfig = parseOpenAIOptions(openaiProvider, selectedModel);
|
|
33691
|
-
}
|
|
33692
|
-
}
|
|
33693
|
-
return Promise.resolve();
|
|
33694
|
-
},
|
|
33695
|
-
tool: {
|
|
33696
|
-
websearch_cited: tool({
|
|
33697
|
-
description: CITED_SEARCH_TOOL_DESCRIPTION,
|
|
33698
|
-
args: WEBSEARCH_ARGS,
|
|
33699
|
-
async execute(args, context) {
|
|
33700
|
-
const argKeys = Object.keys(args ?? {});
|
|
33701
|
-
const extraKeys = argKeys.filter((key) => !WEBSEARCH_ALLOWED_KEYS.has(key));
|
|
33702
|
-
if (extraKeys.length > 0) {
|
|
33703
|
-
throw new Error(`Unknown argument(s): ${extraKeys.join(", ")}, only ${WEBSEARCH_ALLOWED_KEYS_DESCRIPTION} supported.`);
|
|
33704
|
-
}
|
|
33705
|
-
const query = args.query?.trim();
|
|
33706
|
-
if (!query) {
|
|
33707
|
-
throw new Error("The 'query' parameter cannot be empty.");
|
|
33708
|
-
}
|
|
33709
|
-
if (configError) {
|
|
33710
|
-
throw new Error(configError);
|
|
33711
|
-
}
|
|
33712
|
-
if (!selectedProvider || !selectedModel) {
|
|
33713
|
-
throw new Error("Missing web search model configuration.");
|
|
33714
|
-
}
|
|
33715
|
-
if (selectedProvider === OPENAI_PROVIDER_ID) {
|
|
33716
|
-
const getAuth2 = resolveGetAuth(OPENAI_PROVIDER_ID);
|
|
33717
|
-
if (!getAuth2) {
|
|
33718
|
-
throw new Error('Missing auth for provider "openai". Authenticate via `opencode auth login`.');
|
|
33719
|
-
}
|
|
33720
|
-
const client4 = createOpenAIWebsearchClient(selectedModel, openaiConfig);
|
|
33721
|
-
return client4.search(query, context.abort, getAuth2);
|
|
33722
|
-
}
|
|
33723
|
-
if (selectedProvider === OPENROUTER_PROVIDER_ID) {
|
|
33724
|
-
const getAuth2 = resolveGetAuth(OPENROUTER_PROVIDER_ID);
|
|
33725
|
-
if (!getAuth2) {
|
|
33726
|
-
throw new Error('Missing auth for provider "openrouter". Authenticate via `opencode auth login`.');
|
|
33727
|
-
}
|
|
33728
|
-
const client4 = createOpenRouterWebsearchClient(selectedModel);
|
|
33729
|
-
return client4.search(query, context.abort, getAuth2);
|
|
33730
|
-
}
|
|
33731
|
-
const getAuth = resolveGetAuth(GOOGLE_PROVIDER_ID);
|
|
33732
|
-
if (!getAuth) {
|
|
33733
|
-
throw new Error('Missing auth for provider "google". Authenticate via `opencode auth login`.');
|
|
33734
|
-
}
|
|
33735
|
-
const client3 = createGoogleWebsearchClient(selectedModel);
|
|
33736
|
-
return client3.search(query, context.abort, getAuth);
|
|
33737
|
-
}
|
|
33738
|
-
})
|
|
33739
|
-
}
|
|
33740
|
-
});
|
|
33741
|
-
}, WebsearchCitedGooglePlugin = () => {
|
|
33742
|
-
return Promise.resolve({
|
|
33743
|
-
auth: {
|
|
33744
|
-
provider: GOOGLE_PROVIDER_ID,
|
|
33745
|
-
loader(getAuth) {
|
|
33746
|
-
registerGetAuth(GOOGLE_PROVIDER_ID, getAuth);
|
|
33747
|
-
return Promise.resolve({});
|
|
33748
|
-
},
|
|
33749
|
-
methods: [
|
|
33750
|
-
{
|
|
33751
|
-
type: "api",
|
|
33752
|
-
label: "Google API key"
|
|
33753
|
-
}
|
|
33754
|
-
]
|
|
33755
|
-
}
|
|
33756
|
-
});
|
|
33757
|
-
}, WebsearchCitedOpenAIPlugin = () => {
|
|
33758
|
-
return Promise.resolve({
|
|
33759
|
-
auth: {
|
|
33760
|
-
provider: OPENAI_PROVIDER_ID,
|
|
33761
|
-
loader(getAuth) {
|
|
33762
|
-
registerGetAuth(OPENAI_PROVIDER_ID, getAuth);
|
|
33763
|
-
return Promise.resolve({});
|
|
33764
|
-
},
|
|
33765
|
-
methods: [
|
|
33766
|
-
{
|
|
33767
|
-
type: "api",
|
|
33768
|
-
label: "OpenAI API key"
|
|
33769
|
-
}
|
|
33770
|
-
]
|
|
33771
|
-
}
|
|
33772
|
-
});
|
|
33773
|
-
}, websearch_cited_default;
|
|
33774
|
-
var init_websearch_cited = __esm(() => {
|
|
33775
|
-
init_dist();
|
|
33776
|
-
init_google();
|
|
33777
|
-
init_openai();
|
|
33778
|
-
WEBSEARCH_ARGS = {
|
|
33779
|
-
query: tool.schema.string().describe("The natural language web search query.")
|
|
33780
|
-
};
|
|
33781
|
-
WEBSEARCH_ALLOWED_KEYS = new Set(Object.keys(WEBSEARCH_ARGS));
|
|
33782
|
-
WEBSEARCH_ALLOWED_KEYS_DESCRIPTION = Array.from(WEBSEARCH_ALLOWED_KEYS).map((key) => `'${key}'`).join(", ");
|
|
33783
|
-
authRegistry = new Map;
|
|
33784
|
-
websearch_cited_default = WebsearchCitedPlugin;
|
|
33785
|
-
});
|
|
33786
|
-
|
|
33787
32526
|
// node_modules/bun-pty/src/interfaces.ts
|
|
33788
32527
|
class EventEmitter {
|
|
33789
32528
|
listeners = [];
|
|
@@ -33808,8 +32547,8 @@ class EventEmitter {
|
|
|
33808
32547
|
// node_modules/bun-pty/src/terminal.ts
|
|
33809
32548
|
import { dlopen, FFIType, ptr } from "bun:ffi";
|
|
33810
32549
|
import { Buffer as Buffer2 } from "buffer";
|
|
33811
|
-
import { join as
|
|
33812
|
-
import { existsSync as
|
|
32550
|
+
import { join as join105, dirname as dirname32, basename as basename16 } from "path";
|
|
32551
|
+
import { existsSync as existsSync93 } from "fs";
|
|
33813
32552
|
function shQuote(s) {
|
|
33814
32553
|
if (s.length === 0)
|
|
33815
32554
|
return "''";
|
|
@@ -33817,7 +32556,7 @@ function shQuote(s) {
|
|
|
33817
32556
|
}
|
|
33818
32557
|
function resolveLibPath() {
|
|
33819
32558
|
const env = process.env.BUN_PTY_LIB;
|
|
33820
|
-
if (env &&
|
|
32559
|
+
if (env && existsSync93(env))
|
|
33821
32560
|
return env;
|
|
33822
32561
|
try {
|
|
33823
32562
|
const embeddedPath = __require(`../rust-pty/target/release/${process.platform === "win32" ? "rust_pty.dll" : process.platform === "darwin" ? process.arch === "arm64" ? "librust_pty_arm64.dylib" : "librust_pty.dylib" : process.arch === "arm64" ? "librust_pty_arm64.so" : "librust_pty.so"}`);
|
|
@@ -33828,22 +32567,22 @@ function resolveLibPath() {
|
|
|
33828
32567
|
const arch = process.arch;
|
|
33829
32568
|
const filenames = platform2 === "darwin" ? arch === "arm64" ? ["librust_pty_arm64.dylib", "librust_pty.dylib"] : ["librust_pty.dylib"] : platform2 === "win32" ? ["rust_pty.dll"] : arch === "arm64" ? ["librust_pty_arm64.so", "librust_pty.so"] : ["librust_pty.so"];
|
|
33830
32569
|
const base = Bun.fileURLToPath(import.meta.url);
|
|
33831
|
-
const fileDir =
|
|
32570
|
+
const fileDir = dirname32(base);
|
|
33832
32571
|
const dirName = basename16(fileDir);
|
|
33833
|
-
const here = dirName === "src" || dirName === "dist" ?
|
|
32572
|
+
const here = dirName === "src" || dirName === "dist" ? dirname32(fileDir) : fileDir;
|
|
33834
32573
|
const basePaths = [
|
|
33835
|
-
|
|
33836
|
-
|
|
33837
|
-
|
|
32574
|
+
join105(here, "rust-pty", "target", "release"),
|
|
32575
|
+
join105(here, "..", "bun-pty", "rust-pty", "target", "release"),
|
|
32576
|
+
join105(process.cwd(), "node_modules", "bun-pty", "rust-pty", "target", "release")
|
|
33838
32577
|
];
|
|
33839
32578
|
const fallbackPaths = [];
|
|
33840
32579
|
for (const basePath of basePaths) {
|
|
33841
32580
|
for (const filename of filenames) {
|
|
33842
|
-
fallbackPaths.push(
|
|
32581
|
+
fallbackPaths.push(join105(basePath, filename));
|
|
33843
32582
|
}
|
|
33844
32583
|
}
|
|
33845
32584
|
for (const path10 of fallbackPaths) {
|
|
33846
|
-
if (
|
|
32585
|
+
if (existsSync93(path10))
|
|
33847
32586
|
return path10;
|
|
33848
32587
|
}
|
|
33849
32588
|
throw new Error(`librust_pty shared library not found.
|
|
@@ -35060,8 +33799,8 @@ var init_plugin = __esm(() => {
|
|
|
35060
33799
|
});
|
|
35061
33800
|
|
|
35062
33801
|
// src/index.ts
|
|
35063
|
-
import { existsSync as
|
|
35064
|
-
import { join as
|
|
33802
|
+
import { existsSync as existsSync94 } from "fs";
|
|
33803
|
+
import { join as join106 } from "path";
|
|
35065
33804
|
|
|
35066
33805
|
// src/hooks/todo-continuation-enforcer/index.ts
|
|
35067
33806
|
init_logger();
|
|
@@ -113718,6 +112457,73 @@ This file is clean. Here's why:
|
|
|
113718
112457
|
**Conclusion**: This code appears to be human-written or well-reviewed AI code. No changes needed.
|
|
113719
112458
|
\`\`\``
|
|
113720
112459
|
};
|
|
112460
|
+
// src/features/builtin-skills/skills/hiai-opencode-setup.ts
|
|
112461
|
+
var hiaiOpencodeSetupSkill = {
|
|
112462
|
+
name: "hiai-opencode-setup",
|
|
112463
|
+
description: "Use when install/setup/onboarding or MCP debug mentions: install, setup, bootstrap, doctor, mcp-status, MCP not found, mcp list empty, MemPalace, RAG, firecrawl, stitch, sequential-thinking, playwright, DCP, agents, skills, or LSP.",
|
|
112464
|
+
template: `# hiai-opencode Setup And Runtime Operations
|
|
112465
|
+
|
|
112466
|
+
Use this skill for hiai-opencode installation, diagnostics, and integration repair.
|
|
112467
|
+
|
|
112468
|
+
## Architecture
|
|
112469
|
+
|
|
112470
|
+
- hiai-opencode is an OpenCode plugin, not a standalone app.
|
|
112471
|
+
- MCP servers are external upstream tools launched by hiai-opencode wiring.
|
|
112472
|
+
- The user-facing config is \`hiai-opencode.json\` or \`.opencode/hiai-opencode.json\`.
|
|
112473
|
+
- Model provider credentials belong to OpenCode Connect. Do not ask for \`OPENROUTER_API_KEY\`, \`OPENAI_API_KEY\`, or \`ANTHROPIC_API_KEY\` for normal model usage.
|
|
112474
|
+
- Service credentials are separate: \`FIRECRAWL_API_KEY\`, \`STITCH_AI_API_KEY\`, \`CONTEXT7_API_KEY\`.
|
|
112475
|
+
|
|
112476
|
+
## First Diagnostic Commands
|
|
112477
|
+
|
|
112478
|
+
\`\`\`bash
|
|
112479
|
+
hiai-opencode doctor
|
|
112480
|
+
hiai-opencode mcp-status
|
|
112481
|
+
opencode debug config
|
|
112482
|
+
\`\`\`
|
|
112483
|
+
|
|
112484
|
+
If \`opencode mcp list\` is empty but doctor/mcp-status sees servers, explain that OpenCode's list may read only static \`.mcp.json\`. Refresh static visibility:
|
|
112485
|
+
|
|
112486
|
+
\`\`\`bash
|
|
112487
|
+
hiai-opencode export-mcp .mcp.json
|
|
112488
|
+
opencode mcp list --print-logs --log-level INFO
|
|
112489
|
+
\`\`\`
|
|
112490
|
+
|
|
112491
|
+
## Plugin vs MCP
|
|
112492
|
+
|
|
112493
|
+
Install OpenCode plugins with:
|
|
112494
|
+
|
|
112495
|
+
\`\`\`bash
|
|
112496
|
+
opencode plugin @hiai-gg/hiai-opencode@latest --global
|
|
112497
|
+
opencode plugin @tarquinen/opencode-dcp@latest --global
|
|
112498
|
+
\`\`\`
|
|
112499
|
+
|
|
112500
|
+
Do not add MCP packages to the OpenCode plugin array. MCP packages are launched through \`hiai-opencode.json\` and helper scripts.
|
|
112501
|
+
|
|
112502
|
+
## MCP Runtime Notes
|
|
112503
|
+
|
|
112504
|
+
- \`playwright\`: node/npx; browser binaries may need \`HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1\`; Linux system deps may require admin rights.
|
|
112505
|
+
- \`sequential-thinking\`: node/npx; use for complex planning, revision, and branching.
|
|
112506
|
+
- \`firecrawl\`: requires \`FIRECRAWL_API_KEY\`.
|
|
112507
|
+
- \`mempalace\`: prefers \`uv\`; otherwise Python 3.9+ with \`mempalace\`. Use \`mempalace_status\` first, search before answering memory questions, and never invent memories.
|
|
112508
|
+
- \`rag\`: requires \`OPENCODE_RAG_URL\` or a reachable default \`http://localhost:9002/tools/search\`.
|
|
112509
|
+
- \`stitch\`: requires \`STITCH_AI_API_KEY\`.
|
|
112510
|
+
- \`context7\`: remote docs/search; key optional but recommended for limits.
|
|
112511
|
+
|
|
112512
|
+
## Calling MCP
|
|
112513
|
+
|
|
112514
|
+
- Use native MCP tools if OpenCode exposes them.
|
|
112515
|
+
- Use \`skill_mcp\` for skill-embedded MCP or enabled hiai-opencode MCP.
|
|
112516
|
+
- If \`skill_mcp\` says a server is not found, check whether the skill is loaded, whether the MCP is enabled in \`hiai-opencode.json\`, and whether \`.mcp.json\` needs export.
|
|
112517
|
+
|
|
112518
|
+
## Safety Rules
|
|
112519
|
+
|
|
112520
|
+
- Report missing keys by env var name only. Never print key values.
|
|
112521
|
+
- Prefer project-local or user-level installs. Do not use sudo/admin rights unless the user explicitly asks.
|
|
112522
|
+
- Do not edit unrelated OpenCode/Claude/Agents global skill folders unless the user opts in.
|
|
112523
|
+
- Keep DCP separate: it is an optional OpenCode plugin, not part of the hiai-opencode package.
|
|
112524
|
+
`,
|
|
112525
|
+
allowedTools: ["Bash(*)", "Read(*)", "Edit(*)", "Glob(*)", "Grep(*)", "skill_mcp(*)"]
|
|
112526
|
+
};
|
|
113721
112527
|
// src/features/builtin-skills/skills.ts
|
|
113722
112528
|
function createBuiltinSkills(options = {}) {
|
|
113723
112529
|
const { browserProvider = "playwright", disabledSkills } = options;
|
|
@@ -113729,7 +112535,15 @@ function createBuiltinSkills(options = {}) {
|
|
|
113729
112535
|
} else {
|
|
113730
112536
|
browserSkill = playwrightSkill;
|
|
113731
112537
|
}
|
|
113732
|
-
const skills = [
|
|
112538
|
+
const skills = [
|
|
112539
|
+
browserSkill,
|
|
112540
|
+
hiaiOpencodeSetupSkill,
|
|
112541
|
+
frontendUiUxSkill,
|
|
112542
|
+
gitMasterSkill,
|
|
112543
|
+
devBrowserSkill,
|
|
112544
|
+
reviewWorkSkill,
|
|
112545
|
+
aiSlopRemoverSkill
|
|
112546
|
+
];
|
|
113733
112547
|
if (!disabledSkills) {
|
|
113734
112548
|
return skills;
|
|
113735
112549
|
}
|
|
@@ -114056,7 +112870,8 @@ var BuiltinCommandNameSchema = exports_external.enum([
|
|
|
114056
112870
|
"start-work",
|
|
114057
112871
|
"stop-continuation",
|
|
114058
112872
|
"remove-ai-slops",
|
|
114059
|
-
"mcp-status"
|
|
112873
|
+
"mcp-status",
|
|
112874
|
+
"doctor"
|
|
114060
112875
|
]);
|
|
114061
112876
|
// src/config/schema/comment-checker.ts
|
|
114062
112877
|
var CommentCheckerConfigSchema = exports_external.object({
|
|
@@ -114334,9 +113149,6 @@ var WebsearchConfigSchema = exports_external.object({
|
|
|
114334
113149
|
|
|
114335
113150
|
// src/config/schema/oh-my-opencode-config.ts
|
|
114336
113151
|
var AuthConfigSchema = exports_external.object({
|
|
114337
|
-
googleSearch: exports_external.string().optional(),
|
|
114338
|
-
openai: exports_external.string().optional(),
|
|
114339
|
-
openrouter: exports_external.string().optional(),
|
|
114340
113152
|
stitch: exports_external.string().optional(),
|
|
114341
113153
|
firecrawl: exports_external.string().optional(),
|
|
114342
113154
|
context7: exports_external.string().optional()
|
|
@@ -116089,6 +114901,51 @@ Rules:
|
|
|
116089
114901
|
- Do not run package installs unless the user explicitly asks.
|
|
116090
114902
|
`;
|
|
116091
114903
|
|
|
114904
|
+
// src/features/builtin-commands/templates/doctor.ts
|
|
114905
|
+
var DOCTOR_TEMPLATE = `# Hiai OpenCode Doctor Command
|
|
114906
|
+
|
|
114907
|
+
## Purpose
|
|
114908
|
+
|
|
114909
|
+
Use /doctor to run the hiai-opencode install/runtime diagnostic and report actionable setup issues.
|
|
114910
|
+
|
|
114911
|
+
## Execute
|
|
114912
|
+
|
|
114913
|
+
Run:
|
|
114914
|
+
|
|
114915
|
+
\`\`\`bash
|
|
114916
|
+
hiai-opencode doctor
|
|
114917
|
+
\`\`\`
|
|
114918
|
+
|
|
114919
|
+
If the binary is not on PATH, try the package-local fallback:
|
|
114920
|
+
|
|
114921
|
+
\`\`\`bash
|
|
114922
|
+
node ./node_modules/@hiai-gg/hiai-opencode/assets/cli/hiai-opencode.mjs doctor
|
|
114923
|
+
\`\`\`
|
|
114924
|
+
|
|
114925
|
+
## Report
|
|
114926
|
+
|
|
114927
|
+
Summarize:
|
|
114928
|
+
|
|
114929
|
+
- config path
|
|
114930
|
+
- enabled and disabled MCP servers
|
|
114931
|
+
- missing env vars by name only
|
|
114932
|
+
- static \`.mcp.json\` freshness and whether it is managed by hiai-opencode
|
|
114933
|
+
- OpenCode Connect visibility for configured model providers
|
|
114934
|
+
- OpenCode plugin registration sanity (including \`plugin: ["list"]\` misconfiguration warning)
|
|
114935
|
+
- skill materialization status from skill registry
|
|
114936
|
+
- agent count and naming summary
|
|
114937
|
+
- LSP runtime availability
|
|
114938
|
+
- MemPalace python source and selected interpreter (env/config/auto)
|
|
114939
|
+
- MCP tool probes (real connect + tools/list) for stdio and basic endpoint probes for remote MCP
|
|
114940
|
+
|
|
114941
|
+
Rules:
|
|
114942
|
+
|
|
114943
|
+
- Do not print API key values.
|
|
114944
|
+
- Do not ask for model provider env vars such as OPENROUTER_API_KEY or OPENAI_API_KEY; normal model auth belongs to OpenCode Connect.
|
|
114945
|
+
- If \`opencode mcp list\` is empty but doctor/mcp-status sees servers, explain the runtime-vs-static config distinction and run \`hiai-opencode export-mcp .mcp.json\` if the user wants static visibility.
|
|
114946
|
+
- Do not run package installs unless the user explicitly asks.
|
|
114947
|
+
`;
|
|
114948
|
+
|
|
116092
114949
|
// src/features/builtin-commands/commands.ts
|
|
116093
114950
|
function resolveStartWorkAgent(options) {
|
|
116094
114951
|
if (options?.useRegisteredAgents) {
|
|
@@ -116197,6 +115054,12 @@ $ARGUMENTS
|
|
|
116197
115054
|
description: "(builtin) Show hiai-opencode MCP server status, missing keys, and local runtime availability",
|
|
116198
115055
|
template: `<command-instruction>
|
|
116199
115056
|
${MCP_STATUS_TEMPLATE}
|
|
115057
|
+
</command-instruction>`
|
|
115058
|
+
},
|
|
115059
|
+
doctor: {
|
|
115060
|
+
description: "(builtin) Run hiai-opencode install/runtime diagnostics and explain setup issues",
|
|
115061
|
+
template: `<command-instruction>
|
|
115062
|
+
${DOCTOR_TEMPLATE}
|
|
116200
115063
|
</command-instruction>`
|
|
116201
115064
|
}
|
|
116202
115065
|
};
|
|
@@ -120534,14 +119397,42 @@ import * as fs12 from "fs";
|
|
|
120534
119397
|
import * as path6 from "path";
|
|
120535
119398
|
|
|
120536
119399
|
// src/config/loader.ts
|
|
120537
|
-
import { existsSync as
|
|
120538
|
-
import { join as
|
|
119400
|
+
import { existsSync as existsSync58, readFileSync as readFileSync43 } from "fs";
|
|
119401
|
+
import { join as join67 } from "path";
|
|
120539
119402
|
|
|
120540
119403
|
// src/config/platform-schema.ts
|
|
120541
119404
|
var AgentConfigSchema = exports_external.object({
|
|
120542
119405
|
model: exports_external.string(),
|
|
120543
119406
|
description: exports_external.string().optional()
|
|
120544
119407
|
});
|
|
119408
|
+
var ModelRecommendationSchema = exports_external.enum([
|
|
119409
|
+
"xhigh",
|
|
119410
|
+
"high",
|
|
119411
|
+
"middle",
|
|
119412
|
+
"fast",
|
|
119413
|
+
"vision",
|
|
119414
|
+
"writing",
|
|
119415
|
+
"design"
|
|
119416
|
+
]);
|
|
119417
|
+
var ModelSlotConfigSchema = exports_external.union([
|
|
119418
|
+
exports_external.string(),
|
|
119419
|
+
exports_external.object({
|
|
119420
|
+
model: exports_external.string(),
|
|
119421
|
+
recommended: ModelRecommendationSchema.optional()
|
|
119422
|
+
})
|
|
119423
|
+
]);
|
|
119424
|
+
var ModelSlotsConfigSchema = exports_external.object({
|
|
119425
|
+
bob: ModelSlotConfigSchema.optional(),
|
|
119426
|
+
coder: ModelSlotConfigSchema.optional(),
|
|
119427
|
+
strategist: ModelSlotConfigSchema.optional(),
|
|
119428
|
+
guard: ModelSlotConfigSchema.optional(),
|
|
119429
|
+
critic: ModelSlotConfigSchema.optional(),
|
|
119430
|
+
designer: ModelSlotConfigSchema.optional(),
|
|
119431
|
+
researcher: ModelSlotConfigSchema.optional(),
|
|
119432
|
+
manager: ModelSlotConfigSchema.optional(),
|
|
119433
|
+
brainstormer: ModelSlotConfigSchema.optional(),
|
|
119434
|
+
vision: ModelSlotConfigSchema.optional()
|
|
119435
|
+
});
|
|
120545
119436
|
var FallbackEntrySchema = exports_external.object({
|
|
120546
119437
|
providers: exports_external.array(exports_external.string()),
|
|
120547
119438
|
model: exports_external.string(),
|
|
@@ -120575,11 +119466,13 @@ var McpServerConfigSchema = exports_external.object({
|
|
|
120575
119466
|
headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
120576
119467
|
command: exports_external.array(exports_external.string()).optional(),
|
|
120577
119468
|
timeout: exports_external.number().optional(),
|
|
120578
|
-
environment: exports_external.record(exports_external.string(), exports_external.string()).optional()
|
|
119469
|
+
environment: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
119470
|
+
pythonPath: exports_external.string().optional()
|
|
120579
119471
|
});
|
|
120580
119472
|
var LspServerConfigSchema = exports_external.object({
|
|
120581
|
-
|
|
120582
|
-
|
|
119473
|
+
enabled: exports_external.boolean().optional(),
|
|
119474
|
+
command: exports_external.array(exports_external.string()).optional(),
|
|
119475
|
+
extensions: exports_external.array(exports_external.string()).optional(),
|
|
120583
119476
|
initialization: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
120584
119477
|
});
|
|
120585
119478
|
var Subtask2ConfigSchema = exports_external.object({
|
|
@@ -120622,11 +119515,9 @@ var PermissionsConfigSchema = exports_external.object({
|
|
|
120622
119515
|
["*"]: exports_external.record(exports_external.string(), exports_external.enum(["allow", "deny"])).optional()
|
|
120623
119516
|
});
|
|
120624
119517
|
var AuthKeysSchema = exports_external.object({
|
|
120625
|
-
googleSearch: exports_external.string().optional(),
|
|
120626
|
-
openai: exports_external.string().optional(),
|
|
120627
|
-
openrouter: exports_external.string().optional(),
|
|
120628
119518
|
stitch: exports_external.string().optional(),
|
|
120629
|
-
firecrawl: exports_external.string().optional()
|
|
119519
|
+
firecrawl: exports_external.string().optional(),
|
|
119520
|
+
context7: exports_external.string().optional()
|
|
120630
119521
|
});
|
|
120631
119522
|
var OllamaConfigSchema = exports_external.object({
|
|
120632
119523
|
enabled: exports_external.boolean().default(false),
|
|
@@ -120706,6 +119597,7 @@ var AgentRequirementsConfigSchema = exports_external.object({
|
|
|
120706
119597
|
}).catchall(ModelRequirementSchema);
|
|
120707
119598
|
var HiaiOpencodeConfigSchema = exports_external.object({
|
|
120708
119599
|
$schema: exports_external.string().optional(),
|
|
119600
|
+
models: ModelSlotsConfigSchema.optional(),
|
|
120709
119601
|
agents: AgentsConfigSchema.optional(),
|
|
120710
119602
|
agentRequirements: AgentRequirementsConfigSchema.optional(),
|
|
120711
119603
|
categories: exports_external.record(exports_external.string(), CategoryConfigSchema2).optional(),
|
|
@@ -120722,45 +119614,289 @@ var HiaiOpencodeConfigSchema = exports_external.object({
|
|
|
120722
119614
|
});
|
|
120723
119615
|
|
|
120724
119616
|
// src/config/defaults.ts
|
|
120725
|
-
import { existsSync as
|
|
120726
|
-
import { dirname as dirname18, join as
|
|
119617
|
+
import { existsSync as existsSync57, readFileSync as readFileSync42 } from "fs";
|
|
119618
|
+
import { dirname as dirname18, join as join66, normalize as normalize2 } from "path";
|
|
119619
|
+
|
|
119620
|
+
// src/mcp/registry.ts
|
|
119621
|
+
import { join as join65 } from "path";
|
|
119622
|
+
import { existsSync as existsSync56 } from "fs";
|
|
119623
|
+
function resolveAssetScript(...segments) {
|
|
119624
|
+
const candidates = [
|
|
119625
|
+
join65(import.meta.dirname, "..", "assets", ...segments),
|
|
119626
|
+
join65(import.meta.dirname, "..", "..", "assets", ...segments)
|
|
119627
|
+
];
|
|
119628
|
+
return candidates.find((candidate) => existsSync56(candidate)) ?? candidates[0];
|
|
119629
|
+
}
|
|
119630
|
+
function createNpmPackageCommand(pkg, ...args) {
|
|
119631
|
+
return ["node", resolveAssetScript("runtime", "npm-package-runner.mjs"), pkg, ...args];
|
|
119632
|
+
}
|
|
119633
|
+
var HIAI_MCP_REGISTRY = {
|
|
119634
|
+
playwright: {
|
|
119635
|
+
name: "playwright",
|
|
119636
|
+
enabledByDefault: true,
|
|
119637
|
+
install: "npm",
|
|
119638
|
+
optionalEnv: ["HIAI_PLAYWRIGHT_INSTALL_BROWSERS"],
|
|
119639
|
+
config: {
|
|
119640
|
+
enabled: true,
|
|
119641
|
+
command: ["node", resolveAssetScript("mcp", "playwright.mjs")],
|
|
119642
|
+
timeout: 600000
|
|
119643
|
+
}
|
|
119644
|
+
},
|
|
119645
|
+
stitch: {
|
|
119646
|
+
name: "stitch",
|
|
119647
|
+
enabledByDefault: true,
|
|
119648
|
+
install: "remote",
|
|
119649
|
+
requiredEnv: ["STITCH_AI_API_KEY"],
|
|
119650
|
+
config: {
|
|
119651
|
+
enabled: true,
|
|
119652
|
+
type: "remote",
|
|
119653
|
+
url: "https://stitch.googleapis.com/mcp",
|
|
119654
|
+
headers: { "X-Goog-Api-Key": "{env:STITCH_AI_API_KEY}" },
|
|
119655
|
+
timeout: 600000
|
|
119656
|
+
}
|
|
119657
|
+
},
|
|
119658
|
+
"sequential-thinking": {
|
|
119659
|
+
name: "sequential-thinking",
|
|
119660
|
+
enabledByDefault: true,
|
|
119661
|
+
install: "npm",
|
|
119662
|
+
config: {
|
|
119663
|
+
enabled: true,
|
|
119664
|
+
command: createNpmPackageCommand("@modelcontextprotocol/server-sequential-thinking"),
|
|
119665
|
+
timeout: 600000
|
|
119666
|
+
}
|
|
119667
|
+
},
|
|
119668
|
+
firecrawl: {
|
|
119669
|
+
name: "firecrawl",
|
|
119670
|
+
enabledByDefault: true,
|
|
119671
|
+
install: "npm",
|
|
119672
|
+
requiredEnv: ["FIRECRAWL_API_KEY"],
|
|
119673
|
+
config: {
|
|
119674
|
+
enabled: true,
|
|
119675
|
+
command: createNpmPackageCommand("firecrawl-mcp"),
|
|
119676
|
+
timeout: 600000,
|
|
119677
|
+
environment: { FIRECRAWL_API_KEY: "{env:FIRECRAWL_API_KEY}" }
|
|
119678
|
+
}
|
|
119679
|
+
},
|
|
119680
|
+
rag: {
|
|
119681
|
+
name: "rag",
|
|
119682
|
+
enabledByDefault: true,
|
|
119683
|
+
install: "user-service",
|
|
119684
|
+
optionalEnv: ["OPENCODE_RAG_URL"],
|
|
119685
|
+
config: {
|
|
119686
|
+
enabled: true,
|
|
119687
|
+
type: "local",
|
|
119688
|
+
command: ["node", resolveAssetScript("mcp", "rag.mjs")],
|
|
119689
|
+
environment: {
|
|
119690
|
+
OPENCODE_RAG_URL: "{env:OPENCODE_RAG_URL:-http://localhost:9002/tools/search}"
|
|
119691
|
+
},
|
|
119692
|
+
timeout: 600000
|
|
119693
|
+
}
|
|
119694
|
+
},
|
|
119695
|
+
context7: {
|
|
119696
|
+
name: "context7",
|
|
119697
|
+
enabledByDefault: true,
|
|
119698
|
+
install: "remote",
|
|
119699
|
+
optionalEnv: ["CONTEXT7_API_KEY"],
|
|
119700
|
+
config: {
|
|
119701
|
+
enabled: true,
|
|
119702
|
+
type: "remote",
|
|
119703
|
+
url: "https://mcp.context7.com/mcp",
|
|
119704
|
+
headers: { "X-API-KEY": "{env:CONTEXT7_API_KEY}" },
|
|
119705
|
+
timeout: 600000
|
|
119706
|
+
}
|
|
119707
|
+
},
|
|
119708
|
+
mempalace: {
|
|
119709
|
+
name: "mempalace",
|
|
119710
|
+
enabledByDefault: true,
|
|
119711
|
+
install: "python",
|
|
119712
|
+
optionalEnv: ["MEMPALACE_PYTHON", "MEMPALACE_PALACE_PATH", "HIAI_MCP_AUTO_INSTALL"],
|
|
119713
|
+
config: {
|
|
119714
|
+
enabled: true,
|
|
119715
|
+
type: "local",
|
|
119716
|
+
command: ["node", resolveAssetScript("mcp", "mempalace.mjs"), "--palace", "./.opencode/palace"],
|
|
119717
|
+
timeout: 600000
|
|
119718
|
+
}
|
|
119719
|
+
}
|
|
119720
|
+
};
|
|
119721
|
+
function createDefaultMcpConfig() {
|
|
119722
|
+
return Object.fromEntries(Object.entries(HIAI_MCP_REGISTRY).map(([name, entry]) => [
|
|
119723
|
+
name,
|
|
119724
|
+
{ ...entry.config, enabled: entry.enabledByDefault }
|
|
119725
|
+
]));
|
|
119726
|
+
}
|
|
119727
|
+
|
|
119728
|
+
// src/config/defaults.ts
|
|
119729
|
+
var REQUIRED_MODEL_SLOTS = [
|
|
119730
|
+
"bob",
|
|
119731
|
+
"coder",
|
|
119732
|
+
"strategist",
|
|
119733
|
+
"guard",
|
|
119734
|
+
"critic",
|
|
119735
|
+
"designer",
|
|
119736
|
+
"researcher",
|
|
119737
|
+
"manager",
|
|
119738
|
+
"brainstormer",
|
|
119739
|
+
"vision"
|
|
119740
|
+
];
|
|
119741
|
+
var DEFAULT_LSP = {
|
|
119742
|
+
typescript: {
|
|
119743
|
+
enabled: true,
|
|
119744
|
+
command: ["typescript-language-server", "--stdio"],
|
|
119745
|
+
extensions: [".ts", ".tsx", ".mts", ".cts"]
|
|
119746
|
+
},
|
|
119747
|
+
svelte: {
|
|
119748
|
+
enabled: true,
|
|
119749
|
+
command: ["svelteserver", "--stdio"],
|
|
119750
|
+
extensions: [".svelte"]
|
|
119751
|
+
},
|
|
119752
|
+
eslint: {
|
|
119753
|
+
enabled: true,
|
|
119754
|
+
command: ["node", "{pluginRoot}/assets/runtime/npm-package-runner.mjs", "eslint-lsp", "--stdio"],
|
|
119755
|
+
extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
|
|
119756
|
+
},
|
|
119757
|
+
bash: {
|
|
119758
|
+
enabled: true,
|
|
119759
|
+
command: ["node", "{pluginRoot}/assets/runtime/npm-package-runner.mjs", "bash-language-server", "start"],
|
|
119760
|
+
extensions: [".sh", ".bash"]
|
|
119761
|
+
},
|
|
119762
|
+
pyright: {
|
|
119763
|
+
enabled: true,
|
|
119764
|
+
command: ["pyright-langserver", "--stdio"],
|
|
119765
|
+
extensions: [".py"]
|
|
119766
|
+
}
|
|
119767
|
+
};
|
|
120727
119768
|
function findPluginRoot() {
|
|
120728
119769
|
const candidates = [
|
|
120729
|
-
|
|
120730
|
-
|
|
120731
|
-
|
|
119770
|
+
join66(import.meta.dirname, "..", ".."),
|
|
119771
|
+
join66(import.meta.dirname, ".."),
|
|
119772
|
+
join66(import.meta.dirname, "..", ".."),
|
|
120732
119773
|
dirname18(process.argv[1] ?? ""),
|
|
120733
119774
|
process.cwd()
|
|
120734
119775
|
];
|
|
120735
119776
|
for (const candidate of candidates) {
|
|
120736
119777
|
const root = normalize2(candidate);
|
|
120737
|
-
if (
|
|
119778
|
+
if (existsSync57(join66(root, "hiai-opencode.json")))
|
|
120738
119779
|
return root;
|
|
120739
|
-
}
|
|
120740
119780
|
}
|
|
120741
119781
|
throw new Error("[hiai-opencode] Cannot find bundled hiai-opencode.json. The package is incomplete.");
|
|
120742
119782
|
}
|
|
120743
119783
|
function expandPluginRootPlaceholders(value, pluginRoot) {
|
|
120744
|
-
if (typeof value === "string")
|
|
119784
|
+
if (typeof value === "string")
|
|
120745
119785
|
return value.replaceAll("{pluginRoot}", pluginRoot);
|
|
120746
|
-
|
|
120747
|
-
if (Array.isArray(value)) {
|
|
119786
|
+
if (Array.isArray(value))
|
|
120748
119787
|
return value.map((item) => expandPluginRootPlaceholders(item, pluginRoot));
|
|
120749
|
-
}
|
|
120750
119788
|
if (value && typeof value === "object") {
|
|
120751
|
-
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
120752
|
-
key,
|
|
120753
|
-
expandPluginRootPlaceholders(entry, pluginRoot)
|
|
120754
|
-
]));
|
|
119789
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, expandPluginRootPlaceholders(entry, pluginRoot)]));
|
|
120755
119790
|
}
|
|
120756
119791
|
return value;
|
|
120757
119792
|
}
|
|
119793
|
+
function requireModelSlots(config2) {
|
|
119794
|
+
const models = config2.models ?? {};
|
|
119795
|
+
const resolved = Object.fromEntries(REQUIRED_MODEL_SLOTS.map((slot) => {
|
|
119796
|
+
const value = models[slot];
|
|
119797
|
+
const model = typeof value === "string" ? value : value?.model;
|
|
119798
|
+
return [slot, model?.trim() ?? ""];
|
|
119799
|
+
}));
|
|
119800
|
+
const missing = REQUIRED_MODEL_SLOTS.filter((slot) => !resolved[slot]);
|
|
119801
|
+
if (missing.length > 0) {
|
|
119802
|
+
throw new Error(`[hiai-opencode] Missing required model slot(s) in hiai-opencode.json: ${missing.join(", ")}`);
|
|
119803
|
+
}
|
|
119804
|
+
return resolved;
|
|
119805
|
+
}
|
|
119806
|
+
function deriveAgents(models) {
|
|
119807
|
+
return {
|
|
119808
|
+
bob: { model: models.bob },
|
|
119809
|
+
coder: { model: models.coder },
|
|
119810
|
+
strategist: { model: models.strategist },
|
|
119811
|
+
guard: { model: models.guard },
|
|
119812
|
+
critic: { model: models.critic },
|
|
119813
|
+
designer: { model: models.designer },
|
|
119814
|
+
researcher: { model: models.researcher },
|
|
119815
|
+
"platform-manager": { model: models.manager },
|
|
119816
|
+
brainstormer: { model: models.brainstormer },
|
|
119817
|
+
multimodal: { model: models.vision },
|
|
119818
|
+
sub: { model: models.coder },
|
|
119819
|
+
"quality-guardian": { model: models.critic },
|
|
119820
|
+
"agent-skills": { model: models.manager }
|
|
119821
|
+
};
|
|
119822
|
+
}
|
|
119823
|
+
function deriveCategories(models) {
|
|
119824
|
+
return {
|
|
119825
|
+
"visual-engineering": { model: models.designer, variant: "high" },
|
|
119826
|
+
artistry: { model: models.designer, variant: "high" },
|
|
119827
|
+
ultrabrain: { model: models.strategist, variant: "xhigh" },
|
|
119828
|
+
deep: { model: models.coder, variant: "medium" },
|
|
119829
|
+
quick: { model: models.researcher },
|
|
119830
|
+
writing: { model: models.brainstormer },
|
|
119831
|
+
git: { model: models.manager },
|
|
119832
|
+
"unspecified-low": { model: models.coder },
|
|
119833
|
+
"unspecified-high": { model: models.bob, variant: "max" }
|
|
119834
|
+
};
|
|
119835
|
+
}
|
|
119836
|
+
function deriveMcp(config2) {
|
|
119837
|
+
const defaults = createDefaultMcpConfig();
|
|
119838
|
+
const userMcp = config2.mcp ?? {};
|
|
119839
|
+
return Object.fromEntries(Object.entries(defaults).map(([name, entry]) => {
|
|
119840
|
+
const override = userMcp[name] ?? {};
|
|
119841
|
+
const merged = { ...entry, ...override };
|
|
119842
|
+
if (name === "mempalace" && typeof merged.pythonPath === "string" && merged.pythonPath.trim()) {
|
|
119843
|
+
merged.environment = {
|
|
119844
|
+
...entry.environment ?? {},
|
|
119845
|
+
...merged.environment ?? {},
|
|
119846
|
+
MEMPALACE_PYTHON: merged.pythonPath.trim()
|
|
119847
|
+
};
|
|
119848
|
+
}
|
|
119849
|
+
delete merged.pythonPath;
|
|
119850
|
+
return [name, merged];
|
|
119851
|
+
}));
|
|
119852
|
+
}
|
|
119853
|
+
function deriveLsp(config2) {
|
|
119854
|
+
const userLsp = config2.lsp ?? {};
|
|
119855
|
+
return Object.fromEntries(Object.entries(DEFAULT_LSP).map(([name, entry]) => {
|
|
119856
|
+
const override = userLsp[name] ?? {};
|
|
119857
|
+
return [name, { ...entry, ...override }];
|
|
119858
|
+
}));
|
|
119859
|
+
}
|
|
119860
|
+
function materializeConfig(rawConfig) {
|
|
119861
|
+
const models = requireModelSlots(rawConfig);
|
|
119862
|
+
return {
|
|
119863
|
+
...rawConfig,
|
|
119864
|
+
agents: deriveAgents(models),
|
|
119865
|
+
agentRequirements: {},
|
|
119866
|
+
categories: deriveCategories(models),
|
|
119867
|
+
categoryRequirements: {},
|
|
119868
|
+
modelFamilies: [],
|
|
119869
|
+
mcp: deriveMcp(rawConfig),
|
|
119870
|
+
lsp: deriveLsp(rawConfig),
|
|
119871
|
+
subtask2: {
|
|
119872
|
+
replace_generic: true,
|
|
119873
|
+
generic_return: null,
|
|
119874
|
+
...rawConfig.subtask2 ?? {}
|
|
119875
|
+
},
|
|
119876
|
+
skills: {
|
|
119877
|
+
enabled: true,
|
|
119878
|
+
disabled: [],
|
|
119879
|
+
...rawConfig.skills ?? {}
|
|
119880
|
+
},
|
|
119881
|
+
permissions: {
|
|
119882
|
+
read: { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" },
|
|
119883
|
+
edit: { "*": "allow" },
|
|
119884
|
+
bash: { "*": "allow" },
|
|
119885
|
+
deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"],
|
|
119886
|
+
...rawConfig.permissions ?? {}
|
|
119887
|
+
}
|
|
119888
|
+
};
|
|
119889
|
+
}
|
|
120758
119890
|
function loadBundledDefaultConfig() {
|
|
120759
119891
|
const pluginRoot = findPluginRoot();
|
|
120760
|
-
const configPath =
|
|
119892
|
+
const configPath = join66(pluginRoot, "hiai-opencode.json");
|
|
120761
119893
|
const raw = readFileSync42(configPath, "utf-8");
|
|
120762
119894
|
const parsed = JSON.parse(raw);
|
|
120763
|
-
|
|
119895
|
+
const materialized = materializeConfig(parsed);
|
|
119896
|
+
return expandPluginRootPlaceholders(materialized, pluginRoot);
|
|
119897
|
+
}
|
|
119898
|
+
function applyModelSlots(config2) {
|
|
119899
|
+
return materializeConfig(config2);
|
|
120764
119900
|
}
|
|
120765
119901
|
var defaultConfig = loadBundledDefaultConfig();
|
|
120766
119902
|
|
|
@@ -120809,8 +119945,8 @@ function deepMerge2(base, override) {
|
|
|
120809
119945
|
function findConfigFile(searchDirs) {
|
|
120810
119946
|
for (const dir of searchDirs) {
|
|
120811
119947
|
for (const filename of CONFIG_FILENAMES) {
|
|
120812
|
-
const candidate =
|
|
120813
|
-
if (
|
|
119948
|
+
const candidate = join67(dir, filename);
|
|
119949
|
+
if (existsSync58(candidate))
|
|
120814
119950
|
return candidate;
|
|
120815
119951
|
}
|
|
120816
119952
|
}
|
|
@@ -120882,8 +120018,8 @@ function normalizeCompactLspConfig(rawConfig) {
|
|
|
120882
120018
|
function loadConfig(projectDir) {
|
|
120883
120019
|
const searchDirs = [
|
|
120884
120020
|
projectDir,
|
|
120885
|
-
|
|
120886
|
-
|
|
120021
|
+
join67(projectDir, ".opencode"),
|
|
120022
|
+
join67(process.env.HOME || "", ".config", "opencode")
|
|
120887
120023
|
];
|
|
120888
120024
|
const configPath = findConfigFile(searchDirs);
|
|
120889
120025
|
if (!configPath)
|
|
@@ -120893,7 +120029,8 @@ function loadConfig(projectDir) {
|
|
|
120893
120029
|
const normalizedParsed = normalizeCompactLspConfig(parsed);
|
|
120894
120030
|
const validated = HiaiOpencodeConfigSchema.parse(normalizedParsed);
|
|
120895
120031
|
const normalized = normalizeAgentAliases(validated);
|
|
120896
|
-
|
|
120032
|
+
const merged = deepMerge2(BASE_CONFIG, normalized);
|
|
120033
|
+
return applyModelSlots(merged);
|
|
120897
120034
|
}
|
|
120898
120035
|
function resolveEnvVars(value) {
|
|
120899
120036
|
return value.replace(/\{env:([^}]+)\}/g, (_, expression) => {
|
|
@@ -120904,12 +120041,12 @@ function resolveEnvVars(value) {
|
|
|
120904
120041
|
// src/shared/migrate-legacy-config-file.ts
|
|
120905
120042
|
init_logger();
|
|
120906
120043
|
init_plugin_identity();
|
|
120907
|
-
import { existsSync as
|
|
120908
|
-
import { join as
|
|
120044
|
+
import { existsSync as existsSync59, readFileSync as readFileSync44, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
|
|
120045
|
+
import { join as join68, dirname as dirname19, basename as basename9 } from "path";
|
|
120909
120046
|
function buildCanonicalPath(legacyPath) {
|
|
120910
120047
|
const dir = dirname19(legacyPath);
|
|
120911
120048
|
const ext = basename9(legacyPath).includes(".jsonc") ? ".jsonc" : ".json";
|
|
120912
|
-
return
|
|
120049
|
+
return join68(dir, `${CONFIG_BASENAME}${ext}`);
|
|
120913
120050
|
}
|
|
120914
120051
|
function archiveLegacyConfigFile(legacyPath) {
|
|
120915
120052
|
const backupPath = `${legacyPath}.bak`;
|
|
@@ -120941,12 +120078,12 @@ function archiveLegacyConfigFile(legacyPath) {
|
|
|
120941
120078
|
}
|
|
120942
120079
|
}
|
|
120943
120080
|
function migrateLegacyConfigFile(legacyPath) {
|
|
120944
|
-
if (!
|
|
120081
|
+
if (!existsSync59(legacyPath))
|
|
120945
120082
|
return false;
|
|
120946
120083
|
if (!basename9(legacyPath).startsWith(LEGACY_CONFIG_BASENAME))
|
|
120947
120084
|
return false;
|
|
120948
120085
|
const canonicalPath = buildCanonicalPath(legacyPath);
|
|
120949
|
-
if (
|
|
120086
|
+
if (existsSync59(canonicalPath))
|
|
120950
120087
|
return false;
|
|
120951
120088
|
try {
|
|
120952
120089
|
const content = readFileSync44(legacyPath, "utf-8");
|
|
@@ -122469,11 +121606,11 @@ function createRuntimeFallbackHook(ctx, options) {
|
|
|
122469
121606
|
};
|
|
122470
121607
|
}
|
|
122471
121608
|
// src/hooks/write-existing-file-guard/hook.ts
|
|
122472
|
-
import { existsSync as
|
|
122473
|
-
import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute11, join as
|
|
121609
|
+
import { existsSync as existsSync62, realpathSync as realpathSync6 } from "fs";
|
|
121610
|
+
import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute11, join as join70, normalize as normalize3, relative as relative8, resolve as resolve14 } from "path";
|
|
122474
121611
|
|
|
122475
121612
|
// src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
|
|
122476
|
-
import { existsSync as
|
|
121613
|
+
import { existsSync as existsSync61 } from "fs";
|
|
122477
121614
|
|
|
122478
121615
|
// src/hooks/write-existing-file-guard/session-read-permissions.ts
|
|
122479
121616
|
function touchSession(sessionLastAccess, sessionID) {
|
|
@@ -122561,7 +121698,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
122561
121698
|
return;
|
|
122562
121699
|
}
|
|
122563
121700
|
if (toolName === "read") {
|
|
122564
|
-
if (!
|
|
121701
|
+
if (!existsSync61(resolvedPath) || !input.sessionID) {
|
|
122565
121702
|
return;
|
|
122566
121703
|
}
|
|
122567
121704
|
registerReadPermission({
|
|
@@ -122577,7 +121714,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
122577
121714
|
if (argsRecord && "overwrite" in argsRecord) {
|
|
122578
121715
|
delete argsRecord.overwrite;
|
|
122579
121716
|
}
|
|
122580
|
-
if (!
|
|
121717
|
+
if (!existsSync61(resolvedPath)) {
|
|
122581
121718
|
return;
|
|
122582
121719
|
}
|
|
122583
121720
|
const isBobPath2 = canonicalPath.includes("/.bob/");
|
|
@@ -122636,7 +121773,7 @@ function isPathInsideDirectory(pathToCheck, directory) {
|
|
|
122636
121773
|
}
|
|
122637
121774
|
function toCanonicalPath2(absolutePath) {
|
|
122638
121775
|
let canonicalPath = absolutePath;
|
|
122639
|
-
if (
|
|
121776
|
+
if (existsSync62(absolutePath)) {
|
|
122640
121777
|
try {
|
|
122641
121778
|
canonicalPath = realpathSync6.native(absolutePath);
|
|
122642
121779
|
} catch {
|
|
@@ -122644,8 +121781,8 @@ function toCanonicalPath2(absolutePath) {
|
|
|
122644
121781
|
}
|
|
122645
121782
|
} else {
|
|
122646
121783
|
const absoluteDir = dirname21(absolutePath);
|
|
122647
|
-
const resolvedDir =
|
|
122648
|
-
canonicalPath =
|
|
121784
|
+
const resolvedDir = existsSync62(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
|
|
121785
|
+
canonicalPath = join70(resolvedDir, basename11(absolutePath));
|
|
122649
121786
|
}
|
|
122650
121787
|
return normalize3(canonicalPath);
|
|
122651
121788
|
}
|
|
@@ -123921,23 +123058,23 @@ init_logger();
|
|
|
123921
123058
|
init_plugin_identity();
|
|
123922
123059
|
|
|
123923
123060
|
// src/hooks/legacy-plugin-toast/auto-migrate.ts
|
|
123924
|
-
import { existsSync as
|
|
123925
|
-
import { join as
|
|
123061
|
+
import { existsSync as existsSync63, readFileSync as readFileSync46 } from "fs";
|
|
123062
|
+
import { join as join71 } from "path";
|
|
123926
123063
|
init_plugin_identity();
|
|
123927
123064
|
function detectOpenCodeConfigPath(overrideConfigDir) {
|
|
123928
123065
|
if (overrideConfigDir) {
|
|
123929
|
-
const jsoncPath =
|
|
123930
|
-
const jsonPath =
|
|
123931
|
-
if (
|
|
123066
|
+
const jsoncPath = join71(overrideConfigDir, "opencode.jsonc");
|
|
123067
|
+
const jsonPath = join71(overrideConfigDir, "opencode.json");
|
|
123068
|
+
if (existsSync63(jsoncPath))
|
|
123932
123069
|
return jsoncPath;
|
|
123933
|
-
if (
|
|
123070
|
+
if (existsSync63(jsonPath))
|
|
123934
123071
|
return jsonPath;
|
|
123935
123072
|
return null;
|
|
123936
123073
|
}
|
|
123937
123074
|
const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
123938
|
-
if (
|
|
123075
|
+
if (existsSync63(paths.configJsonc))
|
|
123939
123076
|
return paths.configJsonc;
|
|
123940
|
-
if (
|
|
123077
|
+
if (existsSync63(paths.configJson))
|
|
123941
123078
|
return paths.configJson;
|
|
123942
123079
|
return null;
|
|
123943
123080
|
}
|
|
@@ -124064,7 +123201,7 @@ async function queryOllama(args) {
|
|
|
124064
123201
|
}
|
|
124065
123202
|
|
|
124066
123203
|
// src/hooks/fast-apply/tool-execute-before-handler.ts
|
|
124067
|
-
import { existsSync as
|
|
123204
|
+
import { existsSync as existsSync64, readFileSync as readFileSync47 } from "fs";
|
|
124068
123205
|
async function handleFastApplyToolExecuteBefore(args) {
|
|
124069
123206
|
const { input, output, config: config2 } = args;
|
|
124070
123207
|
const normalizedTool = input.tool.toLowerCase();
|
|
@@ -124083,7 +123220,7 @@ async function handleFastApplyToolExecuteBefore(args) {
|
|
|
124083
123220
|
});
|
|
124084
123221
|
return;
|
|
124085
123222
|
}
|
|
124086
|
-
if (!
|
|
123223
|
+
if (!existsSync64(filePath)) {
|
|
124087
123224
|
log("[fast-apply] Skipping: file does not exist (new file)", {
|
|
124088
123225
|
sessionID: input.sessionID,
|
|
124089
123226
|
callID: input.callID,
|
|
@@ -124472,10 +123609,10 @@ var DEFAULT_MAX_SYMBOLS = 200;
|
|
|
124472
123609
|
var DEFAULT_MAX_DIAGNOSTICS = 200;
|
|
124473
123610
|
var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
124474
123611
|
// src/tools/lsp/server-config-loader.ts
|
|
124475
|
-
import { existsSync as
|
|
124476
|
-
import { join as
|
|
123612
|
+
import { existsSync as existsSync65, readFileSync as readFileSync48 } from "fs";
|
|
123613
|
+
import { join as join72 } from "path";
|
|
124477
123614
|
function loadJsonFile(path7) {
|
|
124478
|
-
if (!
|
|
123615
|
+
if (!existsSync65(path7))
|
|
124479
123616
|
return null;
|
|
124480
123617
|
try {
|
|
124481
123618
|
return parseJsonc(readFileSync48(path7, "utf-8"));
|
|
@@ -124487,9 +123624,9 @@ function getConfigPaths2() {
|
|
|
124487
123624
|
const cwd = process.cwd();
|
|
124488
123625
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
124489
123626
|
return {
|
|
124490
|
-
project: detectPluginConfigFile(
|
|
123627
|
+
project: detectPluginConfigFile(join72(cwd, ".opencode")).path,
|
|
124491
123628
|
user: detectPluginConfigFile(configDir).path,
|
|
124492
|
-
opencode: detectConfigFile(
|
|
123629
|
+
opencode: detectConfigFile(join72(configDir, "opencode")).path
|
|
124493
123630
|
};
|
|
124494
123631
|
}
|
|
124495
123632
|
function loadAllConfigs() {
|
|
@@ -124558,20 +123695,20 @@ function getMergedServers() {
|
|
|
124558
123695
|
}
|
|
124559
123696
|
|
|
124560
123697
|
// src/tools/lsp/server-installation.ts
|
|
124561
|
-
import { existsSync as
|
|
124562
|
-
import { delimiter, join as
|
|
123698
|
+
import { existsSync as existsSync66 } from "fs";
|
|
123699
|
+
import { delimiter, join as join74 } from "path";
|
|
124563
123700
|
|
|
124564
123701
|
// src/tools/lsp/server-path-bases.ts
|
|
124565
|
-
import { join as
|
|
123702
|
+
import { join as join73 } from "path";
|
|
124566
123703
|
function getLspServerAdditionalPathBases(workingDirectory) {
|
|
124567
123704
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
124568
|
-
const dataDir =
|
|
123705
|
+
const dataDir = join73(getDataDir(), "opencode");
|
|
124569
123706
|
return [
|
|
124570
|
-
|
|
124571
|
-
|
|
124572
|
-
|
|
124573
|
-
|
|
124574
|
-
|
|
123707
|
+
join73(workingDirectory, "node_modules", ".bin"),
|
|
123708
|
+
join73(configDir, "bin"),
|
|
123709
|
+
join73(configDir, "node_modules", ".bin"),
|
|
123710
|
+
join73(dataDir, "bin"),
|
|
123711
|
+
join73(dataDir, "bin", "node_modules", ".bin")
|
|
124575
123712
|
];
|
|
124576
123713
|
}
|
|
124577
123714
|
|
|
@@ -124581,7 +123718,7 @@ function isServerInstalled(command) {
|
|
|
124581
123718
|
return false;
|
|
124582
123719
|
const cmd = command[0];
|
|
124583
123720
|
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
124584
|
-
if (
|
|
123721
|
+
if (existsSync66(cmd))
|
|
124585
123722
|
return true;
|
|
124586
123723
|
}
|
|
124587
123724
|
const isWindows2 = process.platform === "win32";
|
|
@@ -124602,14 +123739,14 @@ function isServerInstalled(command) {
|
|
|
124602
123739
|
const paths = pathEnv.split(delimiter);
|
|
124603
123740
|
for (const p of paths) {
|
|
124604
123741
|
for (const suffix of exts) {
|
|
124605
|
-
if (
|
|
123742
|
+
if (existsSync66(join74(p, cmd + suffix))) {
|
|
124606
123743
|
return true;
|
|
124607
123744
|
}
|
|
124608
123745
|
}
|
|
124609
123746
|
}
|
|
124610
123747
|
for (const base of getLspServerAdditionalPathBases(process.cwd())) {
|
|
124611
123748
|
for (const suffix of exts) {
|
|
124612
|
-
if (
|
|
123749
|
+
if (existsSync66(join74(base, cmd + suffix))) {
|
|
124613
123750
|
return true;
|
|
124614
123751
|
}
|
|
124615
123752
|
}
|
|
@@ -124667,13 +123804,13 @@ function getLanguageId(ext) {
|
|
|
124667
123804
|
init_logger();
|
|
124668
123805
|
var {spawn: bunSpawn2 } = globalThis.Bun;
|
|
124669
123806
|
import { spawn as nodeSpawn2 } from "child_process";
|
|
124670
|
-
import { existsSync as
|
|
123807
|
+
import { existsSync as existsSync67, statSync as statSync7 } from "fs";
|
|
124671
123808
|
function shouldUseNodeSpawn() {
|
|
124672
123809
|
return process.platform === "win32";
|
|
124673
123810
|
}
|
|
124674
123811
|
function validateCwd(cwd) {
|
|
124675
123812
|
try {
|
|
124676
|
-
if (!
|
|
123813
|
+
if (!existsSync67(cwd)) {
|
|
124677
123814
|
return { valid: false, error: `Working directory does not exist: ${cwd}` };
|
|
124678
123815
|
}
|
|
124679
123816
|
const stats = statSync7(cwd);
|
|
@@ -125435,10 +124572,10 @@ var lspManager = LSPServerManager.getInstance();
|
|
|
125435
124572
|
// src/tools/lsp/lsp-client-wrapper.ts
|
|
125436
124573
|
import { extname as extname5, resolve as resolve16 } from "path";
|
|
125437
124574
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
125438
|
-
import { existsSync as
|
|
124575
|
+
import { existsSync as existsSync68, statSync as statSync8 } from "fs";
|
|
125439
124576
|
init_plugin_identity();
|
|
125440
124577
|
function isDirectoryPath(filePath) {
|
|
125441
|
-
if (!
|
|
124578
|
+
if (!existsSync68(filePath)) {
|
|
125442
124579
|
return false;
|
|
125443
124580
|
}
|
|
125444
124581
|
return statSync8(filePath).isDirectory();
|
|
@@ -125448,14 +124585,14 @@ function uriToPath(uri) {
|
|
|
125448
124585
|
}
|
|
125449
124586
|
function findWorkspaceRoot(filePath) {
|
|
125450
124587
|
let dir = resolve16(filePath);
|
|
125451
|
-
if (!
|
|
124588
|
+
if (!existsSync68(dir) || !isDirectoryPath(dir)) {
|
|
125452
124589
|
dir = __require("path").dirname(dir);
|
|
125453
124590
|
}
|
|
125454
124591
|
const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
|
|
125455
124592
|
let prevDir = "";
|
|
125456
124593
|
while (dir !== prevDir) {
|
|
125457
124594
|
for (const marker of markers) {
|
|
125458
|
-
if (
|
|
124595
|
+
if (existsSync68(__require("path").join(dir, marker))) {
|
|
125459
124596
|
return dir;
|
|
125460
124597
|
}
|
|
125461
124598
|
}
|
|
@@ -125865,8 +125002,8 @@ init_tool();
|
|
|
125865
125002
|
import { resolve as resolve18 } from "path";
|
|
125866
125003
|
|
|
125867
125004
|
// src/tools/lsp/directory-diagnostics.ts
|
|
125868
|
-
import { existsSync as
|
|
125869
|
-
import { extname as extname6, join as
|
|
125005
|
+
import { existsSync as existsSync69, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
|
|
125006
|
+
import { extname as extname6, join as join75, resolve as resolve17 } from "path";
|
|
125870
125007
|
var SKIP_DIRECTORIES = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
125871
125008
|
function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
125872
125009
|
const files = [];
|
|
@@ -125882,7 +125019,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
|
125882
125019
|
for (const entry of entries) {
|
|
125883
125020
|
if (files.length >= maxFiles)
|
|
125884
125021
|
return;
|
|
125885
|
-
const fullPath =
|
|
125022
|
+
const fullPath = join75(currentDir, entry);
|
|
125886
125023
|
let stat;
|
|
125887
125024
|
try {
|
|
125888
125025
|
stat = lstatSync2(fullPath);
|
|
@@ -125911,7 +125048,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
125911
125048
|
throw new Error(`Extension must start with a dot (e.g., ".ts", not "${extension}"). ` + `Use ".${extension}" instead.`);
|
|
125912
125049
|
}
|
|
125913
125050
|
const absDir = resolve17(directory);
|
|
125914
|
-
if (!
|
|
125051
|
+
if (!existsSync69(absDir)) {
|
|
125915
125052
|
throw new Error(`Directory does not exist: ${absDir}`);
|
|
125916
125053
|
}
|
|
125917
125054
|
const serverResult = findServerForExtension(extension);
|
|
@@ -125985,7 +125122,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
125985
125122
|
|
|
125986
125123
|
// src/tools/lsp/infer-extension.ts
|
|
125987
125124
|
import { readdirSync as readdirSync20, lstatSync as lstatSync3 } from "fs";
|
|
125988
|
-
import { extname as extname7, join as
|
|
125125
|
+
import { extname as extname7, join as join76 } from "path";
|
|
125989
125126
|
var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
125990
125127
|
var MAX_SCAN_ENTRIES = 500;
|
|
125991
125128
|
function inferExtensionFromDirectory(directory) {
|
|
@@ -126003,7 +125140,7 @@ function inferExtensionFromDirectory(directory) {
|
|
|
126003
125140
|
for (const entry of entries) {
|
|
126004
125141
|
if (scanned >= MAX_SCAN_ENTRIES)
|
|
126005
125142
|
return;
|
|
126006
|
-
const fullPath =
|
|
125143
|
+
const fullPath = join76(dir, entry);
|
|
126007
125144
|
let stat;
|
|
126008
125145
|
try {
|
|
126009
125146
|
stat = lstatSync3(fullPath);
|
|
@@ -126172,12 +125309,12 @@ var DEFAULT_MAX_MATCHES = 500;
|
|
|
126172
125309
|
|
|
126173
125310
|
// src/tools/ast-grep/sg-cli-path.ts
|
|
126174
125311
|
import { createRequire as createRequire4 } from "module";
|
|
126175
|
-
import { dirname as dirname22, join as
|
|
126176
|
-
import { existsSync as
|
|
125312
|
+
import { dirname as dirname22, join as join78 } from "path";
|
|
125313
|
+
import { existsSync as existsSync71, statSync as statSync9 } from "fs";
|
|
126177
125314
|
|
|
126178
125315
|
// src/tools/ast-grep/downloader.ts
|
|
126179
|
-
import { existsSync as
|
|
126180
|
-
import { join as
|
|
125316
|
+
import { existsSync as existsSync70 } from "fs";
|
|
125317
|
+
import { join as join77 } from "path";
|
|
126181
125318
|
import { homedir as homedir14 } from "os";
|
|
126182
125319
|
import { createRequire as createRequire3 } from "module";
|
|
126183
125320
|
init_logger();
|
|
@@ -126205,12 +125342,12 @@ var PLATFORM_MAP2 = {
|
|
|
126205
125342
|
function getCacheDir3() {
|
|
126206
125343
|
if (process.platform === "win32") {
|
|
126207
125344
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
126208
|
-
const base2 = localAppData ||
|
|
126209
|
-
return
|
|
125345
|
+
const base2 = localAppData || join77(homedir14(), "AppData", "Local");
|
|
125346
|
+
return join77(base2, CACHE_DIR_NAME, "bin");
|
|
126210
125347
|
}
|
|
126211
125348
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
126212
|
-
const base = xdgCache ||
|
|
126213
|
-
return
|
|
125349
|
+
const base = xdgCache || join77(homedir14(), ".cache");
|
|
125350
|
+
return join77(base, CACHE_DIR_NAME, "bin");
|
|
126214
125351
|
}
|
|
126215
125352
|
function getBinaryName3() {
|
|
126216
125353
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
@@ -126227,8 +125364,8 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
|
|
|
126227
125364
|
}
|
|
126228
125365
|
const cacheDir = getCacheDir3();
|
|
126229
125366
|
const binaryName = getBinaryName3();
|
|
126230
|
-
const binaryPath =
|
|
126231
|
-
if (
|
|
125367
|
+
const binaryPath = join77(cacheDir, binaryName);
|
|
125368
|
+
if (existsSync70(binaryPath)) {
|
|
126232
125369
|
return binaryPath;
|
|
126233
125370
|
}
|
|
126234
125371
|
const { arch, os: os4 } = platformInfo;
|
|
@@ -126236,7 +125373,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
|
|
|
126236
125373
|
const downloadUrl = `https://github.com/${REPO2}/releases/download/${version3}/${assetName}`;
|
|
126237
125374
|
log(`[${PUBLISHED_PACKAGE_NAME}] Downloading ast-grep binary...`);
|
|
126238
125375
|
try {
|
|
126239
|
-
const archivePath =
|
|
125376
|
+
const archivePath = join77(cacheDir, assetName);
|
|
126240
125377
|
ensureCacheDir(cacheDir);
|
|
126241
125378
|
await downloadArchive(downloadUrl, archivePath);
|
|
126242
125379
|
await extractZipArchive(archivePath, cacheDir);
|
|
@@ -126290,8 +125427,8 @@ function findSgCliPathSync() {
|
|
|
126290
125427
|
const require2 = createRequire4(import.meta.url);
|
|
126291
125428
|
const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
|
|
126292
125429
|
const cliDirectory = dirname22(cliPackageJsonPath);
|
|
126293
|
-
const sgPath =
|
|
126294
|
-
if (
|
|
125430
|
+
const sgPath = join78(cliDirectory, binaryName);
|
|
125431
|
+
if (existsSync71(sgPath) && isValidBinary(sgPath)) {
|
|
126295
125432
|
return sgPath;
|
|
126296
125433
|
}
|
|
126297
125434
|
} catch {}
|
|
@@ -126302,8 +125439,8 @@ function findSgCliPathSync() {
|
|
|
126302
125439
|
const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
|
|
126303
125440
|
const packageDirectory = dirname22(packageJsonPath);
|
|
126304
125441
|
const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
126305
|
-
const binaryPath =
|
|
126306
|
-
if (
|
|
125442
|
+
const binaryPath = join78(packageDirectory, astGrepBinaryName);
|
|
125443
|
+
if (existsSync71(binaryPath) && isValidBinary(binaryPath)) {
|
|
126307
125444
|
return binaryPath;
|
|
126308
125445
|
}
|
|
126309
125446
|
} catch {}
|
|
@@ -126311,7 +125448,7 @@ function findSgCliPathSync() {
|
|
|
126311
125448
|
if (process.platform === "darwin") {
|
|
126312
125449
|
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
|
|
126313
125450
|
for (const path7 of homebrewPaths) {
|
|
126314
|
-
if (
|
|
125451
|
+
if (existsSync71(path7) && isValidBinary(path7)) {
|
|
126315
125452
|
return path7;
|
|
126316
125453
|
}
|
|
126317
125454
|
}
|
|
@@ -126335,14 +125472,14 @@ function setSgCliPath(path7) {
|
|
|
126335
125472
|
}
|
|
126336
125473
|
// src/tools/ast-grep/cli.ts
|
|
126337
125474
|
var {spawn: spawn17 } = globalThis.Bun;
|
|
126338
|
-
import { existsSync as
|
|
125475
|
+
import { existsSync as existsSync73 } from "fs";
|
|
126339
125476
|
|
|
126340
125477
|
// src/tools/ast-grep/cli-binary-path-resolution.ts
|
|
126341
|
-
import { existsSync as
|
|
125478
|
+
import { existsSync as existsSync72 } from "fs";
|
|
126342
125479
|
var resolvedCliPath3 = null;
|
|
126343
125480
|
var initPromise3 = null;
|
|
126344
125481
|
async function getAstGrepPath() {
|
|
126345
|
-
if (resolvedCliPath3 !== null &&
|
|
125482
|
+
if (resolvedCliPath3 !== null && existsSync72(resolvedCliPath3)) {
|
|
126346
125483
|
return resolvedCliPath3;
|
|
126347
125484
|
}
|
|
126348
125485
|
if (initPromise3) {
|
|
@@ -126350,7 +125487,7 @@ async function getAstGrepPath() {
|
|
|
126350
125487
|
}
|
|
126351
125488
|
initPromise3 = (async () => {
|
|
126352
125489
|
const syncPath = findSgCliPathSync();
|
|
126353
|
-
if (syncPath &&
|
|
125490
|
+
if (syncPath && existsSync72(syncPath)) {
|
|
126354
125491
|
resolvedCliPath3 = syncPath;
|
|
126355
125492
|
setSgCliPath(syncPath);
|
|
126356
125493
|
return syncPath;
|
|
@@ -126449,7 +125586,7 @@ async function runSg(options) {
|
|
|
126449
125586
|
const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
|
|
126450
125587
|
args.push(...paths);
|
|
126451
125588
|
let cliPath = getSgCliPath();
|
|
126452
|
-
if (!cliPath || !
|
|
125589
|
+
if (!cliPath || !existsSync73(cliPath)) {
|
|
126453
125590
|
const downloadedPath = await getAstGrepPath();
|
|
126454
125591
|
if (downloadedPath) {
|
|
126455
125592
|
cliPath = downloadedPath;
|
|
@@ -126704,20 +125841,20 @@ import { resolve as resolve19 } from "path";
|
|
|
126704
125841
|
var {spawn: spawn18 } = globalThis.Bun;
|
|
126705
125842
|
|
|
126706
125843
|
// src/tools/grep/constants.ts
|
|
126707
|
-
import { existsSync as
|
|
126708
|
-
import { join as
|
|
125844
|
+
import { existsSync as existsSync75 } from "fs";
|
|
125845
|
+
import { join as join80, dirname as dirname23 } from "path";
|
|
126709
125846
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
126710
125847
|
|
|
126711
125848
|
// src/tools/grep/downloader.ts
|
|
126712
|
-
import { existsSync as
|
|
126713
|
-
import { join as
|
|
125849
|
+
import { existsSync as existsSync74, readdirSync as readdirSync21 } from "fs";
|
|
125850
|
+
import { join as join79 } from "path";
|
|
126714
125851
|
init_plugin_identity();
|
|
126715
125852
|
function findFileRecursive(dir, filename) {
|
|
126716
125853
|
try {
|
|
126717
125854
|
const entries = readdirSync21(dir, { withFileTypes: true, recursive: true });
|
|
126718
125855
|
for (const entry of entries) {
|
|
126719
125856
|
if (entry.isFile() && entry.name === filename) {
|
|
126720
|
-
return
|
|
125857
|
+
return join79(entry.parentPath ?? dir, entry.name);
|
|
126721
125858
|
}
|
|
126722
125859
|
}
|
|
126723
125860
|
} catch {
|
|
@@ -126738,11 +125875,11 @@ function getPlatformKey() {
|
|
|
126738
125875
|
}
|
|
126739
125876
|
function getInstallDir() {
|
|
126740
125877
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
126741
|
-
return
|
|
125878
|
+
return join79(homeDir, ".cache", CACHE_DIR_NAME, "bin");
|
|
126742
125879
|
}
|
|
126743
125880
|
function getRgPath() {
|
|
126744
125881
|
const isWindows2 = process.platform === "win32";
|
|
126745
|
-
return
|
|
125882
|
+
return join79(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
|
|
126746
125883
|
}
|
|
126747
125884
|
async function extractTarGz2(archivePath, destDir) {
|
|
126748
125885
|
const platformKey = getPlatformKey();
|
|
@@ -126759,7 +125896,7 @@ async function extractZip2(archivePath, destDir) {
|
|
|
126759
125896
|
const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
|
|
126760
125897
|
const foundPath = findFileRecursive(destDir, binaryName);
|
|
126761
125898
|
if (foundPath) {
|
|
126762
|
-
const destPath =
|
|
125899
|
+
const destPath = join79(destDir, binaryName);
|
|
126763
125900
|
if (foundPath !== destPath) {
|
|
126764
125901
|
const { renameSync: renameSync4 } = await import("fs");
|
|
126765
125902
|
renameSync4(foundPath, destPath);
|
|
@@ -126774,13 +125911,13 @@ async function downloadAndInstallRipgrep() {
|
|
|
126774
125911
|
}
|
|
126775
125912
|
const installDir = getInstallDir();
|
|
126776
125913
|
const rgPath = getRgPath();
|
|
126777
|
-
if (
|
|
125914
|
+
if (existsSync74(rgPath)) {
|
|
126778
125915
|
return rgPath;
|
|
126779
125916
|
}
|
|
126780
125917
|
ensureCacheDir(installDir);
|
|
126781
125918
|
const filename = `ripgrep-${RG_VERSION}-${config4.platform}.${config4.extension}`;
|
|
126782
125919
|
const url3 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
|
|
126783
|
-
const archivePath =
|
|
125920
|
+
const archivePath = join79(installDir, filename);
|
|
126784
125921
|
try {
|
|
126785
125922
|
await downloadArchive(url3, archivePath);
|
|
126786
125923
|
if (config4.extension === "tar.gz") {
|
|
@@ -126789,7 +125926,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
126789
125926
|
await extractZip2(archivePath, installDir);
|
|
126790
125927
|
}
|
|
126791
125928
|
ensureExecutable(rgPath);
|
|
126792
|
-
if (!
|
|
125929
|
+
if (!existsSync74(rgPath)) {
|
|
126793
125930
|
throw new Error("ripgrep binary not found after extraction");
|
|
126794
125931
|
}
|
|
126795
125932
|
return rgPath;
|
|
@@ -126801,7 +125938,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
126801
125938
|
}
|
|
126802
125939
|
function getInstalledRipgrepPath() {
|
|
126803
125940
|
const rgPath = getRgPath();
|
|
126804
|
-
return
|
|
125941
|
+
return existsSync74(rgPath) ? rgPath : null;
|
|
126805
125942
|
}
|
|
126806
125943
|
|
|
126807
125944
|
// src/tools/grep/constants.ts
|
|
@@ -126827,14 +125964,14 @@ function getOpenCodeBundledRg() {
|
|
|
126827
125964
|
const isWindows2 = process.platform === "win32";
|
|
126828
125965
|
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
126829
125966
|
const candidates = [
|
|
126830
|
-
|
|
126831
|
-
|
|
126832
|
-
|
|
126833
|
-
|
|
126834
|
-
|
|
125967
|
+
join80(getDataDir(), "opencode", "bin", rgName),
|
|
125968
|
+
join80(execDir, rgName),
|
|
125969
|
+
join80(execDir, "bin", rgName),
|
|
125970
|
+
join80(execDir, "..", "bin", rgName),
|
|
125971
|
+
join80(execDir, "..", "libexec", rgName)
|
|
126835
125972
|
];
|
|
126836
125973
|
for (const candidate of candidates) {
|
|
126837
|
-
if (
|
|
125974
|
+
if (existsSync75(candidate)) {
|
|
126838
125975
|
return candidate;
|
|
126839
125976
|
}
|
|
126840
125977
|
}
|
|
@@ -127961,9 +127098,9 @@ var skill = createSkillTool();
|
|
|
127961
127098
|
init_tool();
|
|
127962
127099
|
|
|
127963
127100
|
// src/tools/session-manager/constants.ts
|
|
127964
|
-
import { join as
|
|
127965
|
-
var TODO_DIR2 =
|
|
127966
|
-
var TRANSCRIPT_DIR2 =
|
|
127101
|
+
import { join as join81 } from "path";
|
|
127102
|
+
var TODO_DIR2 = join81(getClaudeConfigDir(), "todos");
|
|
127103
|
+
var TRANSCRIPT_DIR2 = join81(getClaudeConfigDir(), "transcripts");
|
|
127967
127104
|
var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
|
127968
127105
|
|
|
127969
127106
|
Returns a list of available session IDs with metadata including message count, date range, and agents used.
|
|
@@ -128036,11 +127173,11 @@ Has Todos: Yes (12 items, 8 completed)
|
|
|
128036
127173
|
Has Transcript: Yes (234 entries)`;
|
|
128037
127174
|
|
|
128038
127175
|
// src/tools/session-manager/file-storage.ts
|
|
128039
|
-
import { existsSync as
|
|
127176
|
+
import { existsSync as existsSync76 } from "fs";
|
|
128040
127177
|
import { readdir, readFile } from "fs/promises";
|
|
128041
|
-
import { join as
|
|
127178
|
+
import { join as join82 } from "path";
|
|
128042
127179
|
async function getFileMainSessions(directory) {
|
|
128043
|
-
if (!
|
|
127180
|
+
if (!existsSync76(SESSION_STORAGE))
|
|
128044
127181
|
return [];
|
|
128045
127182
|
const sessions = [];
|
|
128046
127183
|
try {
|
|
@@ -128048,13 +127185,13 @@ async function getFileMainSessions(directory) {
|
|
|
128048
127185
|
for (const projectDir of projectDirs) {
|
|
128049
127186
|
if (!projectDir.isDirectory())
|
|
128050
127187
|
continue;
|
|
128051
|
-
const projectPath =
|
|
127188
|
+
const projectPath = join82(SESSION_STORAGE, projectDir.name);
|
|
128052
127189
|
const sessionFiles = await readdir(projectPath);
|
|
128053
127190
|
for (const file3 of sessionFiles) {
|
|
128054
127191
|
if (!file3.endsWith(".json"))
|
|
128055
127192
|
continue;
|
|
128056
127193
|
try {
|
|
128057
|
-
const content = await readFile(
|
|
127194
|
+
const content = await readFile(join82(projectPath, file3), "utf-8");
|
|
128058
127195
|
const meta3 = JSON.parse(content);
|
|
128059
127196
|
if (meta3.parentID)
|
|
128060
127197
|
continue;
|
|
@@ -128072,7 +127209,7 @@ async function getFileMainSessions(directory) {
|
|
|
128072
127209
|
return sessions.sort((a, b) => b.time.updated - a.time.updated);
|
|
128073
127210
|
}
|
|
128074
127211
|
async function getFileAllSessions() {
|
|
128075
|
-
if (!
|
|
127212
|
+
if (!existsSync76(MESSAGE_STORAGE))
|
|
128076
127213
|
return [];
|
|
128077
127214
|
const sessions = [];
|
|
128078
127215
|
async function scanDirectory(dir) {
|
|
@@ -128081,7 +127218,7 @@ async function getFileAllSessions() {
|
|
|
128081
127218
|
for (const entry of entries) {
|
|
128082
127219
|
if (!entry.isDirectory())
|
|
128083
127220
|
continue;
|
|
128084
|
-
const sessionPath =
|
|
127221
|
+
const sessionPath = join82(dir, entry.name);
|
|
128085
127222
|
const files = await readdir(sessionPath);
|
|
128086
127223
|
if (files.some((file3) => file3.endsWith(".json"))) {
|
|
128087
127224
|
sessions.push(entry.name);
|
|
@@ -128101,7 +127238,7 @@ async function fileSessionExists(sessionID) {
|
|
|
128101
127238
|
}
|
|
128102
127239
|
async function getFileSessionMessages(sessionID) {
|
|
128103
127240
|
const messageDir = getMessageDir(sessionID);
|
|
128104
|
-
if (!messageDir || !
|
|
127241
|
+
if (!messageDir || !existsSync76(messageDir))
|
|
128105
127242
|
return [];
|
|
128106
127243
|
const messages = [];
|
|
128107
127244
|
try {
|
|
@@ -128110,7 +127247,7 @@ async function getFileSessionMessages(sessionID) {
|
|
|
128110
127247
|
if (!file3.endsWith(".json"))
|
|
128111
127248
|
continue;
|
|
128112
127249
|
try {
|
|
128113
|
-
const content = await readFile(
|
|
127250
|
+
const content = await readFile(join82(messageDir, file3), "utf-8");
|
|
128114
127251
|
const meta3 = JSON.parse(content);
|
|
128115
127252
|
const parts = await readParts2(meta3.id);
|
|
128116
127253
|
messages.push({
|
|
@@ -128136,8 +127273,8 @@ async function getFileSessionMessages(sessionID) {
|
|
|
128136
127273
|
});
|
|
128137
127274
|
}
|
|
128138
127275
|
async function readParts2(messageID) {
|
|
128139
|
-
const partDir =
|
|
128140
|
-
if (!
|
|
127276
|
+
const partDir = join82(PART_STORAGE, messageID);
|
|
127277
|
+
if (!existsSync76(partDir))
|
|
128141
127278
|
return [];
|
|
128142
127279
|
const parts = [];
|
|
128143
127280
|
try {
|
|
@@ -128146,7 +127283,7 @@ async function readParts2(messageID) {
|
|
|
128146
127283
|
if (!file3.endsWith(".json"))
|
|
128147
127284
|
continue;
|
|
128148
127285
|
try {
|
|
128149
|
-
const content = await readFile(
|
|
127286
|
+
const content = await readFile(join82(partDir, file3), "utf-8");
|
|
128150
127287
|
parts.push(JSON.parse(content));
|
|
128151
127288
|
} catch {
|
|
128152
127289
|
continue;
|
|
@@ -128158,14 +127295,14 @@ async function readParts2(messageID) {
|
|
|
128158
127295
|
return parts.sort((a, b) => a.id.localeCompare(b.id));
|
|
128159
127296
|
}
|
|
128160
127297
|
async function getFileSessionTodos(sessionID) {
|
|
128161
|
-
if (!
|
|
127298
|
+
if (!existsSync76(TODO_DIR2))
|
|
128162
127299
|
return [];
|
|
128163
127300
|
try {
|
|
128164
127301
|
const allFiles = await readdir(TODO_DIR2);
|
|
128165
127302
|
const todoFiles = allFiles.filter((file3) => file3 === `${sessionID}.json`);
|
|
128166
127303
|
for (const file3 of todoFiles) {
|
|
128167
127304
|
try {
|
|
128168
|
-
const content = await readFile(
|
|
127305
|
+
const content = await readFile(join82(TODO_DIR2, file3), "utf-8");
|
|
128169
127306
|
const data = JSON.parse(content);
|
|
128170
127307
|
if (!Array.isArray(data))
|
|
128171
127308
|
continue;
|
|
@@ -128185,10 +127322,10 @@ async function getFileSessionTodos(sessionID) {
|
|
|
128185
127322
|
return [];
|
|
128186
127323
|
}
|
|
128187
127324
|
async function getFileSessionTranscript(sessionID) {
|
|
128188
|
-
if (!
|
|
127325
|
+
if (!existsSync76(TRANSCRIPT_DIR2))
|
|
128189
127326
|
return 0;
|
|
128190
|
-
const transcriptFile =
|
|
128191
|
-
if (!
|
|
127327
|
+
const transcriptFile = join82(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
|
|
127328
|
+
if (!existsSync76(transcriptFile))
|
|
128192
127329
|
return 0;
|
|
128193
127330
|
try {
|
|
128194
127331
|
const content = await readFile(transcriptFile, "utf-8");
|
|
@@ -128953,6 +128090,26 @@ function findMcpServer(mcpName, skills) {
|
|
|
128953
128090
|
}
|
|
128954
128091
|
return null;
|
|
128955
128092
|
}
|
|
128093
|
+
function convertBuiltinMcpConfig(config4) {
|
|
128094
|
+
if (config4.enabled === false)
|
|
128095
|
+
return null;
|
|
128096
|
+
if (config4.type === "remote") {
|
|
128097
|
+
return {
|
|
128098
|
+
type: "http",
|
|
128099
|
+
url: config4.url,
|
|
128100
|
+
headers: config4.headers
|
|
128101
|
+
};
|
|
128102
|
+
}
|
|
128103
|
+
const [command, ...args] = config4.command ?? [];
|
|
128104
|
+
if (!command)
|
|
128105
|
+
return null;
|
|
128106
|
+
return {
|
|
128107
|
+
type: "stdio",
|
|
128108
|
+
command,
|
|
128109
|
+
args,
|
|
128110
|
+
env: config4.environment
|
|
128111
|
+
};
|
|
128112
|
+
}
|
|
128956
128113
|
function formatAvailableMcps(skills) {
|
|
128957
128114
|
const mcps = [];
|
|
128958
128115
|
for (const skill2 of skills) {
|
|
@@ -128965,6 +128122,11 @@ function formatAvailableMcps(skills) {
|
|
|
128965
128122
|
return mcps.length > 0 ? mcps.join(`
|
|
128966
128123
|
`) : " (none found)";
|
|
128967
128124
|
}
|
|
128125
|
+
function formatAvailableBuiltinMcps(builtinMcp) {
|
|
128126
|
+
const names = Object.entries(builtinMcp ?? {}).filter(([, config4]) => config4.enabled !== false).map(([name]) => ` - "${name}" from hiai-opencode config`);
|
|
128127
|
+
return names.length > 0 ? names.join(`
|
|
128128
|
+
`) : " (none found)";
|
|
128129
|
+
}
|
|
128968
128130
|
function formatBuiltinMcpHint(mcpName) {
|
|
128969
128131
|
const nativeTools = BUILTIN_MCP_TOOL_HINTS[mcpName];
|
|
128970
128132
|
if (!nativeTools)
|
|
@@ -129010,7 +128172,7 @@ function applyGrepFilter(output, pattern) {
|
|
|
129010
128172
|
}
|
|
129011
128173
|
}
|
|
129012
128174
|
function createSkillMcpTool(options) {
|
|
129013
|
-
const { manager, getLoadedSkills, getSessionID } = options;
|
|
128175
|
+
const { manager, getLoadedSkills, getSessionID, builtinMcp } = options;
|
|
129014
128176
|
return tool({
|
|
129015
128177
|
description: SKILL_MCP_DESCRIPTION,
|
|
129016
128178
|
args: {
|
|
@@ -129025,7 +128187,9 @@ function createSkillMcpTool(options) {
|
|
|
129025
128187
|
const operation = validateOperationParams(args);
|
|
129026
128188
|
const skills = getLoadedSkills();
|
|
129027
128189
|
const found = findMcpServer(args.mcp_name, skills);
|
|
129028
|
-
|
|
128190
|
+
const builtinConfig = builtinMcp?.[args.mcp_name];
|
|
128191
|
+
const convertedBuiltinConfig = builtinConfig ? convertBuiltinMcpConfig(builtinConfig) : null;
|
|
128192
|
+
if (!found && !convertedBuiltinConfig) {
|
|
129029
128193
|
const builtinHint = formatBuiltinMcpHint(args.mcp_name);
|
|
129030
128194
|
if (builtinHint) {
|
|
129031
128195
|
throw new Error(builtinHint);
|
|
@@ -129035,7 +128199,10 @@ function createSkillMcpTool(options) {
|
|
|
129035
128199
|
` + `Available MCP servers in loaded skills:
|
|
129036
128200
|
` + formatAvailableMcps(skills) + `
|
|
129037
128201
|
|
|
129038
|
-
` + `
|
|
128202
|
+
` + `Available MCP servers in hiai-opencode config:
|
|
128203
|
+
` + formatAvailableBuiltinMcps(builtinMcp) + `
|
|
128204
|
+
|
|
128205
|
+
` + `Hint: Load the skill first for skill-embedded MCPs. Builtin hiai-opencode MCPs can be called directly when enabled in hiai-opencode.json.`);
|
|
129039
128206
|
}
|
|
129040
128207
|
const sessionID = toolContext.sessionID || getSessionID?.();
|
|
129041
128208
|
if (!sessionID) {
|
|
@@ -129043,13 +128210,13 @@ function createSkillMcpTool(options) {
|
|
|
129043
128210
|
}
|
|
129044
128211
|
const info = {
|
|
129045
128212
|
serverName: args.mcp_name,
|
|
129046
|
-
skillName: found
|
|
128213
|
+
skillName: found?.skill.name ?? "hiai-opencode",
|
|
129047
128214
|
sessionID,
|
|
129048
|
-
scope: found
|
|
128215
|
+
scope: found?.skill.scope ?? "user"
|
|
129049
128216
|
};
|
|
129050
128217
|
const context = {
|
|
129051
|
-
config: found
|
|
129052
|
-
skillName: found
|
|
128218
|
+
config: found?.config ?? convertedBuiltinConfig,
|
|
128219
|
+
skillName: found?.skill.name ?? "hiai-opencode"
|
|
129053
128220
|
};
|
|
129054
128221
|
const parsedArgs = parseArguments(args.arguments);
|
|
129055
128222
|
let output;
|
|
@@ -130568,9 +129735,9 @@ async function resolveMultimodalLookerAgentMetadata(ctx) {
|
|
|
130568
129735
|
|
|
130569
129736
|
// src/tools/look-at/image-converter.ts
|
|
130570
129737
|
import * as childProcess from "child_process";
|
|
130571
|
-
import { existsSync as
|
|
129738
|
+
import { existsSync as existsSync77, mkdtempSync, readFileSync as readFileSync51, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
|
|
130572
129739
|
import { tmpdir as tmpdir7 } from "os";
|
|
130573
|
-
import { dirname as dirname26, join as
|
|
129740
|
+
import { dirname as dirname26, join as join83 } from "path";
|
|
130574
129741
|
var SUPPORTED_FORMATS = new Set([
|
|
130575
129742
|
"image/jpeg",
|
|
130576
129743
|
"image/png",
|
|
@@ -130608,11 +129775,11 @@ function needsConversion(mimeType) {
|
|
|
130608
129775
|
return mimeType.startsWith("image/");
|
|
130609
129776
|
}
|
|
130610
129777
|
function convertImageToJpeg(inputPath, mimeType) {
|
|
130611
|
-
if (!
|
|
129778
|
+
if (!existsSync77(inputPath)) {
|
|
130612
129779
|
throw new Error(`File not found: ${inputPath}`);
|
|
130613
129780
|
}
|
|
130614
|
-
const tempDir = mkdtempSync(
|
|
130615
|
-
const outputPath =
|
|
129781
|
+
const tempDir = mkdtempSync(join83(tmpdir7(), "opencode-img-"));
|
|
129782
|
+
const outputPath = join83(tempDir, "converted.jpg");
|
|
130616
129783
|
log(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
|
|
130617
129784
|
try {
|
|
130618
129785
|
if (process.platform === "darwin") {
|
|
@@ -130622,7 +129789,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130622
129789
|
encoding: "utf-8",
|
|
130623
129790
|
timeout: CONVERSION_TIMEOUT_MS
|
|
130624
129791
|
});
|
|
130625
|
-
if (
|
|
129792
|
+
if (existsSync77(outputPath)) {
|
|
130626
129793
|
log(`[image-converter] Converted using sips: ${outputPath}`);
|
|
130627
129794
|
return outputPath;
|
|
130628
129795
|
}
|
|
@@ -130637,7 +129804,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130637
129804
|
encoding: "utf-8",
|
|
130638
129805
|
timeout: CONVERSION_TIMEOUT_MS
|
|
130639
129806
|
});
|
|
130640
|
-
if (
|
|
129807
|
+
if (existsSync77(outputPath)) {
|
|
130641
129808
|
log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
|
|
130642
129809
|
return outputPath;
|
|
130643
129810
|
}
|
|
@@ -130650,7 +129817,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130650
129817
|
` + ` RHEL/CentOS: sudo yum install ImageMagick`);
|
|
130651
129818
|
} catch (error92) {
|
|
130652
129819
|
try {
|
|
130653
|
-
if (
|
|
129820
|
+
if (existsSync77(outputPath)) {
|
|
130654
129821
|
unlinkSync10(outputPath);
|
|
130655
129822
|
}
|
|
130656
129823
|
} catch {}
|
|
@@ -130664,11 +129831,11 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130664
129831
|
function cleanupConvertedImage(filePath) {
|
|
130665
129832
|
try {
|
|
130666
129833
|
const tempDirectory = dirname26(filePath);
|
|
130667
|
-
if (
|
|
129834
|
+
if (existsSync77(filePath)) {
|
|
130668
129835
|
unlinkSync10(filePath);
|
|
130669
129836
|
log(`[image-converter] Cleaned up temporary file: ${filePath}`);
|
|
130670
129837
|
}
|
|
130671
|
-
if (
|
|
129838
|
+
if (existsSync77(tempDirectory)) {
|
|
130672
129839
|
rmSync3(tempDirectory, { recursive: true, force: true });
|
|
130673
129840
|
log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
|
|
130674
129841
|
}
|
|
@@ -130677,9 +129844,9 @@ function cleanupConvertedImage(filePath) {
|
|
|
130677
129844
|
}
|
|
130678
129845
|
}
|
|
130679
129846
|
function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
130680
|
-
const tempDir = mkdtempSync(
|
|
129847
|
+
const tempDir = mkdtempSync(join83(tmpdir7(), "opencode-b64-"));
|
|
130681
129848
|
const inputExt = mimeType.split("/")[1] || "bin";
|
|
130682
|
-
const inputPath =
|
|
129849
|
+
const inputPath = join83(tempDir, `input.${inputExt}`);
|
|
130683
129850
|
const tempFiles = [inputPath];
|
|
130684
129851
|
try {
|
|
130685
129852
|
const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
|
|
@@ -130695,7 +129862,7 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
|
130695
129862
|
} catch (error92) {
|
|
130696
129863
|
tempFiles.forEach((file3) => {
|
|
130697
129864
|
try {
|
|
130698
|
-
if (
|
|
129865
|
+
if (existsSync77(file3))
|
|
130699
129866
|
unlinkSync10(file3);
|
|
130700
129867
|
} catch {}
|
|
130701
129868
|
});
|
|
@@ -132876,19 +132043,19 @@ function applyFallbackEntrySettings(input) {
|
|
|
132876
132043
|
// src/tools/delegate-task/subagent-discovery.ts
|
|
132877
132044
|
init_agent_display_names();
|
|
132878
132045
|
// src/features/claude-code-agent-loader/loader.ts
|
|
132879
|
-
import { existsSync as
|
|
132880
|
-
import { join as
|
|
132046
|
+
import { existsSync as existsSync80, readdirSync as readdirSync22 } from "fs";
|
|
132047
|
+
import { join as join84 } from "path";
|
|
132881
132048
|
|
|
132882
132049
|
// src/features/claude-code-agent-loader/agent-definitions-loader.ts
|
|
132883
|
-
import { existsSync as
|
|
132050
|
+
import { existsSync as existsSync79, readFileSync as readFileSync53 } from "fs";
|
|
132884
132051
|
import { basename as basename13, extname as extname8 } from "path";
|
|
132885
132052
|
init_logger();
|
|
132886
132053
|
|
|
132887
132054
|
// src/features/claude-code-agent-loader/json-agent-loader.ts
|
|
132888
|
-
import { existsSync as
|
|
132055
|
+
import { existsSync as existsSync78, readFileSync as readFileSync52 } from "fs";
|
|
132889
132056
|
function parseJsonAgentFile(filePath, scope) {
|
|
132890
132057
|
try {
|
|
132891
|
-
if (!
|
|
132058
|
+
if (!existsSync78(filePath)) {
|
|
132892
132059
|
return null;
|
|
132893
132060
|
}
|
|
132894
132061
|
const content = readFileSync52(filePath, "utf-8");
|
|
@@ -132927,7 +132094,7 @@ function parseJsonAgentFile(filePath, scope) {
|
|
|
132927
132094
|
// src/features/claude-code-agent-loader/agent-definitions-loader.ts
|
|
132928
132095
|
function parseMarkdownAgentFile(filePath, scope) {
|
|
132929
132096
|
try {
|
|
132930
|
-
if (!
|
|
132097
|
+
if (!existsSync79(filePath)) {
|
|
132931
132098
|
return null;
|
|
132932
132099
|
}
|
|
132933
132100
|
const content = readFileSync53(filePath, "utf-8");
|
|
@@ -132962,7 +132129,7 @@ function parseMarkdownAgentFile(filePath, scope) {
|
|
|
132962
132129
|
function loadAgentDefinitions(paths, scope) {
|
|
132963
132130
|
const result = Object.create(null);
|
|
132964
132131
|
for (const filePath of paths) {
|
|
132965
|
-
if (!
|
|
132132
|
+
if (!existsSync79(filePath)) {
|
|
132966
132133
|
log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
|
|
132967
132134
|
continue;
|
|
132968
132135
|
}
|
|
@@ -132987,7 +132154,7 @@ function loadAgentDefinitions(paths, scope) {
|
|
|
132987
132154
|
|
|
132988
132155
|
// src/features/claude-code-agent-loader/loader.ts
|
|
132989
132156
|
function loadAgentsFromDir(agentsDir, scope) {
|
|
132990
|
-
if (!
|
|
132157
|
+
if (!existsSync80(agentsDir)) {
|
|
132991
132158
|
return [];
|
|
132992
132159
|
}
|
|
132993
132160
|
const entries = readdirSync22(agentsDir, { withFileTypes: true });
|
|
@@ -132995,7 +132162,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
132995
132162
|
for (const entry of entries) {
|
|
132996
132163
|
if (!isMarkdownFile(entry))
|
|
132997
132164
|
continue;
|
|
132998
|
-
const agentPath =
|
|
132165
|
+
const agentPath = join84(agentsDir, entry.name);
|
|
132999
132166
|
const agent = parseMarkdownAgentFile(agentPath, scope);
|
|
133000
132167
|
if (agent) {
|
|
133001
132168
|
agents.push(agent);
|
|
@@ -133004,7 +132171,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
133004
132171
|
return agents;
|
|
133005
132172
|
}
|
|
133006
132173
|
function loadUserAgents() {
|
|
133007
|
-
const userAgentsDir =
|
|
132174
|
+
const userAgentsDir = join84(getClaudeConfigDir(), "agents");
|
|
133008
132175
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
133009
132176
|
const result = Object.create(null);
|
|
133010
132177
|
for (const agent of agents) {
|
|
@@ -133013,7 +132180,7 @@ function loadUserAgents() {
|
|
|
133013
132180
|
return result;
|
|
133014
132181
|
}
|
|
133015
132182
|
function loadProjectAgents(directory) {
|
|
133016
|
-
const projectAgentsDir =
|
|
132183
|
+
const projectAgentsDir = join84(directory ?? process.cwd(), ".claude", "agents");
|
|
133017
132184
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
133018
132185
|
const result = Object.create(null);
|
|
133019
132186
|
for (const agent of agents) {
|
|
@@ -133023,7 +132190,7 @@ function loadProjectAgents(directory) {
|
|
|
133023
132190
|
}
|
|
133024
132191
|
function loadOpencodeGlobalAgents() {
|
|
133025
132192
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
133026
|
-
const opencodeAgentsDir =
|
|
132193
|
+
const opencodeAgentsDir = join84(configDir, "agents");
|
|
133027
132194
|
const agents = loadAgentsFromDir(opencodeAgentsDir, "opencode");
|
|
133028
132195
|
const result = Object.create(null);
|
|
133029
132196
|
for (const agent of agents) {
|
|
@@ -133032,7 +132199,7 @@ function loadOpencodeGlobalAgents() {
|
|
|
133032
132199
|
return result;
|
|
133033
132200
|
}
|
|
133034
132201
|
function loadOpencodeProjectAgents(directory) {
|
|
133035
|
-
const opencodeProjectDir =
|
|
132202
|
+
const opencodeProjectDir = join84(directory ?? process.cwd(), ".opencode", "agents");
|
|
133036
132203
|
const agents = loadAgentsFromDir(opencodeProjectDir, "opencode-project");
|
|
133037
132204
|
const result = Object.create(null);
|
|
133038
132205
|
for (const agent of agents) {
|
|
@@ -133575,7 +132742,7 @@ function createDelegateTask(options) {
|
|
|
133575
132742
|
init_constants();
|
|
133576
132743
|
// src/tools/task/task-create.ts
|
|
133577
132744
|
init_tool();
|
|
133578
|
-
import { join as
|
|
132745
|
+
import { join as join87 } from "path";
|
|
133579
132746
|
|
|
133580
132747
|
// src/tools/task/types.ts
|
|
133581
132748
|
var TaskStatusSchema = exports_external.enum(["pending", "in_progress", "completed", "deleted"]);
|
|
@@ -133629,18 +132796,18 @@ var TaskDeleteInputSchema = exports_external.object({
|
|
|
133629
132796
|
});
|
|
133630
132797
|
|
|
133631
132798
|
// src/features/claude-tasks/storage.ts
|
|
133632
|
-
import { join as
|
|
133633
|
-
import { existsSync as
|
|
132799
|
+
import { join as join86, dirname as dirname28, basename as basename14, isAbsolute as isAbsolute12 } from "path";
|
|
132800
|
+
import { existsSync as existsSync82, mkdirSync as mkdirSync16, readFileSync as readFileSync55, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
|
|
133634
132801
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
133635
132802
|
function getTaskDir(config4 = {}) {
|
|
133636
132803
|
const tasksConfig = config4.bob?.tasks;
|
|
133637
132804
|
const storagePath = tasksConfig?.storage_path;
|
|
133638
132805
|
if (storagePath) {
|
|
133639
|
-
return isAbsolute12(storagePath) ? storagePath :
|
|
132806
|
+
return isAbsolute12(storagePath) ? storagePath : join86(process.cwd(), storagePath);
|
|
133640
132807
|
}
|
|
133641
132808
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
133642
132809
|
const listId = resolveTaskListId(config4);
|
|
133643
|
-
return
|
|
132810
|
+
return join86(configDir, "tasks", listId);
|
|
133644
132811
|
}
|
|
133645
132812
|
function sanitizePathSegment(value) {
|
|
133646
132813
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
|
|
@@ -133658,13 +132825,13 @@ function resolveTaskListId(config4 = {}) {
|
|
|
133658
132825
|
return sanitizePathSegment(basename14(process.cwd()));
|
|
133659
132826
|
}
|
|
133660
132827
|
function ensureDir(dirPath) {
|
|
133661
|
-
if (!
|
|
132828
|
+
if (!existsSync82(dirPath)) {
|
|
133662
132829
|
mkdirSync16(dirPath, { recursive: true });
|
|
133663
132830
|
}
|
|
133664
132831
|
}
|
|
133665
132832
|
function readJsonSafe(filePath, schema2) {
|
|
133666
132833
|
try {
|
|
133667
|
-
if (!
|
|
132834
|
+
if (!existsSync82(filePath)) {
|
|
133668
132835
|
return null;
|
|
133669
132836
|
}
|
|
133670
132837
|
const content = readFileSync55(filePath, "utf-8");
|
|
@@ -133687,7 +132854,7 @@ function writeJsonAtomic(filePath, data) {
|
|
|
133687
132854
|
renameSync4(tempPath, filePath);
|
|
133688
132855
|
} catch (error92) {
|
|
133689
132856
|
try {
|
|
133690
|
-
if (
|
|
132857
|
+
if (existsSync82(tempPath)) {
|
|
133691
132858
|
unlinkSync11(tempPath);
|
|
133692
132859
|
}
|
|
133693
132860
|
} catch {}
|
|
@@ -133699,7 +132866,7 @@ function generateTaskId() {
|
|
|
133699
132866
|
return `T-${randomUUID2()}`;
|
|
133700
132867
|
}
|
|
133701
132868
|
function acquireLock(dirPath) {
|
|
133702
|
-
const lockPath =
|
|
132869
|
+
const lockPath = join86(dirPath, ".lock");
|
|
133703
132870
|
const lockId = randomUUID2();
|
|
133704
132871
|
const createLock = (timestamp2) => {
|
|
133705
132872
|
writeFileSync19(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
|
|
@@ -133747,7 +132914,7 @@ function acquireLock(dirPath) {
|
|
|
133747
132914
|
acquired: true,
|
|
133748
132915
|
release: () => {
|
|
133749
132916
|
try {
|
|
133750
|
-
if (!
|
|
132917
|
+
if (!existsSync82(lockPath))
|
|
133751
132918
|
return;
|
|
133752
132919
|
const lockContent = readFileSync55(lockPath, "utf-8");
|
|
133753
132920
|
const lockData = JSON.parse(lockContent);
|
|
@@ -133912,7 +133079,7 @@ async function handleCreate(args, config4, ctx, context) {
|
|
|
133912
133079
|
threadID: context.sessionID
|
|
133913
133080
|
};
|
|
133914
133081
|
const validatedTask = TaskObjectSchema.parse(task);
|
|
133915
|
-
writeJsonAtomic(
|
|
133082
|
+
writeJsonAtomic(join87(taskDir, `${taskId}.json`), validatedTask);
|
|
133916
133083
|
await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
|
|
133917
133084
|
return JSON.stringify({
|
|
133918
133085
|
task: {
|
|
@@ -133935,7 +133102,7 @@ async function handleCreate(args, config4, ctx, context) {
|
|
|
133935
133102
|
}
|
|
133936
133103
|
// src/tools/task/task-get.ts
|
|
133937
133104
|
init_tool();
|
|
133938
|
-
import { join as
|
|
133105
|
+
import { join as join88 } from "path";
|
|
133939
133106
|
var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
|
|
133940
133107
|
function parseTaskId(id) {
|
|
133941
133108
|
if (!TASK_ID_PATTERN.test(id))
|
|
@@ -133960,7 +133127,7 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
133960
133127
|
return JSON.stringify({ error: "invalid_task_id" });
|
|
133961
133128
|
}
|
|
133962
133129
|
const taskDir = getTaskDir(config4);
|
|
133963
|
-
const taskPath =
|
|
133130
|
+
const taskPath = join88(taskDir, `${taskId}.json`);
|
|
133964
133131
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
133965
133132
|
return JSON.stringify({ task: task ?? null });
|
|
133966
133133
|
} catch (error92) {
|
|
@@ -133974,8 +133141,8 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
133974
133141
|
}
|
|
133975
133142
|
// src/tools/task/task-list.ts
|
|
133976
133143
|
init_tool();
|
|
133977
|
-
import { join as
|
|
133978
|
-
import { existsSync as
|
|
133144
|
+
import { join as join89 } from "path";
|
|
133145
|
+
import { existsSync as existsSync83, readdirSync as readdirSync24 } from "fs";
|
|
133979
133146
|
function createTaskList(config4) {
|
|
133980
133147
|
return tool({
|
|
133981
133148
|
description: `List all active tasks with summary information.
|
|
@@ -133986,7 +133153,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
133986
133153
|
args: {},
|
|
133987
133154
|
execute: async () => {
|
|
133988
133155
|
const taskDir = getTaskDir(config4);
|
|
133989
|
-
if (!
|
|
133156
|
+
if (!existsSync83(taskDir)) {
|
|
133990
133157
|
return JSON.stringify({ tasks: [] });
|
|
133991
133158
|
}
|
|
133992
133159
|
const files = readdirSync24(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
|
|
@@ -133995,7 +133162,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
133995
133162
|
}
|
|
133996
133163
|
const allTasks = [];
|
|
133997
133164
|
for (const fileId of files) {
|
|
133998
|
-
const task = readJsonSafe(
|
|
133165
|
+
const task = readJsonSafe(join89(taskDir, `${fileId}.json`), TaskObjectSchema);
|
|
133999
133166
|
if (task) {
|
|
134000
133167
|
allTasks.push(task);
|
|
134001
133168
|
}
|
|
@@ -134024,7 +133191,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
134024
133191
|
}
|
|
134025
133192
|
// src/tools/task/task-update.ts
|
|
134026
133193
|
init_tool();
|
|
134027
|
-
import { join as
|
|
133194
|
+
import { join as join90 } from "path";
|
|
134028
133195
|
var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
|
|
134029
133196
|
function parseTaskId2(id) {
|
|
134030
133197
|
if (!TASK_ID_PATTERN2.test(id))
|
|
@@ -134072,7 +133239,7 @@ async function handleUpdate(args, config4, ctx, context) {
|
|
|
134072
133239
|
return JSON.stringify({ error: "task_lock_unavailable" });
|
|
134073
133240
|
}
|
|
134074
133241
|
try {
|
|
134075
|
-
const taskPath =
|
|
133242
|
+
const taskPath = join90(taskDir, `${taskId}.json`);
|
|
134076
133243
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
134077
133244
|
if (!task) {
|
|
134078
133245
|
return JSON.stringify({ error: "task_not_found" });
|
|
@@ -134942,7 +134109,7 @@ Diff.prototype = {
|
|
|
134942
134109
|
tokenize: function tokenize(value) {
|
|
134943
134110
|
return Array.from(value);
|
|
134944
134111
|
},
|
|
134945
|
-
join: function
|
|
134112
|
+
join: function join91(chars) {
|
|
134946
134113
|
return chars.join("");
|
|
134947
134114
|
},
|
|
134948
134115
|
postProcess: function postProcess(changeObjects) {
|
|
@@ -137203,7 +136370,7 @@ function unregisterManagerForCleanup(manager) {
|
|
|
137203
136370
|
|
|
137204
136371
|
// src/features/background-agent/compaction-aware-message-resolver.ts
|
|
137205
136372
|
import { readdirSync as readdirSync25, readFileSync as readFileSync56 } from "fs";
|
|
137206
|
-
import { join as
|
|
136373
|
+
import { join as join92 } from "path";
|
|
137207
136374
|
function hasFullAgentAndModel(message) {
|
|
137208
136375
|
return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
|
|
137209
136376
|
}
|
|
@@ -137282,7 +136449,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
|
|
|
137282
136449
|
const messages = [];
|
|
137283
136450
|
for (const file3 of files) {
|
|
137284
136451
|
try {
|
|
137285
|
-
const content = readFileSync56(
|
|
136452
|
+
const content = readFileSync56(join92(messageDir, file3), "utf-8");
|
|
137286
136453
|
const parsed = JSON.parse(content);
|
|
137287
136454
|
if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
|
|
137288
136455
|
continue;
|
|
@@ -137372,7 +136539,7 @@ function handleSessionIdleBackgroundEvent(args) {
|
|
|
137372
136539
|
}
|
|
137373
136540
|
|
|
137374
136541
|
// src/features/background-agent/manager.ts
|
|
137375
|
-
import { join as
|
|
136542
|
+
import { join as join93 } from "path";
|
|
137376
136543
|
|
|
137377
136544
|
// src/features/background-agent/task-poller.ts
|
|
137378
136545
|
init_plugin_identity();
|
|
@@ -139048,7 +138215,7 @@ ${originalText}`;
|
|
|
139048
138215
|
parentSessionID: task.parentSessionID
|
|
139049
138216
|
});
|
|
139050
138217
|
}
|
|
139051
|
-
const messageDir =
|
|
138218
|
+
const messageDir = join93(MESSAGE_STORAGE, task.parentSessionID);
|
|
139052
138219
|
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionID) : null;
|
|
139053
138220
|
agent = currentMessage?.agent ?? task.parentAgent;
|
|
139054
138221
|
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
@@ -139379,11 +138546,11 @@ ${originalText}`;
|
|
|
139379
138546
|
}
|
|
139380
138547
|
}
|
|
139381
138548
|
// src/features/mcp-oauth/storage.ts
|
|
139382
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
139383
|
-
import { dirname as dirname29, join as
|
|
138549
|
+
import { chmodSync as chmodSync2, existsSync as existsSync84, mkdirSync as mkdirSync17, readFileSync as readFileSync57, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
|
|
138550
|
+
import { dirname as dirname29, join as join94 } from "path";
|
|
139384
138551
|
var STORAGE_FILE_NAME = "mcp-oauth.json";
|
|
139385
138552
|
function getMcpOauthStoragePath() {
|
|
139386
|
-
return
|
|
138553
|
+
return join94(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
|
|
139387
138554
|
}
|
|
139388
138555
|
function normalizeHost(serverHost) {
|
|
139389
138556
|
let host = serverHost.trim();
|
|
@@ -139420,7 +138587,7 @@ function buildKey(serverHost, resource) {
|
|
|
139420
138587
|
}
|
|
139421
138588
|
function readStore() {
|
|
139422
138589
|
const filePath = getMcpOauthStoragePath();
|
|
139423
|
-
if (!
|
|
138590
|
+
if (!existsSync84(filePath)) {
|
|
139424
138591
|
return null;
|
|
139425
138592
|
}
|
|
139426
138593
|
try {
|
|
@@ -139434,7 +138601,7 @@ function writeStore(store2) {
|
|
|
139434
138601
|
const filePath = getMcpOauthStoragePath();
|
|
139435
138602
|
try {
|
|
139436
138603
|
const dir = dirname29(filePath);
|
|
139437
|
-
if (!
|
|
138604
|
+
if (!existsSync84(dir)) {
|
|
139438
138605
|
mkdirSync17(dir, { recursive: true });
|
|
139439
138606
|
}
|
|
139440
138607
|
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
@@ -146081,8 +145248,8 @@ class TmuxSessionManager {
|
|
|
146081
145248
|
var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
|
|
146082
145249
|
var MIN_STABILITY_TIME_MS4 = 10 * 1000;
|
|
146083
145250
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
146084
|
-
import { existsSync as
|
|
146085
|
-
import { join as
|
|
145251
|
+
import { existsSync as existsSync85, readFileSync as readFileSync58 } from "fs";
|
|
145252
|
+
import { join as join95 } from "path";
|
|
146086
145253
|
import { homedir as homedir15 } from "os";
|
|
146087
145254
|
init_logger();
|
|
146088
145255
|
function getMcpConfigPaths() {
|
|
@@ -146090,10 +145257,10 @@ function getMcpConfigPaths() {
|
|
|
146090
145257
|
const cwd = process.cwd();
|
|
146091
145258
|
const explicitClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
146092
145259
|
const candidates = [
|
|
146093
|
-
...explicitClaudeConfigDir ? [] : [{ path:
|
|
146094
|
-
{ path:
|
|
146095
|
-
{ path:
|
|
146096
|
-
{ path:
|
|
145260
|
+
...explicitClaudeConfigDir ? [] : [{ path: join95(homedir15(), ".claude.json"), scope: "user" }],
|
|
145261
|
+
{ path: join95(claudeConfigDir, ".mcp.json"), scope: "user" },
|
|
145262
|
+
{ path: join95(cwd, ".mcp.json"), scope: "project" },
|
|
145263
|
+
{ path: join95(cwd, ".claude", ".mcp.json"), scope: "local" }
|
|
146097
145264
|
];
|
|
146098
145265
|
const seen = new Set;
|
|
146099
145266
|
return candidates.filter(({ path: path9 }) => {
|
|
@@ -146104,7 +145271,7 @@ function getMcpConfigPaths() {
|
|
|
146104
145271
|
});
|
|
146105
145272
|
}
|
|
146106
145273
|
async function loadMcpConfigFile(filePath) {
|
|
146107
|
-
if (!
|
|
145274
|
+
if (!existsSync85(filePath)) {
|
|
146108
145275
|
return null;
|
|
146109
145276
|
}
|
|
146110
145277
|
try {
|
|
@@ -146120,7 +145287,7 @@ function getSystemMcpServerNames() {
|
|
|
146120
145287
|
const paths = getMcpConfigPaths();
|
|
146121
145288
|
const cwd = process.cwd();
|
|
146122
145289
|
for (const { path: path9 } of paths) {
|
|
146123
|
-
if (!
|
|
145290
|
+
if (!existsSync85(path9))
|
|
146124
145291
|
continue;
|
|
146125
145292
|
try {
|
|
146126
145293
|
const content = readFileSync58(path9, "utf-8");
|
|
@@ -146472,7 +145639,7 @@ ${keyTriggers.join(`
|
|
|
146472
145639
|
`)}
|
|
146473
145640
|
- **"Look into" + "create PR"** \u2192 Not just research. Full implementation cycle expected.`;
|
|
146474
145641
|
}
|
|
146475
|
-
function buildToolSelectionTable(agents, tools = [], _skills = []) {
|
|
145642
|
+
function buildToolSelectionTable(agents, tools = [], _skills = [], options = {}) {
|
|
146476
145643
|
const rows = ["### Tool & Agent Selection:", ""];
|
|
146477
145644
|
if (tools.length > 0) {
|
|
146478
145645
|
rows.push(`- ${getToolsPromptDisplay(tools)} - **FREE** - Not Complex, Scope Clear, No Implicit Assumptions`);
|
|
@@ -146485,9 +145652,43 @@ function buildToolSelectionTable(agents, tools = [], _skills = []) {
|
|
|
146485
145652
|
}
|
|
146486
145653
|
rows.push("");
|
|
146487
145654
|
rows.push("**Default flow**: researcher (background) + tools \u2192 strategist (if required) \u2192 critic (high-risk gate)");
|
|
145655
|
+
if (options.includeIntegrationPrimer) {
|
|
145656
|
+
rows.push("");
|
|
145657
|
+
rows.push(buildHiaiIntegrationPrimerSection());
|
|
145658
|
+
}
|
|
146488
145659
|
return rows.join(`
|
|
146489
145660
|
`);
|
|
146490
145661
|
}
|
|
145662
|
+
function buildHiaiIntegrationPrimerSection() {
|
|
145663
|
+
return `<hiai-opencode-integration-primer>
|
|
145664
|
+
## hiai-opencode Architecture And Integration Rules
|
|
145665
|
+
|
|
145666
|
+
This workspace may use hiai-opencode, an OpenCode plugin that wires agents, skills, MCP launchers, LSP, diagnostics, and compatibility helpers around external upstream tools.
|
|
145667
|
+
|
|
145668
|
+
Core rules:
|
|
145669
|
+
- OpenCode plugins are not MCP servers. Keep \`@hiai-gg/hiai-opencode\` and optional \`@tarquinen/opencode-dcp\` in the OpenCode plugin list; never add MCP packages such as \`firecrawl-mcp\`, \`@playwright/mcp\`, or \`@modelcontextprotocol/server-sequential-thinking\` to the plugin list.
|
|
145670
|
+
- User-facing config lives in \`hiai-opencode.json\` or \`.opencode/hiai-opencode.json\`: 10 model slots, MCP enable flags, LSP enable flags, service auth placeholders, and skill discovery switches.
|
|
145671
|
+
- Model provider credentials are configured through OpenCode Connect. Do not ask for \`OPENROUTER_API_KEY\`, \`OPENAI_API_KEY\`, or \`ANTHROPIC_API_KEY\` for normal model usage.
|
|
145672
|
+
- Service keys are separate: \`FIRECRAWL_API_KEY\`, \`STITCH_AI_API_KEY\`, \`CONTEXT7_API_KEY\`, and \`OPENCODE_RAG_URL\` when those services are enabled.
|
|
145673
|
+
|
|
145674
|
+
MCP usage:
|
|
145675
|
+
- Run \`hiai-opencode doctor\` or \`hiai-opencode mcp-status\` for effective runtime MCP status.
|
|
145676
|
+
- \`opencode mcp list\` often reads only static \`.mcp.json\`; plugin runtime MCP may work even when that list is empty.
|
|
145677
|
+
- The plugin auto-exports \`.mcp.json\` when missing. Run \`hiai-opencode export-mcp .mcp.json\` to refresh static visibility.
|
|
145678
|
+
- \`skill_mcp\` can call skill-embedded MCP and enabled hiai-opencode MCP. If an MCP is "not found", check whether the skill was loaded, whether \`hiai-opencode.json\` enables it, and whether static export is needed.
|
|
145679
|
+
|
|
145680
|
+
Memory and retrieval:
|
|
145681
|
+
- MemPalace MCP is external. If enabled, use \`mempalace_status\` first, search before answering about remembered people/projects/past decisions, and write diary entries when appropriate. Never invent memories.
|
|
145682
|
+
- RAG MCP is external/local. Use it for project knowledge search when \`OPENCODE_RAG_URL\` is configured or the default \`http://localhost:9002/tools/search\` is reachable.
|
|
145683
|
+
- Sequential Thinking MCP is for complex planning/revision/branching, not for trivial edits.
|
|
145684
|
+
- Firecrawl/Stitch/Context7 are external web/docs/research services; missing service keys should be reported by env var name only.
|
|
145685
|
+
|
|
145686
|
+
Installation/debugging:
|
|
145687
|
+
- Use \`/doctor\` or \`hiai-opencode doctor\` before changing config.
|
|
145688
|
+
- Prefer user-level or project-local installs. Do not use sudo/admin rights unless explicitly requested.
|
|
145689
|
+
- If DCP is requested, install it separately with \`opencode plugin @tarquinen/opencode-dcp@latest --global\`.
|
|
145690
|
+
</hiai-opencode-integration-primer>`;
|
|
145691
|
+
}
|
|
146491
145692
|
function buildResearcherSection(agents) {
|
|
146492
145693
|
const researcherAgent = agents.find((agent) => agent.name === "researcher");
|
|
146493
145694
|
if (!researcherAgent) {
|
|
@@ -146860,7 +146061,7 @@ When asking for clarification:
|
|
|
146860
146061
|
}
|
|
146861
146062
|
function buildGptProBobPrompt(_model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
146862
146063
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
146863
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
146064
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
146864
146065
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
146865
146066
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
146866
146067
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -147336,7 +146537,7 @@ function buildIntentGate(role) {
|
|
|
147336
146537
|
var MODE = "primary";
|
|
147337
146538
|
function buildDynamicBobPrompt(model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
147338
146539
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
147339
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
146540
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
147340
146541
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
147341
146542
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
147342
146543
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -149166,7 +148367,7 @@ var guardPromptMetadata = {
|
|
|
149166
148367
|
// src/agents/coder/gpt.ts
|
|
149167
148368
|
function buildCoderPrompt(availableAgents = [], availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
149168
148369
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
149169
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
148370
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
149170
148371
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
149171
148372
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
149172
148373
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -149385,7 +148586,7 @@ function canonicalizeCriticSection(section) {
|
|
|
149385
148586
|
}
|
|
149386
148587
|
function buildCoderPrompt2(availableAgents = [], availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
149387
148588
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
149388
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
148589
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
149389
148590
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
149390
148591
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
149391
148592
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -149710,7 +148911,7 @@ createCoderAgent.mode = MODE5;
|
|
|
149710
148911
|
// src/agents/coder/gpt-pro.ts
|
|
149711
148912
|
function buildCoderPrompt3(availableAgents = [], availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
149712
148913
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
149713
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
148914
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
149714
148915
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
149715
148916
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
149716
148917
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -150468,7 +149669,7 @@ var researcherPromptMetadata = {
|
|
|
150468
149669
|
};
|
|
150469
149670
|
|
|
150470
149671
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
150471
|
-
import { existsSync as
|
|
149672
|
+
import { existsSync as existsSync86, readFileSync as readFileSync59 } from "fs";
|
|
150472
149673
|
import { homedir as homedir16 } from "os";
|
|
150473
149674
|
import { isAbsolute as isAbsolute13, resolve as resolve22 } from "path";
|
|
150474
149675
|
init_logger();
|
|
@@ -150493,7 +149694,7 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
150493
149694
|
});
|
|
150494
149695
|
return `[WARNING: Path rejected: ${promptAppend}]`;
|
|
150495
149696
|
}
|
|
150496
|
-
if (!
|
|
149697
|
+
if (!existsSync86(filePath)) {
|
|
150497
149698
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
150498
149699
|
}
|
|
150499
149700
|
try {
|
|
@@ -154448,7 +153649,7 @@ async function applyAgentConfig(params) {
|
|
|
154448
153649
|
init_agent_display_names();
|
|
154449
153650
|
// src/features/claude-code-command-loader/loader.ts
|
|
154450
153651
|
import { promises as fs14 } from "fs";
|
|
154451
|
-
import { join as
|
|
153652
|
+
import { join as join96, basename as basename15 } from "path";
|
|
154452
153653
|
init_logger();
|
|
154453
153654
|
async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
|
|
154454
153655
|
try {
|
|
@@ -154479,7 +153680,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
154479
153680
|
if (entry.isDirectory()) {
|
|
154480
153681
|
if (entry.name.startsWith("."))
|
|
154481
153682
|
continue;
|
|
154482
|
-
const subDirPath =
|
|
153683
|
+
const subDirPath = join96(commandsDir, entry.name);
|
|
154483
153684
|
const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
154484
153685
|
const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
|
|
154485
153686
|
commands2.push(...subCommands);
|
|
@@ -154487,7 +153688,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
154487
153688
|
}
|
|
154488
153689
|
if (!isMarkdownFile(entry))
|
|
154489
153690
|
continue;
|
|
154490
|
-
const commandPath =
|
|
153691
|
+
const commandPath = join96(commandsDir, entry.name);
|
|
154491
153692
|
const baseCommandName = basename15(entry.name, ".md");
|
|
154492
153693
|
const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
|
|
154493
153694
|
try {
|
|
@@ -154546,12 +153747,12 @@ function commandsToRecord(commands2) {
|
|
|
154546
153747
|
return result;
|
|
154547
153748
|
}
|
|
154548
153749
|
async function loadUserCommands() {
|
|
154549
|
-
const userCommandsDir =
|
|
153750
|
+
const userCommandsDir = join96(getClaudeConfigDir(), "commands");
|
|
154550
153751
|
const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
|
|
154551
153752
|
return commandsToRecord(commands2);
|
|
154552
153753
|
}
|
|
154553
153754
|
async function loadProjectCommands(directory) {
|
|
154554
|
-
const projectCommandsDir =
|
|
153755
|
+
const projectCommandsDir = join96(directory ?? process.cwd(), ".claude", "commands");
|
|
154555
153756
|
const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
|
|
154556
153757
|
return commandsToRecord(commands2);
|
|
154557
153758
|
}
|
|
@@ -154637,7 +153838,7 @@ function remapCommandAgentFields(commands2) {
|
|
|
154637
153838
|
|
|
154638
153839
|
// src/plugin-handlers/mcp-config-handler.ts
|
|
154639
153840
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
154640
|
-
import { existsSync as
|
|
153841
|
+
import { existsSync as existsSync87 } from "fs";
|
|
154641
153842
|
|
|
154642
153843
|
// src/mcp/websearch.ts
|
|
154643
153844
|
init_logger();
|
|
@@ -154790,7 +153991,7 @@ function hasUsableLocalMcpRuntime(name, entry) {
|
|
|
154790
153991
|
return false;
|
|
154791
153992
|
}
|
|
154792
153993
|
if (binary2 === "node" && typeof args[0] === "string" && args[0].endsWith(".mjs")) {
|
|
154793
|
-
if (!
|
|
153994
|
+
if (!existsSync87(args[0])) {
|
|
154794
153995
|
return false;
|
|
154795
153996
|
}
|
|
154796
153997
|
const probe2 = spawnSync5(binary2, ["--version"], {
|
|
@@ -155109,6 +154310,8 @@ function applyToolConfig(params) {
|
|
|
155109
154310
|
function buildLspConfig(lsp) {
|
|
155110
154311
|
const result = {};
|
|
155111
154312
|
for (const [name, server] of Object.entries(lsp)) {
|
|
154313
|
+
if (server.enabled === false)
|
|
154314
|
+
continue;
|
|
155112
154315
|
result[name] = {
|
|
155113
154316
|
command: server.command,
|
|
155114
154317
|
extensions: server.extensions,
|
|
@@ -155402,6 +154605,7 @@ function createToolRegistry(args) {
|
|
|
155402
154605
|
managers,
|
|
155403
154606
|
skillContext,
|
|
155404
154607
|
availableCategories,
|
|
154608
|
+
builtinMcp,
|
|
155405
154609
|
interactiveBashEnabled = isInteractiveBashEnabled(),
|
|
155406
154610
|
toolFactories
|
|
155407
154611
|
} = args;
|
|
@@ -155449,7 +154653,8 @@ function createToolRegistry(args) {
|
|
|
155449
154653
|
const skillMcpTool = factories.createSkillMcpTool({
|
|
155450
154654
|
manager: managers.skillMcpManager,
|
|
155451
154655
|
getLoadedSkills: () => skillContext.mergedSkills,
|
|
155452
|
-
getSessionID: getSessionIDForMcp
|
|
154656
|
+
getSessionID: getSessionIDForMcp,
|
|
154657
|
+
builtinMcp
|
|
155453
154658
|
});
|
|
155454
154659
|
const commands2 = factories.discoverCommandsSync(ctx.directory, {
|
|
155455
154660
|
pluginsEnabled: pluginConfig.claude_code?.plugins ?? true,
|
|
@@ -155505,7 +154710,7 @@ function createToolRegistry(args) {
|
|
|
155505
154710
|
|
|
155506
154711
|
// src/create-tools.ts
|
|
155507
154712
|
async function createTools(args) {
|
|
155508
|
-
const { ctx, pluginConfig, managers } = args;
|
|
154713
|
+
const { ctx, pluginConfig, platformConfig, managers } = args;
|
|
155509
154714
|
const skillContext = await createSkillContext({
|
|
155510
154715
|
directory: ctx.directory,
|
|
155511
154716
|
pluginConfig
|
|
@@ -155516,7 +154721,8 @@ async function createTools(args) {
|
|
|
155516
154721
|
pluginConfig,
|
|
155517
154722
|
managers,
|
|
155518
154723
|
skillContext,
|
|
155519
|
-
availableCategories
|
|
154724
|
+
availableCategories,
|
|
154725
|
+
builtinMcp: platformConfig?.mcp
|
|
155520
154726
|
});
|
|
155521
154727
|
return {
|
|
155522
154728
|
filteredTools,
|
|
@@ -155785,10 +154991,10 @@ init_agent_display_names();
|
|
|
155785
154991
|
|
|
155786
154992
|
// src/plugin/ultrawork-db-model-override.ts
|
|
155787
154993
|
import { Database } from "bun:sqlite";
|
|
155788
|
-
import { join as
|
|
155789
|
-
import { existsSync as
|
|
154994
|
+
import { join as join97 } from "path";
|
|
154995
|
+
import { existsSync as existsSync88 } from "fs";
|
|
155790
154996
|
function getDbPath() {
|
|
155791
|
-
return
|
|
154997
|
+
return join97(getDataDir(), "opencode", "opencode.db");
|
|
155792
154998
|
}
|
|
155793
154999
|
var MAX_MICROTASK_RETRIES = 10;
|
|
155794
155000
|
function tryUpdateMessageModel(db, messageId, targetModel, variant) {
|
|
@@ -155865,7 +155071,7 @@ function retryViaMicrotask(db, messageId, targetModel, variant, attempt) {
|
|
|
155865
155071
|
function scheduleDeferredModelOverride(messageId, targetModel, variant) {
|
|
155866
155072
|
queueMicrotask(() => {
|
|
155867
155073
|
const dbPath = getDbPath();
|
|
155868
|
-
if (!
|
|
155074
|
+
if (!existsSync88(dbPath)) {
|
|
155869
155075
|
log("[ultrawork-db-override] DB not found, skipping deferred override");
|
|
155870
155076
|
return;
|
|
155871
155077
|
}
|
|
@@ -157207,114 +156413,98 @@ function createFirstMessageVariantGate() {
|
|
|
157207
156413
|
// src/index.ts
|
|
157208
156414
|
init_plugin_identity();
|
|
157209
156415
|
|
|
157210
|
-
// src/shared/
|
|
157211
|
-
import { existsSync as
|
|
157212
|
-
import { join as join98 } from "path";
|
|
157213
|
-
|
|
157214
|
-
|
|
157215
|
-
|
|
157216
|
-
|
|
157217
|
-
|
|
157218
|
-
|
|
157219
|
-
|
|
157220
|
-
|
|
156416
|
+
// src/shared/mcp-static-export.ts
|
|
156417
|
+
import { existsSync as existsSync89, mkdirSync as mkdirSync18, readFileSync as readFileSync60, writeFileSync as writeFileSync21 } from "fs";
|
|
156418
|
+
import { dirname as dirname30, join as join98 } from "path";
|
|
156419
|
+
init_logger();
|
|
156420
|
+
var MCP_EXPORT_MARKER = "hiai-opencode";
|
|
156421
|
+
function toStaticMcpServer(config4) {
|
|
156422
|
+
if (config4.enabled === false)
|
|
156423
|
+
return null;
|
|
156424
|
+
if (config4.type === "remote") {
|
|
156425
|
+
const headers = config4.headers ? Object.fromEntries(Object.entries(config4.headers).map(([key, value]) => [key, resolveEnvVars(value)])) : undefined;
|
|
156426
|
+
return {
|
|
156427
|
+
type: "http",
|
|
156428
|
+
url: config4.url,
|
|
156429
|
+
...headers ? { headers } : {}
|
|
156430
|
+
};
|
|
156431
|
+
}
|
|
156432
|
+
const [command, ...args] = config4.command ?? [];
|
|
156433
|
+
if (!command)
|
|
156434
|
+
return null;
|
|
156435
|
+
const env = config4.environment ? Object.fromEntries(Object.entries(config4.environment).map(([key, value]) => [key, resolveEnvVars(value)])) : undefined;
|
|
156436
|
+
return {
|
|
156437
|
+
command,
|
|
156438
|
+
...args.length > 0 ? { args } : {},
|
|
156439
|
+
...env ? { env } : {}
|
|
156440
|
+
};
|
|
157221
156441
|
}
|
|
157222
|
-
|
|
157223
|
-
|
|
157224
|
-
|
|
157225
|
-
|
|
157226
|
-
|
|
157227
|
-
|
|
157228
|
-
config: {
|
|
157229
|
-
enabled: true,
|
|
157230
|
-
command: ["node", resolveAssetScript("mcp", "playwright.mjs")],
|
|
157231
|
-
timeout: 600000
|
|
157232
|
-
}
|
|
157233
|
-
},
|
|
157234
|
-
stitch: {
|
|
157235
|
-
name: "stitch",
|
|
157236
|
-
enabledByDefault: true,
|
|
157237
|
-
install: "remote",
|
|
157238
|
-
requiredEnv: ["STITCH_AI_API_KEY"],
|
|
157239
|
-
config: {
|
|
157240
|
-
enabled: true,
|
|
157241
|
-
type: "remote",
|
|
157242
|
-
url: "https://stitch.googleapis.com/mcp",
|
|
157243
|
-
headers: { "X-Goog-Api-Key": "{env:STITCH_AI_API_KEY}" },
|
|
157244
|
-
timeout: 600000
|
|
157245
|
-
}
|
|
157246
|
-
},
|
|
157247
|
-
"sequential-thinking": {
|
|
157248
|
-
name: "sequential-thinking",
|
|
157249
|
-
enabledByDefault: true,
|
|
157250
|
-
install: "npm",
|
|
157251
|
-
config: {
|
|
157252
|
-
enabled: true,
|
|
157253
|
-
command: createNpmPackageCommand("@modelcontextprotocol/server-sequential-thinking"),
|
|
157254
|
-
timeout: 600000
|
|
157255
|
-
}
|
|
157256
|
-
},
|
|
157257
|
-
firecrawl: {
|
|
157258
|
-
name: "firecrawl",
|
|
157259
|
-
enabledByDefault: true,
|
|
157260
|
-
install: "npm",
|
|
157261
|
-
requiredEnv: ["FIRECRAWL_API_KEY"],
|
|
157262
|
-
config: {
|
|
157263
|
-
enabled: true,
|
|
157264
|
-
command: createNpmPackageCommand("firecrawl-mcp"),
|
|
157265
|
-
timeout: 600000,
|
|
157266
|
-
environment: { FIRECRAWL_API_KEY: "{env:FIRECRAWL_API_KEY}" }
|
|
157267
|
-
}
|
|
157268
|
-
},
|
|
157269
|
-
rag: {
|
|
157270
|
-
name: "rag",
|
|
157271
|
-
enabledByDefault: true,
|
|
157272
|
-
install: "user-service",
|
|
157273
|
-
optionalEnv: ["OPENCODE_RAG_URL"],
|
|
157274
|
-
config: {
|
|
157275
|
-
enabled: true,
|
|
157276
|
-
type: "local",
|
|
157277
|
-
command: ["node", resolveAssetScript("mcp", "rag.mjs")],
|
|
157278
|
-
environment: {
|
|
157279
|
-
OPENCODE_RAG_URL: "{env:OPENCODE_RAG_URL:-http://localhost:9002/tools/search}"
|
|
157280
|
-
},
|
|
157281
|
-
timeout: 600000
|
|
157282
|
-
}
|
|
157283
|
-
},
|
|
157284
|
-
context7: {
|
|
157285
|
-
name: "context7",
|
|
157286
|
-
enabledByDefault: true,
|
|
157287
|
-
install: "remote",
|
|
157288
|
-
optionalEnv: ["CONTEXT7_API_KEY"],
|
|
157289
|
-
config: {
|
|
157290
|
-
enabled: true,
|
|
157291
|
-
type: "remote",
|
|
157292
|
-
url: "https://mcp.context7.com/mcp",
|
|
157293
|
-
headers: { "X-API-KEY": "{env:CONTEXT7_API_KEY}" },
|
|
157294
|
-
timeout: 600000
|
|
157295
|
-
}
|
|
157296
|
-
},
|
|
157297
|
-
mempalace: {
|
|
157298
|
-
name: "mempalace",
|
|
157299
|
-
enabledByDefault: true,
|
|
157300
|
-
install: "python",
|
|
157301
|
-
optionalEnv: ["MEMPALACE_PYTHON", "MEMPALACE_PALACE_PATH", "HIAI_MCP_AUTO_INSTALL"],
|
|
157302
|
-
config: {
|
|
157303
|
-
enabled: true,
|
|
157304
|
-
type: "local",
|
|
157305
|
-
command: ["node", resolveAssetScript("mcp", "mempalace.mjs"), "--palace", "./.opencode/palace"],
|
|
157306
|
-
timeout: 600000
|
|
156442
|
+
function buildStaticMcpJson(config4) {
|
|
156443
|
+
const mcpServers = {};
|
|
156444
|
+
for (const [name, serverConfig] of Object.entries(config4.mcp ?? {})) {
|
|
156445
|
+
const converted = toStaticMcpServer(serverConfig);
|
|
156446
|
+
if (converted) {
|
|
156447
|
+
mcpServers[name] = converted;
|
|
157307
156448
|
}
|
|
157308
156449
|
}
|
|
157309
|
-
|
|
156450
|
+
return {
|
|
156451
|
+
_meta: {
|
|
156452
|
+
generatedBy: MCP_EXPORT_MARKER,
|
|
156453
|
+
version: 1,
|
|
156454
|
+
generatedAt: new Date().toISOString()
|
|
156455
|
+
},
|
|
156456
|
+
mcpServers
|
|
156457
|
+
};
|
|
156458
|
+
}
|
|
156459
|
+
function isManagedStaticMcpFile(path9) {
|
|
156460
|
+
if (!existsSync89(path9))
|
|
156461
|
+
return false;
|
|
156462
|
+
try {
|
|
156463
|
+
const raw = readFileSync60(path9, "utf-8");
|
|
156464
|
+
const parsed = JSON.parse(raw);
|
|
156465
|
+
return parsed?._meta?.generatedBy === MCP_EXPORT_MARKER;
|
|
156466
|
+
} catch {
|
|
156467
|
+
return false;
|
|
156468
|
+
}
|
|
156469
|
+
}
|
|
156470
|
+
function autoExportStaticMcpJson(directory, config4) {
|
|
156471
|
+
const mode = process.env.HIAI_OPENCODE_AUTO_EXPORT_MCP?.trim().toLowerCase() || "if-missing";
|
|
156472
|
+
if (mode === "0" || mode === "false" || mode === "no" || mode === "off") {
|
|
156473
|
+
return;
|
|
156474
|
+
}
|
|
156475
|
+
const outputPath = process.env.HIAI_OPENCODE_MCP_EXPORT_PATH?.trim() || join98(directory, ".mcp.json");
|
|
156476
|
+
if (mode === "if-missing" && existsSync89(outputPath)) {
|
|
156477
|
+
return;
|
|
156478
|
+
}
|
|
156479
|
+
const isForceMode = mode === "force";
|
|
156480
|
+
if (mode === "always" && existsSync89(outputPath) && !isManagedStaticMcpFile(outputPath) && !isForceMode) {
|
|
156481
|
+
console.warn(`[hiai-opencode] WARNING: refusing to overwrite non-managed static MCP config at ${outputPath}. ` + "Set HIAI_OPENCODE_AUTO_EXPORT_MCP=force to override.");
|
|
156482
|
+
return;
|
|
156483
|
+
}
|
|
156484
|
+
try {
|
|
156485
|
+
mkdirSync18(dirname30(outputPath), { recursive: true });
|
|
156486
|
+
const payload = buildStaticMcpJson(config4);
|
|
156487
|
+
writeFileSync21(outputPath, `${JSON.stringify(payload, null, 2)}
|
|
156488
|
+
`);
|
|
156489
|
+
log("[hiai-opencode] exported static MCP config", {
|
|
156490
|
+
outputPath,
|
|
156491
|
+
servers: Object.keys(payload.mcpServers)
|
|
156492
|
+
});
|
|
156493
|
+
} catch (error92) {
|
|
156494
|
+
const message = error92 instanceof Error ? error92.message : String(error92);
|
|
156495
|
+
console.warn(`[hiai-opencode] WARNING: failed to export static MCP config to ${outputPath}: ${message}`);
|
|
156496
|
+
}
|
|
156497
|
+
}
|
|
157310
156498
|
|
|
157311
156499
|
// src/shared/startup-diagnostics.ts
|
|
156500
|
+
import { existsSync as existsSync90, readFileSync as readFileSync61 } from "fs";
|
|
156501
|
+
import { join as join99 } from "path";
|
|
157312
156502
|
init_plugin_identity();
|
|
157313
156503
|
function readPlugins(configPath) {
|
|
157314
|
-
if (!
|
|
156504
|
+
if (!existsSync90(configPath))
|
|
157315
156505
|
return [];
|
|
157316
156506
|
try {
|
|
157317
|
-
const content =
|
|
156507
|
+
const content = readFileSync61(configPath, "utf-8");
|
|
157318
156508
|
const parsed = parseJsoncSafe(content);
|
|
157319
156509
|
return (parsed.data?.plugin ?? []).map((entry) => typeof entry === "string" ? entry : Array.isArray(entry) ? entry[0] : "").filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
157320
156510
|
} catch {
|
|
@@ -157324,8 +156514,8 @@ function readPlugins(configPath) {
|
|
|
157324
156514
|
function warnIfListPluginEntry(directory) {
|
|
157325
156515
|
const globalPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
157326
156516
|
const candidates = [
|
|
157327
|
-
|
|
157328
|
-
|
|
156517
|
+
join99(directory, ".opencode", "opencode.json"),
|
|
156518
|
+
join99(directory, ".opencode", "opencode.jsonc"),
|
|
157329
156519
|
globalPaths.configJson,
|
|
157330
156520
|
globalPaths.configJsonc
|
|
157331
156521
|
];
|
|
@@ -157678,8 +156868,8 @@ function resolveResultReferences(text, sessionID) {
|
|
|
157678
156868
|
}
|
|
157679
156869
|
|
|
157680
156870
|
// src/internals/plugins/subtask2/utils/config.ts
|
|
157681
|
-
import { mkdirSync as
|
|
157682
|
-
import { dirname as
|
|
156871
|
+
import { mkdirSync as mkdirSync19 } from "fs";
|
|
156872
|
+
import { dirname as dirname31, join as join100 } from "path";
|
|
157683
156873
|
|
|
157684
156874
|
// src/internals/plugins/subtask2/utils/prompts.ts
|
|
157685
156875
|
var DEFAULT_RETURN_PROMPT = "Review, challenge and verify the task tool output above against the codebase. Then validate or revise it, before continuing with the next logical step.";
|
|
@@ -157745,15 +156935,15 @@ async function getAutoWorkflowPrompt() {
|
|
|
157745
156935
|
var AUTO_WORKFLOW_PROMPT = AUTO_WORKFLOW_PROMPT_TEMPLATE.replace(README_PLACEHOLDER, "[Use getAutoWorkflowPrompt() to get full documentation]");
|
|
157746
156936
|
|
|
157747
156937
|
// src/internals/plugins/subtask2/utils/config.ts
|
|
157748
|
-
var CONFIG_PATH =
|
|
156938
|
+
var CONFIG_PATH = join100(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
|
|
157749
156939
|
var cachedReadmeContent = null;
|
|
157750
156940
|
async function loadReadmeContent() {
|
|
157751
156941
|
if (cachedReadmeContent !== null) {
|
|
157752
156942
|
return cachedReadmeContent;
|
|
157753
156943
|
}
|
|
157754
156944
|
try {
|
|
157755
|
-
const pluginRoot =
|
|
157756
|
-
const readmePath =
|
|
156945
|
+
const pluginRoot = join100(dirname31(import.meta.path), "..", "..");
|
|
156946
|
+
const readmePath = join100(pluginRoot, "README.md");
|
|
157757
156947
|
const file3 = Bun.file(readmePath);
|
|
157758
156948
|
if (await file3.exists()) {
|
|
157759
156949
|
cachedReadmeContent = await file3.text();
|
|
@@ -157788,7 +156978,7 @@ async function loadConfig2() {
|
|
|
157788
156978
|
}
|
|
157789
156979
|
}
|
|
157790
156980
|
} catch {}
|
|
157791
|
-
|
|
156981
|
+
mkdirSync19(dirname31(CONFIG_PATH), { recursive: true });
|
|
157792
156982
|
await Bun.write(CONFIG_PATH, `{
|
|
157793
156983
|
// Replace OpenCode's generic "Summarize..." prompt when no return is specified
|
|
157794
156984
|
"replace_generic": true,
|
|
@@ -157860,7 +157050,7 @@ function clearLog() {
|
|
|
157860
157050
|
}
|
|
157861
157051
|
|
|
157862
157052
|
// src/internals/plugins/subtask2/commands/manifest.ts
|
|
157863
|
-
import { join as
|
|
157053
|
+
import { join as join102 } from "path";
|
|
157864
157054
|
|
|
157865
157055
|
// src/internals/plugins/subtask2/parsing/frontmatter.ts
|
|
157866
157056
|
var import_yaml = __toESM(require_dist2(), 1);
|
|
@@ -158116,8 +157306,8 @@ function parseAutoWorkflowOutput(text) {
|
|
|
158116
157306
|
async function buildManifest() {
|
|
158117
157307
|
const manifest = {};
|
|
158118
157308
|
const dirs = [
|
|
158119
|
-
|
|
158120
|
-
|
|
157309
|
+
join102(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
|
|
157310
|
+
join102(Bun.env.PWD ?? ".", ".opencode", "command")
|
|
158121
157311
|
];
|
|
158122
157312
|
for (const dir of dirs) {
|
|
158123
157313
|
try {
|
|
@@ -158280,11 +157470,11 @@ async function resolveTurnReferences(text, sessionID) {
|
|
|
158280
157470
|
}
|
|
158281
157471
|
|
|
158282
157472
|
// src/internals/plugins/subtask2/commands/loader.ts
|
|
158283
|
-
import { join as
|
|
157473
|
+
import { join as join103 } from "path";
|
|
158284
157474
|
async function loadCommandFile(name) {
|
|
158285
157475
|
const dirs = [
|
|
158286
|
-
|
|
158287
|
-
|
|
157476
|
+
join103(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
|
|
157477
|
+
join103(Bun.env.PWD ?? ".", ".opencode", "command")
|
|
158288
157478
|
];
|
|
158289
157479
|
for (const dir of dirs) {
|
|
158290
157480
|
const directPath = `${dir}/${name}.md`;
|
|
@@ -159558,20 +158748,17 @@ var createPlugin = async (ctx) => {
|
|
|
159558
158748
|
};
|
|
159559
158749
|
};
|
|
159560
158750
|
|
|
159561
|
-
// src/index.ts
|
|
159562
|
-
init_websearch_cited();
|
|
159563
|
-
|
|
159564
158751
|
// src/features/builtin-skills/materialize.ts
|
|
159565
158752
|
import {
|
|
159566
158753
|
cpSync,
|
|
159567
|
-
existsSync as
|
|
159568
|
-
mkdirSync as
|
|
158754
|
+
existsSync as existsSync92,
|
|
158755
|
+
mkdirSync as mkdirSync21,
|
|
159569
158756
|
readdirSync as readdirSync26,
|
|
159570
|
-
readFileSync as
|
|
158757
|
+
readFileSync as readFileSync62,
|
|
159571
158758
|
rmSync as rmSync4,
|
|
159572
|
-
writeFileSync as
|
|
158759
|
+
writeFileSync as writeFileSync23
|
|
159573
158760
|
} from "fs";
|
|
159574
|
-
import { join as
|
|
158761
|
+
import { join as join104 } from "path";
|
|
159575
158762
|
var GENERATED_MARKER = "<!-- Generated by hiai-opencode builtin skill materializer. -->";
|
|
159576
158763
|
var MANAGED_SKILL_METADATA = ".hiai-skill.json";
|
|
159577
158764
|
var LEGACY_MANAGED_DIR_MARKER = ".hiai-plugin-skill";
|
|
@@ -159598,10 +158785,10 @@ function buildSkillFrontmatter(skill2) {
|
|
|
159598
158785
|
`);
|
|
159599
158786
|
}
|
|
159600
158787
|
function shouldWriteSkillFile(skillFilePath) {
|
|
159601
|
-
if (!
|
|
158788
|
+
if (!existsSync92(skillFilePath))
|
|
159602
158789
|
return true;
|
|
159603
158790
|
try {
|
|
159604
|
-
const existing =
|
|
158791
|
+
const existing = readFileSync62(skillFilePath, "utf-8");
|
|
159605
158792
|
return existing.includes(GENERATED_MARKER);
|
|
159606
158793
|
} catch {
|
|
159607
158794
|
return false;
|
|
@@ -159609,13 +158796,13 @@ function shouldWriteSkillFile(skillFilePath) {
|
|
|
159609
158796
|
}
|
|
159610
158797
|
function getSkillLayout() {
|
|
159611
158798
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
159612
|
-
const assembledSkillsDir =
|
|
159613
|
-
const sourceRootDir =
|
|
159614
|
-
const builtinSourceDir =
|
|
159615
|
-
const pluginSourceDir =
|
|
159616
|
-
|
|
159617
|
-
|
|
159618
|
-
|
|
158799
|
+
const assembledSkillsDir = join104(configDir, "skills");
|
|
158800
|
+
const sourceRootDir = join104(configDir, ".hiai", "skills");
|
|
158801
|
+
const builtinSourceDir = join104(sourceRootDir, "builtin");
|
|
158802
|
+
const pluginSourceDir = join104(sourceRootDir, "plugin");
|
|
158803
|
+
mkdirSync21(assembledSkillsDir, { recursive: true });
|
|
158804
|
+
mkdirSync21(builtinSourceDir, { recursive: true });
|
|
158805
|
+
mkdirSync21(pluginSourceDir, { recursive: true });
|
|
159619
158806
|
return {
|
|
159620
158807
|
configDir,
|
|
159621
158808
|
assembledSkillsDir,
|
|
@@ -159625,31 +158812,31 @@ function getSkillLayout() {
|
|
|
159625
158812
|
};
|
|
159626
158813
|
}
|
|
159627
158814
|
function writeManagedSkillMetadata(targetDir, metadata) {
|
|
159628
|
-
|
|
158815
|
+
writeFileSync23(join104(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
|
|
159629
158816
|
`, "utf-8");
|
|
159630
158817
|
}
|
|
159631
158818
|
function readManagedSkillMetadata(targetDir) {
|
|
159632
|
-
const metadataPath =
|
|
159633
|
-
if (!
|
|
158819
|
+
const metadataPath = join104(targetDir, MANAGED_SKILL_METADATA);
|
|
158820
|
+
if (!existsSync92(metadataPath)) {
|
|
159634
158821
|
return null;
|
|
159635
158822
|
}
|
|
159636
158823
|
try {
|
|
159637
|
-
return JSON.parse(
|
|
158824
|
+
return JSON.parse(readFileSync62(metadataPath, "utf-8"));
|
|
159638
158825
|
} catch {
|
|
159639
158826
|
return null;
|
|
159640
158827
|
}
|
|
159641
158828
|
}
|
|
159642
158829
|
function isLegacyManagedSkillDir(targetDir, origin) {
|
|
159643
|
-
if (origin === "plugin" &&
|
|
158830
|
+
if (origin === "plugin" && existsSync92(join104(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
|
|
159644
158831
|
return true;
|
|
159645
158832
|
}
|
|
159646
158833
|
if (origin === "builtin") {
|
|
159647
|
-
const skillFilePath =
|
|
159648
|
-
if (!
|
|
158834
|
+
const skillFilePath = join104(targetDir, "SKILL.md");
|
|
158835
|
+
if (!existsSync92(skillFilePath)) {
|
|
159649
158836
|
return false;
|
|
159650
158837
|
}
|
|
159651
158838
|
try {
|
|
159652
|
-
return
|
|
158839
|
+
return readFileSync62(skillFilePath, "utf-8").includes(GENERATED_MARKER);
|
|
159653
158840
|
} catch {
|
|
159654
158841
|
return false;
|
|
159655
158842
|
}
|
|
@@ -159657,7 +158844,7 @@ function isLegacyManagedSkillDir(targetDir, origin) {
|
|
|
159657
158844
|
return false;
|
|
159658
158845
|
}
|
|
159659
158846
|
function shouldSyncManagedSkillDir(targetDir, origin) {
|
|
159660
|
-
if (!
|
|
158847
|
+
if (!existsSync92(targetDir))
|
|
159661
158848
|
return true;
|
|
159662
158849
|
const metadata = readManagedSkillMetadata(targetDir);
|
|
159663
158850
|
if (metadata?.generatedBy === "hiai-opencode" && metadata.origin === origin) {
|
|
@@ -159673,7 +158860,7 @@ function shouldCleanupManagedSkillDir(targetDir, origin) {
|
|
|
159673
158860
|
return isLegacyManagedSkillDir(targetDir, origin);
|
|
159674
158861
|
}
|
|
159675
158862
|
function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
|
|
159676
|
-
if (!
|
|
158863
|
+
if (!existsSync92(rootDir)) {
|
|
159677
158864
|
return;
|
|
159678
158865
|
}
|
|
159679
158866
|
for (const entry of readdirSync26(rootDir, { withFileTypes: true })) {
|
|
@@ -159681,17 +158868,17 @@ function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
|
|
|
159681
158868
|
continue;
|
|
159682
158869
|
if (expectedSkillNames.has(entry.name))
|
|
159683
158870
|
continue;
|
|
159684
|
-
const targetDir =
|
|
158871
|
+
const targetDir = join104(rootDir, entry.name);
|
|
159685
158872
|
if (shouldCleanupManagedSkillDir(targetDir, origin)) {
|
|
159686
158873
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
159687
158874
|
}
|
|
159688
158875
|
}
|
|
159689
158876
|
}
|
|
159690
158877
|
function writeSkillRegistry(configDir, entries) {
|
|
159691
|
-
const registryDir =
|
|
159692
|
-
const assembledSkillsDir =
|
|
159693
|
-
|
|
159694
|
-
|
|
158878
|
+
const registryDir = join104(configDir, ".hiai");
|
|
158879
|
+
const assembledSkillsDir = join104(configDir, "skills");
|
|
158880
|
+
mkdirSync21(registryDir, { recursive: true });
|
|
158881
|
+
mkdirSync21(assembledSkillsDir, { recursive: true });
|
|
159695
158882
|
const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
|
|
159696
158883
|
const payload = {
|
|
159697
158884
|
generatedBy: "hiai-opencode",
|
|
@@ -159703,12 +158890,12 @@ function writeSkillRegistry(configDir, entries) {
|
|
|
159703
158890
|
},
|
|
159704
158891
|
layout: {
|
|
159705
158892
|
assembledSkillsDir,
|
|
159706
|
-
builtinSourceDir:
|
|
159707
|
-
pluginSourceDir:
|
|
158893
|
+
builtinSourceDir: join104(registryDir, "skills", "builtin"),
|
|
158894
|
+
pluginSourceDir: join104(registryDir, "skills", "plugin")
|
|
159708
158895
|
},
|
|
159709
158896
|
entries: sortedEntries
|
|
159710
158897
|
};
|
|
159711
|
-
|
|
158898
|
+
writeFileSync23(join104(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
|
|
159712
158899
|
`, "utf-8");
|
|
159713
158900
|
const readme = [
|
|
159714
158901
|
"# Hiai Skill Layout",
|
|
@@ -159723,24 +158910,24 @@ function writeSkillRegistry(configDir, entries) {
|
|
|
159723
158910
|
""
|
|
159724
158911
|
].join(`
|
|
159725
158912
|
`);
|
|
159726
|
-
|
|
158913
|
+
writeFileSync23(join104(assembledSkillsDir, "README.md"), readme, "utf-8");
|
|
159727
158914
|
}
|
|
159728
158915
|
function materializeBuiltinSkills(skills) {
|
|
159729
158916
|
const { assembledSkillsDir, builtinSourceDir } = getSkillLayout();
|
|
159730
158917
|
const expectedSkillNames = new Set(skills.map((skill2) => skill2.name));
|
|
159731
158918
|
for (const skill2 of skills) {
|
|
159732
|
-
const sourceSkillDir =
|
|
159733
|
-
const sourceSkillFilePath =
|
|
159734
|
-
const assembledSkillDir =
|
|
159735
|
-
const assembledSkillFilePath =
|
|
158919
|
+
const sourceSkillDir = join104(builtinSourceDir, skill2.name);
|
|
158920
|
+
const sourceSkillFilePath = join104(sourceSkillDir, "SKILL.md");
|
|
158921
|
+
const assembledSkillDir = join104(assembledSkillsDir, skill2.name);
|
|
158922
|
+
const assembledSkillFilePath = join104(assembledSkillDir, "SKILL.md");
|
|
159736
158923
|
const content = buildSkillFrontmatter(skill2);
|
|
159737
|
-
|
|
159738
|
-
|
|
158924
|
+
mkdirSync21(sourceSkillDir, { recursive: true });
|
|
158925
|
+
mkdirSync21(assembledSkillDir, { recursive: true });
|
|
159739
158926
|
if (!shouldWriteSkillFile(sourceSkillFilePath) || !shouldWriteSkillFile(assembledSkillFilePath)) {
|
|
159740
158927
|
continue;
|
|
159741
158928
|
}
|
|
159742
|
-
|
|
159743
|
-
|
|
158929
|
+
writeFileSync23(sourceSkillFilePath, content, "utf-8");
|
|
158930
|
+
writeFileSync23(assembledSkillFilePath, content, "utf-8");
|
|
159744
158931
|
writeManagedSkillMetadata(sourceSkillDir, {
|
|
159745
158932
|
name: skill2.name,
|
|
159746
158933
|
origin: "builtin",
|
|
@@ -159760,8 +158947,8 @@ function materializeBuiltinSkills(skills) {
|
|
|
159760
158947
|
cleanupRemovedManagedSkillDirs(assembledSkillsDir, "builtin", expectedSkillNames);
|
|
159761
158948
|
}
|
|
159762
158949
|
function materializePluginSkillDirectories(pluginRootDir) {
|
|
159763
|
-
const sourceSkillsDir =
|
|
159764
|
-
if (!
|
|
158950
|
+
const sourceSkillsDir = join104(pluginRootDir, "skills");
|
|
158951
|
+
if (!existsSync92(sourceSkillsDir)) {
|
|
159765
158952
|
return;
|
|
159766
158953
|
}
|
|
159767
158954
|
const { assembledSkillsDir, pluginSourceDir, configDir } = getSkillLayout();
|
|
@@ -159773,9 +158960,9 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
159773
158960
|
if (entry.name === "tmp")
|
|
159774
158961
|
continue;
|
|
159775
158962
|
expectedSkillNames.add(entry.name);
|
|
159776
|
-
const sourceDir =
|
|
159777
|
-
const mirroredSourceDir =
|
|
159778
|
-
const assembledDir =
|
|
158963
|
+
const sourceDir = join104(sourceSkillsDir, entry.name);
|
|
158964
|
+
const mirroredSourceDir = join104(pluginSourceDir, entry.name);
|
|
158965
|
+
const assembledDir = join104(assembledSkillsDir, entry.name);
|
|
159779
158966
|
if (!shouldSyncManagedSkillDir(mirroredSourceDir, "plugin") || !shouldSyncManagedSkillDir(assembledDir, "plugin")) {
|
|
159780
158967
|
continue;
|
|
159781
158968
|
}
|
|
@@ -159809,7 +158996,7 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
159809
158996
|
for (const builtinEntry of readdirSync26(assembledSkillsDir, { withFileTypes: true })) {
|
|
159810
158997
|
if (!builtinEntry.isDirectory())
|
|
159811
158998
|
continue;
|
|
159812
|
-
const assembledDir =
|
|
158999
|
+
const assembledDir = join104(assembledSkillsDir, builtinEntry.name);
|
|
159813
159000
|
const metadata = readManagedSkillMetadata(assembledDir);
|
|
159814
159001
|
if (metadata?.generatedBy !== "hiai-opencode" || metadata.origin !== "builtin") {
|
|
159815
159002
|
continue;
|
|
@@ -159832,11 +159019,11 @@ function configureBundledBunPtyLibrary() {
|
|
|
159832
159019
|
}
|
|
159833
159020
|
const libraryName = process.platform === "win32" ? "rust_pty.dll" : process.platform === "darwin" ? process.arch === "arm64" ? "librust_pty_arm64.dylib" : "librust_pty.dylib" : process.arch === "arm64" ? "librust_pty_arm64.so" : "librust_pty.so";
|
|
159834
159021
|
const candidates = [
|
|
159835
|
-
|
|
159836
|
-
|
|
159837
|
-
|
|
159022
|
+
join106(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
|
|
159023
|
+
join106(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName),
|
|
159024
|
+
join106(import.meta.dirname, "..", "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
|
|
159838
159025
|
];
|
|
159839
|
-
const resolved = candidates.find((candidate) =>
|
|
159026
|
+
const resolved = candidates.find((candidate) => existsSync94(candidate));
|
|
159840
159027
|
if (resolved) {
|
|
159841
159028
|
process.env.BUN_PTY_LIB = resolved;
|
|
159842
159029
|
}
|
|
@@ -159858,11 +159045,12 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159858
159045
|
pluginConfig: pluginConfig2,
|
|
159859
159046
|
platformConfig: internalConfig
|
|
159860
159047
|
});
|
|
159048
|
+
autoExportStaticMcpJson(ctx.directory, internalConfig);
|
|
159861
159049
|
materializeBuiltinSkills(createBuiltinSkills({
|
|
159862
159050
|
browserProvider: pluginConfig2.browser_automation_engine?.provider ?? "playwright",
|
|
159863
159051
|
disabledSkills: new Set(pluginConfig2.disabled_skills ?? [])
|
|
159864
159052
|
}));
|
|
159865
|
-
materializePluginSkillDirectories(
|
|
159053
|
+
materializePluginSkillDirectories(join106(import.meta.dirname, ".."));
|
|
159866
159054
|
const { initializeModelRequirements: initializeModelRequirements2 } = await Promise.resolve().then(() => (init_model_requirements(), exports_model_requirements));
|
|
159867
159055
|
initializeModelRequirements2(internalConfig);
|
|
159868
159056
|
const { initializeModelHeuristics: initializeModelHeuristics2 } = await Promise.resolve().then(() => (init_model_capability_heuristics(), exports_model_capability_heuristics));
|
|
@@ -159887,6 +159075,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159887
159075
|
const toolsResult = await createTools({
|
|
159888
159076
|
ctx,
|
|
159889
159077
|
pluginConfig: pluginConfig2,
|
|
159078
|
+
platformConfig: internalConfig,
|
|
159890
159079
|
managers
|
|
159891
159080
|
});
|
|
159892
159081
|
const hooks = createHooks({
|
|
@@ -159922,16 +159111,12 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159922
159111
|
} catch (err) {
|
|
159923
159112
|
console.error("[hiai-opencode] PTYPlugin failed to load:", err);
|
|
159924
159113
|
}
|
|
159925
|
-
const websearchResult = await websearch_cited_default(ctx);
|
|
159926
|
-
const websearchGoogleResult = await WebsearchCitedGooglePlugin(ctx);
|
|
159927
|
-
const websearchOpenAIResult = await WebsearchCitedOpenAIPlugin(ctx);
|
|
159928
159114
|
const combinedResult = {
|
|
159929
159115
|
name: PLUGIN_NAME,
|
|
159930
159116
|
...pluginInterface,
|
|
159931
159117
|
tool: {
|
|
159932
159118
|
...pluginInterface.tool,
|
|
159933
|
-
...ptyResult.tool
|
|
159934
|
-
...websearchResult.tool
|
|
159119
|
+
...ptyResult.tool
|
|
159935
159120
|
},
|
|
159936
159121
|
"command.execute.before": async (input, output) => {
|
|
159937
159122
|
await pluginInterface["command.execute.before"]?.(input, output);
|
|
@@ -159952,38 +159137,12 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159952
159137
|
config: async (input) => {
|
|
159953
159138
|
await pluginInterface.config?.(input);
|
|
159954
159139
|
await subtask2Result.config?.(input);
|
|
159955
|
-
await websearchResult.config?.(input);
|
|
159956
159140
|
},
|
|
159957
159141
|
event: async (input) => {
|
|
159958
159142
|
await pluginInterface.event?.(input);
|
|
159959
159143
|
await subtask2Result.event?.(input);
|
|
159960
159144
|
await ptyResult.event?.(input);
|
|
159961
159145
|
},
|
|
159962
|
-
auth: {
|
|
159963
|
-
provider: "hiai-opencode",
|
|
159964
|
-
methods: [
|
|
159965
|
-
{ type: "api", label: "Google Search API key" }
|
|
159966
|
-
],
|
|
159967
|
-
loader: async (getAuth) => {
|
|
159968
|
-
const authData = await getAuth();
|
|
159969
|
-
const { registerGetAuth: registerGetAuth2, GOOGLE_PROVIDER_ID: GOOGLE_PROVIDER_ID2, OPENAI_PROVIDER_ID: OPENAI_PROVIDER_ID2, OPENROUTER_PROVIDER_ID: OPENROUTER_PROVIDER_ID2 } = await Promise.resolve().then(() => (init_websearch_cited(), exports_websearch_cited));
|
|
159970
|
-
const getConfiguredKey = (configKey) => {
|
|
159971
|
-
if (configKey)
|
|
159972
|
-
return resolveEnvVars(configKey);
|
|
159973
|
-
return;
|
|
159974
|
-
};
|
|
159975
|
-
const googleKey = authData["Google Search API key"] || getConfiguredKey(internalConfig.auth?.googleSearch);
|
|
159976
|
-
const openaiKey = getConfiguredKey(internalConfig.auth?.openai);
|
|
159977
|
-
const openRouterKey = getConfiguredKey(internalConfig.auth?.openrouter);
|
|
159978
|
-
if (googleKey)
|
|
159979
|
-
registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: googleKey }));
|
|
159980
|
-
if (openaiKey)
|
|
159981
|
-
registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openaiKey }));
|
|
159982
|
-
if (openRouterKey)
|
|
159983
|
-
registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openRouterKey }));
|
|
159984
|
-
return {};
|
|
159985
|
-
}
|
|
159986
|
-
},
|
|
159987
159146
|
"experimental.session.compacting": async (_input, output) => {
|
|
159988
159147
|
await hooks.compactionContextInjector?.capture(_input.sessionID);
|
|
159989
159148
|
await hooks.compactionTodoPreserver?.capture(_input.sessionID);
|