@hiai-gg/hiai-opencode 0.1.3 → 0.1.5

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 (64) hide show
  1. package/.env.example +14 -18
  2. package/AGENTS.md +77 -23
  3. package/ARCHITECTURE.md +15 -17
  4. package/LICENSE.md +1 -0
  5. package/README.md +189 -94
  6. package/assets/cli/hiai-opencode.mjs +276 -0
  7. package/assets/mcp/playwright.mjs +7 -0
  8. package/config/hiai-opencode.schema.json +85 -50
  9. package/dist/config/defaults.d.ts +1 -3
  10. package/dist/config/index.d.ts +0 -1
  11. package/dist/config/platform-schema.d.ts +343 -4
  12. package/dist/config/schema/agent-overrides.d.ts +256 -0
  13. package/dist/config/schema/categories.d.ts +1 -1
  14. package/dist/config/schema/commands.d.ts +1 -0
  15. package/dist/config/schema/index.d.ts +2 -0
  16. package/dist/config/schema/oh-my-opencode-config.d.ts +267 -0
  17. package/dist/config/schema/skill-discovery.d.ts +11 -0
  18. package/dist/config/types.d.ts +33 -3
  19. package/dist/create-tools.d.ts +2 -0
  20. package/dist/features/builtin-commands/templates/mcp-status.d.ts +1 -0
  21. package/dist/features/builtin-commands/types.d.ts +1 -1
  22. package/dist/features/opencode-skill-loader/loader.d.ts +2 -0
  23. package/dist/index.js +744 -358
  24. package/dist/internals/plugins/websearch-cited/index.d.ts +7 -1
  25. package/dist/mcp/types.d.ts +1 -1
  26. package/dist/plugin/skill-discovery-config.d.ts +4 -0
  27. package/dist/plugin/tool-registry.d.ts +2 -0
  28. package/dist/shared/startup-diagnostics.d.ts +6 -0
  29. package/dist/tools/skill-mcp/tools.d.ts +2 -0
  30. package/hiai-opencode.json +55 -33
  31. package/package.json +4 -1
  32. package/src/agents/AGENTS.md +3 -4
  33. package/src/config/defaults.ts +186 -77
  34. package/src/config/index.ts +0 -1
  35. package/src/config/loader.test.ts +16 -1
  36. package/src/config/loader.ts +4 -2
  37. package/src/config/platform-schema.ts +53 -4
  38. package/src/config/schema/agent-overrides.ts +2 -0
  39. package/src/config/schema/commands.ts +1 -0
  40. package/src/config/schema/fast-apply.ts +4 -4
  41. package/src/config/schema/index.ts +2 -0
  42. package/src/config/schema/oh-my-opencode-config.ts +3 -0
  43. package/src/config/schema/skill-discovery.ts +25 -0
  44. package/src/config/types.ts +49 -2
  45. package/src/create-tools.ts +4 -1
  46. package/src/features/builtin-commands/commands.ts +7 -0
  47. package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
  48. package/src/features/builtin-commands/types.ts +1 -1
  49. package/src/features/builtin-skills/skills/playwright.ts +24 -2
  50. package/src/features/opencode-skill-loader/loader.ts +11 -0
  51. package/src/index.ts +53 -14
  52. package/src/internals/plugins/websearch-cited/index.ts +10 -5
  53. package/src/lsp/index.ts +1 -0
  54. package/src/mcp/registry.ts +6 -1
  55. package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
  56. package/src/plugin/skill-context.ts +31 -13
  57. package/src/plugin/skill-discovery-config.ts +32 -0
  58. package/src/plugin/tool-registry.ts +4 -0
  59. package/src/plugin-handlers/agent-config-handler.ts +20 -13
  60. package/src/plugin-handlers/command-config-handler.ts +22 -12
  61. package/src/shared/migration/agent-names.ts +5 -5
  62. package/src/shared/startup-diagnostics.ts +77 -0
  63. package/src/tools/skill-mcp/tools.ts +45 -7
  64. package/src/config/models.ts +0 -32
