@hiai-gg/hiai-opencode 0.1.5 → 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 +14 -5
- package/LICENSE.md +0 -1
- package/README.md +42 -23
- package/assets/cli/hiai-opencode.mjs +590 -7
- package/assets/mcp/mempalace.mjs +159 -25
- package/config/hiai-opencode.schema.json +13 -2
- 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/platform-schema.d.ts +2 -6
- 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 +1 -3
- 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 +348 -1424
- 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/hiai-opencode.json +4 -2
- 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 +14 -1
- package/src/config/model-slots-and-export.test.ts +55 -0
- package/src/config/platform-schema.ts +1 -3
- package/src/config/schema/commands.ts +1 -0
- package/src/config/schema/oh-my-opencode-config.ts +0 -3
- package/src/config/types.ts +1 -3
- 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 +3 -75
- 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/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 -17
- 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 -306
- 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,1270 +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 = (_ctx, fallback) => {
|
|
33661
|
-
let selectedProvider = fallback?.providerID;
|
|
33662
|
-
let selectedModel = fallback?.model;
|
|
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
|
-
} else if (!error92 && fallback) {
|
|
33693
|
-
selectedProvider = fallback.providerID;
|
|
33694
|
-
selectedModel = fallback.model;
|
|
33695
|
-
}
|
|
33696
|
-
return Promise.resolve();
|
|
33697
|
-
},
|
|
33698
|
-
tool: {
|
|
33699
|
-
websearch_cited: tool({
|
|
33700
|
-
description: CITED_SEARCH_TOOL_DESCRIPTION,
|
|
33701
|
-
args: WEBSEARCH_ARGS,
|
|
33702
|
-
async execute(args, context) {
|
|
33703
|
-
const argKeys = Object.keys(args ?? {});
|
|
33704
|
-
const extraKeys = argKeys.filter((key) => !WEBSEARCH_ALLOWED_KEYS.has(key));
|
|
33705
|
-
if (extraKeys.length > 0) {
|
|
33706
|
-
throw new Error(`Unknown argument(s): ${extraKeys.join(", ")}, only ${WEBSEARCH_ALLOWED_KEYS_DESCRIPTION} supported.`);
|
|
33707
|
-
}
|
|
33708
|
-
const query = args.query?.trim();
|
|
33709
|
-
if (!query) {
|
|
33710
|
-
throw new Error("The 'query' parameter cannot be empty.");
|
|
33711
|
-
}
|
|
33712
|
-
if (configError) {
|
|
33713
|
-
throw new Error(configError);
|
|
33714
|
-
}
|
|
33715
|
-
if (!selectedProvider || !selectedModel) {
|
|
33716
|
-
throw new Error("Missing web search model configuration.");
|
|
33717
|
-
}
|
|
33718
|
-
if (selectedProvider === OPENAI_PROVIDER_ID) {
|
|
33719
|
-
const getAuth2 = resolveGetAuth(OPENAI_PROVIDER_ID);
|
|
33720
|
-
if (!getAuth2) {
|
|
33721
|
-
throw new Error('Missing auth for provider "openai". Authenticate via `opencode auth login`.');
|
|
33722
|
-
}
|
|
33723
|
-
const client4 = createOpenAIWebsearchClient(selectedModel, openaiConfig);
|
|
33724
|
-
return client4.search(query, context.abort, getAuth2);
|
|
33725
|
-
}
|
|
33726
|
-
if (selectedProvider === OPENROUTER_PROVIDER_ID) {
|
|
33727
|
-
const getAuth2 = resolveGetAuth(OPENROUTER_PROVIDER_ID);
|
|
33728
|
-
if (!getAuth2) {
|
|
33729
|
-
throw new Error('Missing auth for provider "openrouter". Authenticate via `opencode auth login`.');
|
|
33730
|
-
}
|
|
33731
|
-
const client4 = createOpenRouterWebsearchClient(selectedModel);
|
|
33732
|
-
return client4.search(query, context.abort, getAuth2);
|
|
33733
|
-
}
|
|
33734
|
-
const getAuth = resolveGetAuth(GOOGLE_PROVIDER_ID);
|
|
33735
|
-
if (!getAuth) {
|
|
33736
|
-
throw new Error('Missing auth for provider "google". Authenticate via `opencode auth login`.');
|
|
33737
|
-
}
|
|
33738
|
-
const client3 = createGoogleWebsearchClient(selectedModel);
|
|
33739
|
-
return client3.search(query, context.abort, getAuth);
|
|
33740
|
-
}
|
|
33741
|
-
})
|
|
33742
|
-
}
|
|
33743
|
-
});
|
|
33744
|
-
}, WebsearchCitedGooglePlugin = () => {
|
|
33745
|
-
return Promise.resolve({
|
|
33746
|
-
auth: {
|
|
33747
|
-
provider: GOOGLE_PROVIDER_ID,
|
|
33748
|
-
loader(getAuth) {
|
|
33749
|
-
registerGetAuth(GOOGLE_PROVIDER_ID, getAuth);
|
|
33750
|
-
return Promise.resolve({});
|
|
33751
|
-
},
|
|
33752
|
-
methods: [
|
|
33753
|
-
{
|
|
33754
|
-
type: "api",
|
|
33755
|
-
label: "Google API key"
|
|
33756
|
-
}
|
|
33757
|
-
]
|
|
33758
|
-
}
|
|
33759
|
-
});
|
|
33760
|
-
}, WebsearchCitedOpenAIPlugin = () => {
|
|
33761
|
-
return Promise.resolve({
|
|
33762
|
-
auth: {
|
|
33763
|
-
provider: OPENAI_PROVIDER_ID,
|
|
33764
|
-
loader(getAuth) {
|
|
33765
|
-
registerGetAuth(OPENAI_PROVIDER_ID, getAuth);
|
|
33766
|
-
return Promise.resolve({});
|
|
33767
|
-
},
|
|
33768
|
-
methods: [
|
|
33769
|
-
{
|
|
33770
|
-
type: "api",
|
|
33771
|
-
label: "OpenAI API key"
|
|
33772
|
-
}
|
|
33773
|
-
]
|
|
33774
|
-
}
|
|
33775
|
-
});
|
|
33776
|
-
}, websearch_cited_default;
|
|
33777
|
-
var init_websearch_cited = __esm(() => {
|
|
33778
|
-
init_dist();
|
|
33779
|
-
init_google();
|
|
33780
|
-
init_openai();
|
|
33781
|
-
WEBSEARCH_ARGS = {
|
|
33782
|
-
query: tool.schema.string().describe("The natural language web search query.")
|
|
33783
|
-
};
|
|
33784
|
-
WEBSEARCH_ALLOWED_KEYS = new Set(Object.keys(WEBSEARCH_ARGS));
|
|
33785
|
-
WEBSEARCH_ALLOWED_KEYS_DESCRIPTION = Array.from(WEBSEARCH_ALLOWED_KEYS).map((key) => `'${key}'`).join(", ");
|
|
33786
|
-
authRegistry = new Map;
|
|
33787
|
-
websearch_cited_default = WebsearchCitedPlugin;
|
|
33788
|
-
});
|
|
33789
|
-
|
|
33790
32526
|
// node_modules/bun-pty/src/interfaces.ts
|
|
33791
32527
|
class EventEmitter {
|
|
33792
32528
|
listeners = [];
|
|
@@ -33811,8 +32547,8 @@ class EventEmitter {
|
|
|
33811
32547
|
// node_modules/bun-pty/src/terminal.ts
|
|
33812
32548
|
import { dlopen, FFIType, ptr } from "bun:ffi";
|
|
33813
32549
|
import { Buffer as Buffer2 } from "buffer";
|
|
33814
|
-
import { join as
|
|
33815
|
-
import { existsSync as
|
|
32550
|
+
import { join as join105, dirname as dirname32, basename as basename16 } from "path";
|
|
32551
|
+
import { existsSync as existsSync93 } from "fs";
|
|
33816
32552
|
function shQuote(s) {
|
|
33817
32553
|
if (s.length === 0)
|
|
33818
32554
|
return "''";
|
|
@@ -33820,7 +32556,7 @@ function shQuote(s) {
|
|
|
33820
32556
|
}
|
|
33821
32557
|
function resolveLibPath() {
|
|
33822
32558
|
const env = process.env.BUN_PTY_LIB;
|
|
33823
|
-
if (env &&
|
|
32559
|
+
if (env && existsSync93(env))
|
|
33824
32560
|
return env;
|
|
33825
32561
|
try {
|
|
33826
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"}`);
|
|
@@ -33831,22 +32567,22 @@ function resolveLibPath() {
|
|
|
33831
32567
|
const arch = process.arch;
|
|
33832
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"];
|
|
33833
32569
|
const base = Bun.fileURLToPath(import.meta.url);
|
|
33834
|
-
const fileDir =
|
|
32570
|
+
const fileDir = dirname32(base);
|
|
33835
32571
|
const dirName = basename16(fileDir);
|
|
33836
|
-
const here = dirName === "src" || dirName === "dist" ?
|
|
32572
|
+
const here = dirName === "src" || dirName === "dist" ? dirname32(fileDir) : fileDir;
|
|
33837
32573
|
const basePaths = [
|
|
33838
|
-
|
|
33839
|
-
|
|
33840
|
-
|
|
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")
|
|
33841
32577
|
];
|
|
33842
32578
|
const fallbackPaths = [];
|
|
33843
32579
|
for (const basePath of basePaths) {
|
|
33844
32580
|
for (const filename of filenames) {
|
|
33845
|
-
fallbackPaths.push(
|
|
32581
|
+
fallbackPaths.push(join105(basePath, filename));
|
|
33846
32582
|
}
|
|
33847
32583
|
}
|
|
33848
32584
|
for (const path10 of fallbackPaths) {
|
|
33849
|
-
if (
|
|
32585
|
+
if (existsSync93(path10))
|
|
33850
32586
|
return path10;
|
|
33851
32587
|
}
|
|
33852
32588
|
throw new Error(`librust_pty shared library not found.
|
|
@@ -35063,8 +33799,8 @@ var init_plugin = __esm(() => {
|
|
|
35063
33799
|
});
|
|
35064
33800
|
|
|
35065
33801
|
// src/index.ts
|
|
35066
|
-
import { existsSync as
|
|
35067
|
-
import { join as
|
|
33802
|
+
import { existsSync as existsSync94 } from "fs";
|
|
33803
|
+
import { join as join106 } from "path";
|
|
35068
33804
|
|
|
35069
33805
|
// src/hooks/todo-continuation-enforcer/index.ts
|
|
35070
33806
|
init_logger();
|
|
@@ -113721,6 +112457,73 @@ This file is clean. Here's why:
|
|
|
113721
112457
|
**Conclusion**: This code appears to be human-written or well-reviewed AI code. No changes needed.
|
|
113722
112458
|
\`\`\``
|
|
113723
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
|
+
};
|
|
113724
112527
|
// src/features/builtin-skills/skills.ts
|
|
113725
112528
|
function createBuiltinSkills(options = {}) {
|
|
113726
112529
|
const { browserProvider = "playwright", disabledSkills } = options;
|
|
@@ -113732,7 +112535,15 @@ function createBuiltinSkills(options = {}) {
|
|
|
113732
112535
|
} else {
|
|
113733
112536
|
browserSkill = playwrightSkill;
|
|
113734
112537
|
}
|
|
113735
|
-
const skills = [
|
|
112538
|
+
const skills = [
|
|
112539
|
+
browserSkill,
|
|
112540
|
+
hiaiOpencodeSetupSkill,
|
|
112541
|
+
frontendUiUxSkill,
|
|
112542
|
+
gitMasterSkill,
|
|
112543
|
+
devBrowserSkill,
|
|
112544
|
+
reviewWorkSkill,
|
|
112545
|
+
aiSlopRemoverSkill
|
|
112546
|
+
];
|
|
113736
112547
|
if (!disabledSkills) {
|
|
113737
112548
|
return skills;
|
|
113738
112549
|
}
|
|
@@ -114059,7 +112870,8 @@ var BuiltinCommandNameSchema = exports_external.enum([
|
|
|
114059
112870
|
"start-work",
|
|
114060
112871
|
"stop-continuation",
|
|
114061
112872
|
"remove-ai-slops",
|
|
114062
|
-
"mcp-status"
|
|
112873
|
+
"mcp-status",
|
|
112874
|
+
"doctor"
|
|
114063
112875
|
]);
|
|
114064
112876
|
// src/config/schema/comment-checker.ts
|
|
114065
112877
|
var CommentCheckerConfigSchema = exports_external.object({
|
|
@@ -114337,9 +113149,6 @@ var WebsearchConfigSchema = exports_external.object({
|
|
|
114337
113149
|
|
|
114338
113150
|
// src/config/schema/oh-my-opencode-config.ts
|
|
114339
113151
|
var AuthConfigSchema = exports_external.object({
|
|
114340
|
-
googleSearch: exports_external.string().optional(),
|
|
114341
|
-
openai: exports_external.string().optional(),
|
|
114342
|
-
openrouter: exports_external.string().optional(),
|
|
114343
113152
|
stitch: exports_external.string().optional(),
|
|
114344
113153
|
firecrawl: exports_external.string().optional(),
|
|
114345
113154
|
context7: exports_external.string().optional()
|
|
@@ -116092,6 +114901,51 @@ Rules:
|
|
|
116092
114901
|
- Do not run package installs unless the user explicitly asks.
|
|
116093
114902
|
`;
|
|
116094
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
|
+
|
|
116095
114949
|
// src/features/builtin-commands/commands.ts
|
|
116096
114950
|
function resolveStartWorkAgent(options) {
|
|
116097
114951
|
if (options?.useRegisteredAgents) {
|
|
@@ -116200,6 +115054,12 @@ $ARGUMENTS
|
|
|
116200
115054
|
description: "(builtin) Show hiai-opencode MCP server status, missing keys, and local runtime availability",
|
|
116201
115055
|
template: `<command-instruction>
|
|
116202
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}
|
|
116203
115063
|
</command-instruction>`
|
|
116204
115064
|
}
|
|
116205
115065
|
};
|
|
@@ -120606,7 +119466,8 @@ var McpServerConfigSchema = exports_external.object({
|
|
|
120606
119466
|
headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
120607
119467
|
command: exports_external.array(exports_external.string()).optional(),
|
|
120608
119468
|
timeout: exports_external.number().optional(),
|
|
120609
|
-
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()
|
|
120610
119471
|
});
|
|
120611
119472
|
var LspServerConfigSchema = exports_external.object({
|
|
120612
119473
|
enabled: exports_external.boolean().optional(),
|
|
@@ -120654,9 +119515,6 @@ var PermissionsConfigSchema = exports_external.object({
|
|
|
120654
119515
|
["*"]: exports_external.record(exports_external.string(), exports_external.enum(["allow", "deny"])).optional()
|
|
120655
119516
|
});
|
|
120656
119517
|
var AuthKeysSchema = exports_external.object({
|
|
120657
|
-
googleSearch: exports_external.string().optional(),
|
|
120658
|
-
openai: exports_external.string().optional(),
|
|
120659
|
-
openrouter: exports_external.string().optional(),
|
|
120660
119518
|
stitch: exports_external.string().optional(),
|
|
120661
119519
|
firecrawl: exports_external.string().optional(),
|
|
120662
119520
|
context7: exports_external.string().optional()
|
|
@@ -120980,7 +119838,16 @@ function deriveMcp(config2) {
|
|
|
120980
119838
|
const userMcp = config2.mcp ?? {};
|
|
120981
119839
|
return Object.fromEntries(Object.entries(defaults).map(([name, entry]) => {
|
|
120982
119840
|
const override = userMcp[name] ?? {};
|
|
120983
|
-
|
|
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];
|
|
120984
119851
|
}));
|
|
120985
119852
|
}
|
|
120986
119853
|
function deriveLsp(config2) {
|
|
@@ -146772,7 +145639,7 @@ ${keyTriggers.join(`
|
|
|
146772
145639
|
`)}
|
|
146773
145640
|
- **"Look into" + "create PR"** \u2192 Not just research. Full implementation cycle expected.`;
|
|
146774
145641
|
}
|
|
146775
|
-
function buildToolSelectionTable(agents, tools = [], _skills = []) {
|
|
145642
|
+
function buildToolSelectionTable(agents, tools = [], _skills = [], options = {}) {
|
|
146776
145643
|
const rows = ["### Tool & Agent Selection:", ""];
|
|
146777
145644
|
if (tools.length > 0) {
|
|
146778
145645
|
rows.push(`- ${getToolsPromptDisplay(tools)} - **FREE** - Not Complex, Scope Clear, No Implicit Assumptions`);
|
|
@@ -146785,9 +145652,43 @@ function buildToolSelectionTable(agents, tools = [], _skills = []) {
|
|
|
146785
145652
|
}
|
|
146786
145653
|
rows.push("");
|
|
146787
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
|
+
}
|
|
146788
145659
|
return rows.join(`
|
|
146789
145660
|
`);
|
|
146790
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
|
+
}
|
|
146791
145692
|
function buildResearcherSection(agents) {
|
|
146792
145693
|
const researcherAgent = agents.find((agent) => agent.name === "researcher");
|
|
146793
145694
|
if (!researcherAgent) {
|
|
@@ -147160,7 +146061,7 @@ When asking for clarification:
|
|
|
147160
146061
|
}
|
|
147161
146062
|
function buildGptProBobPrompt(_model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
147162
146063
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
147163
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
146064
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
147164
146065
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
147165
146066
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
147166
146067
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -147636,7 +146537,7 @@ function buildIntentGate(role) {
|
|
|
147636
146537
|
var MODE = "primary";
|
|
147637
146538
|
function buildDynamicBobPrompt(model, availableAgents, availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
147638
146539
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
147639
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
146540
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
147640
146541
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
147641
146542
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
147642
146543
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -149466,7 +148367,7 @@ var guardPromptMetadata = {
|
|
|
149466
148367
|
// src/agents/coder/gpt.ts
|
|
149467
148368
|
function buildCoderPrompt(availableAgents = [], availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
149468
148369
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
149469
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
148370
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
149470
148371
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
149471
148372
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
149472
148373
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -149685,7 +148586,7 @@ function canonicalizeCriticSection(section) {
|
|
|
149685
148586
|
}
|
|
149686
148587
|
function buildCoderPrompt2(availableAgents = [], availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
149687
148588
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
149688
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
148589
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
149689
148590
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
149690
148591
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
149691
148592
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -150010,7 +148911,7 @@ createCoderAgent.mode = MODE5;
|
|
|
150010
148911
|
// src/agents/coder/gpt-pro.ts
|
|
150011
148912
|
function buildCoderPrompt3(availableAgents = [], availableTools = [], availableSkills = [], availableCategories = [], useTaskSystem = false) {
|
|
150012
148913
|
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
150013
|
-
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
148914
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills, { includeIntegrationPrimer: true });
|
|
150014
148915
|
const researcherSection = buildResearcherSection(availableAgents);
|
|
150015
148916
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
150016
148917
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
@@ -157512,15 +156413,98 @@ function createFirstMessageVariantGate() {
|
|
|
157512
156413
|
// src/index.ts
|
|
157513
156414
|
init_plugin_identity();
|
|
157514
156415
|
|
|
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
|
+
};
|
|
156441
|
+
}
|
|
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;
|
|
156448
|
+
}
|
|
156449
|
+
}
|
|
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
|
+
}
|
|
156498
|
+
|
|
157515
156499
|
// src/shared/startup-diagnostics.ts
|
|
157516
|
-
import { existsSync as
|
|
157517
|
-
import { join as
|
|
156500
|
+
import { existsSync as existsSync90, readFileSync as readFileSync61 } from "fs";
|
|
156501
|
+
import { join as join99 } from "path";
|
|
157518
156502
|
init_plugin_identity();
|
|
157519
156503
|
function readPlugins(configPath) {
|
|
157520
|
-
if (!
|
|
156504
|
+
if (!existsSync90(configPath))
|
|
157521
156505
|
return [];
|
|
157522
156506
|
try {
|
|
157523
|
-
const content =
|
|
156507
|
+
const content = readFileSync61(configPath, "utf-8");
|
|
157524
156508
|
const parsed = parseJsoncSafe(content);
|
|
157525
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);
|
|
157526
156510
|
} catch {
|
|
@@ -157530,8 +156514,8 @@ function readPlugins(configPath) {
|
|
|
157530
156514
|
function warnIfListPluginEntry(directory) {
|
|
157531
156515
|
const globalPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
157532
156516
|
const candidates = [
|
|
157533
|
-
|
|
157534
|
-
|
|
156517
|
+
join99(directory, ".opencode", "opencode.json"),
|
|
156518
|
+
join99(directory, ".opencode", "opencode.jsonc"),
|
|
157535
156519
|
globalPaths.configJson,
|
|
157536
156520
|
globalPaths.configJsonc
|
|
157537
156521
|
];
|
|
@@ -157884,8 +156868,8 @@ function resolveResultReferences(text, sessionID) {
|
|
|
157884
156868
|
}
|
|
157885
156869
|
|
|
157886
156870
|
// src/internals/plugins/subtask2/utils/config.ts
|
|
157887
|
-
import { mkdirSync as
|
|
157888
|
-
import { dirname as
|
|
156871
|
+
import { mkdirSync as mkdirSync19 } from "fs";
|
|
156872
|
+
import { dirname as dirname31, join as join100 } from "path";
|
|
157889
156873
|
|
|
157890
156874
|
// src/internals/plugins/subtask2/utils/prompts.ts
|
|
157891
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.";
|
|
@@ -157951,15 +156935,15 @@ async function getAutoWorkflowPrompt() {
|
|
|
157951
156935
|
var AUTO_WORKFLOW_PROMPT = AUTO_WORKFLOW_PROMPT_TEMPLATE.replace(README_PLACEHOLDER, "[Use getAutoWorkflowPrompt() to get full documentation]");
|
|
157952
156936
|
|
|
157953
156937
|
// src/internals/plugins/subtask2/utils/config.ts
|
|
157954
|
-
var CONFIG_PATH =
|
|
156938
|
+
var CONFIG_PATH = join100(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
|
|
157955
156939
|
var cachedReadmeContent = null;
|
|
157956
156940
|
async function loadReadmeContent() {
|
|
157957
156941
|
if (cachedReadmeContent !== null) {
|
|
157958
156942
|
return cachedReadmeContent;
|
|
157959
156943
|
}
|
|
157960
156944
|
try {
|
|
157961
|
-
const pluginRoot =
|
|
157962
|
-
const readmePath =
|
|
156945
|
+
const pluginRoot = join100(dirname31(import.meta.path), "..", "..");
|
|
156946
|
+
const readmePath = join100(pluginRoot, "README.md");
|
|
157963
156947
|
const file3 = Bun.file(readmePath);
|
|
157964
156948
|
if (await file3.exists()) {
|
|
157965
156949
|
cachedReadmeContent = await file3.text();
|
|
@@ -157994,7 +156978,7 @@ async function loadConfig2() {
|
|
|
157994
156978
|
}
|
|
157995
156979
|
}
|
|
157996
156980
|
} catch {}
|
|
157997
|
-
|
|
156981
|
+
mkdirSync19(dirname31(CONFIG_PATH), { recursive: true });
|
|
157998
156982
|
await Bun.write(CONFIG_PATH, `{
|
|
157999
156983
|
// Replace OpenCode's generic "Summarize..." prompt when no return is specified
|
|
158000
156984
|
"replace_generic": true,
|
|
@@ -158066,7 +157050,7 @@ function clearLog() {
|
|
|
158066
157050
|
}
|
|
158067
157051
|
|
|
158068
157052
|
// src/internals/plugins/subtask2/commands/manifest.ts
|
|
158069
|
-
import { join as
|
|
157053
|
+
import { join as join102 } from "path";
|
|
158070
157054
|
|
|
158071
157055
|
// src/internals/plugins/subtask2/parsing/frontmatter.ts
|
|
158072
157056
|
var import_yaml = __toESM(require_dist2(), 1);
|
|
@@ -158322,8 +157306,8 @@ function parseAutoWorkflowOutput(text) {
|
|
|
158322
157306
|
async function buildManifest() {
|
|
158323
157307
|
const manifest = {};
|
|
158324
157308
|
const dirs = [
|
|
158325
|
-
|
|
158326
|
-
|
|
157309
|
+
join102(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
|
|
157310
|
+
join102(Bun.env.PWD ?? ".", ".opencode", "command")
|
|
158327
157311
|
];
|
|
158328
157312
|
for (const dir of dirs) {
|
|
158329
157313
|
try {
|
|
@@ -158486,11 +157470,11 @@ async function resolveTurnReferences(text, sessionID) {
|
|
|
158486
157470
|
}
|
|
158487
157471
|
|
|
158488
157472
|
// src/internals/plugins/subtask2/commands/loader.ts
|
|
158489
|
-
import { join as
|
|
157473
|
+
import { join as join103 } from "path";
|
|
158490
157474
|
async function loadCommandFile(name) {
|
|
158491
157475
|
const dirs = [
|
|
158492
|
-
|
|
158493
|
-
|
|
157476
|
+
join103(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
|
|
157477
|
+
join103(Bun.env.PWD ?? ".", ".opencode", "command")
|
|
158494
157478
|
];
|
|
158495
157479
|
for (const dir of dirs) {
|
|
158496
157480
|
const directPath = `${dir}/${name}.md`;
|
|
@@ -159764,20 +158748,17 @@ var createPlugin = async (ctx) => {
|
|
|
159764
158748
|
};
|
|
159765
158749
|
};
|
|
159766
158750
|
|
|
159767
|
-
// src/index.ts
|
|
159768
|
-
init_websearch_cited();
|
|
159769
|
-
|
|
159770
158751
|
// src/features/builtin-skills/materialize.ts
|
|
159771
158752
|
import {
|
|
159772
158753
|
cpSync,
|
|
159773
|
-
existsSync as
|
|
159774
|
-
mkdirSync as
|
|
158754
|
+
existsSync as existsSync92,
|
|
158755
|
+
mkdirSync as mkdirSync21,
|
|
159775
158756
|
readdirSync as readdirSync26,
|
|
159776
|
-
readFileSync as
|
|
158757
|
+
readFileSync as readFileSync62,
|
|
159777
158758
|
rmSync as rmSync4,
|
|
159778
|
-
writeFileSync as
|
|
158759
|
+
writeFileSync as writeFileSync23
|
|
159779
158760
|
} from "fs";
|
|
159780
|
-
import { join as
|
|
158761
|
+
import { join as join104 } from "path";
|
|
159781
158762
|
var GENERATED_MARKER = "<!-- Generated by hiai-opencode builtin skill materializer. -->";
|
|
159782
158763
|
var MANAGED_SKILL_METADATA = ".hiai-skill.json";
|
|
159783
158764
|
var LEGACY_MANAGED_DIR_MARKER = ".hiai-plugin-skill";
|
|
@@ -159804,10 +158785,10 @@ function buildSkillFrontmatter(skill2) {
|
|
|
159804
158785
|
`);
|
|
159805
158786
|
}
|
|
159806
158787
|
function shouldWriteSkillFile(skillFilePath) {
|
|
159807
|
-
if (!
|
|
158788
|
+
if (!existsSync92(skillFilePath))
|
|
159808
158789
|
return true;
|
|
159809
158790
|
try {
|
|
159810
|
-
const existing =
|
|
158791
|
+
const existing = readFileSync62(skillFilePath, "utf-8");
|
|
159811
158792
|
return existing.includes(GENERATED_MARKER);
|
|
159812
158793
|
} catch {
|
|
159813
158794
|
return false;
|
|
@@ -159815,13 +158796,13 @@ function shouldWriteSkillFile(skillFilePath) {
|
|
|
159815
158796
|
}
|
|
159816
158797
|
function getSkillLayout() {
|
|
159817
158798
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
159818
|
-
const assembledSkillsDir =
|
|
159819
|
-
const sourceRootDir =
|
|
159820
|
-
const builtinSourceDir =
|
|
159821
|
-
const pluginSourceDir =
|
|
159822
|
-
|
|
159823
|
-
|
|
159824
|
-
|
|
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 });
|
|
159825
158806
|
return {
|
|
159826
158807
|
configDir,
|
|
159827
158808
|
assembledSkillsDir,
|
|
@@ -159831,31 +158812,31 @@ function getSkillLayout() {
|
|
|
159831
158812
|
};
|
|
159832
158813
|
}
|
|
159833
158814
|
function writeManagedSkillMetadata(targetDir, metadata) {
|
|
159834
|
-
|
|
158815
|
+
writeFileSync23(join104(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
|
|
159835
158816
|
`, "utf-8");
|
|
159836
158817
|
}
|
|
159837
158818
|
function readManagedSkillMetadata(targetDir) {
|
|
159838
|
-
const metadataPath =
|
|
159839
|
-
if (!
|
|
158819
|
+
const metadataPath = join104(targetDir, MANAGED_SKILL_METADATA);
|
|
158820
|
+
if (!existsSync92(metadataPath)) {
|
|
159840
158821
|
return null;
|
|
159841
158822
|
}
|
|
159842
158823
|
try {
|
|
159843
|
-
return JSON.parse(
|
|
158824
|
+
return JSON.parse(readFileSync62(metadataPath, "utf-8"));
|
|
159844
158825
|
} catch {
|
|
159845
158826
|
return null;
|
|
159846
158827
|
}
|
|
159847
158828
|
}
|
|
159848
158829
|
function isLegacyManagedSkillDir(targetDir, origin) {
|
|
159849
|
-
if (origin === "plugin" &&
|
|
158830
|
+
if (origin === "plugin" && existsSync92(join104(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
|
|
159850
158831
|
return true;
|
|
159851
158832
|
}
|
|
159852
158833
|
if (origin === "builtin") {
|
|
159853
|
-
const skillFilePath =
|
|
159854
|
-
if (!
|
|
158834
|
+
const skillFilePath = join104(targetDir, "SKILL.md");
|
|
158835
|
+
if (!existsSync92(skillFilePath)) {
|
|
159855
158836
|
return false;
|
|
159856
158837
|
}
|
|
159857
158838
|
try {
|
|
159858
|
-
return
|
|
158839
|
+
return readFileSync62(skillFilePath, "utf-8").includes(GENERATED_MARKER);
|
|
159859
158840
|
} catch {
|
|
159860
158841
|
return false;
|
|
159861
158842
|
}
|
|
@@ -159863,7 +158844,7 @@ function isLegacyManagedSkillDir(targetDir, origin) {
|
|
|
159863
158844
|
return false;
|
|
159864
158845
|
}
|
|
159865
158846
|
function shouldSyncManagedSkillDir(targetDir, origin) {
|
|
159866
|
-
if (!
|
|
158847
|
+
if (!existsSync92(targetDir))
|
|
159867
158848
|
return true;
|
|
159868
158849
|
const metadata = readManagedSkillMetadata(targetDir);
|
|
159869
158850
|
if (metadata?.generatedBy === "hiai-opencode" && metadata.origin === origin) {
|
|
@@ -159879,7 +158860,7 @@ function shouldCleanupManagedSkillDir(targetDir, origin) {
|
|
|
159879
158860
|
return isLegacyManagedSkillDir(targetDir, origin);
|
|
159880
158861
|
}
|
|
159881
158862
|
function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
|
|
159882
|
-
if (!
|
|
158863
|
+
if (!existsSync92(rootDir)) {
|
|
159883
158864
|
return;
|
|
159884
158865
|
}
|
|
159885
158866
|
for (const entry of readdirSync26(rootDir, { withFileTypes: true })) {
|
|
@@ -159887,17 +158868,17 @@ function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
|
|
|
159887
158868
|
continue;
|
|
159888
158869
|
if (expectedSkillNames.has(entry.name))
|
|
159889
158870
|
continue;
|
|
159890
|
-
const targetDir =
|
|
158871
|
+
const targetDir = join104(rootDir, entry.name);
|
|
159891
158872
|
if (shouldCleanupManagedSkillDir(targetDir, origin)) {
|
|
159892
158873
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
159893
158874
|
}
|
|
159894
158875
|
}
|
|
159895
158876
|
}
|
|
159896
158877
|
function writeSkillRegistry(configDir, entries) {
|
|
159897
|
-
const registryDir =
|
|
159898
|
-
const assembledSkillsDir =
|
|
159899
|
-
|
|
159900
|
-
|
|
158878
|
+
const registryDir = join104(configDir, ".hiai");
|
|
158879
|
+
const assembledSkillsDir = join104(configDir, "skills");
|
|
158880
|
+
mkdirSync21(registryDir, { recursive: true });
|
|
158881
|
+
mkdirSync21(assembledSkillsDir, { recursive: true });
|
|
159901
158882
|
const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
|
|
159902
158883
|
const payload = {
|
|
159903
158884
|
generatedBy: "hiai-opencode",
|
|
@@ -159909,12 +158890,12 @@ function writeSkillRegistry(configDir, entries) {
|
|
|
159909
158890
|
},
|
|
159910
158891
|
layout: {
|
|
159911
158892
|
assembledSkillsDir,
|
|
159912
|
-
builtinSourceDir:
|
|
159913
|
-
pluginSourceDir:
|
|
158893
|
+
builtinSourceDir: join104(registryDir, "skills", "builtin"),
|
|
158894
|
+
pluginSourceDir: join104(registryDir, "skills", "plugin")
|
|
159914
158895
|
},
|
|
159915
158896
|
entries: sortedEntries
|
|
159916
158897
|
};
|
|
159917
|
-
|
|
158898
|
+
writeFileSync23(join104(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
|
|
159918
158899
|
`, "utf-8");
|
|
159919
158900
|
const readme = [
|
|
159920
158901
|
"# Hiai Skill Layout",
|
|
@@ -159929,24 +158910,24 @@ function writeSkillRegistry(configDir, entries) {
|
|
|
159929
158910
|
""
|
|
159930
158911
|
].join(`
|
|
159931
158912
|
`);
|
|
159932
|
-
|
|
158913
|
+
writeFileSync23(join104(assembledSkillsDir, "README.md"), readme, "utf-8");
|
|
159933
158914
|
}
|
|
159934
158915
|
function materializeBuiltinSkills(skills) {
|
|
159935
158916
|
const { assembledSkillsDir, builtinSourceDir } = getSkillLayout();
|
|
159936
158917
|
const expectedSkillNames = new Set(skills.map((skill2) => skill2.name));
|
|
159937
158918
|
for (const skill2 of skills) {
|
|
159938
|
-
const sourceSkillDir =
|
|
159939
|
-
const sourceSkillFilePath =
|
|
159940
|
-
const assembledSkillDir =
|
|
159941
|
-
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");
|
|
159942
158923
|
const content = buildSkillFrontmatter(skill2);
|
|
159943
|
-
|
|
159944
|
-
|
|
158924
|
+
mkdirSync21(sourceSkillDir, { recursive: true });
|
|
158925
|
+
mkdirSync21(assembledSkillDir, { recursive: true });
|
|
159945
158926
|
if (!shouldWriteSkillFile(sourceSkillFilePath) || !shouldWriteSkillFile(assembledSkillFilePath)) {
|
|
159946
158927
|
continue;
|
|
159947
158928
|
}
|
|
159948
|
-
|
|
159949
|
-
|
|
158929
|
+
writeFileSync23(sourceSkillFilePath, content, "utf-8");
|
|
158930
|
+
writeFileSync23(assembledSkillFilePath, content, "utf-8");
|
|
159950
158931
|
writeManagedSkillMetadata(sourceSkillDir, {
|
|
159951
158932
|
name: skill2.name,
|
|
159952
158933
|
origin: "builtin",
|
|
@@ -159966,8 +158947,8 @@ function materializeBuiltinSkills(skills) {
|
|
|
159966
158947
|
cleanupRemovedManagedSkillDirs(assembledSkillsDir, "builtin", expectedSkillNames);
|
|
159967
158948
|
}
|
|
159968
158949
|
function materializePluginSkillDirectories(pluginRootDir) {
|
|
159969
|
-
const sourceSkillsDir =
|
|
159970
|
-
if (!
|
|
158950
|
+
const sourceSkillsDir = join104(pluginRootDir, "skills");
|
|
158951
|
+
if (!existsSync92(sourceSkillsDir)) {
|
|
159971
158952
|
return;
|
|
159972
158953
|
}
|
|
159973
158954
|
const { assembledSkillsDir, pluginSourceDir, configDir } = getSkillLayout();
|
|
@@ -159979,9 +158960,9 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
159979
158960
|
if (entry.name === "tmp")
|
|
159980
158961
|
continue;
|
|
159981
158962
|
expectedSkillNames.add(entry.name);
|
|
159982
|
-
const sourceDir =
|
|
159983
|
-
const mirroredSourceDir =
|
|
159984
|
-
const assembledDir =
|
|
158963
|
+
const sourceDir = join104(sourceSkillsDir, entry.name);
|
|
158964
|
+
const mirroredSourceDir = join104(pluginSourceDir, entry.name);
|
|
158965
|
+
const assembledDir = join104(assembledSkillsDir, entry.name);
|
|
159985
158966
|
if (!shouldSyncManagedSkillDir(mirroredSourceDir, "plugin") || !shouldSyncManagedSkillDir(assembledDir, "plugin")) {
|
|
159986
158967
|
continue;
|
|
159987
158968
|
}
|
|
@@ -160015,7 +158996,7 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
160015
158996
|
for (const builtinEntry of readdirSync26(assembledSkillsDir, { withFileTypes: true })) {
|
|
160016
158997
|
if (!builtinEntry.isDirectory())
|
|
160017
158998
|
continue;
|
|
160018
|
-
const assembledDir =
|
|
158999
|
+
const assembledDir = join104(assembledSkillsDir, builtinEntry.name);
|
|
160019
159000
|
const metadata = readManagedSkillMetadata(assembledDir);
|
|
160020
159001
|
if (metadata?.generatedBy !== "hiai-opencode" || metadata.origin !== "builtin") {
|
|
160021
159002
|
continue;
|
|
@@ -160032,45 +159013,17 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
160032
159013
|
|
|
160033
159014
|
// src/index.ts
|
|
160034
159015
|
var activePluginDispose = null;
|
|
160035
|
-
function createWebsearchFallback(config4) {
|
|
160036
|
-
const model = config4.agents?.researcher?.model?.trim();
|
|
160037
|
-
if (!model) {
|
|
160038
|
-
return;
|
|
160039
|
-
}
|
|
160040
|
-
if (model.startsWith("openrouter/")) {
|
|
160041
|
-
return {
|
|
160042
|
-
providerID: OPENROUTER_PROVIDER_ID,
|
|
160043
|
-
model: model.slice("openrouter/".length)
|
|
160044
|
-
};
|
|
160045
|
-
}
|
|
160046
|
-
if (model.startsWith("openai/")) {
|
|
160047
|
-
return {
|
|
160048
|
-
providerID: OPENAI_PROVIDER_ID,
|
|
160049
|
-
model: model.slice("openai/".length)
|
|
160050
|
-
};
|
|
160051
|
-
}
|
|
160052
|
-
if (model.startsWith("google/")) {
|
|
160053
|
-
return {
|
|
160054
|
-
providerID: GOOGLE_PROVIDER_ID,
|
|
160055
|
-
model: model.slice("google/".length)
|
|
160056
|
-
};
|
|
160057
|
-
}
|
|
160058
|
-
return {
|
|
160059
|
-
providerID: OPENROUTER_PROVIDER_ID,
|
|
160060
|
-
model
|
|
160061
|
-
};
|
|
160062
|
-
}
|
|
160063
159016
|
function configureBundledBunPtyLibrary() {
|
|
160064
159017
|
if (process.env.BUN_PTY_LIB?.trim()) {
|
|
160065
159018
|
return;
|
|
160066
159019
|
}
|
|
160067
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";
|
|
160068
159021
|
const candidates = [
|
|
160069
|
-
|
|
160070
|
-
|
|
160071
|
-
|
|
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)
|
|
160072
159025
|
];
|
|
160073
|
-
const resolved = candidates.find((candidate) =>
|
|
159026
|
+
const resolved = candidates.find((candidate) => existsSync94(candidate));
|
|
160074
159027
|
if (resolved) {
|
|
160075
159028
|
process.env.BUN_PTY_LIB = resolved;
|
|
160076
159029
|
}
|
|
@@ -160092,11 +159045,12 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
160092
159045
|
pluginConfig: pluginConfig2,
|
|
160093
159046
|
platformConfig: internalConfig
|
|
160094
159047
|
});
|
|
159048
|
+
autoExportStaticMcpJson(ctx.directory, internalConfig);
|
|
160095
159049
|
materializeBuiltinSkills(createBuiltinSkills({
|
|
160096
159050
|
browserProvider: pluginConfig2.browser_automation_engine?.provider ?? "playwright",
|
|
160097
159051
|
disabledSkills: new Set(pluginConfig2.disabled_skills ?? [])
|
|
160098
159052
|
}));
|
|
160099
|
-
materializePluginSkillDirectories(
|
|
159053
|
+
materializePluginSkillDirectories(join106(import.meta.dirname, ".."));
|
|
160100
159054
|
const { initializeModelRequirements: initializeModelRequirements2 } = await Promise.resolve().then(() => (init_model_requirements(), exports_model_requirements));
|
|
160101
159055
|
initializeModelRequirements2(internalConfig);
|
|
160102
159056
|
const { initializeModelHeuristics: initializeModelHeuristics2 } = await Promise.resolve().then(() => (init_model_capability_heuristics(), exports_model_capability_heuristics));
|
|
@@ -160157,16 +159111,12 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
160157
159111
|
} catch (err) {
|
|
160158
159112
|
console.error("[hiai-opencode] PTYPlugin failed to load:", err);
|
|
160159
159113
|
}
|
|
160160
|
-
const websearchResult = await websearch_cited_default(ctx, createWebsearchFallback(internalConfig));
|
|
160161
|
-
const websearchGoogleResult = await WebsearchCitedGooglePlugin(ctx);
|
|
160162
|
-
const websearchOpenAIResult = await WebsearchCitedOpenAIPlugin(ctx);
|
|
160163
159114
|
const combinedResult = {
|
|
160164
159115
|
name: PLUGIN_NAME,
|
|
160165
159116
|
...pluginInterface,
|
|
160166
159117
|
tool: {
|
|
160167
159118
|
...pluginInterface.tool,
|
|
160168
|
-
...ptyResult.tool
|
|
160169
|
-
...websearchResult.tool
|
|
159119
|
+
...ptyResult.tool
|
|
160170
159120
|
},
|
|
160171
159121
|
"command.execute.before": async (input, output) => {
|
|
160172
159122
|
await pluginInterface["command.execute.before"]?.(input, output);
|
|
@@ -160187,38 +159137,12 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
160187
159137
|
config: async (input) => {
|
|
160188
159138
|
await pluginInterface.config?.(input);
|
|
160189
159139
|
await subtask2Result.config?.(input);
|
|
160190
|
-
await websearchResult.config?.(input);
|
|
160191
159140
|
},
|
|
160192
159141
|
event: async (input) => {
|
|
160193
159142
|
await pluginInterface.event?.(input);
|
|
160194
159143
|
await subtask2Result.event?.(input);
|
|
160195
159144
|
await ptyResult.event?.(input);
|
|
160196
159145
|
},
|
|
160197
|
-
auth: {
|
|
160198
|
-
provider: "hiai-opencode",
|
|
160199
|
-
methods: [
|
|
160200
|
-
{ type: "api", label: "Google Search API key" }
|
|
160201
|
-
],
|
|
160202
|
-
loader: async (getAuth) => {
|
|
160203
|
-
const authData = await getAuth();
|
|
160204
|
-
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));
|
|
160205
|
-
const getConfiguredKey = (configKey) => {
|
|
160206
|
-
if (configKey)
|
|
160207
|
-
return resolveEnvVars(configKey);
|
|
160208
|
-
return;
|
|
160209
|
-
};
|
|
160210
|
-
const googleKey = authData["Google Search API key"] || getConfiguredKey(internalConfig.auth?.googleSearch);
|
|
160211
|
-
const openaiKey = getConfiguredKey(internalConfig.auth?.openai);
|
|
160212
|
-
const openRouterKey = getConfiguredKey(internalConfig.auth?.openrouter);
|
|
160213
|
-
if (googleKey)
|
|
160214
|
-
registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: googleKey }));
|
|
160215
|
-
if (openaiKey)
|
|
160216
|
-
registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openaiKey }));
|
|
160217
|
-
if (openRouterKey)
|
|
160218
|
-
registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openRouterKey }));
|
|
160219
|
-
return {};
|
|
160220
|
-
}
|
|
160221
|
-
},
|
|
160222
159146
|
"experimental.session.compacting": async (_input, output) => {
|
|
160223
159147
|
await hooks.compactionContextInjector?.capture(_input.sessionID);
|
|
160224
159148
|
await hooks.compactionTodoPreserver?.capture(_input.sessionID);
|