@hiai-gg/hiai-opencode 0.1.4 → 0.1.6

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