package/dist/index.js CHANGED
@@ -146,9 +146,9 @@ var init_agent_names = __esm(() => {
146
146
  subagent: "coder",
147
147
  sub: "coder",
148
148
  designer: "designer",
149
- ui: "ui",
150
- vision: "ui",
151
- multimodal: "ui"
149
+ ui: "multimodal",
150
+ vision: "multimodal",
151
+ multimodal: "multimodal"
152
152
  };
153
153
  BUILTIN_AGENT_NAMES = new Set([
154
154
  "bob",
@@ -157,7 +157,7 @@ var init_agent_names = __esm(() => {
157
157
  "critic",
158
158
  "designer",
159
159
  "researcher",
160
- "ui",
160
+ "multimodal",
161
161
  "platform-manager",
162
162
  "guard"
163
163
  ]);
@@ -20778,8 +20778,8 @@ var require_resolve = __commonJS((exports) => {
20778
20778
  }
20779
20779
  return count;
20780
20780
  }
20781
- function getFullPath(resolver, id = "", normalize3) {
20782
- if (normalize3 !== false)
20781
+ function getFullPath(resolver, id = "", normalize4) {
20782
+ if (normalize4 !== false)
20783
20783
  id = normalizeId(id);
20784
20784
  const p = resolver.parse(id);
20785
20785
  return _getFullPath(resolver, p);
@@ -22066,7 +22066,7 @@ var require_schemes = __commonJS((exports, module) => {
22066
22066
  var require_fast_uri = __commonJS((exports, module) => {
22067
22067
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils2();
22068
22068
  var { SCHEMES, getSchemeHandler } = require_schemes();
22069
- function normalize3(uri, options) {
22069
+ function normalize4(uri, options) {
22070
22070
  if (typeof uri === "string") {
22071
22071
  uri = serialize(parse11(uri, options), options);
22072
22072
  } else if (typeof uri === "object") {
@@ -22301,7 +22301,7 @@ var require_fast_uri = __commonJS((exports, module) => {
22301
22301
  }
22302
22302
  var fastUri = {
22303
22303
  SCHEMES,
22304
- normalize: normalize3,
22304
+ normalize: normalize4,
22305
22305
  resolve: resolve22,
22306
22306
  resolveComponent,
22307
22307
  equal,
@@ -33657,9 +33657,9 @@ function parseOpenAIOptions(providerConfig, model) {
33657
33657
  }
33658
33658
  return result;
33659
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;
33660
+ var GOOGLE_PROVIDER_ID = "google", OPENAI_PROVIDER_ID = "openai", OPENROUTER_PROVIDER_ID = "openrouter", CITED_SEARCH_TOOL_DESCRIPTION = "Performs a Gemini-style grounded web search: returns a concise digest with inline citations and a Sources list of URLs. NOTE: for LLM rate limits, DO NOT parallel this tool > 5", WEBSEARCH_ARGS, WEBSEARCH_ALLOWED_KEYS, WEBSEARCH_ALLOWED_KEYS_DESCRIPTION, authRegistry, WebsearchCitedPlugin = (_ctx, fallback) => {
33661
+ let selectedProvider = fallback?.providerID;
33662
+ let selectedModel = fallback?.model;
33663
33663
  let openaiConfig = {};
33664
33664
  let configError;
33665
33665
  return Promise.resolve({
@@ -33689,6 +33689,9 @@ var GOOGLE_PROVIDER_ID = "google", OPENAI_PROVIDER_ID = "openai", OPENROUTER_PRO
33689
33689
  const openaiProvider = config4.provider?.openai;
33690
33690
  openaiConfig = parseOpenAIOptions(openaiProvider, selectedModel);
33691
33691
  }
33692
+ } else if (!error92 && fallback) {
33693
+ selectedProvider = fallback.providerID;
33694
+ selectedModel = fallback.model;
33692
33695
  }
33693
33696
  return Promise.resolve();
33694
33697
  },
@@ -33808,8 +33811,8 @@ class EventEmitter {
33808
33811
  // node_modules/bun-pty/src/terminal.ts
33809
33812
  import { dlopen, FFIType, ptr } from "bun:ffi";
33810
33813
  import { Buffer as Buffer2 } from "buffer";
33811
- import { join as join103, dirname as dirname30, basename as basename16 } from "path";
33812
- import { existsSync as existsSync89 } from "fs";
33814
+ import { join as join104, dirname as dirname31, basename as basename16 } from "path";
33815
+ import { existsSync as existsSync92 } from "fs";
33813
33816
  function shQuote(s) {
33814
33817
  if (s.length === 0)
33815
33818
  return "''";
@@ -33817,7 +33820,7 @@ function shQuote(s) {
33817
33820
  }
33818
33821
  function resolveLibPath() {
33819
33822
  const env = process.env.BUN_PTY_LIB;
33820
- if (env && existsSync89(env))
33823
+ if (env && existsSync92(env))
33821
33824
  return env;
33822
33825
  try {
33823
33826
  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 +33831,22 @@ function resolveLibPath() {
33828
33831
  const arch = process.arch;
33829
33832
  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
33833
  const base = Bun.fileURLToPath(import.meta.url);
33831
- const fileDir = dirname30(base);
33834
+ const fileDir = dirname31(base);
33832
33835
  const dirName = basename16(fileDir);
33833
- const here = dirName === "src" || dirName === "dist" ? dirname30(fileDir) : fileDir;
33836
+ const here = dirName === "src" || dirName === "dist" ? dirname31(fileDir) : fileDir;
33834
33837
  const basePaths = [
33835
- join103(here, "rust-pty", "target", "release"),
33836
- join103(here, "..", "bun-pty", "rust-pty", "target", "release"),
33837
- join103(process.cwd(), "node_modules", "bun-pty", "rust-pty", "target", "release")
33838
+ join104(here, "rust-pty", "target", "release"),
33839
+ join104(here, "..", "bun-pty", "rust-pty", "target", "release"),
33840
+ join104(process.cwd(), "node_modules", "bun-pty", "rust-pty", "target", "release")
33838
33841
  ];
33839
33842
  const fallbackPaths = [];
33840
33843
  for (const basePath of basePaths) {
33841
33844
  for (const filename of filenames) {
33842
- fallbackPaths.push(join103(basePath, filename));
33845
+ fallbackPaths.push(join104(basePath, filename));
33843
33846
  }
33844
33847
  }
33845
33848
  for (const path10 of fallbackPaths) {
33846
- if (existsSync89(path10))
33849
+ if (existsSync92(path10))
33847
33850
  return path10;
33848
33851
  }
33849
33852
  throw new Error(`librust_pty shared library not found.
@@ -35060,8 +35063,8 @@ var init_plugin = __esm(() => {
35060
35063
  });
35061
35064
 
35062
35065
  // src/index.ts
35063
- import { existsSync as existsSync90 } from "fs";
35064
- import { join as join104 } from "path";
35066
+ import { existsSync as existsSync93 } from "fs";
35067
+ import { join as join105 } from "path";
35065
35068
 
35066
35069
  // src/hooks/todo-continuation-enforcer/index.ts
35067
35070
  init_logger();
@@ -110591,6 +110594,11 @@ async function loadGlobalAgentsSkills() {
110591
110594
  const skills = await loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
110592
110595
  return skillsToCommandDefinitionRecord(skills);
110593
110596
  }
110597
+ async function loadManagedPluginSkills() {
110598
+ const skillsDir = join60(getOpenCodeConfigDir({ binary: "opencode" }), ".hiai", "skills", "plugin");
110599
+ const skills = await loadSkillsFromDir({ skillsDir, scope: "builtin" });
110600
+ return skillsToCommandDefinitionRecord(skills);
110601
+ }
110594
110602
  async function discoverAllSkills(directory) {
110595
110603
  const [opencodeProjectSkills, opencodeGlobalSkills, projectSkills, userSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
110596
110604
  discoverOpencodeProjectSkills(directory),
@@ -110661,6 +110669,10 @@ async function discoverGlobalAgentsSkills() {
110661
110669
  const agentsGlobalDir = join60(getAgentsConfigDir(), "skills");
110662
110670
  return loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
110663
110671
  }
110672
+ async function discoverManagedPluginSkills() {
110673
+ const skillsDir = join60(getOpenCodeConfigDir({ binary: "opencode" }), ".hiai", "skills", "plugin");
110674
+ return loadSkillsFromDir({ skillsDir, scope: "builtin" });
110675
+ }
110664
110676
  // src/features/opencode-skill-loader/merger/builtin-skill-converter.ts
110665
110677
  function builtinToLoadedSkill(builtin) {
110666
110678
  const definition = {
@@ -110893,11 +110905,33 @@ var playwrightSkill = {
110893
110905
  description: "MUST USE for any browser-related tasks. Browser automation via Playwright MCP - verification, browsing, information gathering, web scraping, testing, screenshots, and all browser interactions.",
110894
110906
  template: `# Playwright Browser Automation
110895
110907
 
110896
- This skill provides browser automation capabilities via the Playwright MCP server.`,
110908
+ This skill provides browser automation capabilities via the Playwright MCP server.
110909
+
110910
+ ## Required workflow
110911
+
110912
+ 1. Load this skill before calling \`skill_mcp\`.
110913
+ 2. Use \`skill_mcp\` with \`mcp_name="playwright"\` for browser navigation, interaction, screenshots, and visual verification.
110914
+ 3. If the host says \`MCP server "playwright" not found\`, do not conclude that Playwright is impossible. First report that the skill was not loaded or the Playwright MCP server was not registered in this session.
110915
+ 4. If Chromium starts but fails with missing Linux libraries such as \`libnspr4\`, \`libnss3\`, \`libatk-bridge\`, \`libgtk-3\`, or similar, distinguish browser OS dependencies from MCP availability.
110916
+
110917
+ ## Linux dependency fallback
110918
+
110919
+ Playwright has two dependency layers:
110920
+
110921
+ - Browser binary: installable without sudo with \`npx playwright install chromium\` or by setting \`HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1\` before OpenCode starts.
110922
+ - System libraries: on minimal Linux images these usually require admin rights via \`sudo npx playwright install-deps chromium\` or OS package manager equivalents.
110923
+
110924
+ If sudo is unavailable, try these alternatives before falling back to curl-only checks:
110925
+
110926
+ - Use an already installed Chrome/Chromium/Edge by adding Playwright MCP args in \`hiai-opencode.json\`, for example \`--browser chrome\` or \`--browser msedge\`.
110927
+ - Use a remote/browser service or CDP-backed browser when available.
110928
+ - Switch the browser automation provider to \`agent-browser\` or \`playwright-cli\` if the workspace has those tools installed.
110929
+
110930
+ Only use \`curl\` as a final degraded check. Clearly say that HTTP checks do not replace interactive browser verification.`,
110897
110931
  mcpConfig: {
110898
110932
  playwright: {
110899
110933
  command: "npx",
110900
- args: ["@playwright/mcp@latest"]
110934
+ args: ["-y", "@playwright/mcp@latest"]
110901
110935
  }
110902
110936
  }
110903
110937
  };
@@ -113926,6 +113960,8 @@ var AgentOverridesSchema = exports_external.object({
113926
113960
  general: AgentOverrideConfigSchema.optional(),
113927
113961
  zoe: AgentOverrideConfigSchema.optional(),
113928
113962
  "pre-plan": AgentOverrideConfigSchema.optional(),
113963
+ manager: AgentOverrideConfigSchema.optional(),
113964
+ vision: AgentOverrideConfigSchema.optional(),
113929
113965
  logician: AgentOverrideConfigSchema.optional(),
113930
113966
  librarian: AgentOverrideConfigSchema.optional(),
113931
113967
  explore: AgentOverrideConfigSchema.optional(),
@@ -114022,7 +114058,8 @@ var BuiltinCommandNameSchema = exports_external.enum([
114022
114058
  "refactor",
114023
114059
  "start-work",
114024
114060
  "stop-continuation",
114025
- "remove-ai-slops"
114061
+ "remove-ai-slops",
114062
+ "mcp-status"
114026
114063
  ]);
114027
114064
  // src/config/schema/comment-checker.ts
114028
114065
  var CommentCheckerConfigSchema = exports_external.object({
@@ -114077,8 +114114,8 @@ var ExperimentalConfigSchema = exports_external.object({
114077
114114
  // src/config/schema/fast-apply.ts
114078
114115
  var FastApplyConfigSchema = exports_external.object({
114079
114116
  enabled: exports_external.boolean().optional().default(false),
114080
- ollama_url: exports_external.string().optional().default("http://localhost:11434"),
114081
- model: exports_external.string().optional().default("qwen3.5:9b"),
114117
+ ollama_url: exports_external.string().optional().default(""),
114118
+ model: exports_external.string().optional().default(""),
114082
114119
  timeout: exports_external.number().int().positive().optional().default(30000)
114083
114120
  });
114084
114121
  // src/config/schema/git-env-prefix.ts
@@ -114235,6 +114272,17 @@ var SkillsConfigSchema = exports_external.union([
114235
114272
  }).catchall(SkillEntrySchema)
114236
114273
  ]);
114237
114274
 
114275
+ // src/config/schema/skill-discovery.ts
114276
+ var SkillDiscoveryConfigSchema = exports_external.object({
114277
+ config_sources: exports_external.boolean().default(true),
114278
+ project_opencode: exports_external.boolean().default(true),
114279
+ global_opencode: exports_external.boolean().default(false),
114280
+ project_claude: exports_external.boolean().default(false),
114281
+ global_claude: exports_external.boolean().default(false),
114282
+ project_agents: exports_external.boolean().default(false),
114283
+ global_agents: exports_external.boolean().default(false)
114284
+ });
114285
+
114238
114286
  // src/config/schema/bob.ts
114239
114287
  var BobTasksConfigSchema = exports_external.object({
114240
114288
  storage_path: exports_external.string().optional(),
@@ -114293,7 +114341,8 @@ var AuthConfigSchema = exports_external.object({
114293
114341
  openai: exports_external.string().optional(),
114294
114342
  openrouter: exports_external.string().optional(),
114295
114343
  stitch: exports_external.string().optional(),
114296
- firecrawl: exports_external.string().optional()
114344
+ firecrawl: exports_external.string().optional(),
114345
+ context7: exports_external.string().optional()
114297
114346
  }).optional();
114298
114347
  var HiaiOpenCodeConfigSchema = exports_external.object({
114299
114348
  $schema: exports_external.string().optional(),
@@ -114317,6 +114366,7 @@ var HiaiOpenCodeConfigSchema = exports_external.object({
114317
114366
  experimental: ExperimentalConfigSchema.optional(),
114318
114367
  auto_update: exports_external.boolean().optional(),
114319
114368
  skills: SkillsConfigSchema.optional(),
114369
+ skill_discovery: SkillDiscoveryConfigSchema.optional(),
114320
114370
  ralph_loop: RalphLoopConfigSchema.optional(),
114321
114371
  runtime_fallback: exports_external.union([exports_external.boolean(), RuntimeFallbackConfigSchema]).optional(),
114322
114372
  background_task: BackgroundTaskConfigSchema.optional(),
@@ -116004,6 +116054,44 @@ If any issues are found during critical review:
116004
116054
  - ALWAYS preserve test coverage
116005
116055
  - If uncertain about a change, err on the side of keeping the original code`;
116006
116056
 
116057
+ // src/features/builtin-commands/templates/mcp-status.ts
116058
+ var MCP_STATUS_TEMPLATE = `# MCP Status Command
116059
+
116060
+ ## Purpose
116061
+
116062
+ Use /mcp-status to show the effective hiai-opencode MCP setup without relying on OpenCode's mcp list output.
116063
+
116064
+ ## Execute
116065
+
116066
+ Run:
116067
+
116068
+ \`\`\`bash
116069
+ hiai-opencode mcp-status
116070
+ \`\`\`
116071
+
116072
+ If the binary is not on PATH, try the package-local fallback:
116073
+
116074
+ \`\`\`bash
116075
+ node ./node_modules/@hiai-gg/hiai-opencode/assets/cli/hiai-opencode.mjs mcp-status
116076
+ \`\`\`
116077
+
116078
+ ## Report
116079
+
116080
+ Summarize the output in a compact status table:
116081
+
116082
+ - MCP server name
116083
+ - status: ok, warning, error, disabled
116084
+ - cause or next action
116085
+
116086
+ Rules:
116087
+
116088
+ - Do not print API key values.
116089
+ - If a key is missing, name the env var only.
116090
+ - If a runtime is missing, give the exact install hint from the command output or the shortest safe next command.
116091
+ - Do not edit config unless the user explicitly asks.
116092
+ - Do not run package installs unless the user explicitly asks.
116093
+ `;
116094
+
116007
116095
  // src/features/builtin-commands/commands.ts
116008
116096
  function resolveStartWorkAgent(options) {
116009
116097
  if (options?.useRegisteredAgents) {
@@ -116107,6 +116195,12 @@ Timestamp: $TIMESTAMP
116107
116195
  $ARGUMENTS
116108
116196
  </user-request>`,
116109
116197
  argumentHint: "[goal]"
116198
+ },
116199
+ "mcp-status": {
116200
+ description: "(builtin) Show hiai-opencode MCP server status, missing keys, and local runtime availability",
116201
+ template: `<command-instruction>
116202
+ ${MCP_STATUS_TEMPLATE}
116203
+ </command-instruction>`
116110
116204
  }
116111
116205
  };
116112
116206
  }
@@ -120443,7 +120537,7 @@ import * as fs12 from "fs";
120443
120537
  import * as path6 from "path";
120444
120538
 
120445
120539
  // src/config/loader.ts
120446
- import { existsSync as existsSync56, readFileSync as readFileSync42 } from "fs";
120540
+ import { existsSync as existsSync58, readFileSync as readFileSync43 } from "fs";
120447
120541
  import { join as join67 } from "path";
120448
120542
 
120449
120543
  // src/config/platform-schema.ts
@@ -120451,6 +120545,34 @@ var AgentConfigSchema = exports_external.object({
120451
120545
  model: exports_external.string(),
120452
120546
  description: exports_external.string().optional()
120453
120547
  });
120548
+ var ModelRecommendationSchema = exports_external.enum([
120549
+ "xhigh",
120550
+ "high",
120551
+ "middle",
120552
+ "fast",
120553
+ "vision",
120554
+ "writing",
120555
+ "design"
120556
+ ]);
120557
+ var ModelSlotConfigSchema = exports_external.union([
120558
+ exports_external.string(),
120559
+ exports_external.object({
120560
+ model: exports_external.string(),
120561
+ recommended: ModelRecommendationSchema.optional()
120562
+ })
120563
+ ]);
120564
+ var ModelSlotsConfigSchema = exports_external.object({
120565
+ bob: ModelSlotConfigSchema.optional(),
120566
+ coder: ModelSlotConfigSchema.optional(),
120567
+ strategist: ModelSlotConfigSchema.optional(),
120568
+ guard: ModelSlotConfigSchema.optional(),
120569
+ critic: ModelSlotConfigSchema.optional(),
120570
+ designer: ModelSlotConfigSchema.optional(),
120571
+ researcher: ModelSlotConfigSchema.optional(),
120572
+ manager: ModelSlotConfigSchema.optional(),
120573
+ brainstormer: ModelSlotConfigSchema.optional(),
120574
+ vision: ModelSlotConfigSchema.optional()
120575
+ });
120454
120576
  var FallbackEntrySchema = exports_external.object({
120455
120577
  providers: exports_external.array(exports_external.string()),
120456
120578
  model: exports_external.string(),
@@ -120487,8 +120609,9 @@ var McpServerConfigSchema = exports_external.object({
120487
120609
  environment: exports_external.record(exports_external.string(), exports_external.string()).optional()
120488
120610
  });
120489
120611
  var LspServerConfigSchema = exports_external.object({
120490
- command: exports_external.array(exports_external.string()),
120491
- extensions: exports_external.array(exports_external.string()),
120612
+ enabled: exports_external.boolean().optional(),
120613
+ command: exports_external.array(exports_external.string()).optional(),
120614
+ extensions: exports_external.array(exports_external.string()).optional(),
120492
120615
  initialization: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
120493
120616
  });
120494
120617
  var Subtask2ConfigSchema = exports_external.object({
@@ -120499,6 +120622,15 @@ var SkillsConfigSchema2 = exports_external.object({
120499
120622
  enabled: exports_external.boolean().optional(),
120500
120623
  disabled: exports_external.array(exports_external.string()).optional()
120501
120624
  });
120625
+ var SkillDiscoveryConfigSchema2 = exports_external.object({
120626
+ config_sources: exports_external.boolean().optional(),
120627
+ project_opencode: exports_external.boolean().optional(),
120628
+ global_opencode: exports_external.boolean().optional(),
120629
+ project_claude: exports_external.boolean().optional(),
120630
+ global_claude: exports_external.boolean().optional(),
120631
+ project_agents: exports_external.boolean().optional(),
120632
+ global_agents: exports_external.boolean().optional()
120633
+ });
120502
120634
  var PermissionsConfigSchema = exports_external.object({
120503
120635
  read: exports_external.record(exports_external.string(), exports_external.string()).optional(),
120504
120636
  edit: exports_external.record(exports_external.string(), exports_external.string()).optional(),
@@ -120526,12 +120658,13 @@ var AuthKeysSchema = exports_external.object({
120526
120658
  openai: exports_external.string().optional(),
120527
120659
  openrouter: exports_external.string().optional(),
120528
120660
  stitch: exports_external.string().optional(),
120529
- firecrawl: exports_external.string().optional()
120661
+ firecrawl: exports_external.string().optional(),
120662
+ context7: exports_external.string().optional()
120530
120663
  });
120531
120664
  var OllamaConfigSchema = exports_external.object({
120532
120665
  enabled: exports_external.boolean().default(false),
120533
- model: exports_external.string().default("qwen3.5:4b"),
120534
- baseUrl: exports_external.string().default("http://localhost:11434"),
120666
+ model: exports_external.string().default(""),
120667
+ baseUrl: exports_external.string().default(""),
120535
120668
  purpose: exports_external.enum(["verification", "helper", "fallback"]).default("helper")
120536
120669
  });
120537
120670
  var ModelFamilySchema = exports_external.object({
@@ -120560,6 +120693,8 @@ var AgentsConfigSchema = exports_external.object({
120560
120693
  zoe: AgentConfigSchema.optional(),
120561
120694
  build: AgentConfigSchema.optional(),
120562
120695
  "pre-plan": AgentConfigSchema.optional(),
120696
+ manager: AgentConfigSchema.optional(),
120697
+ vision: AgentConfigSchema.optional(),
120563
120698
  logician: AgentConfigSchema.optional(),
120564
120699
  librarian: AgentConfigSchema.optional(),
120565
120700
  explore: AgentConfigSchema.optional(),
@@ -120589,6 +120724,8 @@ var AgentRequirementsConfigSchema = exports_external.object({
120589
120724
  zoe: ModelRequirementSchema.optional(),
120590
120725
  build: ModelRequirementSchema.optional(),
120591
120726
  "pre-plan": ModelRequirementSchema.optional(),
120727
+ manager: ModelRequirementSchema.optional(),
120728
+ vision: ModelRequirementSchema.optional(),
120592
120729
  logician: ModelRequirementSchema.optional(),
120593
120730
  librarian: ModelRequirementSchema.optional(),
120594
120731
  explore: ModelRequirementSchema.optional(),
@@ -120602,6 +120739,7 @@ var AgentRequirementsConfigSchema = exports_external.object({
120602
120739
  }).catchall(ModelRequirementSchema);
120603
120740
  var HiaiOpencodeConfigSchema = exports_external.object({
120604
120741
  $schema: exports_external.string().optional(),
120742
+ models: ModelSlotsConfigSchema.optional(),
120605
120743
  agents: AgentsConfigSchema.optional(),
120606
120744
  agentRequirements: AgentRequirementsConfigSchema.optional(),
120607
120745
  categories: exports_external.record(exports_external.string(), CategoryConfigSchema2).optional(),
@@ -120611,28 +120749,25 @@ var HiaiOpencodeConfigSchema = exports_external.object({
120611
120749
  lsp: exports_external.record(exports_external.string(), LspServerConfigSchema).optional(),
120612
120750
  subtask2: Subtask2ConfigSchema.optional(),
120613
120751
  skills: SkillsConfigSchema2.optional(),
120752
+ skill_discovery: SkillDiscoveryConfigSchema2.optional(),
120614
120753
  permissions: PermissionsConfigSchema.optional(),
120615
120754
  auth: AuthKeysSchema.optional(),
120616
120755
  ollama: OllamaConfigSchema.optional()
120617
120756
  });
120618
120757
 
120619
- // src/config/models.ts
120620
- var MODEL_PRESETS = {
120621
- fast: "openrouter/google/gemini-2.0-flash",
120622
- mid: "openrouter/anthropic/claude-3.5-sonnet",
120623
- high: "openrouter/anthropic/claude-3.5-opus",
120624
- ultrahigh: "openrouter/openai/gpt-4o",
120625
- vision: "openrouter/google/gemini-2.0-pro-exp-02-05",
120626
- reasoning: "openrouter/openai/o1",
120627
- strategist: "openrouter/z-ai/glm-5.1",
120628
- critic: "openrouter/qwen/qwen2.5-72b-instruct",
120629
- writing: "openrouter/kimi/kimi-latest"
120630
- };
120758
+ // src/config/defaults.ts
120759
+ import { existsSync as existsSync57, readFileSync as readFileSync42 } from "fs";
120760
+ import { dirname as dirname18, join as join66, normalize as normalize2 } from "path";
120631
120761
 
120632
120762
  // src/mcp/registry.ts
120633
120763
  import { join as join65 } from "path";
120764
+ import { existsSync as existsSync56 } from "fs";
120634
120765
  function resolveAssetScript(...segments) {
120635
- return join65(import.meta.dirname, "..", "assets", ...segments);
120766
+ const candidates = [
120767
+ join65(import.meta.dirname, "..", "assets", ...segments),
120768
+ join65(import.meta.dirname, "..", "..", "assets", ...segments)
120769
+ ];
120770
+ return candidates.find((candidate) => existsSync56(candidate)) ?? candidates[0];
120636
120771
  }
120637
120772
  function createNpmPackageCommand(pkg, ...args) {
120638
120773
  return ["node", resolveAssetScript("runtime", "npm-package-runner.mjs"), pkg, ...args];
@@ -120733,83 +120868,170 @@ function createDefaultMcpConfig() {
120733
120868
  }
120734
120869
 
120735
120870
  // src/config/defaults.ts
120736
- import { join as join66 } from "path";
120737
- var defaultConfig = {
120738
- agents: {
120739
- bob: { model: MODEL_PRESETS.high },
120740
- guard: { model: MODEL_PRESETS.ultrahigh },
120741
- strategist: { model: MODEL_PRESETS.strategist },
120742
- critic: { model: MODEL_PRESETS.critic },
120743
- coder: { model: MODEL_PRESETS.mid },
120744
- designer: {
120745
- model: "openrouter/google/gemini-3.1-pro",
120746
- description: "Creative visual problem-solver for high-touch UI, interaction, and brand-level interface direction. Best used when the task needs taste, composition, and design judgment rather than plain implementation. (Designer - HiaiOpenCode)"
120747
- },
120748
- sub: { model: MODEL_PRESETS.fast },
120749
- researcher: { model: MODEL_PRESETS.fast },
120750
- multimodal: { model: MODEL_PRESETS.vision },
120751
- "quality-guardian": { model: MODEL_PRESETS.mid },
120752
- "platform-manager": { model: MODEL_PRESETS.fast },
120753
- brainstormer: { model: MODEL_PRESETS.fast },
120754
- "agent-skills": { model: MODEL_PRESETS.fast }
120755
- },
120756
- agentRequirements: {},
120757
- categories: {
120758
- "visual-engineering": { model: MODEL_PRESETS.vision, variant: "high" },
120759
- artistry: { model: MODEL_PRESETS.vision, variant: "high" },
120760
- ultrabrain: { model: MODEL_PRESETS.ultrahigh, variant: "xhigh" },
120761
- deep: { model: MODEL_PRESETS.reasoning, variant: "medium" },
120762
- quick: { model: MODEL_PRESETS.fast },
120763
- writing: { model: MODEL_PRESETS.writing },
120764
- git: { model: MODEL_PRESETS.fast },
120765
- "unspecified-low": { model: MODEL_PRESETS.mid },
120766
- "unspecified-high": { model: MODEL_PRESETS.high, variant: "max" }
120767
- },
120768
- categoryRequirements: {},
120769
- mcp: createDefaultMcpConfig(),
120770
- lsp: {
120771
- typescript: {
120772
- command: ["typescript-language-server", "--stdio"],
120773
- extensions: [".ts", ".tsx", ".mts", ".cts"]
120774
- },
120775
- svelte: {
120776
- command: ["svelteserver", "--stdio"],
120777
- extensions: [".svelte"]
120778
- },
120779
- eslint: {
120780
- command: ["node", join66(import.meta.dirname, "..", "assets", "runtime", "npm-package-runner.mjs"), "eslint-lsp", "--stdio"],
120781
- extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
120782
- },
120783
- bash: {
120784
- command: ["node", join66(import.meta.dirname, "..", "assets", "runtime", "npm-package-runner.mjs"), "bash-language-server", "start"],
120785
- extensions: [".sh", ".bash"]
120786
- },
120787
- pyright: {
120788
- command: ["pyright-langserver", "--stdio"],
120789
- extensions: [".py"]
120790
- }
120871
+ var REQUIRED_MODEL_SLOTS = [
120872
+ "bob",
120873
+ "coder",
120874
+ "strategist",
120875
+ "guard",
120876
+ "critic",
120877
+ "designer",
120878
+ "researcher",
120879
+ "manager",
120880
+ "brainstormer",
120881
+ "vision"
120882
+ ];
120883
+ var DEFAULT_LSP = {
120884
+ typescript: {
120885
+ enabled: true,
120886
+ command: ["typescript-language-server", "--stdio"],
120887
+ extensions: [".ts", ".tsx", ".mts", ".cts"]
120791
120888
  },
120792
- subtask2: {
120793
- replace_generic: true,
120794
- generic_return: null
120889
+ svelte: {
120890
+ enabled: true,
120891
+ command: ["svelteserver", "--stdio"],
120892
+ extensions: [".svelte"]
120795
120893
  },
120796
- skills: {
120894
+ eslint: {
120797
120895
  enabled: true,
120798
- disabled: []
120896
+ command: ["node", "{pluginRoot}/assets/runtime/npm-package-runner.mjs", "eslint-lsp", "--stdio"],
120897
+ extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
120799
120898
  },
120800
- permissions: {
120801
- read: { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" },
120802
- edit: { "*": "allow" },
120803
- bash: { "*": "allow" },
120804
- deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"]
120899
+ bash: {
120900
+ enabled: true,
120901
+ command: ["node", "{pluginRoot}/assets/runtime/npm-package-runner.mjs", "bash-language-server", "start"],
120902
+ extensions: [".sh", ".bash"]
120805
120903
  },
120806
- ollama: {
120807
- enabled: false,
120808
- model: "{env:OLLAMA_MODEL:-qwen3.5:4b}",
120809
- baseUrl: "http://localhost:11434",
120810
- purpose: "helper"
120904
+ pyright: {
120905
+ enabled: true,
120906
+ command: ["pyright-langserver", "--stdio"],
120907
+ extensions: [".py"]
120811
120908
  }
120812
120909
  };
120910
+ function findPluginRoot() {
120911
+ const candidates = [
120912
+ join66(import.meta.dirname, "..", ".."),
120913
+ join66(import.meta.dirname, ".."),
120914
+ join66(import.meta.dirname, "..", ".."),
120915
+ dirname18(process.argv[1] ?? ""),
120916
+ process.cwd()
120917
+ ];
120918
+ for (const candidate of candidates) {
120919
+ const root = normalize2(candidate);
120920
+ if (existsSync57(join66(root, "hiai-opencode.json")))
120921
+ return root;
120922
+ }
120923
+ throw new Error("[hiai-opencode] Cannot find bundled hiai-opencode.json. The package is incomplete.");
120924
+ }
120925
+ function expandPluginRootPlaceholders(value, pluginRoot) {
120926
+ if (typeof value === "string")
120927
+ return value.replaceAll("{pluginRoot}", pluginRoot);
120928
+ if (Array.isArray(value))
120929
+ return value.map((item) => expandPluginRootPlaceholders(item, pluginRoot));
120930
+ if (value && typeof value === "object") {
120931
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, expandPluginRootPlaceholders(entry, pluginRoot)]));
120932
+ }
120933
+ return value;
120934
+ }
120935
+ function requireModelSlots(config2) {
120936
+ const models = config2.models ?? {};
120937
+ const resolved = Object.fromEntries(REQUIRED_MODEL_SLOTS.map((slot) => {
120938
+ const value = models[slot];
120939
+ const model = typeof value === "string" ? value : value?.model;
120940
+ return [slot, model?.trim() ?? ""];
120941
+ }));
120942
+ const missing = REQUIRED_MODEL_SLOTS.filter((slot) => !resolved[slot]);
120943
+ if (missing.length > 0) {
120944
+ throw new Error(`[hiai-opencode] Missing required model slot(s) in hiai-opencode.json: ${missing.join(", ")}`);
120945
+ }
120946
+ return resolved;
120947
+ }
120948
+ function deriveAgents(models) {
120949
+ return {
120950
+ bob: { model: models.bob },
120951
+ coder: { model: models.coder },
120952
+ strategist: { model: models.strategist },
120953
+ guard: { model: models.guard },
120954
+ critic: { model: models.critic },
120955
+ designer: { model: models.designer },
120956
+ researcher: { model: models.researcher },
120957
+ "platform-manager": { model: models.manager },
120958
+ brainstormer: { model: models.brainstormer },
120959
+ multimodal: { model: models.vision },
120960
+ sub: { model: models.coder },
120961
+ "quality-guardian": { model: models.critic },
120962
+ "agent-skills": { model: models.manager }
120963
+ };
120964
+ }
120965
+ function deriveCategories(models) {
120966
+ return {
120967
+ "visual-engineering": { model: models.designer, variant: "high" },
120968
+ artistry: { model: models.designer, variant: "high" },
120969
+ ultrabrain: { model: models.strategist, variant: "xhigh" },
120970
+ deep: { model: models.coder, variant: "medium" },
120971
+ quick: { model: models.researcher },
120972
+ writing: { model: models.brainstormer },
120973
+ git: { model: models.manager },
120974
+ "unspecified-low": { model: models.coder },
120975
+ "unspecified-high": { model: models.bob, variant: "max" }
120976
+ };
120977
+ }
120978
+ function deriveMcp(config2) {
120979
+ const defaults = createDefaultMcpConfig();
120980
+ const userMcp = config2.mcp ?? {};
120981
+ return Object.fromEntries(Object.entries(defaults).map(([name, entry]) => {
120982
+ const override = userMcp[name] ?? {};
120983
+ return [name, { ...entry, ...override }];
120984
+ }));
120985
+ }
120986
+ function deriveLsp(config2) {
120987
+ const userLsp = config2.lsp ?? {};
120988
+ return Object.fromEntries(Object.entries(DEFAULT_LSP).map(([name, entry]) => {
120989
+ const override = userLsp[name] ?? {};
120990
+ return [name, { ...entry, ...override }];
120991
+ }));
120992
+ }
120993
+ function materializeConfig(rawConfig) {
120994
+ const models = requireModelSlots(rawConfig);
120995
+ return {
120996
+ ...rawConfig,
120997
+ agents: deriveAgents(models),
120998
+ agentRequirements: {},
120999
+ categories: deriveCategories(models),
121000
+ categoryRequirements: {},
121001
+ modelFamilies: [],
121002
+ mcp: deriveMcp(rawConfig),
121003
+ lsp: deriveLsp(rawConfig),
121004
+ subtask2: {
121005
+ replace_generic: true,
121006
+ generic_return: null,
121007
+ ...rawConfig.subtask2 ?? {}
121008
+ },
121009
+ skills: {
121010
+ enabled: true,
121011
+ disabled: [],
121012
+ ...rawConfig.skills ?? {}
121013
+ },
121014
+ permissions: {
121015
+ read: { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" },
121016
+ edit: { "*": "allow" },
121017
+ bash: { "*": "allow" },
121018
+ deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"],
121019
+ ...rawConfig.permissions ?? {}
121020
+ }
121021
+ };
121022
+ }
121023
+ function loadBundledDefaultConfig() {
121024
+ const pluginRoot = findPluginRoot();
121025
+ const configPath = join66(pluginRoot, "hiai-opencode.json");
121026
+ const raw = readFileSync42(configPath, "utf-8");
121027
+ const parsed = JSON.parse(raw);
121028
+ const materialized = materializeConfig(parsed);
121029
+ return expandPluginRootPlaceholders(materialized, pluginRoot);
121030
+ }
121031
+ function applyModelSlots(config2) {
121032
+ return materializeConfig(config2);
121033
+ }
121034
+ var defaultConfig = loadBundledDefaultConfig();
120813
121035
 
120814
121036
  // src/config/types.ts
120815
121037
  var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
@@ -120817,6 +121039,8 @@ var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
120817
121039
  zoe: "bob",
120818
121040
  build: "bob",
120819
121041
  "pre-plan": "strategist",
121042
+ manager: "platform-manager",
121043
+ vision: "multimodal",
120820
121044
  logician: "strategist",
120821
121045
  librarian: "researcher",
120822
121046
  explore: "researcher",
@@ -120855,7 +121079,7 @@ function findConfigFile(searchDirs) {
120855
121079
  for (const dir of searchDirs) {
120856
121080
  for (const filename of CONFIG_FILENAMES) {
120857
121081
  const candidate = join67(dir, filename);
120858
- if (existsSync56(candidate))
121082
+ if (existsSync58(candidate))
120859
121083
  return candidate;
120860
121084
  }
120861
121085
  }
@@ -120933,12 +121157,13 @@ function loadConfig(projectDir) {
120933
121157
  const configPath = findConfigFile(searchDirs);
120934
121158
  if (!configPath)
120935
121159
  return BASE_CONFIG;
120936
- const raw = readFileSync42(configPath, "utf-8");
121160
+ const raw = readFileSync43(configPath, "utf-8");
120937
121161
  const parsed = parse2(raw);
120938
121162
  const normalizedParsed = normalizeCompactLspConfig(parsed);
120939
121163
  const validated = HiaiOpencodeConfigSchema.parse(normalizedParsed);
120940
121164
  const normalized = normalizeAgentAliases(validated);
120941
- return deepMerge2(BASE_CONFIG, normalized);
121165
+ const merged = deepMerge2(BASE_CONFIG, normalized);
121166
+ return applyModelSlots(merged);
120942
121167
  }
120943
121168
  function resolveEnvVars(value) {
120944
121169
  return value.replace(/\{env:([^}]+)\}/g, (_, expression) => {
@@ -120949,10 +121174,10 @@ function resolveEnvVars(value) {
120949
121174
  // src/shared/migrate-legacy-config-file.ts
120950
121175
  init_logger();
120951
121176
  init_plugin_identity();
120952
- import { existsSync as existsSync57, readFileSync as readFileSync43, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
120953
- import { join as join68, dirname as dirname18, basename as basename9 } from "path";
121177
+ import { existsSync as existsSync59, readFileSync as readFileSync44, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
121178
+ import { join as join68, dirname as dirname19, basename as basename9 } from "path";
120954
121179
  function buildCanonicalPath(legacyPath) {
120955
- const dir = dirname18(legacyPath);
121180
+ const dir = dirname19(legacyPath);
120956
121181
  const ext = basename9(legacyPath).includes(".jsonc") ? ".jsonc" : ".json";
120957
121182
  return join68(dir, `${CONFIG_BASENAME}${ext}`);
120958
121183
  }
@@ -120986,15 +121211,15 @@ function archiveLegacyConfigFile(legacyPath) {
120986
121211
  }
120987
121212
  }
120988
121213
  function migrateLegacyConfigFile(legacyPath) {
120989
- if (!existsSync57(legacyPath))
121214
+ if (!existsSync59(legacyPath))
120990
121215
  return false;
120991
121216
  if (!basename9(legacyPath).startsWith(LEGACY_CONFIG_BASENAME))
120992
121217
  return false;
120993
121218
  const canonicalPath = buildCanonicalPath(legacyPath);
120994
- if (existsSync57(canonicalPath))
121219
+ if (existsSync59(canonicalPath))
120995
121220
  return false;
120996
121221
  try {
120997
- const content = readFileSync43(legacyPath, "utf-8");
121222
+ const content = readFileSync44(legacyPath, "utf-8");
120998
121223
  writeFileAtomically(canonicalPath, content);
120999
121224
  const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath);
121000
121225
  log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
@@ -122514,11 +122739,11 @@ function createRuntimeFallbackHook(ctx, options) {
122514
122739
  };
122515
122740
  }
122516
122741
  // src/hooks/write-existing-file-guard/hook.ts
122517
- import { existsSync as existsSync60, realpathSync as realpathSync6 } from "fs";
122518
- import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute11, join as join70, normalize as normalize2, relative as relative8, resolve as resolve14 } from "path";
122742
+ import { existsSync as existsSync62, realpathSync as realpathSync6 } from "fs";
122743
+ import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute11, join as join70, normalize as normalize3, relative as relative8, resolve as resolve14 } from "path";
122519
122744
 
122520
122745
  // src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
122521
- import { existsSync as existsSync59 } from "fs";
122746
+ import { existsSync as existsSync61 } from "fs";
122522
122747
 
122523
122748
  // src/hooks/write-existing-file-guard/session-read-permissions.ts
122524
122749
  function touchSession(sessionLastAccess, sessionID) {
@@ -122606,7 +122831,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
122606
122831
  return;
122607
122832
  }
122608
122833
  if (toolName === "read") {
122609
- if (!existsSync59(resolvedPath) || !input.sessionID) {
122834
+ if (!existsSync61(resolvedPath) || !input.sessionID) {
122610
122835
  return;
122611
122836
  }
122612
122837
  registerReadPermission({
@@ -122622,7 +122847,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
122622
122847
  if (argsRecord && "overwrite" in argsRecord) {
122623
122848
  delete argsRecord.overwrite;
122624
122849
  }
122625
- if (!existsSync59(resolvedPath)) {
122850
+ if (!existsSync61(resolvedPath)) {
122626
122851
  return;
122627
122852
  }
122628
122853
  const isBobPath2 = canonicalPath.includes("/.bob/");
@@ -122673,7 +122898,7 @@ function getPathFromArgs(args) {
122673
122898
  return args?.filePath ?? args?.path ?? args?.file_path;
122674
122899
  }
122675
122900
  function resolveInputPath(ctx, inputPath) {
122676
- return normalize2(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
122901
+ return normalize3(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
122677
122902
  }
122678
122903
  function isPathInsideDirectory(pathToCheck, directory) {
122679
122904
  const relativePath = relative8(directory, pathToCheck);
@@ -122681,18 +122906,18 @@ function isPathInsideDirectory(pathToCheck, directory) {
122681
122906
  }
122682
122907
  function toCanonicalPath2(absolutePath) {
122683
122908
  let canonicalPath = absolutePath;
122684
- if (existsSync60(absolutePath)) {
122909
+ if (existsSync62(absolutePath)) {
122685
122910
  try {
122686
122911
  canonicalPath = realpathSync6.native(absolutePath);
122687
122912
  } catch {
122688
122913
  canonicalPath = absolutePath;
122689
122914
  }
122690
122915
  } else {
122691
- const absoluteDir = dirname20(absolutePath);
122692
- const resolvedDir = existsSync60(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
122916
+ const absoluteDir = dirname21(absolutePath);
122917
+ const resolvedDir = existsSync62(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
122693
122918
  canonicalPath = join70(resolvedDir, basename11(absolutePath));
122694
122919
  }
122695
- return normalize2(canonicalPath);
122920
+ return normalize3(canonicalPath);
122696
122921
  }
122697
122922
  function isOverwriteEnabled(value) {
122698
122923
  if (value === true) {
@@ -123966,23 +124191,23 @@ init_logger();
123966
124191
  init_plugin_identity();
123967
124192
 
123968
124193
  // src/hooks/legacy-plugin-toast/auto-migrate.ts
123969
- import { existsSync as existsSync61, readFileSync as readFileSync45 } from "fs";
124194
+ import { existsSync as existsSync63, readFileSync as readFileSync46 } from "fs";
123970
124195
  import { join as join71 } from "path";
123971
124196
  init_plugin_identity();
123972
124197
  function detectOpenCodeConfigPath(overrideConfigDir) {
123973
124198
  if (overrideConfigDir) {
123974
124199
  const jsoncPath = join71(overrideConfigDir, "opencode.jsonc");
123975
124200
  const jsonPath = join71(overrideConfigDir, "opencode.json");
123976
- if (existsSync61(jsoncPath))
124201
+ if (existsSync63(jsoncPath))
123977
124202
  return jsoncPath;
123978
- if (existsSync61(jsonPath))
124203
+ if (existsSync63(jsonPath))
123979
124204
  return jsonPath;
123980
124205
  return null;
123981
124206
  }
123982
124207
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
123983
- if (existsSync61(paths.configJsonc))
124208
+ if (existsSync63(paths.configJsonc))
123984
124209
  return paths.configJsonc;
123985
- if (existsSync61(paths.configJson))
124210
+ if (existsSync63(paths.configJson))
123986
124211
  return paths.configJson;
123987
124212
  return null;
123988
124213
  }
@@ -123991,7 +124216,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
123991
124216
  if (!configPath)
123992
124217
  return { migrated: false, from: null, to: null, configPath: null };
123993
124218
  try {
123994
- const content = readFileSync45(configPath, "utf-8");
124219
+ const content = readFileSync46(configPath, "utf-8");
123995
124220
  const parseResult = parseJsoncSafe(content);
123996
124221
  if (!parseResult.data?.plugin)
123997
124222
  return { migrated: false, from: null, to: null, configPath };
@@ -124109,7 +124334,7 @@ async function queryOllama(args) {
124109
124334
  }
124110
124335
 
124111
124336
  // src/hooks/fast-apply/tool-execute-before-handler.ts
124112
- import { existsSync as existsSync62, readFileSync as readFileSync46 } from "fs";
124337
+ import { existsSync as existsSync64, readFileSync as readFileSync47 } from "fs";
124113
124338
  async function handleFastApplyToolExecuteBefore(args) {
124114
124339
  const { input, output, config: config2 } = args;
124115
124340
  const normalizedTool = input.tool.toLowerCase();
@@ -124128,7 +124353,7 @@ async function handleFastApplyToolExecuteBefore(args) {
124128
124353
  });
124129
124354
  return;
124130
124355
  }
124131
- if (!existsSync62(filePath)) {
124356
+ if (!existsSync64(filePath)) {
124132
124357
  log("[fast-apply] Skipping: file does not exist (new file)", {
124133
124358
  sessionID: input.sessionID,
124134
124359
  callID: input.callID,
@@ -124138,7 +124363,7 @@ async function handleFastApplyToolExecuteBefore(args) {
124138
124363
  }
124139
124364
  let originalContent;
124140
124365
  try {
124141
- originalContent = readFileSync46(filePath, "utf-8");
124366
+ originalContent = readFileSync47(filePath, "utf-8");
124142
124367
  } catch (err) {
124143
124368
  log("[fast-apply] Failed to read file, falling back to default", {
124144
124369
  sessionID: input.sessionID,
@@ -124517,13 +124742,13 @@ var DEFAULT_MAX_SYMBOLS = 200;
124517
124742
  var DEFAULT_MAX_DIAGNOSTICS = 200;
124518
124743
  var DEFAULT_MAX_DIRECTORY_FILES = 50;
124519
124744
  // src/tools/lsp/server-config-loader.ts
124520
- import { existsSync as existsSync63, readFileSync as readFileSync47 } from "fs";
124745
+ import { existsSync as existsSync65, readFileSync as readFileSync48 } from "fs";
124521
124746
  import { join as join72 } from "path";
124522
124747
  function loadJsonFile(path7) {
124523
- if (!existsSync63(path7))
124748
+ if (!existsSync65(path7))
124524
124749
  return null;
124525
124750
  try {
124526
- return parseJsonc(readFileSync47(path7, "utf-8"));
124751
+ return parseJsonc(readFileSync48(path7, "utf-8"));
124527
124752
  } catch {
124528
124753
  return null;
124529
124754
  }
@@ -124603,7 +124828,7 @@ function getMergedServers() {
124603
124828
  }
124604
124829
 
124605
124830
  // src/tools/lsp/server-installation.ts
124606
- import { existsSync as existsSync64 } from "fs";
124831
+ import { existsSync as existsSync66 } from "fs";
124607
124832
  import { delimiter, join as join74 } from "path";
124608
124833
 
124609
124834
  // src/tools/lsp/server-path-bases.ts
@@ -124626,7 +124851,7 @@ function isServerInstalled(command) {
124626
124851
  return false;
124627
124852
  const cmd = command[0];
124628
124853
  if (cmd.includes("/") || cmd.includes("\\")) {
124629
- if (existsSync64(cmd))
124854
+ if (existsSync66(cmd))
124630
124855
  return true;
124631
124856
  }
124632
124857
  const isWindows2 = process.platform === "win32";
@@ -124647,14 +124872,14 @@ function isServerInstalled(command) {
124647
124872
  const paths = pathEnv.split(delimiter);
124648
124873
  for (const p of paths) {
124649
124874
  for (const suffix of exts) {
124650
- if (existsSync64(join74(p, cmd + suffix))) {
124875
+ if (existsSync66(join74(p, cmd + suffix))) {
124651
124876
  return true;
124652
124877
  }
124653
124878
  }
124654
124879
  }
124655
124880
  for (const base of getLspServerAdditionalPathBases(process.cwd())) {
124656
124881
  for (const suffix of exts) {
124657
- if (existsSync64(join74(base, cmd + suffix))) {
124882
+ if (existsSync66(join74(base, cmd + suffix))) {
124658
124883
  return true;
124659
124884
  }
124660
124885
  }
@@ -124712,13 +124937,13 @@ function getLanguageId(ext) {
124712
124937
  init_logger();
124713
124938
  var {spawn: bunSpawn2 } = globalThis.Bun;
124714
124939
  import { spawn as nodeSpawn2 } from "child_process";
124715
- import { existsSync as existsSync65, statSync as statSync7 } from "fs";
124940
+ import { existsSync as existsSync67, statSync as statSync7 } from "fs";
124716
124941
  function shouldUseNodeSpawn() {
124717
124942
  return process.platform === "win32";
124718
124943
  }
124719
124944
  function validateCwd(cwd) {
124720
124945
  try {
124721
- if (!existsSync65(cwd)) {
124946
+ if (!existsSync67(cwd)) {
124722
124947
  return { valid: false, error: `Working directory does not exist: ${cwd}` };
124723
124948
  }
124724
124949
  const stats = statSync7(cwd);
@@ -124850,7 +125075,7 @@ function spawnProcess(command, options) {
124850
125075
  return proc;
124851
125076
  }
124852
125077
  // src/tools/lsp/lsp-client.ts
124853
- import { readFileSync as readFileSync48 } from "fs";
125078
+ import { readFileSync as readFileSync49 } from "fs";
124854
125079
  import { extname as extname4, resolve as resolve15 } from "path";
124855
125080
  import { pathToFileURL as pathToFileURL2 } from "url";
124856
125081
 
@@ -125122,7 +125347,7 @@ class LSPClient extends LSPClientConnection {
125122
125347
  async openFile(filePath) {
125123
125348
  const absPath = resolve15(filePath);
125124
125349
  const uri = pathToFileURL2(absPath).href;
125125
- const text = readFileSync48(absPath, "utf-8");
125350
+ const text = readFileSync49(absPath, "utf-8");
125126
125351
  if (!this.openedFiles.has(absPath)) {
125127
125352
  const ext = extname4(absPath);
125128
125353
  const languageId = getLanguageId(ext);
@@ -125480,10 +125705,10 @@ var lspManager = LSPServerManager.getInstance();
125480
125705
  // src/tools/lsp/lsp-client-wrapper.ts
125481
125706
  import { extname as extname5, resolve as resolve16 } from "path";
125482
125707
  import { fileURLToPath as fileURLToPath2 } from "url";
125483
- import { existsSync as existsSync66, statSync as statSync8 } from "fs";
125708
+ import { existsSync as existsSync68, statSync as statSync8 } from "fs";
125484
125709
  init_plugin_identity();
125485
125710
  function isDirectoryPath(filePath) {
125486
- if (!existsSync66(filePath)) {
125711
+ if (!existsSync68(filePath)) {
125487
125712
  return false;
125488
125713
  }
125489
125714
  return statSync8(filePath).isDirectory();
@@ -125493,14 +125718,14 @@ function uriToPath(uri) {
125493
125718
  }
125494
125719
  function findWorkspaceRoot(filePath) {
125495
125720
  let dir = resolve16(filePath);
125496
- if (!existsSync66(dir) || !isDirectoryPath(dir)) {
125721
+ if (!existsSync68(dir) || !isDirectoryPath(dir)) {
125497
125722
  dir = __require("path").dirname(dir);
125498
125723
  }
125499
125724
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
125500
125725
  let prevDir = "";
125501
125726
  while (dir !== prevDir) {
125502
125727
  for (const marker of markers) {
125503
- if (existsSync66(__require("path").join(dir, marker))) {
125728
+ if (existsSync68(__require("path").join(dir, marker))) {
125504
125729
  return dir;
125505
125730
  }
125506
125731
  }
@@ -125675,10 +125900,10 @@ function formatApplyResult(result) {
125675
125900
  `);
125676
125901
  }
125677
125902
  // src/tools/lsp/workspace-edit.ts
125678
- import { readFileSync as readFileSync49, writeFileSync as writeFileSync17 } from "fs";
125903
+ import { readFileSync as readFileSync50, writeFileSync as writeFileSync17 } from "fs";
125679
125904
  function applyTextEditsToFile(filePath, edits) {
125680
125905
  try {
125681
- let content = readFileSync49(filePath, "utf-8");
125906
+ let content = readFileSync50(filePath, "utf-8");
125682
125907
  const lines = content.split(`
125683
125908
  `);
125684
125909
  const sortedEdits = [...edits].sort((a, b) => {
@@ -125744,7 +125969,7 @@ function applyWorkspaceEdit(edit) {
125744
125969
  try {
125745
125970
  const oldPath = uriToPath(change.oldUri);
125746
125971
  const newPath = uriToPath(change.newUri);
125747
- const content = readFileSync49(oldPath, "utf-8");
125972
+ const content = readFileSync50(oldPath, "utf-8");
125748
125973
  writeFileSync17(newPath, content, "utf-8");
125749
125974
  __require("fs").unlinkSync(oldPath);
125750
125975
  result.filesModified.push(newPath);
@@ -125910,7 +126135,7 @@ init_tool();
125910
126135
  import { resolve as resolve18 } from "path";
125911
126136
 
125912
126137
  // src/tools/lsp/directory-diagnostics.ts
125913
- import { existsSync as existsSync67, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
126138
+ import { existsSync as existsSync69, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
125914
126139
  import { extname as extname6, join as join75, resolve as resolve17 } from "path";
125915
126140
  var SKIP_DIRECTORIES = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
125916
126141
  function collectFilesWithExtension(dir, extension, maxFiles) {
@@ -125956,7 +126181,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
125956
126181
  throw new Error(`Extension must start with a dot (e.g., ".ts", not "${extension}"). ` + `Use ".${extension}" instead.`);
125957
126182
  }
125958
126183
  const absDir = resolve17(directory);
125959
- if (!existsSync67(absDir)) {
126184
+ if (!existsSync69(absDir)) {
125960
126185
  throw new Error(`Directory does not exist: ${absDir}`);
125961
126186
  }
125962
126187
  const serverResult = findServerForExtension(extension);
@@ -126217,11 +126442,11 @@ var DEFAULT_MAX_MATCHES = 500;
126217
126442
 
126218
126443
  // src/tools/ast-grep/sg-cli-path.ts
126219
126444
  import { createRequire as createRequire4 } from "module";
126220
- import { dirname as dirname21, join as join78 } from "path";
126221
- import { existsSync as existsSync69, statSync as statSync9 } from "fs";
126445
+ import { dirname as dirname22, join as join78 } from "path";
126446
+ import { existsSync as existsSync71, statSync as statSync9 } from "fs";
126222
126447
 
126223
126448
  // src/tools/ast-grep/downloader.ts
126224
- import { existsSync as existsSync68 } from "fs";
126449
+ import { existsSync as existsSync70 } from "fs";
126225
126450
  import { join as join77 } from "path";
126226
126451
  import { homedir as homedir14 } from "os";
126227
126452
  import { createRequire as createRequire3 } from "module";
@@ -126273,7 +126498,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
126273
126498
  const cacheDir = getCacheDir3();
126274
126499
  const binaryName = getBinaryName3();
126275
126500
  const binaryPath = join77(cacheDir, binaryName);
126276
- if (existsSync68(binaryPath)) {
126501
+ if (existsSync70(binaryPath)) {
126277
126502
  return binaryPath;
126278
126503
  }
126279
126504
  const { arch, os: os4 } = platformInfo;
@@ -126334,9 +126559,9 @@ function findSgCliPathSync() {
126334
126559
  try {
126335
126560
  const require2 = createRequire4(import.meta.url);
126336
126561
  const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
126337
- const cliDirectory = dirname21(cliPackageJsonPath);
126562
+ const cliDirectory = dirname22(cliPackageJsonPath);
126338
126563
  const sgPath = join78(cliDirectory, binaryName);
126339
- if (existsSync69(sgPath) && isValidBinary(sgPath)) {
126564
+ if (existsSync71(sgPath) && isValidBinary(sgPath)) {
126340
126565
  return sgPath;
126341
126566
  }
126342
126567
  } catch {}
@@ -126345,10 +126570,10 @@ function findSgCliPathSync() {
126345
126570
  try {
126346
126571
  const require2 = createRequire4(import.meta.url);
126347
126572
  const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
126348
- const packageDirectory = dirname21(packageJsonPath);
126573
+ const packageDirectory = dirname22(packageJsonPath);
126349
126574
  const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
126350
126575
  const binaryPath = join78(packageDirectory, astGrepBinaryName);
126351
- if (existsSync69(binaryPath) && isValidBinary(binaryPath)) {
126576
+ if (existsSync71(binaryPath) && isValidBinary(binaryPath)) {
126352
126577
  return binaryPath;
126353
126578
  }
126354
126579
  } catch {}
@@ -126356,7 +126581,7 @@ function findSgCliPathSync() {
126356
126581
  if (process.platform === "darwin") {
126357
126582
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
126358
126583
  for (const path7 of homebrewPaths) {
126359
- if (existsSync69(path7) && isValidBinary(path7)) {
126584
+ if (existsSync71(path7) && isValidBinary(path7)) {
126360
126585
  return path7;
126361
126586
  }
126362
126587
  }
@@ -126380,14 +126605,14 @@ function setSgCliPath(path7) {
126380
126605
  }
126381
126606
  // src/tools/ast-grep/cli.ts
126382
126607
  var {spawn: spawn17 } = globalThis.Bun;
126383
- import { existsSync as existsSync71 } from "fs";
126608
+ import { existsSync as existsSync73 } from "fs";
126384
126609
 
126385
126610
  // src/tools/ast-grep/cli-binary-path-resolution.ts
126386
- import { existsSync as existsSync70 } from "fs";
126611
+ import { existsSync as existsSync72 } from "fs";
126387
126612
  var resolvedCliPath3 = null;
126388
126613
  var initPromise3 = null;
126389
126614
  async function getAstGrepPath() {
126390
- if (resolvedCliPath3 !== null && existsSync70(resolvedCliPath3)) {
126615
+ if (resolvedCliPath3 !== null && existsSync72(resolvedCliPath3)) {
126391
126616
  return resolvedCliPath3;
126392
126617
  }
126393
126618
  if (initPromise3) {
@@ -126395,7 +126620,7 @@ async function getAstGrepPath() {
126395
126620
  }
126396
126621
  initPromise3 = (async () => {
126397
126622
  const syncPath = findSgCliPathSync();
126398
- if (syncPath && existsSync70(syncPath)) {
126623
+ if (syncPath && existsSync72(syncPath)) {
126399
126624
  resolvedCliPath3 = syncPath;
126400
126625
  setSgCliPath(syncPath);
126401
126626
  return syncPath;
@@ -126494,7 +126719,7 @@ async function runSg(options) {
126494
126719
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
126495
126720
  args.push(...paths);
126496
126721
  let cliPath = getSgCliPath();
126497
- if (!cliPath || !existsSync71(cliPath)) {
126722
+ if (!cliPath || !existsSync73(cliPath)) {
126498
126723
  const downloadedPath = await getAstGrepPath();
126499
126724
  if (downloadedPath) {
126500
126725
  cliPath = downloadedPath;
@@ -126749,12 +126974,12 @@ import { resolve as resolve19 } from "path";
126749
126974
  var {spawn: spawn18 } = globalThis.Bun;
126750
126975
 
126751
126976
  // src/tools/grep/constants.ts
126752
- import { existsSync as existsSync73 } from "fs";
126753
- import { join as join80, dirname as dirname22 } from "path";
126977
+ import { existsSync as existsSync75 } from "fs";
126978
+ import { join as join80, dirname as dirname23 } from "path";
126754
126979
  import { spawnSync as spawnSync4 } from "child_process";
126755
126980
 
126756
126981
  // src/tools/grep/downloader.ts
126757
- import { existsSync as existsSync72, readdirSync as readdirSync21 } from "fs";
126982
+ import { existsSync as existsSync74, readdirSync as readdirSync21 } from "fs";
126758
126983
  import { join as join79 } from "path";
126759
126984
  init_plugin_identity();
126760
126985
  function findFileRecursive(dir, filename) {
@@ -126819,7 +127044,7 @@ async function downloadAndInstallRipgrep() {
126819
127044
  }
126820
127045
  const installDir = getInstallDir();
126821
127046
  const rgPath = getRgPath();
126822
- if (existsSync72(rgPath)) {
127047
+ if (existsSync74(rgPath)) {
126823
127048
  return rgPath;
126824
127049
  }
126825
127050
  ensureCacheDir(installDir);
@@ -126834,7 +127059,7 @@ async function downloadAndInstallRipgrep() {
126834
127059
  await extractZip2(archivePath, installDir);
126835
127060
  }
126836
127061
  ensureExecutable(rgPath);
126837
- if (!existsSync72(rgPath)) {
127062
+ if (!existsSync74(rgPath)) {
126838
127063
  throw new Error("ripgrep binary not found after extraction");
126839
127064
  }
126840
127065
  return rgPath;
@@ -126846,7 +127071,7 @@ async function downloadAndInstallRipgrep() {
126846
127071
  }
126847
127072
  function getInstalledRipgrepPath() {
126848
127073
  const rgPath = getRgPath();
126849
- return existsSync72(rgPath) ? rgPath : null;
127074
+ return existsSync74(rgPath) ? rgPath : null;
126850
127075
  }
126851
127076
 
126852
127077
  // src/tools/grep/constants.ts
@@ -126868,7 +127093,7 @@ function findExecutable(name) {
126868
127093
  }
126869
127094
  function getOpenCodeBundledRg() {
126870
127095
  const execPath = process.execPath;
126871
- const execDir = dirname22(execPath);
127096
+ const execDir = dirname23(execPath);
126872
127097
  const isWindows2 = process.platform === "win32";
126873
127098
  const rgName = isWindows2 ? "rg.exe" : "rg";
126874
127099
  const candidates = [
@@ -126879,7 +127104,7 @@ function getOpenCodeBundledRg() {
126879
127104
  join80(execDir, "..", "libexec", rgName)
126880
127105
  ];
126881
127106
  for (const candidate of candidates) {
126882
- if (existsSync73(candidate)) {
127107
+ if (existsSync75(candidate)) {
126883
127108
  return candidate;
126884
127109
  }
126885
127110
  }
@@ -127531,10 +127756,10 @@ Use this when a task matches an available skill's or command's description.
127531
127756
  `;
127532
127757
  // src/tools/skill/tools.ts
127533
127758
  init_dist();
127534
- import { dirname as dirname24 } from "path";
127759
+ import { dirname as dirname25 } from "path";
127535
127760
 
127536
127761
  // src/tools/slashcommand/command-output-formatter.ts
127537
- import { dirname as dirname23 } from "path";
127762
+ import { dirname as dirname24 } from "path";
127538
127763
  async function formatLoadedCommand(command, userMessage) {
127539
127764
  const sections = [];
127540
127765
  sections.push(`# /${command.name} Command
@@ -127573,7 +127798,7 @@ async function formatLoadedCommand(command, userMessage) {
127573
127798
  if (!content && command.lazyContentLoader) {
127574
127799
  content = await command.lazyContentLoader.load();
127575
127800
  }
127576
- const commandDir = command.path ? dirname23(command.path) : process.cwd();
127801
+ const commandDir = command.path ? dirname24(command.path) : process.cwd();
127577
127802
  const withFileReferences = await resolveFileReferencesInText(content, commandDir);
127578
127803
  const resolvedContent = await resolveCommandsInText(withFileReferences);
127579
127804
  let finalContent = resolvedContent.trim();
@@ -127963,7 +128188,7 @@ function createSkillTool(options = {}) {
127963
128188
  if (matchedSkill.name === "git-master") {
127964
128189
  body = injectGitMasterConfig(body, options.gitMasterConfig);
127965
128190
  }
127966
- const dir = matchedSkill.path ? dirname24(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
128191
+ const dir = matchedSkill.path ? dirname25(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
127967
128192
  const output = [
127968
128193
  `## Skill: ${matchedSkill.name}`,
127969
128194
  "",
@@ -128081,11 +128306,11 @@ Has Todos: Yes (12 items, 8 completed)
128081
128306
  Has Transcript: Yes (234 entries)`;
128082
128307
 
128083
128308
  // src/tools/session-manager/file-storage.ts
128084
- import { existsSync as existsSync74 } from "fs";
128309
+ import { existsSync as existsSync76 } from "fs";
128085
128310
  import { readdir, readFile } from "fs/promises";
128086
128311
  import { join as join82 } from "path";
128087
128312
  async function getFileMainSessions(directory) {
128088
- if (!existsSync74(SESSION_STORAGE))
128313
+ if (!existsSync76(SESSION_STORAGE))
128089
128314
  return [];
128090
128315
  const sessions = [];
128091
128316
  try {
@@ -128117,7 +128342,7 @@ async function getFileMainSessions(directory) {
128117
128342
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
128118
128343
  }
128119
128344
  async function getFileAllSessions() {
128120
- if (!existsSync74(MESSAGE_STORAGE))
128345
+ if (!existsSync76(MESSAGE_STORAGE))
128121
128346
  return [];
128122
128347
  const sessions = [];
128123
128348
  async function scanDirectory(dir) {
@@ -128146,7 +128371,7 @@ async function fileSessionExists(sessionID) {
128146
128371
  }
128147
128372
  async function getFileSessionMessages(sessionID) {
128148
128373
  const messageDir = getMessageDir(sessionID);
128149
- if (!messageDir || !existsSync74(messageDir))
128374
+ if (!messageDir || !existsSync76(messageDir))
128150
128375
  return [];
128151
128376
  const messages = [];
128152
128377
  try {
@@ -128182,7 +128407,7 @@ async function getFileSessionMessages(sessionID) {
128182
128407
  }
128183
128408
  async function readParts2(messageID) {
128184
128409
  const partDir = join82(PART_STORAGE, messageID);
128185
- if (!existsSync74(partDir))
128410
+ if (!existsSync76(partDir))
128186
128411
  return [];
128187
128412
  const parts = [];
128188
128413
  try {
@@ -128203,7 +128428,7 @@ async function readParts2(messageID) {
128203
128428
  return parts.sort((a, b) => a.id.localeCompare(b.id));
128204
128429
  }
128205
128430
  async function getFileSessionTodos(sessionID) {
128206
- if (!existsSync74(TODO_DIR2))
128431
+ if (!existsSync76(TODO_DIR2))
128207
128432
  return [];
128208
128433
  try {
128209
128434
  const allFiles = await readdir(TODO_DIR2);
@@ -128230,10 +128455,10 @@ async function getFileSessionTodos(sessionID) {
128230
128455
  return [];
128231
128456
  }
128232
128457
  async function getFileSessionTranscript(sessionID) {
128233
- if (!existsSync74(TRANSCRIPT_DIR2))
128458
+ if (!existsSync76(TRANSCRIPT_DIR2))
128234
128459
  return 0;
128235
128460
  const transcriptFile = join82(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
128236
- if (!existsSync74(transcriptFile))
128461
+ if (!existsSync76(transcriptFile))
128237
128462
  return 0;
128238
128463
  try {
128239
128464
  const content = await readFile(transcriptFile, "utf-8");
@@ -128998,6 +129223,26 @@ function findMcpServer(mcpName, skills) {
128998
129223
  }
128999
129224
  return null;
129000
129225
  }
129226
+ function convertBuiltinMcpConfig(config4) {
129227
+ if (config4.enabled === false)
129228
+ return null;
129229
+ if (config4.type === "remote") {
129230
+ return {
129231
+ type: "http",
129232
+ url: config4.url,
129233
+ headers: config4.headers
129234
+ };
129235
+ }
129236
+ const [command, ...args] = config4.command ?? [];
129237
+ if (!command)
129238
+ return null;
129239
+ return {
129240
+ type: "stdio",
129241
+ command,
129242
+ args,
129243
+ env: config4.environment
129244
+ };
129245
+ }
129001
129246
  function formatAvailableMcps(skills) {
129002
129247
  const mcps = [];
129003
129248
  for (const skill2 of skills) {
@@ -129010,6 +129255,11 @@ function formatAvailableMcps(skills) {
129010
129255
  return mcps.length > 0 ? mcps.join(`
129011
129256
  `) : " (none found)";
129012
129257
  }
129258
+ function formatAvailableBuiltinMcps(builtinMcp) {
129259
+ const names = Object.entries(builtinMcp ?? {}).filter(([, config4]) => config4.enabled !== false).map(([name]) => ` - "${name}" from hiai-opencode config`);
129260
+ return names.length > 0 ? names.join(`
129261
+ `) : " (none found)";
129262
+ }
129013
129263
  function formatBuiltinMcpHint(mcpName) {
129014
129264
  const nativeTools = BUILTIN_MCP_TOOL_HINTS[mcpName];
129015
129265
  if (!nativeTools)
@@ -129055,7 +129305,7 @@ function applyGrepFilter(output, pattern) {
129055
129305
  }
129056
129306
  }
129057
129307
  function createSkillMcpTool(options) {
129058
- const { manager, getLoadedSkills, getSessionID } = options;
129308
+ const { manager, getLoadedSkills, getSessionID, builtinMcp } = options;
129059
129309
  return tool({
129060
129310
  description: SKILL_MCP_DESCRIPTION,
129061
129311
  args: {
@@ -129070,7 +129320,9 @@ function createSkillMcpTool(options) {
129070
129320
  const operation = validateOperationParams(args);
129071
129321
  const skills = getLoadedSkills();
129072
129322
  const found = findMcpServer(args.mcp_name, skills);
129073
- if (!found) {
129323
+ const builtinConfig = builtinMcp?.[args.mcp_name];
129324
+ const convertedBuiltinConfig = builtinConfig ? convertBuiltinMcpConfig(builtinConfig) : null;
129325
+ if (!found && !convertedBuiltinConfig) {
129074
129326
  const builtinHint = formatBuiltinMcpHint(args.mcp_name);
129075
129327
  if (builtinHint) {
129076
129328
  throw new Error(builtinHint);
@@ -129080,7 +129332,10 @@ function createSkillMcpTool(options) {
129080
129332
  ` + `Available MCP servers in loaded skills:
129081
129333
  ` + formatAvailableMcps(skills) + `
129082
129334
 
129083
- ` + `Hint: Load the skill first using the 'skill' tool, then call skill_mcp.`);
129335
+ ` + `Available MCP servers in hiai-opencode config:
129336
+ ` + formatAvailableBuiltinMcps(builtinMcp) + `
129337
+
129338
+ ` + `Hint: Load the skill first for skill-embedded MCPs. Builtin hiai-opencode MCPs can be called directly when enabled in hiai-opencode.json.`);
129084
129339
  }
129085
129340
  const sessionID = toolContext.sessionID || getSessionID?.();
129086
129341
  if (!sessionID) {
@@ -129088,13 +129343,13 @@ function createSkillMcpTool(options) {
129088
129343
  }
129089
129344
  const info = {
129090
129345
  serverName: args.mcp_name,
129091
- skillName: found.skill.name,
129346
+ skillName: found?.skill.name ?? "hiai-opencode",
129092
129347
  sessionID,
129093
- scope: found.skill.scope
129348
+ scope: found?.skill.scope ?? "user"
129094
129349
  };
129095
129350
  const context = {
129096
- config: found.config,
129097
- skillName: found.skill.name
129351
+ config: found?.config ?? convertedBuiltinConfig,
129352
+ skillName: found?.skill.name ?? "hiai-opencode"
129098
129353
  };
129099
129354
  const parsedArgs = parseArguments(args.arguments);
129100
129355
  let output;
@@ -130613,9 +130868,9 @@ async function resolveMultimodalLookerAgentMetadata(ctx) {
130613
130868
 
130614
130869
  // src/tools/look-at/image-converter.ts
130615
130870
  import * as childProcess from "child_process";
130616
- import { existsSync as existsSync75, mkdtempSync, readFileSync as readFileSync50, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
130871
+ import { existsSync as existsSync77, mkdtempSync, readFileSync as readFileSync51, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
130617
130872
  import { tmpdir as tmpdir7 } from "os";
130618
- import { dirname as dirname25, join as join83 } from "path";
130873
+ import { dirname as dirname26, join as join83 } from "path";
130619
130874
  var SUPPORTED_FORMATS = new Set([
130620
130875
  "image/jpeg",
130621
130876
  "image/png",
@@ -130653,7 +130908,7 @@ function needsConversion(mimeType) {
130653
130908
  return mimeType.startsWith("image/");
130654
130909
  }
130655
130910
  function convertImageToJpeg(inputPath, mimeType) {
130656
- if (!existsSync75(inputPath)) {
130911
+ if (!existsSync77(inputPath)) {
130657
130912
  throw new Error(`File not found: ${inputPath}`);
130658
130913
  }
130659
130914
  const tempDir = mkdtempSync(join83(tmpdir7(), "opencode-img-"));
@@ -130667,7 +130922,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130667
130922
  encoding: "utf-8",
130668
130923
  timeout: CONVERSION_TIMEOUT_MS
130669
130924
  });
130670
- if (existsSync75(outputPath)) {
130925
+ if (existsSync77(outputPath)) {
130671
130926
  log(`[image-converter] Converted using sips: ${outputPath}`);
130672
130927
  return outputPath;
130673
130928
  }
@@ -130682,7 +130937,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130682
130937
  encoding: "utf-8",
130683
130938
  timeout: CONVERSION_TIMEOUT_MS
130684
130939
  });
130685
- if (existsSync75(outputPath)) {
130940
+ if (existsSync77(outputPath)) {
130686
130941
  log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
130687
130942
  return outputPath;
130688
130943
  }
@@ -130695,7 +130950,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130695
130950
  ` + ` RHEL/CentOS: sudo yum install ImageMagick`);
130696
130951
  } catch (error92) {
130697
130952
  try {
130698
- if (existsSync75(outputPath)) {
130953
+ if (existsSync77(outputPath)) {
130699
130954
  unlinkSync10(outputPath);
130700
130955
  }
130701
130956
  } catch {}
@@ -130708,12 +130963,12 @@ function convertImageToJpeg(inputPath, mimeType) {
130708
130963
  }
130709
130964
  function cleanupConvertedImage(filePath) {
130710
130965
  try {
130711
- const tempDirectory = dirname25(filePath);
130712
- if (existsSync75(filePath)) {
130966
+ const tempDirectory = dirname26(filePath);
130967
+ if (existsSync77(filePath)) {
130713
130968
  unlinkSync10(filePath);
130714
130969
  log(`[image-converter] Cleaned up temporary file: ${filePath}`);
130715
130970
  }
130716
- if (existsSync75(tempDirectory)) {
130971
+ if (existsSync77(tempDirectory)) {
130717
130972
  rmSync3(tempDirectory, { recursive: true, force: true });
130718
130973
  log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
130719
130974
  }
@@ -130733,14 +130988,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
130733
130988
  log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
130734
130989
  const outputPath = convertImageToJpeg(inputPath, mimeType);
130735
130990
  tempFiles.push(outputPath);
130736
- const convertedBuffer = readFileSync50(outputPath);
130991
+ const convertedBuffer = readFileSync51(outputPath);
130737
130992
  const convertedBase64 = convertedBuffer.toString("base64");
130738
130993
  log(`[image-converter] Base64 conversion successful`);
130739
130994
  return { base64: convertedBase64, tempFiles };
130740
130995
  } catch (error92) {
130741
130996
  tempFiles.forEach((file3) => {
130742
130997
  try {
130743
- if (existsSync75(file3))
130998
+ if (existsSync77(file3))
130744
130999
  unlinkSync10(file3);
130745
131000
  } catch {}
130746
131001
  });
@@ -132921,22 +133176,22 @@ function applyFallbackEntrySettings(input) {
132921
133176
  // src/tools/delegate-task/subagent-discovery.ts
132922
133177
  init_agent_display_names();
132923
133178
  // src/features/claude-code-agent-loader/loader.ts
132924
- import { existsSync as existsSync78, readdirSync as readdirSync22 } from "fs";
133179
+ import { existsSync as existsSync80, readdirSync as readdirSync22 } from "fs";
132925
133180
  import { join as join84 } from "path";
132926
133181
 
132927
133182
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
132928
- import { existsSync as existsSync77, readFileSync as readFileSync52 } from "fs";
133183
+ import { existsSync as existsSync79, readFileSync as readFileSync53 } from "fs";
132929
133184
  import { basename as basename13, extname as extname8 } from "path";
132930
133185
  init_logger();
132931
133186
 
132932
133187
  // src/features/claude-code-agent-loader/json-agent-loader.ts
132933
- import { existsSync as existsSync76, readFileSync as readFileSync51 } from "fs";
133188
+ import { existsSync as existsSync78, readFileSync as readFileSync52 } from "fs";
132934
133189
  function parseJsonAgentFile(filePath, scope) {
132935
133190
  try {
132936
- if (!existsSync76(filePath)) {
133191
+ if (!existsSync78(filePath)) {
132937
133192
  return null;
132938
133193
  }
132939
- const content = readFileSync51(filePath, "utf-8");
133194
+ const content = readFileSync52(filePath, "utf-8");
132940
133195
  const { data } = parseJsoncSafe(content);
132941
133196
  if (!data) {
132942
133197
  return null;
@@ -132972,10 +133227,10 @@ function parseJsonAgentFile(filePath, scope) {
132972
133227
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
132973
133228
  function parseMarkdownAgentFile(filePath, scope) {
132974
133229
  try {
132975
- if (!existsSync77(filePath)) {
133230
+ if (!existsSync79(filePath)) {
132976
133231
  return null;
132977
133232
  }
132978
- const content = readFileSync52(filePath, "utf-8");
133233
+ const content = readFileSync53(filePath, "utf-8");
132979
133234
  const { data, body } = parseFrontmatter(content);
132980
133235
  const fileName = basename13(filePath);
132981
133236
  const agentName = fileName.replace(/\.md$/i, "");
@@ -133007,7 +133262,7 @@ function parseMarkdownAgentFile(filePath, scope) {
133007
133262
  function loadAgentDefinitions(paths, scope) {
133008
133263
  const result = Object.create(null);
133009
133264
  for (const filePath of paths) {
133010
- if (!existsSync77(filePath)) {
133265
+ if (!existsSync79(filePath)) {
133011
133266
  log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
133012
133267
  continue;
133013
133268
  }
@@ -133032,7 +133287,7 @@ function loadAgentDefinitions(paths, scope) {
133032
133287
 
133033
133288
  // src/features/claude-code-agent-loader/loader.ts
133034
133289
  function loadAgentsFromDir(agentsDir, scope) {
133035
- if (!existsSync78(agentsDir)) {
133290
+ if (!existsSync80(agentsDir)) {
133036
133291
  return [];
133037
133292
  }
133038
133293
  const entries = readdirSync22(agentsDir, { withFileTypes: true });
@@ -133674,8 +133929,8 @@ var TaskDeleteInputSchema = exports_external.object({
133674
133929
  });
133675
133930
 
133676
133931
  // src/features/claude-tasks/storage.ts
133677
- import { join as join86, dirname as dirname27, basename as basename14, isAbsolute as isAbsolute12 } from "path";
133678
- import { existsSync as existsSync80, mkdirSync as mkdirSync16, readFileSync as readFileSync54, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
133932
+ import { join as join86, dirname as dirname28, basename as basename14, isAbsolute as isAbsolute12 } from "path";
133933
+ import { existsSync as existsSync82, mkdirSync as mkdirSync16, readFileSync as readFileSync55, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
133679
133934
  import { randomUUID as randomUUID2 } from "crypto";
133680
133935
  function getTaskDir(config4 = {}) {
133681
133936
  const tasksConfig = config4.bob?.tasks;
@@ -133703,16 +133958,16 @@ function resolveTaskListId(config4 = {}) {
133703
133958
  return sanitizePathSegment(basename14(process.cwd()));
133704
133959
  }
133705
133960
  function ensureDir(dirPath) {
133706
- if (!existsSync80(dirPath)) {
133961
+ if (!existsSync82(dirPath)) {
133707
133962
  mkdirSync16(dirPath, { recursive: true });
133708
133963
  }
133709
133964
  }
133710
133965
  function readJsonSafe(filePath, schema2) {
133711
133966
  try {
133712
- if (!existsSync80(filePath)) {
133967
+ if (!existsSync82(filePath)) {
133713
133968
  return null;
133714
133969
  }
133715
- const content = readFileSync54(filePath, "utf-8");
133970
+ const content = readFileSync55(filePath, "utf-8");
133716
133971
  const parsed = JSON.parse(content);
133717
133972
  const result = schema2.safeParse(parsed);
133718
133973
  if (!result.success) {
@@ -133724,7 +133979,7 @@ function readJsonSafe(filePath, schema2) {
133724
133979
  }
133725
133980
  }
133726
133981
  function writeJsonAtomic(filePath, data) {
133727
- const dir = dirname27(filePath);
133982
+ const dir = dirname28(filePath);
133728
133983
  ensureDir(dir);
133729
133984
  const tempPath = `${filePath}.tmp.${Date.now()}`;
133730
133985
  try {
@@ -133732,7 +133987,7 @@ function writeJsonAtomic(filePath, data) {
133732
133987
  renameSync4(tempPath, filePath);
133733
133988
  } catch (error92) {
133734
133989
  try {
133735
- if (existsSync80(tempPath)) {
133990
+ if (existsSync82(tempPath)) {
133736
133991
  unlinkSync11(tempPath);
133737
133992
  }
133738
133993
  } catch {}
@@ -133754,7 +134009,7 @@ function acquireLock(dirPath) {
133754
134009
  };
133755
134010
  const isStale = () => {
133756
134011
  try {
133757
- const lockContent = readFileSync54(lockPath, "utf-8");
134012
+ const lockContent = readFileSync55(lockPath, "utf-8");
133758
134013
  const lockData = JSON.parse(lockContent);
133759
134014
  const lockAge = Date.now() - lockData.timestamp;
133760
134015
  return lockAge > STALE_LOCK_THRESHOLD_MS;
@@ -133792,9 +134047,9 @@ function acquireLock(dirPath) {
133792
134047
  acquired: true,
133793
134048
  release: () => {
133794
134049
  try {
133795
- if (!existsSync80(lockPath))
134050
+ if (!existsSync82(lockPath))
133796
134051
  return;
133797
- const lockContent = readFileSync54(lockPath, "utf-8");
134052
+ const lockContent = readFileSync55(lockPath, "utf-8");
133798
134053
  const lockData = JSON.parse(lockContent);
133799
134054
  if (lockData.id !== lockId)
133800
134055
  return;
@@ -134020,7 +134275,7 @@ Returns null if the task does not exist or the file is invalid.`,
134020
134275
  // src/tools/task/task-list.ts
134021
134276
  init_tool();
134022
134277
  import { join as join89 } from "path";
134023
- import { existsSync as existsSync81, readdirSync as readdirSync24 } from "fs";
134278
+ import { existsSync as existsSync83, readdirSync as readdirSync24 } from "fs";
134024
134279
  function createTaskList(config4) {
134025
134280
  return tool({
134026
134281
  description: `List all active tasks with summary information.
@@ -134031,7 +134286,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
134031
134286
  args: {},
134032
134287
  execute: async () => {
134033
134288
  const taskDir = getTaskDir(config4);
134034
- if (!existsSync81(taskDir)) {
134289
+ if (!existsSync83(taskDir)) {
134035
134290
  return JSON.stringify({ tasks: [] });
134036
134291
  }
134037
134292
  const files = readdirSync24(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
@@ -136334,7 +136589,7 @@ function createToolGuardHooks(args) {
136334
136589
  const readImageResizer = isHookEnabled("read-image-resizer") ? safeHook("read-image-resizer", () => createReadImageResizerHook(ctx)) : null;
136335
136590
  const todoDescriptionOverride = isHookEnabled("todo-description-override") ? safeHook("todo-description-override", () => createTodoDescriptionOverrideHook()) : null;
136336
136591
  const webfetchRedirectGuard = isHookEnabled("webfetch-redirect-guard") ? safeHook("webfetch-redirect-guard", () => createWebFetchRedirectGuardHook(ctx)) : null;
136337
- const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "http://localhost:11434", model: "qwen3.5:9b", timeout: 30000 })) : null;
136592
+ const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "", model: "", timeout: 30000 })) : null;
136338
136593
  return {
136339
136594
  commentChecker,
136340
136595
  toolOutputTruncator,
@@ -137247,7 +137502,7 @@ function unregisterManagerForCleanup(manager) {
137247
137502
  }
137248
137503
 
137249
137504
  // src/features/background-agent/compaction-aware-message-resolver.ts
137250
- import { readdirSync as readdirSync25, readFileSync as readFileSync55 } from "fs";
137505
+ import { readdirSync as readdirSync25, readFileSync as readFileSync56 } from "fs";
137251
137506
  import { join as join92 } from "path";
137252
137507
  function hasFullAgentAndModel(message) {
137253
137508
  return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
@@ -137327,7 +137582,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
137327
137582
  const messages = [];
137328
137583
  for (const file3 of files) {
137329
137584
  try {
137330
- const content = readFileSync55(join92(messageDir, file3), "utf-8");
137585
+ const content = readFileSync56(join92(messageDir, file3), "utf-8");
137331
137586
  const parsed = JSON.parse(content);
137332
137587
  if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
137333
137588
  continue;
@@ -139424,8 +139679,8 @@ ${originalText}`;
139424
139679
  }
139425
139680
  }
139426
139681
  // src/features/mcp-oauth/storage.ts
139427
- import { chmodSync as chmodSync2, existsSync as existsSync82, mkdirSync as mkdirSync17, readFileSync as readFileSync56, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
139428
- import { dirname as dirname28, join as join94 } from "path";
139682
+ import { chmodSync as chmodSync2, existsSync as existsSync84, mkdirSync as mkdirSync17, readFileSync as readFileSync57, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
139683
+ import { dirname as dirname29, join as join94 } from "path";
139429
139684
  var STORAGE_FILE_NAME = "mcp-oauth.json";
139430
139685
  function getMcpOauthStoragePath() {
139431
139686
  return join94(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
@@ -139465,11 +139720,11 @@ function buildKey(serverHost, resource) {
139465
139720
  }
139466
139721
  function readStore() {
139467
139722
  const filePath = getMcpOauthStoragePath();
139468
- if (!existsSync82(filePath)) {
139723
+ if (!existsSync84(filePath)) {
139469
139724
  return null;
139470
139725
  }
139471
139726
  try {
139472
- const content = readFileSync56(filePath, "utf-8");
139727
+ const content = readFileSync57(filePath, "utf-8");
139473
139728
  return JSON.parse(content);
139474
139729
  } catch {
139475
139730
  return null;
@@ -139478,8 +139733,8 @@ function readStore() {
139478
139733
  function writeStore(store2) {
139479
139734
  const filePath = getMcpOauthStoragePath();
139480
139735
  try {
139481
- const dir = dirname28(filePath);
139482
- if (!existsSync82(dir)) {
139736
+ const dir = dirname29(filePath);
139737
+ if (!existsSync84(dir)) {
139483
139738
  mkdirSync17(dir, { recursive: true });
139484
139739
  }
139485
139740
  const tempPath = `${filePath}.tmp.${Date.now()}`;
@@ -146126,7 +146381,7 @@ class TmuxSessionManager {
146126
146381
  var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
146127
146382
  var MIN_STABILITY_TIME_MS4 = 10 * 1000;
146128
146383
  // src/features/claude-code-mcp-loader/loader.ts
146129
- import { existsSync as existsSync83, readFileSync as readFileSync57 } from "fs";
146384
+ import { existsSync as existsSync85, readFileSync as readFileSync58 } from "fs";
146130
146385
  import { join as join95 } from "path";
146131
146386
  import { homedir as homedir15 } from "os";
146132
146387
  init_logger();
@@ -146149,7 +146404,7 @@ function getMcpConfigPaths() {
146149
146404
  });
146150
146405
  }
146151
146406
  async function loadMcpConfigFile(filePath) {
146152
- if (!existsSync83(filePath)) {
146407
+ if (!existsSync85(filePath)) {
146153
146408
  return null;
146154
146409
  }
146155
146410
  try {
@@ -146165,10 +146420,10 @@ function getSystemMcpServerNames() {
146165
146420
  const paths = getMcpConfigPaths();
146166
146421
  const cwd = process.cwd();
146167
146422
  for (const { path: path9 } of paths) {
146168
- if (!existsSync83(path9))
146423
+ if (!existsSync85(path9))
146169
146424
  continue;
146170
146425
  try {
146171
- const content = readFileSync57(path9, "utf-8");
146426
+ const content = readFileSync58(path9, "utf-8");
146172
146427
  const config4 = JSON.parse(content);
146173
146428
  if (!config4?.mcpServers)
146174
146429
  continue;
@@ -150513,7 +150768,7 @@ var researcherPromptMetadata = {
150513
150768
  };
150514
150769
 
150515
150770
  // src/agents/builtin-agents/resolve-file-uri.ts
150516
- import { existsSync as existsSync84, readFileSync as readFileSync58 } from "fs";
150771
+ import { existsSync as existsSync86, readFileSync as readFileSync59 } from "fs";
150517
150772
  import { homedir as homedir16 } from "os";
150518
150773
  import { isAbsolute as isAbsolute13, resolve as resolve22 } from "path";
150519
150774
  init_logger();
@@ -150538,11 +150793,11 @@ function resolvePromptAppend(promptAppend, configDir) {
150538
150793
  });
150539
150794
  return `[WARNING: Path rejected: ${promptAppend}]`;
150540
150795
  }
150541
- if (!existsSync84(filePath)) {
150796
+ if (!existsSync86(filePath)) {
150542
150797
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
150543
150798
  }
150544
150799
  try {
150545
- return readFileSync58(filePath, "utf8");
150800
+ return readFileSync59(filePath, "utf8");
150546
150801
  } catch {
150547
150802
  return `[WARNING: Could not read file: ${promptAppend}]`;
150548
150803
  }
@@ -154176,6 +154431,28 @@ async function buildStrategistAgentConfig(params) {
154176
154431
  return merged;
154177
154432
  }
154178
154433
 
154434
+ // src/plugin/skill-discovery-config.ts
154435
+ var DEFAULT_SKILL_DISCOVERY = {
154436
+ config_sources: true,
154437
+ project_opencode: true,
154438
+ global_opencode: false,
154439
+ project_claude: false,
154440
+ global_claude: false,
154441
+ project_agents: false,
154442
+ global_agents: false
154443
+ };
154444
+ function resolveSkillDiscoveryConfig(pluginConfig) {
154445
+ const resolved = {
154446
+ ...DEFAULT_SKILL_DISCOVERY,
154447
+ ...pluginConfig.skill_discovery ?? {}
154448
+ };
154449
+ if (pluginConfig.claude_code?.skills === false) {
154450
+ resolved.project_claude = false;
154451
+ resolved.global_claude = false;
154452
+ }
154453
+ return resolved;
154454
+ }
154455
+
154179
154456
  // src/plugin-handlers/agent-config-handler.ts
154180
154457
  var CANONICAL_VISIBLE_AGENT_NAMES = [
154181
154458
  "Bob",
@@ -154238,8 +154515,9 @@ async function applyAgentConfig(params) {
154238
154515
  const migratedDisabledAgents = (params.pluginConfig.disabled_agents ?? []).map((agent) => {
154239
154516
  return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
154240
154517
  });
154241
- const includeClaudeSkillsForAwareness = params.pluginConfig.claude_code?.skills ?? true;
154518
+ const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
154242
154519
  const [
154520
+ discoveredManagedPluginSkills,
154243
154521
  discoveredConfigSourceSkills,
154244
154522
  discoveredUserSkills,
154245
154523
  discoveredProjectSkills,
@@ -154248,18 +154526,20 @@ async function applyAgentConfig(params) {
154248
154526
  discoveredOpencodeProjectSkills,
154249
154527
  discoveredGlobalAgentsSkills
154250
154528
  ] = await Promise.all([
154251
- discoverConfigSourceSkills({
154529
+ discoverManagedPluginSkills(),
154530
+ discovery2.config_sources ? discoverConfigSourceSkills({
154252
154531
  config: params.pluginConfig.skills,
154253
154532
  configDir: params.ctx.directory
154254
- }),
154255
- includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]),
154256
- includeClaudeSkillsForAwareness ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]),
154257
- includeClaudeSkillsForAwareness ? discoverProjectAgentsSkills(params.ctx.directory) : Promise.resolve([]),
154258
- discoverOpencodeGlobalSkills(),
154259
- discoverOpencodeProjectSkills(params.ctx.directory),
154260
- includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([])
154533
+ }) : Promise.resolve([]),
154534
+ discovery2.global_claude ? discoverUserClaudeSkills() : Promise.resolve([]),
154535
+ discovery2.project_claude ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]),
154536
+ discovery2.project_agents ? discoverProjectAgentsSkills(params.ctx.directory) : Promise.resolve([]),
154537
+ discovery2.global_opencode ? discoverOpencodeGlobalSkills() : Promise.resolve([]),
154538
+ discovery2.project_opencode ? discoverOpencodeProjectSkills(params.ctx.directory) : Promise.resolve([]),
154539
+ discovery2.global_agents ? discoverGlobalAgentsSkills() : Promise.resolve([])
154261
154540
  ]);
154262
154541
  const allDiscoveredSkills = [
154542
+ ...discoveredManagedPluginSkills,
154263
154543
  ...discoveredConfigSourceSkills,
154264
154544
  ...discoveredOpencodeProjectSkills,
154265
154545
  ...discoveredProjectSkills,
@@ -154592,9 +154872,9 @@ async function applyCommandConfig(params) {
154592
154872
  });
154593
154873
  const systemCommands = params.config.command ?? {};
154594
154874
  const includeClaudeCommands = params.pluginConfig.claude_code?.commands ?? true;
154595
- const includeClaudeSkills = params.pluginConfig.claude_code?.skills ?? true;
154875
+ const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
154596
154876
  const externalSkillPlugin = detectExternalSkillPlugin(params.ctx.directory);
154597
- if (includeClaudeSkills && externalSkillPlugin.detected) {
154877
+ if ((discovery2.project_claude || discovery2.global_claude || discovery2.global_opencode) && externalSkillPlugin.detected) {
154598
154878
  log(getSkillPluginConflictWarning(externalSkillPlugin.pluginName));
154599
154879
  }
154600
154880
  const [
@@ -154603,6 +154883,7 @@ async function applyCommandConfig(params) {
154603
154883
  projectCommands,
154604
154884
  opencodeGlobalCommands,
154605
154885
  opencodeProjectCommands,
154886
+ managedPluginSkills,
154606
154887
  userSkills,
154607
154888
  globalAgentsSkills,
154608
154889
  projectSkills,
@@ -154610,23 +154891,25 @@ async function applyCommandConfig(params) {
154610
154891
  opencodeGlobalSkills,
154611
154892
  opencodeProjectSkills
154612
154893
  ] = await Promise.all([
154613
- discoverConfigSourceSkills({
154894
+ discovery2.config_sources ? discoverConfigSourceSkills({
154614
154895
  config: params.pluginConfig.skills,
154615
154896
  configDir: params.ctx.directory
154616
- }),
154897
+ }) : Promise.resolve([]),
154617
154898
  includeClaudeCommands ? loadUserCommands() : Promise.resolve({}),
154618
154899
  includeClaudeCommands ? loadProjectCommands(params.ctx.directory) : Promise.resolve({}),
154619
154900
  loadOpencodeGlobalCommands(),
154620
154901
  loadOpencodeProjectCommands(params.ctx.directory),
154621
- includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
154622
- includeClaudeSkills ? loadGlobalAgentsSkills() : Promise.resolve({}),
154623
- includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
154624
- includeClaudeSkills ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
154625
- loadOpencodeGlobalSkills(),
154626
- loadOpencodeProjectSkills(params.ctx.directory)
154902
+ loadManagedPluginSkills(),
154903
+ discovery2.global_claude ? loadUserSkills() : Promise.resolve({}),
154904
+ discovery2.global_agents ? loadGlobalAgentsSkills() : Promise.resolve({}),
154905
+ discovery2.project_claude ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
154906
+ discovery2.project_agents ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
154907
+ discovery2.global_opencode ? loadOpencodeGlobalSkills() : Promise.resolve({}),
154908
+ discovery2.project_opencode ? loadOpencodeProjectSkills(params.ctx.directory) : Promise.resolve({})
154627
154909
  ]);
154628
154910
  params.config.command = {
154629
154911
  ...builtinCommands,
154912
+ ...managedPluginSkills,
154630
154913
  ...skillsToCommandDefinitionRecord(configSourceSkills),
154631
154914
  ...userCommands,
154632
154915
  ...userSkills,
@@ -154654,7 +154937,7 @@ function remapCommandAgentFields(commands2) {
154654
154937
 
154655
154938
  // src/plugin-handlers/mcp-config-handler.ts
154656
154939
  import { spawnSync as spawnSync5 } from "child_process";
154657
- import { existsSync as existsSync85 } from "fs";
154940
+ import { existsSync as existsSync87 } from "fs";
154658
154941
 
154659
154942
  // src/mcp/websearch.ts
154660
154943
  init_logger();
@@ -154807,7 +155090,7 @@ function hasUsableLocalMcpRuntime(name, entry) {
154807
155090
  return false;
154808
155091
  }
154809
155092
  if (binary2 === "node" && typeof args[0] === "string" && args[0].endsWith(".mjs")) {
154810
- if (!existsSync85(args[0])) {
155093
+ if (!existsSync87(args[0])) {
154811
155094
  return false;
154812
155095
  }
154813
155096
  const probe2 = spawnSync5(binary2, ["--version"], {
@@ -155126,6 +155409,8 @@ function applyToolConfig(params) {
155126
155409
  function buildLspConfig(lsp) {
155127
155410
  const result = {};
155128
155411
  for (const [name, server] of Object.entries(lsp)) {
155412
+ if (server.enabled === false)
155413
+ continue;
155129
155414
  result[name] = {
155130
155415
  command: server.command,
155131
155416
  extensions: server.extensions,
@@ -155281,19 +155566,30 @@ async function createSkillContext(args) {
155281
155566
  }
155282
155567
  return true;
155283
155568
  });
155284
- const includeClaudeSkills = pluginConfig.claude_code?.skills !== false;
155285
- const [configSourceSkills, userSkills, globalSkills, projectSkills, opencodeProjectSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
155286
- discoverConfigSourceSkills({
155569
+ const discovery2 = resolveSkillDiscoveryConfig(pluginConfig);
155570
+ const [
155571
+ managedPluginSkills,
155572
+ configSourceSkills,
155573
+ userSkills,
155574
+ globalSkills,
155575
+ projectSkills,
155576
+ opencodeProjectSkills,
155577
+ agentsProjectSkills,
155578
+ agentsGlobalSkills
155579
+ ] = await Promise.all([
155580
+ discoverManagedPluginSkills(),
155581
+ discovery2.config_sources ? discoverConfigSourceSkills({
155287
155582
  config: pluginConfig.skills,
155288
155583
  configDir: directory
155289
- }),
155290
- includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
155291
- discoverOpencodeGlobalSkills(),
155292
- includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
155293
- discoverOpencodeProjectSkills(directory),
155294
- discoverProjectAgentsSkills(directory),
155295
- discoverGlobalAgentsSkills()
155584
+ }) : Promise.resolve([]),
155585
+ discovery2.global_claude ? discoverUserClaudeSkills() : Promise.resolve([]),
155586
+ discovery2.global_opencode ? discoverOpencodeGlobalSkills() : Promise.resolve([]),
155587
+ discovery2.project_claude ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
155588
+ discovery2.project_opencode ? discoverOpencodeProjectSkills(directory) : Promise.resolve([]),
155589
+ discovery2.project_agents ? discoverProjectAgentsSkills(directory) : Promise.resolve([]),
155590
+ discovery2.global_agents ? discoverGlobalAgentsSkills() : Promise.resolve([])
155296
155591
  ]);
155592
+ const filteredManagedPluginSkills = filterProviderGatedSkills(managedPluginSkills, browserProvider);
155297
155593
  const filteredConfigSourceSkills = filterProviderGatedSkills(configSourceSkills, browserProvider);
155298
155594
  const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
155299
155595
  const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
@@ -155301,7 +155597,7 @@ async function createSkillContext(args) {
155301
155597
  const filteredOpencodeProjectSkills = filterProviderGatedSkills(opencodeProjectSkills, browserProvider);
155302
155598
  const filteredAgentsProjectSkills = filterProviderGatedSkills(agentsProjectSkills, browserProvider);
155303
155599
  const filteredAgentsGlobalSkills = filterProviderGatedSkills(agentsGlobalSkills, browserProvider);
155304
- const mergedSkills = mergeSkills(builtinSkills, pluginConfig.skills, filteredConfigSourceSkills, [...filteredUserSkills, ...filteredAgentsGlobalSkills], filteredGlobalSkills, [...filteredProjectSkills, ...filteredAgentsProjectSkills], filteredOpencodeProjectSkills, { configDir: directory });
155600
+ const mergedSkills = mergeSkills(builtinSkills, pluginConfig.skills, [...filteredManagedPluginSkills, ...filteredConfigSourceSkills], [...filteredUserSkills, ...filteredAgentsGlobalSkills], filteredGlobalSkills, [...filteredProjectSkills, ...filteredAgentsProjectSkills], filteredOpencodeProjectSkills, { configDir: directory });
155305
155601
  const availableSkills = mergedSkills.map((skill2) => ({
155306
155602
  name: skill2.name,
155307
155603
  description: skill2.definition.description ?? "",
@@ -155408,6 +155704,7 @@ function createToolRegistry(args) {
155408
155704
  managers,
155409
155705
  skillContext,
155410
155706
  availableCategories,
155707
+ builtinMcp,
155411
155708
  interactiveBashEnabled = isInteractiveBashEnabled(),
155412
155709
  toolFactories
155413
155710
  } = args;
@@ -155455,7 +155752,8 @@ function createToolRegistry(args) {
155455
155752
  const skillMcpTool = factories.createSkillMcpTool({
155456
155753
  manager: managers.skillMcpManager,
155457
155754
  getLoadedSkills: () => skillContext.mergedSkills,
155458
- getSessionID: getSessionIDForMcp
155755
+ getSessionID: getSessionIDForMcp,
155756
+ builtinMcp
155459
155757
  });
155460
155758
  const commands2 = factories.discoverCommandsSync(ctx.directory, {
155461
155759
  pluginsEnabled: pluginConfig.claude_code?.plugins ?? true,
@@ -155511,7 +155809,7 @@ function createToolRegistry(args) {
155511
155809
 
155512
155810
  // src/create-tools.ts
155513
155811
  async function createTools(args) {
155514
- const { ctx, pluginConfig, managers } = args;
155812
+ const { ctx, pluginConfig, platformConfig, managers } = args;
155515
155813
  const skillContext = await createSkillContext({
155516
155814
  directory: ctx.directory,
155517
155815
  pluginConfig
@@ -155522,7 +155820,8 @@ async function createTools(args) {
155522
155820
  pluginConfig,
155523
155821
  managers,
155524
155822
  skillContext,
155525
- availableCategories
155823
+ availableCategories,
155824
+ builtinMcp: platformConfig?.mcp
155526
155825
  });
155527
155826
  return {
155528
155827
  filteredTools,
@@ -155792,7 +156091,7 @@ init_agent_display_names();
155792
156091
  // src/plugin/ultrawork-db-model-override.ts
155793
156092
  import { Database } from "bun:sqlite";
155794
156093
  import { join as join97 } from "path";
155795
- import { existsSync as existsSync86 } from "fs";
156094
+ import { existsSync as existsSync88 } from "fs";
155796
156095
  function getDbPath() {
155797
156096
  return join97(getDataDir(), "opencode", "opencode.db");
155798
156097
  }
@@ -155871,7 +156170,7 @@ function retryViaMicrotask(db, messageId, targetModel, variant, attempt) {
155871
156170
  function scheduleDeferredModelOverride(messageId, targetModel, variant) {
155872
156171
  queueMicrotask(() => {
155873
156172
  const dbPath = getDbPath();
155874
- if (!existsSync86(dbPath)) {
156173
+ if (!existsSync88(dbPath)) {
155875
156174
  log("[ultrawork-db-override] DB not found, skipping deferred override");
155876
156175
  return;
155877
156176
  }
@@ -157213,6 +157512,64 @@ function createFirstMessageVariantGate() {
157213
157512
  // src/index.ts
157214
157513
  init_plugin_identity();
157215
157514
 
157515
+ // src/shared/startup-diagnostics.ts
157516
+ import { existsSync as existsSync89, readFileSync as readFileSync60 } from "fs";
157517
+ import { join as join98 } from "path";
157518
+ init_plugin_identity();
157519
+ function readPlugins(configPath) {
157520
+ if (!existsSync89(configPath))
157521
+ return [];
157522
+ try {
157523
+ const content = readFileSync60(configPath, "utf-8");
157524
+ const parsed = parseJsoncSafe(content);
157525
+ return (parsed.data?.plugin ?? []).map((entry) => typeof entry === "string" ? entry : Array.isArray(entry) ? entry[0] : "").filter((entry) => typeof entry === "string" && entry.trim().length > 0);
157526
+ } catch {
157527
+ return [];
157528
+ }
157529
+ }
157530
+ function warnIfListPluginEntry(directory) {
157531
+ const globalPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
157532
+ const candidates = [
157533
+ join98(directory, ".opencode", "opencode.json"),
157534
+ join98(directory, ".opencode", "opencode.jsonc"),
157535
+ globalPaths.configJson,
157536
+ globalPaths.configJsonc
157537
+ ];
157538
+ for (const configPath of candidates) {
157539
+ const plugins = readPlugins(configPath);
157540
+ if (!plugins.includes("list"))
157541
+ continue;
157542
+ console.warn(`[hiai-opencode] WARNING: ${configPath} contains plugin: ["list"].`);
157543
+ console.warn("[hiai-opencode] This can prevent hiai-opencode MCP servers from loading from that config scope.");
157544
+ console.warn(`[hiai-opencode] Update it to: plugin: ["${PLUGIN_NAME}"]`);
157545
+ }
157546
+ }
157547
+ function hasConfigAuthFallback(pluginConfig, envName) {
157548
+ if (envName === "FIRECRAWL_API_KEY")
157549
+ return !!pluginConfig.auth?.firecrawl?.trim();
157550
+ if (envName === "STITCH_AI_API_KEY")
157551
+ return !!pluginConfig.auth?.stitch?.trim();
157552
+ if (envName === "CONTEXT7_API_KEY")
157553
+ return !!pluginConfig.auth?.context7?.trim();
157554
+ return false;
157555
+ }
157556
+ function warnMissingRequiredMcpEnv(args) {
157557
+ const disabled = new Set(args.pluginConfig.disabled_mcps ?? []);
157558
+ const mcpConfig = args.platformConfig.mcp ?? {};
157559
+ for (const [name, entry] of Object.entries(HIAI_MCP_REGISTRY)) {
157560
+ if (disabled.has(name))
157561
+ continue;
157562
+ if (mcpConfig[name]?.enabled === false)
157563
+ continue;
157564
+ if (!entry.requiredEnv || entry.requiredEnv.length === 0)
157565
+ continue;
157566
+ const missing = entry.requiredEnv.filter((envName) => !process.env[envName]?.trim() && !hasConfigAuthFallback(args.pluginConfig, envName));
157567
+ if (missing.length === 0)
157568
+ continue;
157569
+ console.warn(`[hiai-opencode] MCP "${name}" is enabled but missing required env: ${missing.join(", ")}.` + " The plugin will continue to load; set the key or disable this MCP in hiai-opencode.json.");
157570
+ }
157571
+ }
157572
+
157216
157573
  // src/internals/plugins/subtask2/core/state.ts
157217
157574
  var configs = {};
157218
157575
  var pluginConfig = { replace_generic: true };
@@ -157528,7 +157885,7 @@ function resolveResultReferences(text, sessionID) {
157528
157885
 
157529
157886
  // src/internals/plugins/subtask2/utils/config.ts
157530
157887
  import { mkdirSync as mkdirSync18 } from "fs";
157531
- import { dirname as dirname29, join as join98 } from "path";
157888
+ import { dirname as dirname30, join as join99 } from "path";
157532
157889
 
157533
157890
  // src/internals/plugins/subtask2/utils/prompts.ts
157534
157891
  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.";
@@ -157594,15 +157951,15 @@ async function getAutoWorkflowPrompt() {
157594
157951
  var AUTO_WORKFLOW_PROMPT = AUTO_WORKFLOW_PROMPT_TEMPLATE.replace(README_PLACEHOLDER, "[Use getAutoWorkflowPrompt() to get full documentation]");
157595
157952
 
157596
157953
  // src/internals/plugins/subtask2/utils/config.ts
157597
- var CONFIG_PATH = join98(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
157954
+ var CONFIG_PATH = join99(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
157598
157955
  var cachedReadmeContent = null;
157599
157956
  async function loadReadmeContent() {
157600
157957
  if (cachedReadmeContent !== null) {
157601
157958
  return cachedReadmeContent;
157602
157959
  }
157603
157960
  try {
157604
- const pluginRoot = join98(dirname29(import.meta.path), "..", "..");
157605
- const readmePath = join98(pluginRoot, "README.md");
157961
+ const pluginRoot = join99(dirname30(import.meta.path), "..", "..");
157962
+ const readmePath = join99(pluginRoot, "README.md");
157606
157963
  const file3 = Bun.file(readmePath);
157607
157964
  if (await file3.exists()) {
157608
157965
  cachedReadmeContent = await file3.text();
@@ -157637,7 +157994,7 @@ async function loadConfig2() {
157637
157994
  }
157638
157995
  }
157639
157996
  } catch {}
157640
- mkdirSync18(dirname29(CONFIG_PATH), { recursive: true });
157997
+ mkdirSync18(dirname30(CONFIG_PATH), { recursive: true });
157641
157998
  await Bun.write(CONFIG_PATH, `{
157642
157999
  // Replace OpenCode's generic "Summarize..." prompt when no return is specified
157643
158000
  "replace_generic": true,
@@ -157709,7 +158066,7 @@ function clearLog() {
157709
158066
  }
157710
158067
 
157711
158068
  // src/internals/plugins/subtask2/commands/manifest.ts
157712
- import { join as join100 } from "path";
158069
+ import { join as join101 } from "path";
157713
158070
 
157714
158071
  // src/internals/plugins/subtask2/parsing/frontmatter.ts
157715
158072
  var import_yaml = __toESM(require_dist2(), 1);
@@ -157965,8 +158322,8 @@ function parseAutoWorkflowOutput(text) {
157965
158322
  async function buildManifest() {
157966
158323
  const manifest = {};
157967
158324
  const dirs = [
157968
- join100(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
157969
- join100(Bun.env.PWD ?? ".", ".opencode", "command")
158325
+ join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158326
+ join101(Bun.env.PWD ?? ".", ".opencode", "command")
157970
158327
  ];
157971
158328
  for (const dir of dirs) {
157972
158329
  try {
@@ -158129,11 +158486,11 @@ async function resolveTurnReferences(text, sessionID) {
158129
158486
  }
158130
158487
 
158131
158488
  // src/internals/plugins/subtask2/commands/loader.ts
158132
- import { join as join101 } from "path";
158489
+ import { join as join102 } from "path";
158133
158490
  async function loadCommandFile(name) {
158134
158491
  const dirs = [
158135
- join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158136
- join101(Bun.env.PWD ?? ".", ".opencode", "command")
158492
+ join102(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158493
+ join102(Bun.env.PWD ?? ".", ".opencode", "command")
158137
158494
  ];
158138
158495
  for (const dir of dirs) {
158139
158496
  const directPath = `${dir}/${name}.md`;
@@ -159413,14 +159770,14 @@ init_websearch_cited();
159413
159770
  // src/features/builtin-skills/materialize.ts
159414
159771
  import {
159415
159772
  cpSync,
159416
- existsSync as existsSync88,
159773
+ existsSync as existsSync91,
159417
159774
  mkdirSync as mkdirSync20,
159418
159775
  readdirSync as readdirSync26,
159419
- readFileSync as readFileSync59,
159776
+ readFileSync as readFileSync61,
159420
159777
  rmSync as rmSync4,
159421
159778
  writeFileSync as writeFileSync22
159422
159779
  } from "fs";
159423
- import { join as join102 } from "path";
159780
+ import { join as join103 } from "path";
159424
159781
  var GENERATED_MARKER = "<!-- Generated by hiai-opencode builtin skill materializer. -->";
159425
159782
  var MANAGED_SKILL_METADATA = ".hiai-skill.json";
159426
159783
  var LEGACY_MANAGED_DIR_MARKER = ".hiai-plugin-skill";
@@ -159447,10 +159804,10 @@ function buildSkillFrontmatter(skill2) {
159447
159804
  `);
159448
159805
  }
159449
159806
  function shouldWriteSkillFile(skillFilePath) {
159450
- if (!existsSync88(skillFilePath))
159807
+ if (!existsSync91(skillFilePath))
159451
159808
  return true;
159452
159809
  try {
159453
- const existing = readFileSync59(skillFilePath, "utf-8");
159810
+ const existing = readFileSync61(skillFilePath, "utf-8");
159454
159811
  return existing.includes(GENERATED_MARKER);
159455
159812
  } catch {
159456
159813
  return false;
@@ -159458,10 +159815,10 @@ function shouldWriteSkillFile(skillFilePath) {
159458
159815
  }
159459
159816
  function getSkillLayout() {
159460
159817
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
159461
- const assembledSkillsDir = join102(configDir, "skills");
159462
- const sourceRootDir = join102(configDir, ".hiai", "skills");
159463
- const builtinSourceDir = join102(sourceRootDir, "builtin");
159464
- const pluginSourceDir = join102(sourceRootDir, "plugin");
159818
+ const assembledSkillsDir = join103(configDir, "skills");
159819
+ const sourceRootDir = join103(configDir, ".hiai", "skills");
159820
+ const builtinSourceDir = join103(sourceRootDir, "builtin");
159821
+ const pluginSourceDir = join103(sourceRootDir, "plugin");
159465
159822
  mkdirSync20(assembledSkillsDir, { recursive: true });
159466
159823
  mkdirSync20(builtinSourceDir, { recursive: true });
159467
159824
  mkdirSync20(pluginSourceDir, { recursive: true });
@@ -159474,31 +159831,31 @@ function getSkillLayout() {
159474
159831
  };
159475
159832
  }
159476
159833
  function writeManagedSkillMetadata(targetDir, metadata) {
159477
- writeFileSync22(join102(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
159834
+ writeFileSync22(join103(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
159478
159835
  `, "utf-8");
159479
159836
  }
159480
159837
  function readManagedSkillMetadata(targetDir) {
159481
- const metadataPath = join102(targetDir, MANAGED_SKILL_METADATA);
159482
- if (!existsSync88(metadataPath)) {
159838
+ const metadataPath = join103(targetDir, MANAGED_SKILL_METADATA);
159839
+ if (!existsSync91(metadataPath)) {
159483
159840
  return null;
159484
159841
  }
159485
159842
  try {
159486
- return JSON.parse(readFileSync59(metadataPath, "utf-8"));
159843
+ return JSON.parse(readFileSync61(metadataPath, "utf-8"));
159487
159844
  } catch {
159488
159845
  return null;
159489
159846
  }
159490
159847
  }
159491
159848
  function isLegacyManagedSkillDir(targetDir, origin) {
159492
- if (origin === "plugin" && existsSync88(join102(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
159849
+ if (origin === "plugin" && existsSync91(join103(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
159493
159850
  return true;
159494
159851
  }
159495
159852
  if (origin === "builtin") {
159496
- const skillFilePath = join102(targetDir, "SKILL.md");
159497
- if (!existsSync88(skillFilePath)) {
159853
+ const skillFilePath = join103(targetDir, "SKILL.md");
159854
+ if (!existsSync91(skillFilePath)) {
159498
159855
  return false;
159499
159856
  }
159500
159857
  try {
159501
- return readFileSync59(skillFilePath, "utf-8").includes(GENERATED_MARKER);
159858
+ return readFileSync61(skillFilePath, "utf-8").includes(GENERATED_MARKER);
159502
159859
  } catch {
159503
159860
  return false;
159504
159861
  }
@@ -159506,7 +159863,7 @@ function isLegacyManagedSkillDir(targetDir, origin) {
159506
159863
  return false;
159507
159864
  }
159508
159865
  function shouldSyncManagedSkillDir(targetDir, origin) {
159509
- if (!existsSync88(targetDir))
159866
+ if (!existsSync91(targetDir))
159510
159867
  return true;
159511
159868
  const metadata = readManagedSkillMetadata(targetDir);
159512
159869
  if (metadata?.generatedBy === "hiai-opencode" && metadata.origin === origin) {
@@ -159522,7 +159879,7 @@ function shouldCleanupManagedSkillDir(targetDir, origin) {
159522
159879
  return isLegacyManagedSkillDir(targetDir, origin);
159523
159880
  }
159524
159881
  function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
159525
- if (!existsSync88(rootDir)) {
159882
+ if (!existsSync91(rootDir)) {
159526
159883
  return;
159527
159884
  }
159528
159885
  for (const entry of readdirSync26(rootDir, { withFileTypes: true })) {
@@ -159530,15 +159887,15 @@ function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
159530
159887
  continue;
159531
159888
  if (expectedSkillNames.has(entry.name))
159532
159889
  continue;
159533
- const targetDir = join102(rootDir, entry.name);
159890
+ const targetDir = join103(rootDir, entry.name);
159534
159891
  if (shouldCleanupManagedSkillDir(targetDir, origin)) {
159535
159892
  rmSync4(targetDir, { recursive: true, force: true });
159536
159893
  }
159537
159894
  }
159538
159895
  }
159539
159896
  function writeSkillRegistry(configDir, entries) {
159540
- const registryDir = join102(configDir, ".hiai");
159541
- const assembledSkillsDir = join102(configDir, "skills");
159897
+ const registryDir = join103(configDir, ".hiai");
159898
+ const assembledSkillsDir = join103(configDir, "skills");
159542
159899
  mkdirSync20(registryDir, { recursive: true });
159543
159900
  mkdirSync20(assembledSkillsDir, { recursive: true });
159544
159901
  const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
@@ -159552,12 +159909,12 @@ function writeSkillRegistry(configDir, entries) {
159552
159909
  },
159553
159910
  layout: {
159554
159911
  assembledSkillsDir,
159555
- builtinSourceDir: join102(registryDir, "skills", "builtin"),
159556
- pluginSourceDir: join102(registryDir, "skills", "plugin")
159912
+ builtinSourceDir: join103(registryDir, "skills", "builtin"),
159913
+ pluginSourceDir: join103(registryDir, "skills", "plugin")
159557
159914
  },
159558
159915
  entries: sortedEntries
159559
159916
  };
159560
- writeFileSync22(join102(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
159917
+ writeFileSync22(join103(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
159561
159918
  `, "utf-8");
159562
159919
  const readme = [
159563
159920
  "# Hiai Skill Layout",
@@ -159572,16 +159929,16 @@ function writeSkillRegistry(configDir, entries) {
159572
159929
  ""
159573
159930
  ].join(`
159574
159931
  `);
159575
- writeFileSync22(join102(assembledSkillsDir, "README.md"), readme, "utf-8");
159932
+ writeFileSync22(join103(assembledSkillsDir, "README.md"), readme, "utf-8");
159576
159933
  }
159577
159934
  function materializeBuiltinSkills(skills) {
159578
159935
  const { assembledSkillsDir, builtinSourceDir } = getSkillLayout();
159579
159936
  const expectedSkillNames = new Set(skills.map((skill2) => skill2.name));
159580
159937
  for (const skill2 of skills) {
159581
- const sourceSkillDir = join102(builtinSourceDir, skill2.name);
159582
- const sourceSkillFilePath = join102(sourceSkillDir, "SKILL.md");
159583
- const assembledSkillDir = join102(assembledSkillsDir, skill2.name);
159584
- const assembledSkillFilePath = join102(assembledSkillDir, "SKILL.md");
159938
+ const sourceSkillDir = join103(builtinSourceDir, skill2.name);
159939
+ const sourceSkillFilePath = join103(sourceSkillDir, "SKILL.md");
159940
+ const assembledSkillDir = join103(assembledSkillsDir, skill2.name);
159941
+ const assembledSkillFilePath = join103(assembledSkillDir, "SKILL.md");
159585
159942
  const content = buildSkillFrontmatter(skill2);
159586
159943
  mkdirSync20(sourceSkillDir, { recursive: true });
159587
159944
  mkdirSync20(assembledSkillDir, { recursive: true });
@@ -159609,8 +159966,8 @@ function materializeBuiltinSkills(skills) {
159609
159966
  cleanupRemovedManagedSkillDirs(assembledSkillsDir, "builtin", expectedSkillNames);
159610
159967
  }
159611
159968
  function materializePluginSkillDirectories(pluginRootDir) {
159612
- const sourceSkillsDir = join102(pluginRootDir, "skills");
159613
- if (!existsSync88(sourceSkillsDir)) {
159969
+ const sourceSkillsDir = join103(pluginRootDir, "skills");
159970
+ if (!existsSync91(sourceSkillsDir)) {
159614
159971
  return;
159615
159972
  }
159616
159973
  const { assembledSkillsDir, pluginSourceDir, configDir } = getSkillLayout();
@@ -159622,9 +159979,9 @@ function materializePluginSkillDirectories(pluginRootDir) {
159622
159979
  if (entry.name === "tmp")
159623
159980
  continue;
159624
159981
  expectedSkillNames.add(entry.name);
159625
- const sourceDir = join102(sourceSkillsDir, entry.name);
159626
- const mirroredSourceDir = join102(pluginSourceDir, entry.name);
159627
- const assembledDir = join102(assembledSkillsDir, entry.name);
159982
+ const sourceDir = join103(sourceSkillsDir, entry.name);
159983
+ const mirroredSourceDir = join103(pluginSourceDir, entry.name);
159984
+ const assembledDir = join103(assembledSkillsDir, entry.name);
159628
159985
  if (!shouldSyncManagedSkillDir(mirroredSourceDir, "plugin") || !shouldSyncManagedSkillDir(assembledDir, "plugin")) {
159629
159986
  continue;
159630
159987
  }
@@ -159658,7 +160015,7 @@ function materializePluginSkillDirectories(pluginRootDir) {
159658
160015
  for (const builtinEntry of readdirSync26(assembledSkillsDir, { withFileTypes: true })) {
159659
160016
  if (!builtinEntry.isDirectory())
159660
160017
  continue;
159661
- const assembledDir = join102(assembledSkillsDir, builtinEntry.name);
160018
+ const assembledDir = join103(assembledSkillsDir, builtinEntry.name);
159662
160019
  const metadata = readManagedSkillMetadata(assembledDir);
159663
160020
  if (metadata?.generatedBy !== "hiai-opencode" || metadata.origin !== "builtin") {
159664
160021
  continue;
@@ -159675,17 +160032,45 @@ function materializePluginSkillDirectories(pluginRootDir) {
159675
160032
 
159676
160033
  // src/index.ts
159677
160034
  var activePluginDispose = null;
160035
+ function createWebsearchFallback(config4) {
160036
+ const model = config4.agents?.researcher?.model?.trim();
160037
+ if (!model) {
160038
+ return;
160039
+ }
160040
+ if (model.startsWith("openrouter/")) {
160041
+ return {
160042
+ providerID: OPENROUTER_PROVIDER_ID,
160043
+ model: model.slice("openrouter/".length)
160044
+ };
160045
+ }
160046
+ if (model.startsWith("openai/")) {
160047
+ return {
160048
+ providerID: OPENAI_PROVIDER_ID,
160049
+ model: model.slice("openai/".length)
160050
+ };
160051
+ }
160052
+ if (model.startsWith("google/")) {
160053
+ return {
160054
+ providerID: GOOGLE_PROVIDER_ID,
160055
+ model: model.slice("google/".length)
160056
+ };
160057
+ }
160058
+ return {
160059
+ providerID: OPENROUTER_PROVIDER_ID,
160060
+ model
160061
+ };
160062
+ }
159678
160063
  function configureBundledBunPtyLibrary() {
159679
160064
  if (process.env.BUN_PTY_LIB?.trim()) {
159680
160065
  return;
159681
160066
  }
159682
160067
  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";
159683
160068
  const candidates = [
159684
- join104(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
159685
- join104(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName),
159686
- join104(import.meta.dirname, "..", "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
160069
+ join105(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
160070
+ join105(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName),
160071
+ join105(import.meta.dirname, "..", "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
159687
160072
  ];
159688
- const resolved = candidates.find((candidate) => existsSync90(candidate));
160073
+ const resolved = candidates.find((candidate) => existsSync93(candidate));
159689
160074
  if (resolved) {
159690
160075
  process.env.BUN_PTY_LIB = resolved;
159691
160076
  }
@@ -159694,6 +160079,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
159694
160079
  log("[HiaiOpenCodePlugin] ENTRY - plugin loading", {
159695
160080
  directory: ctx.directory
159696
160081
  });
160082
+ warnIfListPluginEntry(ctx.directory);
159697
160083
  const skillPluginCheck = detectExternalSkillPlugin(ctx.directory);
159698
160084
  if (skillPluginCheck.detected && skillPluginCheck.pluginName) {
159699
160085
  console.warn(getSkillPluginConflictWarning(skillPluginCheck.pluginName));
@@ -159702,11 +160088,15 @@ var HiaiOpenCodePlugin = async (ctx) => {
159702
160088
  await activePluginDispose?.();
159703
160089
  const internalConfig = loadConfig(ctx.directory);
159704
160090
  const pluginConfig2 = hydratePluginConfigWithPlatformDefaults(loadPluginConfig(ctx.directory, ctx), internalConfig);
160091
+ warnMissingRequiredMcpEnv({
160092
+ pluginConfig: pluginConfig2,
160093
+ platformConfig: internalConfig
160094
+ });
159705
160095
  materializeBuiltinSkills(createBuiltinSkills({
159706
160096
  browserProvider: pluginConfig2.browser_automation_engine?.provider ?? "playwright",
159707
160097
  disabledSkills: new Set(pluginConfig2.disabled_skills ?? [])
159708
160098
  }));
159709
- materializePluginSkillDirectories(join104(import.meta.dirname, ".."));
160099
+ materializePluginSkillDirectories(join105(import.meta.dirname, ".."));
159710
160100
  const { initializeModelRequirements: initializeModelRequirements2 } = await Promise.resolve().then(() => (init_model_requirements(), exports_model_requirements));
159711
160101
  initializeModelRequirements2(internalConfig);
159712
160102
  const { initializeModelHeuristics: initializeModelHeuristics2 } = await Promise.resolve().then(() => (init_model_capability_heuristics(), exports_model_capability_heuristics));
@@ -159731,6 +160121,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
159731
160121
  const toolsResult = await createTools({
159732
160122
  ctx,
159733
160123
  pluginConfig: pluginConfig2,
160124
+ platformConfig: internalConfig,
159734
160125
  managers
159735
160126
  });
159736
160127
  const hooks = createHooks({
@@ -159766,7 +160157,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
159766
160157
  } catch (err) {
159767
160158
  console.error("[hiai-opencode] PTYPlugin failed to load:", err);
159768
160159
  }
159769
- const websearchResult = await websearch_cited_default(ctx);
160160
+ const websearchResult = await websearch_cited_default(ctx, createWebsearchFallback(internalConfig));
159770
160161
  const websearchGoogleResult = await WebsearchCitedGooglePlugin(ctx);
159771
160162
  const websearchOpenAIResult = await WebsearchCitedOpenAIPlugin(ctx);
159772
160163
  const combinedResult = {
@@ -159806,30 +160197,25 @@ var HiaiOpenCodePlugin = async (ctx) => {
159806
160197
  auth: {
159807
160198
  provider: "hiai-opencode",
159808
160199
  methods: [
159809
- { type: "api", label: "Google API key" },
159810
- { type: "api", label: "OpenAI API key" },
159811
- { type: "api", label: "OpenRouter API key" }
160200
+ { type: "api", label: "Google Search API key" }
159812
160201
  ],
159813
160202
  loader: async (getAuth) => {
159814
160203
  const authData = await getAuth();
159815
160204
  const { registerGetAuth: registerGetAuth2, GOOGLE_PROVIDER_ID: GOOGLE_PROVIDER_ID2, OPENAI_PROVIDER_ID: OPENAI_PROVIDER_ID2, OPENROUTER_PROVIDER_ID: OPENROUTER_PROVIDER_ID2 } = await Promise.resolve().then(() => (init_websearch_cited(), exports_websearch_cited));
159816
- const getKey = (label, configKey) => {
159817
- const fromAuth = authData[label];
159818
- if (fromAuth)
159819
- return fromAuth;
160205
+ const getConfiguredKey = (configKey) => {
159820
160206
  if (configKey)
159821
160207
  return resolveEnvVars(configKey);
159822
160208
  return;
159823
160209
  };
159824
- const googleKey = getKey("Google API key", internalConfig.auth?.googleSearch);
159825
- const openaiKey = getKey("OpenAI API key", internalConfig.auth?.openai);
159826
- const openRouterKey = getKey("OpenRouter API key", internalConfig.auth?.openrouter);
160210
+ const googleKey = authData["Google Search API key"] || getConfiguredKey(internalConfig.auth?.googleSearch);
160211
+ const openaiKey = getConfiguredKey(internalConfig.auth?.openai);
160212
+ const openRouterKey = getConfiguredKey(internalConfig.auth?.openrouter);
159827
160213
  if (googleKey)
159828
- registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve(googleKey));
160214
+ registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: googleKey }));
159829
160215
  if (openaiKey)
159830
- registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve(openaiKey));
160216
+ registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openaiKey }));
159831
160217
  if (openRouterKey)
159832
- registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve(openRouterKey));
160218
+ registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openRouterKey }));
159833
160219
  return {};
159834
160220
  }
159835
160221
  },