@hiai-gg/hiai-opencode 0.1.2 → 0.1.4

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 (58) hide show
  1. package/.env.example +28 -21
  2. package/AGENTS.md +183 -28
  3. package/ARCHITECTURE.md +17 -20
  4. package/LICENSE.md +1 -0
  5. package/README.md +269 -66
  6. package/assets/cli/hiai-opencode.mjs +276 -0
  7. package/assets/mcp/mempalace.mjs +47 -4
  8. package/assets/mcp/playwright.mjs +83 -0
  9. package/config/hiai-opencode.schema.json +113 -1
  10. package/dist/config/index.d.ts +0 -1
  11. package/dist/config/platform-schema.d.ts +72 -0
  12. package/dist/config/schema/agent-overrides.d.ts +256 -0
  13. package/dist/config/schema/categories.d.ts +2 -2
  14. package/dist/config/schema/commands.d.ts +1 -0
  15. package/dist/config/schema/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 +12 -1
  19. package/dist/features/builtin-commands/templates/mcp-status.d.ts +1 -0
  20. package/dist/features/builtin-commands/types.d.ts +1 -1
  21. package/dist/features/opencode-skill-loader/loader.d.ts +2 -0
  22. package/dist/index.js +617 -421
  23. package/dist/mcp/registry.d.ts +14 -0
  24. package/dist/mcp/types.d.ts +6 -0
  25. package/dist/plugin/skill-discovery-config.d.ts +4 -0
  26. package/dist/shared/startup-diagnostics.d.ts +6 -0
  27. package/hiai-opencode.json +192 -36
  28. package/package.json +4 -1
  29. package/src/agents/AGENTS.md +3 -4
  30. package/src/config/defaults.ts +55 -133
  31. package/src/config/index.ts +0 -1
  32. package/src/config/loader.ts +4 -1
  33. package/src/config/platform-schema.ts +18 -2
  34. package/src/config/schema/agent-overrides.ts +2 -0
  35. package/src/config/schema/commands.ts +1 -0
  36. package/src/config/schema/fast-apply.ts +4 -4
  37. package/src/config/schema/index.ts +2 -0
  38. package/src/config/schema/oh-my-opencode-config.ts +3 -0
  39. package/src/config/schema/skill-discovery.ts +25 -0
  40. package/src/config/types.ts +16 -0
  41. package/src/features/builtin-commands/commands.ts +7 -0
  42. package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
  43. package/src/features/builtin-commands/types.ts +1 -1
  44. package/src/features/builtin-skills/skills/playwright.ts +24 -2
  45. package/src/features/opencode-skill-loader/loader.ts +11 -0
  46. package/src/index.ts +15 -13
  47. package/src/mcp/index.ts +0 -33
  48. package/src/mcp/omo-mcp-index.ts +0 -5
  49. package/src/mcp/registry.ts +132 -0
  50. package/src/mcp/types.ts +11 -1
  51. package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
  52. package/src/plugin/skill-context.ts +31 -13
  53. package/src/plugin/skill-discovery-config.ts +32 -0
  54. package/src/plugin-handlers/agent-config-handler.ts +20 -13
  55. package/src/plugin-handlers/command-config-handler.ts +22 -12
  56. package/src/shared/migration/agent-names.ts +5 -5
  57. package/src/shared/startup-diagnostics.ts +77 -0
  58. 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,
@@ -33808,8 +33808,8 @@ class EventEmitter {
33808
33808
  // node_modules/bun-pty/src/terminal.ts
33809
33809
  import { dlopen, FFIType, ptr } from "bun:ffi";
33810
33810
  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";
33811
+ import { join as join104, dirname as dirname31, basename as basename16 } from "path";
33812
+ import { existsSync as existsSync91 } from "fs";
33813
33813
  function shQuote(s) {
33814
33814
  if (s.length === 0)
33815
33815
  return "''";
@@ -33817,7 +33817,7 @@ function shQuote(s) {
33817
33817
  }
33818
33818
  function resolveLibPath() {
33819
33819
  const env = process.env.BUN_PTY_LIB;
33820
- if (env && existsSync89(env))
33820
+ if (env && existsSync91(env))
33821
33821
  return env;
33822
33822
  try {
33823
33823
  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 +33828,22 @@ function resolveLibPath() {
33828
33828
  const arch = process.arch;
33829
33829
  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
33830
  const base = Bun.fileURLToPath(import.meta.url);
33831
- const fileDir = dirname30(base);
33831
+ const fileDir = dirname31(base);
33832
33832
  const dirName = basename16(fileDir);
33833
- const here = dirName === "src" || dirName === "dist" ? dirname30(fileDir) : fileDir;
33833
+ const here = dirName === "src" || dirName === "dist" ? dirname31(fileDir) : fileDir;
33834
33834
  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")
33835
+ join104(here, "rust-pty", "target", "release"),
33836
+ join104(here, "..", "bun-pty", "rust-pty", "target", "release"),
33837
+ join104(process.cwd(), "node_modules", "bun-pty", "rust-pty", "target", "release")
33838
33838
  ];
33839
33839
  const fallbackPaths = [];
33840
33840
  for (const basePath of basePaths) {
33841
33841
  for (const filename of filenames) {
33842
- fallbackPaths.push(join103(basePath, filename));
33842
+ fallbackPaths.push(join104(basePath, filename));
33843
33843
  }
33844
33844
  }
33845
33845
  for (const path10 of fallbackPaths) {
33846
- if (existsSync89(path10))
33846
+ if (existsSync91(path10))
33847
33847
  return path10;
33848
33848
  }
33849
33849
  throw new Error(`librust_pty shared library not found.
@@ -35060,8 +35060,8 @@ var init_plugin = __esm(() => {
35060
35060
  });
35061
35061
 
35062
35062
  // src/index.ts
35063
- import { existsSync as existsSync90 } from "fs";
35064
- import { join as join104 } from "path";
35063
+ import { existsSync as existsSync92 } from "fs";
35064
+ import { join as join105 } from "path";
35065
35065
 
35066
35066
  // src/hooks/todo-continuation-enforcer/index.ts
35067
35067
  init_logger();
@@ -110591,6 +110591,11 @@ async function loadGlobalAgentsSkills() {
110591
110591
  const skills = await loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
110592
110592
  return skillsToCommandDefinitionRecord(skills);
110593
110593
  }
110594
+ async function loadManagedPluginSkills() {
110595
+ const skillsDir = join60(getOpenCodeConfigDir({ binary: "opencode" }), ".hiai", "skills", "plugin");
110596
+ const skills = await loadSkillsFromDir({ skillsDir, scope: "builtin" });
110597
+ return skillsToCommandDefinitionRecord(skills);
110598
+ }
110594
110599
  async function discoverAllSkills(directory) {
110595
110600
  const [opencodeProjectSkills, opencodeGlobalSkills, projectSkills, userSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
110596
110601
  discoverOpencodeProjectSkills(directory),
@@ -110661,6 +110666,10 @@ async function discoverGlobalAgentsSkills() {
110661
110666
  const agentsGlobalDir = join60(getAgentsConfigDir(), "skills");
110662
110667
  return loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
110663
110668
  }
110669
+ async function discoverManagedPluginSkills() {
110670
+ const skillsDir = join60(getOpenCodeConfigDir({ binary: "opencode" }), ".hiai", "skills", "plugin");
110671
+ return loadSkillsFromDir({ skillsDir, scope: "builtin" });
110672
+ }
110664
110673
  // src/features/opencode-skill-loader/merger/builtin-skill-converter.ts
110665
110674
  function builtinToLoadedSkill(builtin) {
110666
110675
  const definition = {
@@ -110893,11 +110902,33 @@ var playwrightSkill = {
110893
110902
  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
110903
  template: `# Playwright Browser Automation
110895
110904
 
110896
- This skill provides browser automation capabilities via the Playwright MCP server.`,
110905
+ This skill provides browser automation capabilities via the Playwright MCP server.
110906
+
110907
+ ## Required workflow
110908
+
110909
+ 1. Load this skill before calling \`skill_mcp\`.
110910
+ 2. Use \`skill_mcp\` with \`mcp_name="playwright"\` for browser navigation, interaction, screenshots, and visual verification.
110911
+ 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.
110912
+ 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.
110913
+
110914
+ ## Linux dependency fallback
110915
+
110916
+ Playwright has two dependency layers:
110917
+
110918
+ - Browser binary: installable without sudo with \`npx playwright install chromium\` or by setting \`HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1\` before OpenCode starts.
110919
+ - System libraries: on minimal Linux images these usually require admin rights via \`sudo npx playwright install-deps chromium\` or OS package manager equivalents.
110920
+
110921
+ If sudo is unavailable, try these alternatives before falling back to curl-only checks:
110922
+
110923
+ - Use an already installed Chrome/Chromium/Edge by adding Playwright MCP args in \`hiai-opencode.json\`, for example \`--browser chrome\` or \`--browser msedge\`.
110924
+ - Use a remote/browser service or CDP-backed browser when available.
110925
+ - Switch the browser automation provider to \`agent-browser\` or \`playwright-cli\` if the workspace has those tools installed.
110926
+
110927
+ Only use \`curl\` as a final degraded check. Clearly say that HTTP checks do not replace interactive browser verification.`,
110897
110928
  mcpConfig: {
110898
110929
  playwright: {
110899
110930
  command: "npx",
110900
- args: ["@playwright/mcp@latest"]
110931
+ args: ["-y", "@playwright/mcp@latest"]
110901
110932
  }
110902
110933
  }
110903
110934
  };
@@ -113926,6 +113957,8 @@ var AgentOverridesSchema = exports_external.object({
113926
113957
  general: AgentOverrideConfigSchema.optional(),
113927
113958
  zoe: AgentOverrideConfigSchema.optional(),
113928
113959
  "pre-plan": AgentOverrideConfigSchema.optional(),
113960
+ manager: AgentOverrideConfigSchema.optional(),
113961
+ vision: AgentOverrideConfigSchema.optional(),
113929
113962
  logician: AgentOverrideConfigSchema.optional(),
113930
113963
  librarian: AgentOverrideConfigSchema.optional(),
113931
113964
  explore: AgentOverrideConfigSchema.optional(),
@@ -114022,7 +114055,8 @@ var BuiltinCommandNameSchema = exports_external.enum([
114022
114055
  "refactor",
114023
114056
  "start-work",
114024
114057
  "stop-continuation",
114025
- "remove-ai-slops"
114058
+ "remove-ai-slops",
114059
+ "mcp-status"
114026
114060
  ]);
114027
114061
  // src/config/schema/comment-checker.ts
114028
114062
  var CommentCheckerConfigSchema = exports_external.object({
@@ -114077,8 +114111,8 @@ var ExperimentalConfigSchema = exports_external.object({
114077
114111
  // src/config/schema/fast-apply.ts
114078
114112
  var FastApplyConfigSchema = exports_external.object({
114079
114113
  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"),
114114
+ ollama_url: exports_external.string().optional().default(""),
114115
+ model: exports_external.string().optional().default(""),
114082
114116
  timeout: exports_external.number().int().positive().optional().default(30000)
114083
114117
  });
114084
114118
  // src/config/schema/git-env-prefix.ts
@@ -114171,7 +114205,17 @@ var NotificationConfigSchema = exports_external.object({
114171
114205
  force_enable: exports_external.boolean().optional()
114172
114206
  });
114173
114207
  // src/mcp/types.ts
114174
- var McpNameSchema = exports_external.enum(["websearch", "context7", "grep_app"]);
114208
+ var McpNameSchema = exports_external.enum([
114209
+ "playwright",
114210
+ "stitch",
114211
+ "sequential-thinking",
114212
+ "firecrawl",
114213
+ "rag",
114214
+ "context7",
114215
+ "mempalace",
114216
+ "websearch",
114217
+ "grep_app"
114218
+ ]);
114175
114219
  var AnyMcpNameSchema = exports_external.string().min(1);
114176
114220
 
114177
114221
  // src/config/schema/ralph-loop.ts
@@ -114225,6 +114269,17 @@ var SkillsConfigSchema = exports_external.union([
114225
114269
  }).catchall(SkillEntrySchema)
114226
114270
  ]);
114227
114271
 
114272
+ // src/config/schema/skill-discovery.ts
114273
+ var SkillDiscoveryConfigSchema = exports_external.object({
114274
+ config_sources: exports_external.boolean().default(true),
114275
+ project_opencode: exports_external.boolean().default(true),
114276
+ global_opencode: exports_external.boolean().default(false),
114277
+ project_claude: exports_external.boolean().default(false),
114278
+ global_claude: exports_external.boolean().default(false),
114279
+ project_agents: exports_external.boolean().default(false),
114280
+ global_agents: exports_external.boolean().default(false)
114281
+ });
114282
+
114228
114283
  // src/config/schema/bob.ts
114229
114284
  var BobTasksConfigSchema = exports_external.object({
114230
114285
  storage_path: exports_external.string().optional(),
@@ -114283,7 +114338,8 @@ var AuthConfigSchema = exports_external.object({
114283
114338
  openai: exports_external.string().optional(),
114284
114339
  openrouter: exports_external.string().optional(),
114285
114340
  stitch: exports_external.string().optional(),
114286
- firecrawl: exports_external.string().optional()
114341
+ firecrawl: exports_external.string().optional(),
114342
+ context7: exports_external.string().optional()
114287
114343
  }).optional();
114288
114344
  var HiaiOpenCodeConfigSchema = exports_external.object({
114289
114345
  $schema: exports_external.string().optional(),
@@ -114307,6 +114363,7 @@ var HiaiOpenCodeConfigSchema = exports_external.object({
114307
114363
  experimental: ExperimentalConfigSchema.optional(),
114308
114364
  auto_update: exports_external.boolean().optional(),
114309
114365
  skills: SkillsConfigSchema.optional(),
114366
+ skill_discovery: SkillDiscoveryConfigSchema.optional(),
114310
114367
  ralph_loop: RalphLoopConfigSchema.optional(),
114311
114368
  runtime_fallback: exports_external.union([exports_external.boolean(), RuntimeFallbackConfigSchema]).optional(),
114312
114369
  background_task: BackgroundTaskConfigSchema.optional(),
@@ -115994,6 +116051,44 @@ If any issues are found during critical review:
115994
116051
  - ALWAYS preserve test coverage
115995
116052
  - If uncertain about a change, err on the side of keeping the original code`;
115996
116053
 
116054
+ // src/features/builtin-commands/templates/mcp-status.ts
116055
+ var MCP_STATUS_TEMPLATE = `# MCP Status Command
116056
+
116057
+ ## Purpose
116058
+
116059
+ Use /mcp-status to show the effective hiai-opencode MCP setup without relying on OpenCode's mcp list output.
116060
+
116061
+ ## Execute
116062
+
116063
+ Run:
116064
+
116065
+ \`\`\`bash
116066
+ hiai-opencode mcp-status
116067
+ \`\`\`
116068
+
116069
+ If the binary is not on PATH, try the package-local fallback:
116070
+
116071
+ \`\`\`bash
116072
+ node ./node_modules/@hiai-gg/hiai-opencode/assets/cli/hiai-opencode.mjs mcp-status
116073
+ \`\`\`
116074
+
116075
+ ## Report
116076
+
116077
+ Summarize the output in a compact status table:
116078
+
116079
+ - MCP server name
116080
+ - status: ok, warning, error, disabled
116081
+ - cause or next action
116082
+
116083
+ Rules:
116084
+
116085
+ - Do not print API key values.
116086
+ - If a key is missing, name the env var only.
116087
+ - If a runtime is missing, give the exact install hint from the command output or the shortest safe next command.
116088
+ - Do not edit config unless the user explicitly asks.
116089
+ - Do not run package installs unless the user explicitly asks.
116090
+ `;
116091
+
115997
116092
  // src/features/builtin-commands/commands.ts
115998
116093
  function resolveStartWorkAgent(options) {
115999
116094
  if (options?.useRegisteredAgents) {
@@ -116097,6 +116192,12 @@ Timestamp: $TIMESTAMP
116097
116192
  $ARGUMENTS
116098
116193
  </user-request>`,
116099
116194
  argumentHint: "[goal]"
116195
+ },
116196
+ "mcp-status": {
116197
+ description: "(builtin) Show hiai-opencode MCP server status, missing keys, and local runtime availability",
116198
+ template: `<command-instruction>
116199
+ ${MCP_STATUS_TEMPLATE}
116200
+ </command-instruction>`
116100
116201
  }
116101
116202
  };
116102
116203
  }
@@ -120433,7 +120534,7 @@ import * as fs12 from "fs";
120433
120534
  import * as path6 from "path";
120434
120535
 
120435
120536
  // src/config/loader.ts
120436
- import { existsSync as existsSync56, readFileSync as readFileSync42 } from "fs";
120537
+ import { existsSync as existsSync57, readFileSync as readFileSync43 } from "fs";
120437
120538
  import { join as join66 } from "path";
120438
120539
 
120439
120540
  // src/config/platform-schema.ts
@@ -120471,6 +120572,7 @@ var McpServerConfigSchema = exports_external.object({
120471
120572
  enabled: exports_external.boolean().default(true),
120472
120573
  type: exports_external.enum(["remote", "local"]).optional(),
120473
120574
  url: exports_external.string().optional(),
120575
+ headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
120474
120576
  command: exports_external.array(exports_external.string()).optional(),
120475
120577
  timeout: exports_external.number().optional(),
120476
120578
  environment: exports_external.record(exports_external.string(), exports_external.string()).optional()
@@ -120488,6 +120590,15 @@ var SkillsConfigSchema2 = exports_external.object({
120488
120590
  enabled: exports_external.boolean().optional(),
120489
120591
  disabled: exports_external.array(exports_external.string()).optional()
120490
120592
  });
120593
+ var SkillDiscoveryConfigSchema2 = exports_external.object({
120594
+ config_sources: exports_external.boolean().optional(),
120595
+ project_opencode: exports_external.boolean().optional(),
120596
+ global_opencode: exports_external.boolean().optional(),
120597
+ project_claude: exports_external.boolean().optional(),
120598
+ global_claude: exports_external.boolean().optional(),
120599
+ project_agents: exports_external.boolean().optional(),
120600
+ global_agents: exports_external.boolean().optional()
120601
+ });
120491
120602
  var PermissionsConfigSchema = exports_external.object({
120492
120603
  read: exports_external.record(exports_external.string(), exports_external.string()).optional(),
120493
120604
  edit: exports_external.record(exports_external.string(), exports_external.string()).optional(),
@@ -120519,8 +120630,8 @@ var AuthKeysSchema = exports_external.object({
120519
120630
  });
120520
120631
  var OllamaConfigSchema = exports_external.object({
120521
120632
  enabled: exports_external.boolean().default(false),
120522
- model: exports_external.string().default("qwen3.5:4b"),
120523
- baseUrl: exports_external.string().default("http://localhost:11434"),
120633
+ model: exports_external.string().default(""),
120634
+ baseUrl: exports_external.string().default(""),
120524
120635
  purpose: exports_external.enum(["verification", "helper", "fallback"]).default("helper")
120525
120636
  });
120526
120637
  var ModelFamilySchema = exports_external.object({
@@ -120549,6 +120660,8 @@ var AgentsConfigSchema = exports_external.object({
120549
120660
  zoe: AgentConfigSchema.optional(),
120550
120661
  build: AgentConfigSchema.optional(),
120551
120662
  "pre-plan": AgentConfigSchema.optional(),
120663
+ manager: AgentConfigSchema.optional(),
120664
+ vision: AgentConfigSchema.optional(),
120552
120665
  logician: AgentConfigSchema.optional(),
120553
120666
  librarian: AgentConfigSchema.optional(),
120554
120667
  explore: AgentConfigSchema.optional(),
@@ -120578,6 +120691,8 @@ var AgentRequirementsConfigSchema = exports_external.object({
120578
120691
  zoe: ModelRequirementSchema.optional(),
120579
120692
  build: ModelRequirementSchema.optional(),
120580
120693
  "pre-plan": ModelRequirementSchema.optional(),
120694
+ manager: ModelRequirementSchema.optional(),
120695
+ vision: ModelRequirementSchema.optional(),
120581
120696
  logician: ModelRequirementSchema.optional(),
120582
120697
  librarian: ModelRequirementSchema.optional(),
120583
120698
  explore: ModelRequirementSchema.optional(),
@@ -120600,158 +120715,54 @@ var HiaiOpencodeConfigSchema = exports_external.object({
120600
120715
  lsp: exports_external.record(exports_external.string(), LspServerConfigSchema).optional(),
120601
120716
  subtask2: Subtask2ConfigSchema.optional(),
120602
120717
  skills: SkillsConfigSchema2.optional(),
120718
+ skill_discovery: SkillDiscoveryConfigSchema2.optional(),
120603
120719
  permissions: PermissionsConfigSchema.optional(),
120604
120720
  auth: AuthKeysSchema.optional(),
120605
120721
  ollama: OllamaConfigSchema.optional()
120606
120722
  });
120607
120723
 
120608
120724
  // src/config/defaults.ts
120609
- import { join as join65 } from "path";
120610
-
120611
- // src/config/models.ts
120612
- var MODEL_PRESETS = {
120613
- fast: "openrouter/google/gemini-2.0-flash",
120614
- mid: "openrouter/anthropic/claude-3.5-sonnet",
120615
- high: "openrouter/anthropic/claude-3.5-opus",
120616
- ultrahigh: "openrouter/openai/gpt-4o",
120617
- vision: "openrouter/google/gemini-2.0-pro-exp-02-05",
120618
- reasoning: "openrouter/openai/o1",
120619
- strategist: "openrouter/z-ai/glm-5.1",
120620
- critic: "openrouter/qwen/qwen2.5-72b-instruct",
120621
- writing: "openrouter/kimi/kimi-latest"
120622
- };
120623
-
120624
- // src/config/defaults.ts
120625
- function resolveAssetScript(...segments) {
120626
- return join65(import.meta.dirname, "..", "assets", ...segments);
120627
- }
120628
- function createNpmPackageCommand(pkg, ...args) {
120629
- return ["node", resolveAssetScript("runtime", "npm-package-runner.mjs"), pkg, ...args];
120630
- }
120631
- function createUpstreamNpxCommand(pkg, ...args) {
120632
- if (process.platform === "win32") {
120633
- return ["cmd", "/c", "npx", "-y", pkg, ...args];
120634
- }
120635
- return ["npx", "-y", pkg, ...args];
120636
- }
120637
- var defaultConfig = {
120638
- agents: {
120639
- bob: { model: MODEL_PRESETS.high },
120640
- guard: { model: MODEL_PRESETS.ultrahigh },
120641
- strategist: { model: MODEL_PRESETS.strategist },
120642
- critic: { model: MODEL_PRESETS.critic },
120643
- coder: { model: MODEL_PRESETS.mid },
120644
- designer: {
120645
- model: "openrouter/google/gemini-3.1-pro",
120646
- 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)"
120647
- },
120648
- sub: { model: MODEL_PRESETS.fast },
120649
- researcher: { model: MODEL_PRESETS.fast },
120650
- multimodal: { model: MODEL_PRESETS.vision },
120651
- "quality-guardian": { model: MODEL_PRESETS.mid },
120652
- "platform-manager": { model: MODEL_PRESETS.fast },
120653
- brainstormer: { model: MODEL_PRESETS.fast },
120654
- "agent-skills": { model: MODEL_PRESETS.fast }
120655
- },
120656
- agentRequirements: {},
120657
- categories: {
120658
- "visual-engineering": { model: MODEL_PRESETS.vision, variant: "high" },
120659
- artistry: { model: MODEL_PRESETS.vision, variant: "high" },
120660
- ultrabrain: { model: MODEL_PRESETS.ultrahigh, variant: "xhigh" },
120661
- deep: { model: MODEL_PRESETS.reasoning, variant: "medium" },
120662
- quick: { model: MODEL_PRESETS.fast },
120663
- writing: { model: MODEL_PRESETS.writing },
120664
- git: { model: MODEL_PRESETS.fast },
120665
- "unspecified-low": { model: MODEL_PRESETS.mid },
120666
- "unspecified-high": { model: MODEL_PRESETS.high, variant: "max" }
120667
- },
120668
- categoryRequirements: {},
120669
- mcp: {
120670
- playwright: {
120671
- enabled: true,
120672
- command: createNpmPackageCommand("@playwright/mcp@latest"),
120673
- timeout: 600000
120674
- },
120675
- stitch: {
120676
- enabled: true,
120677
- type: "remote",
120678
- url: "https://stitch.googleapis.com/mcp",
120679
- headers: { "X-Goog-Api-Key": "{env:STITCH_AI_API_KEY}" },
120680
- timeout: 600000
120681
- },
120682
- "sequential-thinking": {
120683
- enabled: true,
120684
- command: createUpstreamNpxCommand("@modelcontextprotocol/server-sequential-thinking"),
120685
- timeout: 600000
120686
- },
120687
- firecrawl: {
120688
- enabled: true,
120689
- command: createUpstreamNpxCommand("firecrawl-mcp"),
120690
- timeout: 600000,
120691
- environment: { FIRECRAWL_API_KEY: "{env:FIRECRAWL_API_KEY}" }
120692
- },
120693
- rag: {
120694
- enabled: true,
120695
- type: "remote",
120696
- url: "http://localhost:9002",
120697
- timeout: 600000
120698
- },
120699
- context7: {
120700
- enabled: true,
120701
- type: "remote",
120702
- url: "https://mcp.context7.com/mcp",
120703
- headers: { "X-API-KEY": "{env:CONTEXT7_API_KEY}" },
120704
- timeout: 600000
120705
- },
120706
- mempalace: {
120707
- enabled: true,
120708
- command: ["node", resolveAssetScript("mcp", "mempalace.mjs"), "--palace", "./.opencode/palace"],
120709
- timeout: 600000
120710
- }
120711
- },
120712
- lsp: {
120713
- typescript: {
120714
- command: ["typescript-language-server", "--stdio"],
120715
- extensions: [".ts", ".tsx", ".mts", ".cts"]
120716
- },
120717
- svelte: {
120718
- command: ["svelteserver", "--stdio"],
120719
- extensions: [".svelte"]
120720
- },
120721
- eslint: {
120722
- command: createNpmPackageCommand("eslint-lsp", "--stdio"),
120723
- extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
120724
- },
120725
- bash: {
120726
- command: createNpmPackageCommand("bash-language-server", "start"),
120727
- extensions: [".sh", ".bash"]
120728
- },
120729
- pyright: {
120730
- command: ["pyright-langserver", "--stdio"],
120731
- extensions: [".py"]
120725
+ import { existsSync as existsSync56, readFileSync as readFileSync42 } from "fs";
120726
+ import { dirname as dirname18, join as join65, normalize as normalize2 } from "path";
120727
+ function findPluginRoot() {
120728
+ const candidates = [
120729
+ join65(import.meta.dirname, "..", ".."),
120730
+ join65(import.meta.dirname, ".."),
120731
+ join65(import.meta.dirname, "..", ".."),
120732
+ dirname18(process.argv[1] ?? ""),
120733
+ process.cwd()
120734
+ ];
120735
+ for (const candidate of candidates) {
120736
+ const root = normalize2(candidate);
120737
+ if (existsSync56(join65(root, "hiai-opencode.json"))) {
120738
+ return root;
120732
120739
  }
120733
- },
120734
- subtask2: {
120735
- replace_generic: true,
120736
- generic_return: null
120737
- },
120738
- skills: {
120739
- enabled: true,
120740
- disabled: []
120741
- },
120742
- permissions: {
120743
- read: { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" },
120744
- edit: { "*": "allow" },
120745
- bash: { "*": "allow" },
120746
- deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"]
120747
- },
120748
- ollama: {
120749
- enabled: false,
120750
- model: "{env:OLLAMA_MODEL:-qwen3.5:4b}",
120751
- baseUrl: "http://localhost:11434",
120752
- purpose: "helper"
120753
120740
  }
120754
- };
120741
+ throw new Error("[hiai-opencode] Cannot find bundled hiai-opencode.json. The package is incomplete.");
120742
+ }
120743
+ function expandPluginRootPlaceholders(value, pluginRoot) {
120744
+ if (typeof value === "string") {
120745
+ return value.replaceAll("{pluginRoot}", pluginRoot);
120746
+ }
120747
+ if (Array.isArray(value)) {
120748
+ return value.map((item) => expandPluginRootPlaceholders(item, pluginRoot));
120749
+ }
120750
+ if (value && typeof value === "object") {
120751
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
120752
+ key,
120753
+ expandPluginRootPlaceholders(entry, pluginRoot)
120754
+ ]));
120755
+ }
120756
+ return value;
120757
+ }
120758
+ function loadBundledDefaultConfig() {
120759
+ const pluginRoot = findPluginRoot();
120760
+ const configPath = join65(pluginRoot, "hiai-opencode.json");
120761
+ const raw = readFileSync42(configPath, "utf-8");
120762
+ const parsed = JSON.parse(raw);
120763
+ return expandPluginRootPlaceholders(parsed, pluginRoot);
120764
+ }
120765
+ var defaultConfig = loadBundledDefaultConfig();
120755
120766
 
120756
120767
  // src/config/types.ts
120757
120768
  var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
@@ -120759,6 +120770,8 @@ var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
120759
120770
  zoe: "bob",
120760
120771
  build: "bob",
120761
120772
  "pre-plan": "strategist",
120773
+ manager: "platform-manager",
120774
+ vision: "multimodal",
120762
120775
  logician: "strategist",
120763
120776
  librarian: "researcher",
120764
120777
  explore: "researcher",
@@ -120797,7 +120810,7 @@ function findConfigFile(searchDirs) {
120797
120810
  for (const dir of searchDirs) {
120798
120811
  for (const filename of CONFIG_FILENAMES) {
120799
120812
  const candidate = join66(dir, filename);
120800
- if (existsSync56(candidate))
120813
+ if (existsSync57(candidate))
120801
120814
  return candidate;
120802
120815
  }
120803
120816
  }
@@ -120875,7 +120888,7 @@ function loadConfig(projectDir) {
120875
120888
  const configPath = findConfigFile(searchDirs);
120876
120889
  if (!configPath)
120877
120890
  return BASE_CONFIG;
120878
- const raw = readFileSync42(configPath, "utf-8");
120891
+ const raw = readFileSync43(configPath, "utf-8");
120879
120892
  const parsed = parse2(raw);
120880
120893
  const normalizedParsed = normalizeCompactLspConfig(parsed);
120881
120894
  const validated = HiaiOpencodeConfigSchema.parse(normalizedParsed);
@@ -120883,15 +120896,18 @@ function loadConfig(projectDir) {
120883
120896
  return deepMerge2(BASE_CONFIG, normalized);
120884
120897
  }
120885
120898
  function resolveEnvVars(value) {
120886
- return value.replace(/\{env:([^}]+)\}/g, (_, key) => process.env[key] || "");
120899
+ return value.replace(/\{env:([^}]+)\}/g, (_, expression) => {
120900
+ const [key, fallback] = String(expression).split(":-", 2);
120901
+ return process.env[key] || fallback || "";
120902
+ });
120887
120903
  }
120888
120904
  // src/shared/migrate-legacy-config-file.ts
120889
120905
  init_logger();
120890
120906
  init_plugin_identity();
120891
- import { existsSync as existsSync57, readFileSync as readFileSync43, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
120892
- import { join as join67, dirname as dirname18, basename as basename9 } from "path";
120907
+ import { existsSync as existsSync58, readFileSync as readFileSync44, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
120908
+ import { join as join67, dirname as dirname19, basename as basename9 } from "path";
120893
120909
  function buildCanonicalPath(legacyPath) {
120894
- const dir = dirname18(legacyPath);
120910
+ const dir = dirname19(legacyPath);
120895
120911
  const ext = basename9(legacyPath).includes(".jsonc") ? ".jsonc" : ".json";
120896
120912
  return join67(dir, `${CONFIG_BASENAME}${ext}`);
120897
120913
  }
@@ -120925,15 +120941,15 @@ function archiveLegacyConfigFile(legacyPath) {
120925
120941
  }
120926
120942
  }
120927
120943
  function migrateLegacyConfigFile(legacyPath) {
120928
- if (!existsSync57(legacyPath))
120944
+ if (!existsSync58(legacyPath))
120929
120945
  return false;
120930
120946
  if (!basename9(legacyPath).startsWith(LEGACY_CONFIG_BASENAME))
120931
120947
  return false;
120932
120948
  const canonicalPath = buildCanonicalPath(legacyPath);
120933
- if (existsSync57(canonicalPath))
120949
+ if (existsSync58(canonicalPath))
120934
120950
  return false;
120935
120951
  try {
120936
- const content = readFileSync43(legacyPath, "utf-8");
120952
+ const content = readFileSync44(legacyPath, "utf-8");
120937
120953
  writeFileAtomically(canonicalPath, content);
120938
120954
  const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath);
120939
120955
  log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
@@ -122453,11 +122469,11 @@ function createRuntimeFallbackHook(ctx, options) {
122453
122469
  };
122454
122470
  }
122455
122471
  // src/hooks/write-existing-file-guard/hook.ts
122456
- import { existsSync as existsSync60, realpathSync as realpathSync6 } from "fs";
122457
- import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute11, join as join69, normalize as normalize2, relative as relative8, resolve as resolve14 } from "path";
122472
+ import { existsSync as existsSync61, realpathSync as realpathSync6 } from "fs";
122473
+ import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute11, join as join69, normalize as normalize3, relative as relative8, resolve as resolve14 } from "path";
122458
122474
 
122459
122475
  // src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
122460
- import { existsSync as existsSync59 } from "fs";
122476
+ import { existsSync as existsSync60 } from "fs";
122461
122477
 
122462
122478
  // src/hooks/write-existing-file-guard/session-read-permissions.ts
122463
122479
  function touchSession(sessionLastAccess, sessionID) {
@@ -122545,7 +122561,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
122545
122561
  return;
122546
122562
  }
122547
122563
  if (toolName === "read") {
122548
- if (!existsSync59(resolvedPath) || !input.sessionID) {
122564
+ if (!existsSync60(resolvedPath) || !input.sessionID) {
122549
122565
  return;
122550
122566
  }
122551
122567
  registerReadPermission({
@@ -122561,7 +122577,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
122561
122577
  if (argsRecord && "overwrite" in argsRecord) {
122562
122578
  delete argsRecord.overwrite;
122563
122579
  }
122564
- if (!existsSync59(resolvedPath)) {
122580
+ if (!existsSync60(resolvedPath)) {
122565
122581
  return;
122566
122582
  }
122567
122583
  const isBobPath2 = canonicalPath.includes("/.bob/");
@@ -122612,7 +122628,7 @@ function getPathFromArgs(args) {
122612
122628
  return args?.filePath ?? args?.path ?? args?.file_path;
122613
122629
  }
122614
122630
  function resolveInputPath(ctx, inputPath) {
122615
- return normalize2(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
122631
+ return normalize3(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
122616
122632
  }
122617
122633
  function isPathInsideDirectory(pathToCheck, directory) {
122618
122634
  const relativePath = relative8(directory, pathToCheck);
@@ -122620,18 +122636,18 @@ function isPathInsideDirectory(pathToCheck, directory) {
122620
122636
  }
122621
122637
  function toCanonicalPath2(absolutePath) {
122622
122638
  let canonicalPath = absolutePath;
122623
- if (existsSync60(absolutePath)) {
122639
+ if (existsSync61(absolutePath)) {
122624
122640
  try {
122625
122641
  canonicalPath = realpathSync6.native(absolutePath);
122626
122642
  } catch {
122627
122643
  canonicalPath = absolutePath;
122628
122644
  }
122629
122645
  } else {
122630
- const absoluteDir = dirname20(absolutePath);
122631
- const resolvedDir = existsSync60(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
122646
+ const absoluteDir = dirname21(absolutePath);
122647
+ const resolvedDir = existsSync61(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
122632
122648
  canonicalPath = join69(resolvedDir, basename11(absolutePath));
122633
122649
  }
122634
- return normalize2(canonicalPath);
122650
+ return normalize3(canonicalPath);
122635
122651
  }
122636
122652
  function isOverwriteEnabled(value) {
122637
122653
  if (value === true) {
@@ -123905,23 +123921,23 @@ init_logger();
123905
123921
  init_plugin_identity();
123906
123922
 
123907
123923
  // src/hooks/legacy-plugin-toast/auto-migrate.ts
123908
- import { existsSync as existsSync61, readFileSync as readFileSync45 } from "fs";
123924
+ import { existsSync as existsSync62, readFileSync as readFileSync46 } from "fs";
123909
123925
  import { join as join70 } from "path";
123910
123926
  init_plugin_identity();
123911
123927
  function detectOpenCodeConfigPath(overrideConfigDir) {
123912
123928
  if (overrideConfigDir) {
123913
123929
  const jsoncPath = join70(overrideConfigDir, "opencode.jsonc");
123914
123930
  const jsonPath = join70(overrideConfigDir, "opencode.json");
123915
- if (existsSync61(jsoncPath))
123931
+ if (existsSync62(jsoncPath))
123916
123932
  return jsoncPath;
123917
- if (existsSync61(jsonPath))
123933
+ if (existsSync62(jsonPath))
123918
123934
  return jsonPath;
123919
123935
  return null;
123920
123936
  }
123921
123937
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
123922
- if (existsSync61(paths.configJsonc))
123938
+ if (existsSync62(paths.configJsonc))
123923
123939
  return paths.configJsonc;
123924
- if (existsSync61(paths.configJson))
123940
+ if (existsSync62(paths.configJson))
123925
123941
  return paths.configJson;
123926
123942
  return null;
123927
123943
  }
@@ -123930,7 +123946,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
123930
123946
  if (!configPath)
123931
123947
  return { migrated: false, from: null, to: null, configPath: null };
123932
123948
  try {
123933
- const content = readFileSync45(configPath, "utf-8");
123949
+ const content = readFileSync46(configPath, "utf-8");
123934
123950
  const parseResult = parseJsoncSafe(content);
123935
123951
  if (!parseResult.data?.plugin)
123936
123952
  return { migrated: false, from: null, to: null, configPath };
@@ -124048,7 +124064,7 @@ async function queryOllama(args) {
124048
124064
  }
124049
124065
 
124050
124066
  // src/hooks/fast-apply/tool-execute-before-handler.ts
124051
- import { existsSync as existsSync62, readFileSync as readFileSync46 } from "fs";
124067
+ import { existsSync as existsSync63, readFileSync as readFileSync47 } from "fs";
124052
124068
  async function handleFastApplyToolExecuteBefore(args) {
124053
124069
  const { input, output, config: config2 } = args;
124054
124070
  const normalizedTool = input.tool.toLowerCase();
@@ -124067,7 +124083,7 @@ async function handleFastApplyToolExecuteBefore(args) {
124067
124083
  });
124068
124084
  return;
124069
124085
  }
124070
- if (!existsSync62(filePath)) {
124086
+ if (!existsSync63(filePath)) {
124071
124087
  log("[fast-apply] Skipping: file does not exist (new file)", {
124072
124088
  sessionID: input.sessionID,
124073
124089
  callID: input.callID,
@@ -124077,7 +124093,7 @@ async function handleFastApplyToolExecuteBefore(args) {
124077
124093
  }
124078
124094
  let originalContent;
124079
124095
  try {
124080
- originalContent = readFileSync46(filePath, "utf-8");
124096
+ originalContent = readFileSync47(filePath, "utf-8");
124081
124097
  } catch (err) {
124082
124098
  log("[fast-apply] Failed to read file, falling back to default", {
124083
124099
  sessionID: input.sessionID,
@@ -124456,13 +124472,13 @@ var DEFAULT_MAX_SYMBOLS = 200;
124456
124472
  var DEFAULT_MAX_DIAGNOSTICS = 200;
124457
124473
  var DEFAULT_MAX_DIRECTORY_FILES = 50;
124458
124474
  // src/tools/lsp/server-config-loader.ts
124459
- import { existsSync as existsSync63, readFileSync as readFileSync47 } from "fs";
124475
+ import { existsSync as existsSync64, readFileSync as readFileSync48 } from "fs";
124460
124476
  import { join as join71 } from "path";
124461
124477
  function loadJsonFile(path7) {
124462
- if (!existsSync63(path7))
124478
+ if (!existsSync64(path7))
124463
124479
  return null;
124464
124480
  try {
124465
- return parseJsonc(readFileSync47(path7, "utf-8"));
124481
+ return parseJsonc(readFileSync48(path7, "utf-8"));
124466
124482
  } catch {
124467
124483
  return null;
124468
124484
  }
@@ -124542,7 +124558,7 @@ function getMergedServers() {
124542
124558
  }
124543
124559
 
124544
124560
  // src/tools/lsp/server-installation.ts
124545
- import { existsSync as existsSync64 } from "fs";
124561
+ import { existsSync as existsSync65 } from "fs";
124546
124562
  import { delimiter, join as join73 } from "path";
124547
124563
 
124548
124564
  // src/tools/lsp/server-path-bases.ts
@@ -124565,7 +124581,7 @@ function isServerInstalled(command) {
124565
124581
  return false;
124566
124582
  const cmd = command[0];
124567
124583
  if (cmd.includes("/") || cmd.includes("\\")) {
124568
- if (existsSync64(cmd))
124584
+ if (existsSync65(cmd))
124569
124585
  return true;
124570
124586
  }
124571
124587
  const isWindows2 = process.platform === "win32";
@@ -124586,14 +124602,14 @@ function isServerInstalled(command) {
124586
124602
  const paths = pathEnv.split(delimiter);
124587
124603
  for (const p of paths) {
124588
124604
  for (const suffix of exts) {
124589
- if (existsSync64(join73(p, cmd + suffix))) {
124605
+ if (existsSync65(join73(p, cmd + suffix))) {
124590
124606
  return true;
124591
124607
  }
124592
124608
  }
124593
124609
  }
124594
124610
  for (const base of getLspServerAdditionalPathBases(process.cwd())) {
124595
124611
  for (const suffix of exts) {
124596
- if (existsSync64(join73(base, cmd + suffix))) {
124612
+ if (existsSync65(join73(base, cmd + suffix))) {
124597
124613
  return true;
124598
124614
  }
124599
124615
  }
@@ -124651,13 +124667,13 @@ function getLanguageId(ext) {
124651
124667
  init_logger();
124652
124668
  var {spawn: bunSpawn2 } = globalThis.Bun;
124653
124669
  import { spawn as nodeSpawn2 } from "child_process";
124654
- import { existsSync as existsSync65, statSync as statSync7 } from "fs";
124670
+ import { existsSync as existsSync66, statSync as statSync7 } from "fs";
124655
124671
  function shouldUseNodeSpawn() {
124656
124672
  return process.platform === "win32";
124657
124673
  }
124658
124674
  function validateCwd(cwd) {
124659
124675
  try {
124660
- if (!existsSync65(cwd)) {
124676
+ if (!existsSync66(cwd)) {
124661
124677
  return { valid: false, error: `Working directory does not exist: ${cwd}` };
124662
124678
  }
124663
124679
  const stats = statSync7(cwd);
@@ -124789,7 +124805,7 @@ function spawnProcess(command, options) {
124789
124805
  return proc;
124790
124806
  }
124791
124807
  // src/tools/lsp/lsp-client.ts
124792
- import { readFileSync as readFileSync48 } from "fs";
124808
+ import { readFileSync as readFileSync49 } from "fs";
124793
124809
  import { extname as extname4, resolve as resolve15 } from "path";
124794
124810
  import { pathToFileURL as pathToFileURL2 } from "url";
124795
124811
 
@@ -125061,7 +125077,7 @@ class LSPClient extends LSPClientConnection {
125061
125077
  async openFile(filePath) {
125062
125078
  const absPath = resolve15(filePath);
125063
125079
  const uri = pathToFileURL2(absPath).href;
125064
- const text = readFileSync48(absPath, "utf-8");
125080
+ const text = readFileSync49(absPath, "utf-8");
125065
125081
  if (!this.openedFiles.has(absPath)) {
125066
125082
  const ext = extname4(absPath);
125067
125083
  const languageId = getLanguageId(ext);
@@ -125419,10 +125435,10 @@ var lspManager = LSPServerManager.getInstance();
125419
125435
  // src/tools/lsp/lsp-client-wrapper.ts
125420
125436
  import { extname as extname5, resolve as resolve16 } from "path";
125421
125437
  import { fileURLToPath as fileURLToPath2 } from "url";
125422
- import { existsSync as existsSync66, statSync as statSync8 } from "fs";
125438
+ import { existsSync as existsSync67, statSync as statSync8 } from "fs";
125423
125439
  init_plugin_identity();
125424
125440
  function isDirectoryPath(filePath) {
125425
- if (!existsSync66(filePath)) {
125441
+ if (!existsSync67(filePath)) {
125426
125442
  return false;
125427
125443
  }
125428
125444
  return statSync8(filePath).isDirectory();
@@ -125432,14 +125448,14 @@ function uriToPath(uri) {
125432
125448
  }
125433
125449
  function findWorkspaceRoot(filePath) {
125434
125450
  let dir = resolve16(filePath);
125435
- if (!existsSync66(dir) || !isDirectoryPath(dir)) {
125451
+ if (!existsSync67(dir) || !isDirectoryPath(dir)) {
125436
125452
  dir = __require("path").dirname(dir);
125437
125453
  }
125438
125454
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
125439
125455
  let prevDir = "";
125440
125456
  while (dir !== prevDir) {
125441
125457
  for (const marker of markers) {
125442
- if (existsSync66(__require("path").join(dir, marker))) {
125458
+ if (existsSync67(__require("path").join(dir, marker))) {
125443
125459
  return dir;
125444
125460
  }
125445
125461
  }
@@ -125614,10 +125630,10 @@ function formatApplyResult(result) {
125614
125630
  `);
125615
125631
  }
125616
125632
  // src/tools/lsp/workspace-edit.ts
125617
- import { readFileSync as readFileSync49, writeFileSync as writeFileSync17 } from "fs";
125633
+ import { readFileSync as readFileSync50, writeFileSync as writeFileSync17 } from "fs";
125618
125634
  function applyTextEditsToFile(filePath, edits) {
125619
125635
  try {
125620
- let content = readFileSync49(filePath, "utf-8");
125636
+ let content = readFileSync50(filePath, "utf-8");
125621
125637
  const lines = content.split(`
125622
125638
  `);
125623
125639
  const sortedEdits = [...edits].sort((a, b) => {
@@ -125683,7 +125699,7 @@ function applyWorkspaceEdit(edit) {
125683
125699
  try {
125684
125700
  const oldPath = uriToPath(change.oldUri);
125685
125701
  const newPath = uriToPath(change.newUri);
125686
- const content = readFileSync49(oldPath, "utf-8");
125702
+ const content = readFileSync50(oldPath, "utf-8");
125687
125703
  writeFileSync17(newPath, content, "utf-8");
125688
125704
  __require("fs").unlinkSync(oldPath);
125689
125705
  result.filesModified.push(newPath);
@@ -125849,7 +125865,7 @@ init_tool();
125849
125865
  import { resolve as resolve18 } from "path";
125850
125866
 
125851
125867
  // src/tools/lsp/directory-diagnostics.ts
125852
- import { existsSync as existsSync67, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
125868
+ import { existsSync as existsSync68, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
125853
125869
  import { extname as extname6, join as join74, resolve as resolve17 } from "path";
125854
125870
  var SKIP_DIRECTORIES = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
125855
125871
  function collectFilesWithExtension(dir, extension, maxFiles) {
@@ -125895,7 +125911,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
125895
125911
  throw new Error(`Extension must start with a dot (e.g., ".ts", not "${extension}"). ` + `Use ".${extension}" instead.`);
125896
125912
  }
125897
125913
  const absDir = resolve17(directory);
125898
- if (!existsSync67(absDir)) {
125914
+ if (!existsSync68(absDir)) {
125899
125915
  throw new Error(`Directory does not exist: ${absDir}`);
125900
125916
  }
125901
125917
  const serverResult = findServerForExtension(extension);
@@ -126156,11 +126172,11 @@ var DEFAULT_MAX_MATCHES = 500;
126156
126172
 
126157
126173
  // src/tools/ast-grep/sg-cli-path.ts
126158
126174
  import { createRequire as createRequire4 } from "module";
126159
- import { dirname as dirname21, join as join77 } from "path";
126160
- import { existsSync as existsSync69, statSync as statSync9 } from "fs";
126175
+ import { dirname as dirname22, join as join77 } from "path";
126176
+ import { existsSync as existsSync70, statSync as statSync9 } from "fs";
126161
126177
 
126162
126178
  // src/tools/ast-grep/downloader.ts
126163
- import { existsSync as existsSync68 } from "fs";
126179
+ import { existsSync as existsSync69 } from "fs";
126164
126180
  import { join as join76 } from "path";
126165
126181
  import { homedir as homedir14 } from "os";
126166
126182
  import { createRequire as createRequire3 } from "module";
@@ -126212,7 +126228,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
126212
126228
  const cacheDir = getCacheDir3();
126213
126229
  const binaryName = getBinaryName3();
126214
126230
  const binaryPath = join76(cacheDir, binaryName);
126215
- if (existsSync68(binaryPath)) {
126231
+ if (existsSync69(binaryPath)) {
126216
126232
  return binaryPath;
126217
126233
  }
126218
126234
  const { arch, os: os4 } = platformInfo;
@@ -126273,9 +126289,9 @@ function findSgCliPathSync() {
126273
126289
  try {
126274
126290
  const require2 = createRequire4(import.meta.url);
126275
126291
  const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
126276
- const cliDirectory = dirname21(cliPackageJsonPath);
126292
+ const cliDirectory = dirname22(cliPackageJsonPath);
126277
126293
  const sgPath = join77(cliDirectory, binaryName);
126278
- if (existsSync69(sgPath) && isValidBinary(sgPath)) {
126294
+ if (existsSync70(sgPath) && isValidBinary(sgPath)) {
126279
126295
  return sgPath;
126280
126296
  }
126281
126297
  } catch {}
@@ -126284,10 +126300,10 @@ function findSgCliPathSync() {
126284
126300
  try {
126285
126301
  const require2 = createRequire4(import.meta.url);
126286
126302
  const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
126287
- const packageDirectory = dirname21(packageJsonPath);
126303
+ const packageDirectory = dirname22(packageJsonPath);
126288
126304
  const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
126289
126305
  const binaryPath = join77(packageDirectory, astGrepBinaryName);
126290
- if (existsSync69(binaryPath) && isValidBinary(binaryPath)) {
126306
+ if (existsSync70(binaryPath) && isValidBinary(binaryPath)) {
126291
126307
  return binaryPath;
126292
126308
  }
126293
126309
  } catch {}
@@ -126295,7 +126311,7 @@ function findSgCliPathSync() {
126295
126311
  if (process.platform === "darwin") {
126296
126312
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
126297
126313
  for (const path7 of homebrewPaths) {
126298
- if (existsSync69(path7) && isValidBinary(path7)) {
126314
+ if (existsSync70(path7) && isValidBinary(path7)) {
126299
126315
  return path7;
126300
126316
  }
126301
126317
  }
@@ -126319,14 +126335,14 @@ function setSgCliPath(path7) {
126319
126335
  }
126320
126336
  // src/tools/ast-grep/cli.ts
126321
126337
  var {spawn: spawn17 } = globalThis.Bun;
126322
- import { existsSync as existsSync71 } from "fs";
126338
+ import { existsSync as existsSync72 } from "fs";
126323
126339
 
126324
126340
  // src/tools/ast-grep/cli-binary-path-resolution.ts
126325
- import { existsSync as existsSync70 } from "fs";
126341
+ import { existsSync as existsSync71 } from "fs";
126326
126342
  var resolvedCliPath3 = null;
126327
126343
  var initPromise3 = null;
126328
126344
  async function getAstGrepPath() {
126329
- if (resolvedCliPath3 !== null && existsSync70(resolvedCliPath3)) {
126345
+ if (resolvedCliPath3 !== null && existsSync71(resolvedCliPath3)) {
126330
126346
  return resolvedCliPath3;
126331
126347
  }
126332
126348
  if (initPromise3) {
@@ -126334,7 +126350,7 @@ async function getAstGrepPath() {
126334
126350
  }
126335
126351
  initPromise3 = (async () => {
126336
126352
  const syncPath = findSgCliPathSync();
126337
- if (syncPath && existsSync70(syncPath)) {
126353
+ if (syncPath && existsSync71(syncPath)) {
126338
126354
  resolvedCliPath3 = syncPath;
126339
126355
  setSgCliPath(syncPath);
126340
126356
  return syncPath;
@@ -126433,7 +126449,7 @@ async function runSg(options) {
126433
126449
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
126434
126450
  args.push(...paths);
126435
126451
  let cliPath = getSgCliPath();
126436
- if (!cliPath || !existsSync71(cliPath)) {
126452
+ if (!cliPath || !existsSync72(cliPath)) {
126437
126453
  const downloadedPath = await getAstGrepPath();
126438
126454
  if (downloadedPath) {
126439
126455
  cliPath = downloadedPath;
@@ -126688,12 +126704,12 @@ import { resolve as resolve19 } from "path";
126688
126704
  var {spawn: spawn18 } = globalThis.Bun;
126689
126705
 
126690
126706
  // src/tools/grep/constants.ts
126691
- import { existsSync as existsSync73 } from "fs";
126692
- import { join as join79, dirname as dirname22 } from "path";
126707
+ import { existsSync as existsSync74 } from "fs";
126708
+ import { join as join79, dirname as dirname23 } from "path";
126693
126709
  import { spawnSync as spawnSync4 } from "child_process";
126694
126710
 
126695
126711
  // src/tools/grep/downloader.ts
126696
- import { existsSync as existsSync72, readdirSync as readdirSync21 } from "fs";
126712
+ import { existsSync as existsSync73, readdirSync as readdirSync21 } from "fs";
126697
126713
  import { join as join78 } from "path";
126698
126714
  init_plugin_identity();
126699
126715
  function findFileRecursive(dir, filename) {
@@ -126758,7 +126774,7 @@ async function downloadAndInstallRipgrep() {
126758
126774
  }
126759
126775
  const installDir = getInstallDir();
126760
126776
  const rgPath = getRgPath();
126761
- if (existsSync72(rgPath)) {
126777
+ if (existsSync73(rgPath)) {
126762
126778
  return rgPath;
126763
126779
  }
126764
126780
  ensureCacheDir(installDir);
@@ -126773,7 +126789,7 @@ async function downloadAndInstallRipgrep() {
126773
126789
  await extractZip2(archivePath, installDir);
126774
126790
  }
126775
126791
  ensureExecutable(rgPath);
126776
- if (!existsSync72(rgPath)) {
126792
+ if (!existsSync73(rgPath)) {
126777
126793
  throw new Error("ripgrep binary not found after extraction");
126778
126794
  }
126779
126795
  return rgPath;
@@ -126785,7 +126801,7 @@ async function downloadAndInstallRipgrep() {
126785
126801
  }
126786
126802
  function getInstalledRipgrepPath() {
126787
126803
  const rgPath = getRgPath();
126788
- return existsSync72(rgPath) ? rgPath : null;
126804
+ return existsSync73(rgPath) ? rgPath : null;
126789
126805
  }
126790
126806
 
126791
126807
  // src/tools/grep/constants.ts
@@ -126807,7 +126823,7 @@ function findExecutable(name) {
126807
126823
  }
126808
126824
  function getOpenCodeBundledRg() {
126809
126825
  const execPath = process.execPath;
126810
- const execDir = dirname22(execPath);
126826
+ const execDir = dirname23(execPath);
126811
126827
  const isWindows2 = process.platform === "win32";
126812
126828
  const rgName = isWindows2 ? "rg.exe" : "rg";
126813
126829
  const candidates = [
@@ -126818,7 +126834,7 @@ function getOpenCodeBundledRg() {
126818
126834
  join79(execDir, "..", "libexec", rgName)
126819
126835
  ];
126820
126836
  for (const candidate of candidates) {
126821
- if (existsSync73(candidate)) {
126837
+ if (existsSync74(candidate)) {
126822
126838
  return candidate;
126823
126839
  }
126824
126840
  }
@@ -127470,10 +127486,10 @@ Use this when a task matches an available skill's or command's description.
127470
127486
  `;
127471
127487
  // src/tools/skill/tools.ts
127472
127488
  init_dist();
127473
- import { dirname as dirname24 } from "path";
127489
+ import { dirname as dirname25 } from "path";
127474
127490
 
127475
127491
  // src/tools/slashcommand/command-output-formatter.ts
127476
- import { dirname as dirname23 } from "path";
127492
+ import { dirname as dirname24 } from "path";
127477
127493
  async function formatLoadedCommand(command, userMessage) {
127478
127494
  const sections = [];
127479
127495
  sections.push(`# /${command.name} Command
@@ -127512,7 +127528,7 @@ async function formatLoadedCommand(command, userMessage) {
127512
127528
  if (!content && command.lazyContentLoader) {
127513
127529
  content = await command.lazyContentLoader.load();
127514
127530
  }
127515
- const commandDir = command.path ? dirname23(command.path) : process.cwd();
127531
+ const commandDir = command.path ? dirname24(command.path) : process.cwd();
127516
127532
  const withFileReferences = await resolveFileReferencesInText(content, commandDir);
127517
127533
  const resolvedContent = await resolveCommandsInText(withFileReferences);
127518
127534
  let finalContent = resolvedContent.trim();
@@ -127902,7 +127918,7 @@ function createSkillTool(options = {}) {
127902
127918
  if (matchedSkill.name === "git-master") {
127903
127919
  body = injectGitMasterConfig(body, options.gitMasterConfig);
127904
127920
  }
127905
- const dir = matchedSkill.path ? dirname24(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
127921
+ const dir = matchedSkill.path ? dirname25(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
127906
127922
  const output = [
127907
127923
  `## Skill: ${matchedSkill.name}`,
127908
127924
  "",
@@ -128020,11 +128036,11 @@ Has Todos: Yes (12 items, 8 completed)
128020
128036
  Has Transcript: Yes (234 entries)`;
128021
128037
 
128022
128038
  // src/tools/session-manager/file-storage.ts
128023
- import { existsSync as existsSync74 } from "fs";
128039
+ import { existsSync as existsSync75 } from "fs";
128024
128040
  import { readdir, readFile } from "fs/promises";
128025
128041
  import { join as join81 } from "path";
128026
128042
  async function getFileMainSessions(directory) {
128027
- if (!existsSync74(SESSION_STORAGE))
128043
+ if (!existsSync75(SESSION_STORAGE))
128028
128044
  return [];
128029
128045
  const sessions = [];
128030
128046
  try {
@@ -128056,7 +128072,7 @@ async function getFileMainSessions(directory) {
128056
128072
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
128057
128073
  }
128058
128074
  async function getFileAllSessions() {
128059
- if (!existsSync74(MESSAGE_STORAGE))
128075
+ if (!existsSync75(MESSAGE_STORAGE))
128060
128076
  return [];
128061
128077
  const sessions = [];
128062
128078
  async function scanDirectory(dir) {
@@ -128085,7 +128101,7 @@ async function fileSessionExists(sessionID) {
128085
128101
  }
128086
128102
  async function getFileSessionMessages(sessionID) {
128087
128103
  const messageDir = getMessageDir(sessionID);
128088
- if (!messageDir || !existsSync74(messageDir))
128104
+ if (!messageDir || !existsSync75(messageDir))
128089
128105
  return [];
128090
128106
  const messages = [];
128091
128107
  try {
@@ -128121,7 +128137,7 @@ async function getFileSessionMessages(sessionID) {
128121
128137
  }
128122
128138
  async function readParts2(messageID) {
128123
128139
  const partDir = join81(PART_STORAGE, messageID);
128124
- if (!existsSync74(partDir))
128140
+ if (!existsSync75(partDir))
128125
128141
  return [];
128126
128142
  const parts = [];
128127
128143
  try {
@@ -128142,7 +128158,7 @@ async function readParts2(messageID) {
128142
128158
  return parts.sort((a, b) => a.id.localeCompare(b.id));
128143
128159
  }
128144
128160
  async function getFileSessionTodos(sessionID) {
128145
- if (!existsSync74(TODO_DIR2))
128161
+ if (!existsSync75(TODO_DIR2))
128146
128162
  return [];
128147
128163
  try {
128148
128164
  const allFiles = await readdir(TODO_DIR2);
@@ -128169,10 +128185,10 @@ async function getFileSessionTodos(sessionID) {
128169
128185
  return [];
128170
128186
  }
128171
128187
  async function getFileSessionTranscript(sessionID) {
128172
- if (!existsSync74(TRANSCRIPT_DIR2))
128188
+ if (!existsSync75(TRANSCRIPT_DIR2))
128173
128189
  return 0;
128174
128190
  const transcriptFile = join81(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
128175
- if (!existsSync74(transcriptFile))
128191
+ if (!existsSync75(transcriptFile))
128176
128192
  return 0;
128177
128193
  try {
128178
128194
  const content = await readFile(transcriptFile, "utf-8");
@@ -130552,9 +130568,9 @@ async function resolveMultimodalLookerAgentMetadata(ctx) {
130552
130568
 
130553
130569
  // src/tools/look-at/image-converter.ts
130554
130570
  import * as childProcess from "child_process";
130555
- import { existsSync as existsSync75, mkdtempSync, readFileSync as readFileSync50, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
130571
+ import { existsSync as existsSync76, mkdtempSync, readFileSync as readFileSync51, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
130556
130572
  import { tmpdir as tmpdir7 } from "os";
130557
- import { dirname as dirname25, join as join82 } from "path";
130573
+ import { dirname as dirname26, join as join82 } from "path";
130558
130574
  var SUPPORTED_FORMATS = new Set([
130559
130575
  "image/jpeg",
130560
130576
  "image/png",
@@ -130592,7 +130608,7 @@ function needsConversion(mimeType) {
130592
130608
  return mimeType.startsWith("image/");
130593
130609
  }
130594
130610
  function convertImageToJpeg(inputPath, mimeType) {
130595
- if (!existsSync75(inputPath)) {
130611
+ if (!existsSync76(inputPath)) {
130596
130612
  throw new Error(`File not found: ${inputPath}`);
130597
130613
  }
130598
130614
  const tempDir = mkdtempSync(join82(tmpdir7(), "opencode-img-"));
@@ -130606,7 +130622,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130606
130622
  encoding: "utf-8",
130607
130623
  timeout: CONVERSION_TIMEOUT_MS
130608
130624
  });
130609
- if (existsSync75(outputPath)) {
130625
+ if (existsSync76(outputPath)) {
130610
130626
  log(`[image-converter] Converted using sips: ${outputPath}`);
130611
130627
  return outputPath;
130612
130628
  }
@@ -130621,7 +130637,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130621
130637
  encoding: "utf-8",
130622
130638
  timeout: CONVERSION_TIMEOUT_MS
130623
130639
  });
130624
- if (existsSync75(outputPath)) {
130640
+ if (existsSync76(outputPath)) {
130625
130641
  log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
130626
130642
  return outputPath;
130627
130643
  }
@@ -130634,7 +130650,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130634
130650
  ` + ` RHEL/CentOS: sudo yum install ImageMagick`);
130635
130651
  } catch (error92) {
130636
130652
  try {
130637
- if (existsSync75(outputPath)) {
130653
+ if (existsSync76(outputPath)) {
130638
130654
  unlinkSync10(outputPath);
130639
130655
  }
130640
130656
  } catch {}
@@ -130647,12 +130663,12 @@ function convertImageToJpeg(inputPath, mimeType) {
130647
130663
  }
130648
130664
  function cleanupConvertedImage(filePath) {
130649
130665
  try {
130650
- const tempDirectory = dirname25(filePath);
130651
- if (existsSync75(filePath)) {
130666
+ const tempDirectory = dirname26(filePath);
130667
+ if (existsSync76(filePath)) {
130652
130668
  unlinkSync10(filePath);
130653
130669
  log(`[image-converter] Cleaned up temporary file: ${filePath}`);
130654
130670
  }
130655
- if (existsSync75(tempDirectory)) {
130671
+ if (existsSync76(tempDirectory)) {
130656
130672
  rmSync3(tempDirectory, { recursive: true, force: true });
130657
130673
  log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
130658
130674
  }
@@ -130672,14 +130688,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
130672
130688
  log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
130673
130689
  const outputPath = convertImageToJpeg(inputPath, mimeType);
130674
130690
  tempFiles.push(outputPath);
130675
- const convertedBuffer = readFileSync50(outputPath);
130691
+ const convertedBuffer = readFileSync51(outputPath);
130676
130692
  const convertedBase64 = convertedBuffer.toString("base64");
130677
130693
  log(`[image-converter] Base64 conversion successful`);
130678
130694
  return { base64: convertedBase64, tempFiles };
130679
130695
  } catch (error92) {
130680
130696
  tempFiles.forEach((file3) => {
130681
130697
  try {
130682
- if (existsSync75(file3))
130698
+ if (existsSync76(file3))
130683
130699
  unlinkSync10(file3);
130684
130700
  } catch {}
130685
130701
  });
@@ -132860,22 +132876,22 @@ function applyFallbackEntrySettings(input) {
132860
132876
  // src/tools/delegate-task/subagent-discovery.ts
132861
132877
  init_agent_display_names();
132862
132878
  // src/features/claude-code-agent-loader/loader.ts
132863
- import { existsSync as existsSync78, readdirSync as readdirSync22 } from "fs";
132879
+ import { existsSync as existsSync79, readdirSync as readdirSync22 } from "fs";
132864
132880
  import { join as join83 } from "path";
132865
132881
 
132866
132882
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
132867
- import { existsSync as existsSync77, readFileSync as readFileSync52 } from "fs";
132883
+ import { existsSync as existsSync78, readFileSync as readFileSync53 } from "fs";
132868
132884
  import { basename as basename13, extname as extname8 } from "path";
132869
132885
  init_logger();
132870
132886
 
132871
132887
  // src/features/claude-code-agent-loader/json-agent-loader.ts
132872
- import { existsSync as existsSync76, readFileSync as readFileSync51 } from "fs";
132888
+ import { existsSync as existsSync77, readFileSync as readFileSync52 } from "fs";
132873
132889
  function parseJsonAgentFile(filePath, scope) {
132874
132890
  try {
132875
- if (!existsSync76(filePath)) {
132891
+ if (!existsSync77(filePath)) {
132876
132892
  return null;
132877
132893
  }
132878
- const content = readFileSync51(filePath, "utf-8");
132894
+ const content = readFileSync52(filePath, "utf-8");
132879
132895
  const { data } = parseJsoncSafe(content);
132880
132896
  if (!data) {
132881
132897
  return null;
@@ -132911,10 +132927,10 @@ function parseJsonAgentFile(filePath, scope) {
132911
132927
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
132912
132928
  function parseMarkdownAgentFile(filePath, scope) {
132913
132929
  try {
132914
- if (!existsSync77(filePath)) {
132930
+ if (!existsSync78(filePath)) {
132915
132931
  return null;
132916
132932
  }
132917
- const content = readFileSync52(filePath, "utf-8");
132933
+ const content = readFileSync53(filePath, "utf-8");
132918
132934
  const { data, body } = parseFrontmatter(content);
132919
132935
  const fileName = basename13(filePath);
132920
132936
  const agentName = fileName.replace(/\.md$/i, "");
@@ -132946,7 +132962,7 @@ function parseMarkdownAgentFile(filePath, scope) {
132946
132962
  function loadAgentDefinitions(paths, scope) {
132947
132963
  const result = Object.create(null);
132948
132964
  for (const filePath of paths) {
132949
- if (!existsSync77(filePath)) {
132965
+ if (!existsSync78(filePath)) {
132950
132966
  log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
132951
132967
  continue;
132952
132968
  }
@@ -132971,7 +132987,7 @@ function loadAgentDefinitions(paths, scope) {
132971
132987
 
132972
132988
  // src/features/claude-code-agent-loader/loader.ts
132973
132989
  function loadAgentsFromDir(agentsDir, scope) {
132974
- if (!existsSync78(agentsDir)) {
132990
+ if (!existsSync79(agentsDir)) {
132975
132991
  return [];
132976
132992
  }
132977
132993
  const entries = readdirSync22(agentsDir, { withFileTypes: true });
@@ -133613,8 +133629,8 @@ var TaskDeleteInputSchema = exports_external.object({
133613
133629
  });
133614
133630
 
133615
133631
  // src/features/claude-tasks/storage.ts
133616
- import { join as join85, dirname as dirname27, basename as basename14, isAbsolute as isAbsolute12 } from "path";
133617
- import { existsSync as existsSync80, mkdirSync as mkdirSync16, readFileSync as readFileSync54, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
133632
+ import { join as join85, dirname as dirname28, basename as basename14, isAbsolute as isAbsolute12 } from "path";
133633
+ import { existsSync as existsSync81, mkdirSync as mkdirSync16, readFileSync as readFileSync55, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
133618
133634
  import { randomUUID as randomUUID2 } from "crypto";
133619
133635
  function getTaskDir(config4 = {}) {
133620
133636
  const tasksConfig = config4.bob?.tasks;
@@ -133642,16 +133658,16 @@ function resolveTaskListId(config4 = {}) {
133642
133658
  return sanitizePathSegment(basename14(process.cwd()));
133643
133659
  }
133644
133660
  function ensureDir(dirPath) {
133645
- if (!existsSync80(dirPath)) {
133661
+ if (!existsSync81(dirPath)) {
133646
133662
  mkdirSync16(dirPath, { recursive: true });
133647
133663
  }
133648
133664
  }
133649
133665
  function readJsonSafe(filePath, schema2) {
133650
133666
  try {
133651
- if (!existsSync80(filePath)) {
133667
+ if (!existsSync81(filePath)) {
133652
133668
  return null;
133653
133669
  }
133654
- const content = readFileSync54(filePath, "utf-8");
133670
+ const content = readFileSync55(filePath, "utf-8");
133655
133671
  const parsed = JSON.parse(content);
133656
133672
  const result = schema2.safeParse(parsed);
133657
133673
  if (!result.success) {
@@ -133663,7 +133679,7 @@ function readJsonSafe(filePath, schema2) {
133663
133679
  }
133664
133680
  }
133665
133681
  function writeJsonAtomic(filePath, data) {
133666
- const dir = dirname27(filePath);
133682
+ const dir = dirname28(filePath);
133667
133683
  ensureDir(dir);
133668
133684
  const tempPath = `${filePath}.tmp.${Date.now()}`;
133669
133685
  try {
@@ -133671,7 +133687,7 @@ function writeJsonAtomic(filePath, data) {
133671
133687
  renameSync4(tempPath, filePath);
133672
133688
  } catch (error92) {
133673
133689
  try {
133674
- if (existsSync80(tempPath)) {
133690
+ if (existsSync81(tempPath)) {
133675
133691
  unlinkSync11(tempPath);
133676
133692
  }
133677
133693
  } catch {}
@@ -133693,7 +133709,7 @@ function acquireLock(dirPath) {
133693
133709
  };
133694
133710
  const isStale = () => {
133695
133711
  try {
133696
- const lockContent = readFileSync54(lockPath, "utf-8");
133712
+ const lockContent = readFileSync55(lockPath, "utf-8");
133697
133713
  const lockData = JSON.parse(lockContent);
133698
133714
  const lockAge = Date.now() - lockData.timestamp;
133699
133715
  return lockAge > STALE_LOCK_THRESHOLD_MS;
@@ -133731,9 +133747,9 @@ function acquireLock(dirPath) {
133731
133747
  acquired: true,
133732
133748
  release: () => {
133733
133749
  try {
133734
- if (!existsSync80(lockPath))
133750
+ if (!existsSync81(lockPath))
133735
133751
  return;
133736
- const lockContent = readFileSync54(lockPath, "utf-8");
133752
+ const lockContent = readFileSync55(lockPath, "utf-8");
133737
133753
  const lockData = JSON.parse(lockContent);
133738
133754
  if (lockData.id !== lockId)
133739
133755
  return;
@@ -133959,7 +133975,7 @@ Returns null if the task does not exist or the file is invalid.`,
133959
133975
  // src/tools/task/task-list.ts
133960
133976
  init_tool();
133961
133977
  import { join as join88 } from "path";
133962
- import { existsSync as existsSync81, readdirSync as readdirSync24 } from "fs";
133978
+ import { existsSync as existsSync82, readdirSync as readdirSync24 } from "fs";
133963
133979
  function createTaskList(config4) {
133964
133980
  return tool({
133965
133981
  description: `List all active tasks with summary information.
@@ -133970,7 +133986,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
133970
133986
  args: {},
133971
133987
  execute: async () => {
133972
133988
  const taskDir = getTaskDir(config4);
133973
- if (!existsSync81(taskDir)) {
133989
+ if (!existsSync82(taskDir)) {
133974
133990
  return JSON.stringify({ tasks: [] });
133975
133991
  }
133976
133992
  const files = readdirSync24(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
@@ -136273,7 +136289,7 @@ function createToolGuardHooks(args) {
136273
136289
  const readImageResizer = isHookEnabled("read-image-resizer") ? safeHook("read-image-resizer", () => createReadImageResizerHook(ctx)) : null;
136274
136290
  const todoDescriptionOverride = isHookEnabled("todo-description-override") ? safeHook("todo-description-override", () => createTodoDescriptionOverrideHook()) : null;
136275
136291
  const webfetchRedirectGuard = isHookEnabled("webfetch-redirect-guard") ? safeHook("webfetch-redirect-guard", () => createWebFetchRedirectGuardHook(ctx)) : null;
136276
- 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;
136292
+ const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "", model: "", timeout: 30000 })) : null;
136277
136293
  return {
136278
136294
  commentChecker,
136279
136295
  toolOutputTruncator,
@@ -137186,7 +137202,7 @@ function unregisterManagerForCleanup(manager) {
137186
137202
  }
137187
137203
 
137188
137204
  // src/features/background-agent/compaction-aware-message-resolver.ts
137189
- import { readdirSync as readdirSync25, readFileSync as readFileSync55 } from "fs";
137205
+ import { readdirSync as readdirSync25, readFileSync as readFileSync56 } from "fs";
137190
137206
  import { join as join91 } from "path";
137191
137207
  function hasFullAgentAndModel(message) {
137192
137208
  return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
@@ -137266,7 +137282,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
137266
137282
  const messages = [];
137267
137283
  for (const file3 of files) {
137268
137284
  try {
137269
- const content = readFileSync55(join91(messageDir, file3), "utf-8");
137285
+ const content = readFileSync56(join91(messageDir, file3), "utf-8");
137270
137286
  const parsed = JSON.parse(content);
137271
137287
  if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
137272
137288
  continue;
@@ -139363,8 +139379,8 @@ ${originalText}`;
139363
139379
  }
139364
139380
  }
139365
139381
  // src/features/mcp-oauth/storage.ts
139366
- import { chmodSync as chmodSync2, existsSync as existsSync82, mkdirSync as mkdirSync17, readFileSync as readFileSync56, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
139367
- import { dirname as dirname28, join as join93 } from "path";
139382
+ import { chmodSync as chmodSync2, existsSync as existsSync83, mkdirSync as mkdirSync17, readFileSync as readFileSync57, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
139383
+ import { dirname as dirname29, join as join93 } from "path";
139368
139384
  var STORAGE_FILE_NAME = "mcp-oauth.json";
139369
139385
  function getMcpOauthStoragePath() {
139370
139386
  return join93(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
@@ -139404,11 +139420,11 @@ function buildKey(serverHost, resource) {
139404
139420
  }
139405
139421
  function readStore() {
139406
139422
  const filePath = getMcpOauthStoragePath();
139407
- if (!existsSync82(filePath)) {
139423
+ if (!existsSync83(filePath)) {
139408
139424
  return null;
139409
139425
  }
139410
139426
  try {
139411
- const content = readFileSync56(filePath, "utf-8");
139427
+ const content = readFileSync57(filePath, "utf-8");
139412
139428
  return JSON.parse(content);
139413
139429
  } catch {
139414
139430
  return null;
@@ -139417,8 +139433,8 @@ function readStore() {
139417
139433
  function writeStore(store2) {
139418
139434
  const filePath = getMcpOauthStoragePath();
139419
139435
  try {
139420
- const dir = dirname28(filePath);
139421
- if (!existsSync82(dir)) {
139436
+ const dir = dirname29(filePath);
139437
+ if (!existsSync83(dir)) {
139422
139438
  mkdirSync17(dir, { recursive: true });
139423
139439
  }
139424
139440
  const tempPath = `${filePath}.tmp.${Date.now()}`;
@@ -146065,7 +146081,7 @@ class TmuxSessionManager {
146065
146081
  var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
146066
146082
  var MIN_STABILITY_TIME_MS4 = 10 * 1000;
146067
146083
  // src/features/claude-code-mcp-loader/loader.ts
146068
- import { existsSync as existsSync83, readFileSync as readFileSync57 } from "fs";
146084
+ import { existsSync as existsSync84, readFileSync as readFileSync58 } from "fs";
146069
146085
  import { join as join94 } from "path";
146070
146086
  import { homedir as homedir15 } from "os";
146071
146087
  init_logger();
@@ -146088,7 +146104,7 @@ function getMcpConfigPaths() {
146088
146104
  });
146089
146105
  }
146090
146106
  async function loadMcpConfigFile(filePath) {
146091
- if (!existsSync83(filePath)) {
146107
+ if (!existsSync84(filePath)) {
146092
146108
  return null;
146093
146109
  }
146094
146110
  try {
@@ -146104,10 +146120,10 @@ function getSystemMcpServerNames() {
146104
146120
  const paths = getMcpConfigPaths();
146105
146121
  const cwd = process.cwd();
146106
146122
  for (const { path: path9 } of paths) {
146107
- if (!existsSync83(path9))
146123
+ if (!existsSync84(path9))
146108
146124
  continue;
146109
146125
  try {
146110
- const content = readFileSync57(path9, "utf-8");
146126
+ const content = readFileSync58(path9, "utf-8");
146111
146127
  const config4 = JSON.parse(content);
146112
146128
  if (!config4?.mcpServers)
146113
146129
  continue;
@@ -150452,7 +150468,7 @@ var researcherPromptMetadata = {
150452
150468
  };
150453
150469
 
150454
150470
  // src/agents/builtin-agents/resolve-file-uri.ts
150455
- import { existsSync as existsSync84, readFileSync as readFileSync58 } from "fs";
150471
+ import { existsSync as existsSync85, readFileSync as readFileSync59 } from "fs";
150456
150472
  import { homedir as homedir16 } from "os";
150457
150473
  import { isAbsolute as isAbsolute13, resolve as resolve22 } from "path";
150458
150474
  init_logger();
@@ -150477,11 +150493,11 @@ function resolvePromptAppend(promptAppend, configDir) {
150477
150493
  });
150478
150494
  return `[WARNING: Path rejected: ${promptAppend}]`;
150479
150495
  }
150480
- if (!existsSync84(filePath)) {
150496
+ if (!existsSync85(filePath)) {
150481
150497
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
150482
150498
  }
150483
150499
  try {
150484
- return readFileSync58(filePath, "utf8");
150500
+ return readFileSync59(filePath, "utf8");
150485
150501
  } catch {
150486
150502
  return `[WARNING: Could not read file: ${promptAppend}]`;
150487
150503
  }
@@ -154115,6 +154131,28 @@ async function buildStrategistAgentConfig(params) {
154115
154131
  return merged;
154116
154132
  }
154117
154133
 
154134
+ // src/plugin/skill-discovery-config.ts
154135
+ var DEFAULT_SKILL_DISCOVERY = {
154136
+ config_sources: true,
154137
+ project_opencode: true,
154138
+ global_opencode: false,
154139
+ project_claude: false,
154140
+ global_claude: false,
154141
+ project_agents: false,
154142
+ global_agents: false
154143
+ };
154144
+ function resolveSkillDiscoveryConfig(pluginConfig) {
154145
+ const resolved = {
154146
+ ...DEFAULT_SKILL_DISCOVERY,
154147
+ ...pluginConfig.skill_discovery ?? {}
154148
+ };
154149
+ if (pluginConfig.claude_code?.skills === false) {
154150
+ resolved.project_claude = false;
154151
+ resolved.global_claude = false;
154152
+ }
154153
+ return resolved;
154154
+ }
154155
+
154118
154156
  // src/plugin-handlers/agent-config-handler.ts
154119
154157
  var CANONICAL_VISIBLE_AGENT_NAMES = [
154120
154158
  "Bob",
@@ -154177,8 +154215,9 @@ async function applyAgentConfig(params) {
154177
154215
  const migratedDisabledAgents = (params.pluginConfig.disabled_agents ?? []).map((agent) => {
154178
154216
  return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
154179
154217
  });
154180
- const includeClaudeSkillsForAwareness = params.pluginConfig.claude_code?.skills ?? true;
154218
+ const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
154181
154219
  const [
154220
+ discoveredManagedPluginSkills,
154182
154221
  discoveredConfigSourceSkills,
154183
154222
  discoveredUserSkills,
154184
154223
  discoveredProjectSkills,
@@ -154187,18 +154226,20 @@ async function applyAgentConfig(params) {
154187
154226
  discoveredOpencodeProjectSkills,
154188
154227
  discoveredGlobalAgentsSkills
154189
154228
  ] = await Promise.all([
154190
- discoverConfigSourceSkills({
154229
+ discoverManagedPluginSkills(),
154230
+ discovery2.config_sources ? discoverConfigSourceSkills({
154191
154231
  config: params.pluginConfig.skills,
154192
154232
  configDir: params.ctx.directory
154193
- }),
154194
- includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]),
154195
- includeClaudeSkillsForAwareness ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]),
154196
- includeClaudeSkillsForAwareness ? discoverProjectAgentsSkills(params.ctx.directory) : Promise.resolve([]),
154197
- discoverOpencodeGlobalSkills(),
154198
- discoverOpencodeProjectSkills(params.ctx.directory),
154199
- includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([])
154233
+ }) : Promise.resolve([]),
154234
+ discovery2.global_claude ? discoverUserClaudeSkills() : Promise.resolve([]),
154235
+ discovery2.project_claude ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]),
154236
+ discovery2.project_agents ? discoverProjectAgentsSkills(params.ctx.directory) : Promise.resolve([]),
154237
+ discovery2.global_opencode ? discoverOpencodeGlobalSkills() : Promise.resolve([]),
154238
+ discovery2.project_opencode ? discoverOpencodeProjectSkills(params.ctx.directory) : Promise.resolve([]),
154239
+ discovery2.global_agents ? discoverGlobalAgentsSkills() : Promise.resolve([])
154200
154240
  ]);
154201
154241
  const allDiscoveredSkills = [
154242
+ ...discoveredManagedPluginSkills,
154202
154243
  ...discoveredConfigSourceSkills,
154203
154244
  ...discoveredOpencodeProjectSkills,
154204
154245
  ...discoveredProjectSkills,
@@ -154531,9 +154572,9 @@ async function applyCommandConfig(params) {
154531
154572
  });
154532
154573
  const systemCommands = params.config.command ?? {};
154533
154574
  const includeClaudeCommands = params.pluginConfig.claude_code?.commands ?? true;
154534
- const includeClaudeSkills = params.pluginConfig.claude_code?.skills ?? true;
154575
+ const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
154535
154576
  const externalSkillPlugin = detectExternalSkillPlugin(params.ctx.directory);
154536
- if (includeClaudeSkills && externalSkillPlugin.detected) {
154577
+ if ((discovery2.project_claude || discovery2.global_claude || discovery2.global_opencode) && externalSkillPlugin.detected) {
154537
154578
  log(getSkillPluginConflictWarning(externalSkillPlugin.pluginName));
154538
154579
  }
154539
154580
  const [
@@ -154542,6 +154583,7 @@ async function applyCommandConfig(params) {
154542
154583
  projectCommands,
154543
154584
  opencodeGlobalCommands,
154544
154585
  opencodeProjectCommands,
154586
+ managedPluginSkills,
154545
154587
  userSkills,
154546
154588
  globalAgentsSkills,
154547
154589
  projectSkills,
@@ -154549,23 +154591,25 @@ async function applyCommandConfig(params) {
154549
154591
  opencodeGlobalSkills,
154550
154592
  opencodeProjectSkills
154551
154593
  ] = await Promise.all([
154552
- discoverConfigSourceSkills({
154594
+ discovery2.config_sources ? discoverConfigSourceSkills({
154553
154595
  config: params.pluginConfig.skills,
154554
154596
  configDir: params.ctx.directory
154555
- }),
154597
+ }) : Promise.resolve([]),
154556
154598
  includeClaudeCommands ? loadUserCommands() : Promise.resolve({}),
154557
154599
  includeClaudeCommands ? loadProjectCommands(params.ctx.directory) : Promise.resolve({}),
154558
154600
  loadOpencodeGlobalCommands(),
154559
154601
  loadOpencodeProjectCommands(params.ctx.directory),
154560
- includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
154561
- includeClaudeSkills ? loadGlobalAgentsSkills() : Promise.resolve({}),
154562
- includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
154563
- includeClaudeSkills ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
154564
- loadOpencodeGlobalSkills(),
154565
- loadOpencodeProjectSkills(params.ctx.directory)
154602
+ loadManagedPluginSkills(),
154603
+ discovery2.global_claude ? loadUserSkills() : Promise.resolve({}),
154604
+ discovery2.global_agents ? loadGlobalAgentsSkills() : Promise.resolve({}),
154605
+ discovery2.project_claude ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
154606
+ discovery2.project_agents ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
154607
+ discovery2.global_opencode ? loadOpencodeGlobalSkills() : Promise.resolve({}),
154608
+ discovery2.project_opencode ? loadOpencodeProjectSkills(params.ctx.directory) : Promise.resolve({})
154566
154609
  ]);
154567
154610
  params.config.command = {
154568
154611
  ...builtinCommands,
154612
+ ...managedPluginSkills,
154569
154613
  ...skillsToCommandDefinitionRecord(configSourceSkills),
154570
154614
  ...userCommands,
154571
154615
  ...userSkills,
@@ -154593,7 +154637,7 @@ function remapCommandAgentFields(commands2) {
154593
154637
 
154594
154638
  // src/plugin-handlers/mcp-config-handler.ts
154595
154639
  import { spawnSync as spawnSync5 } from "child_process";
154596
- import { existsSync as existsSync85 } from "fs";
154640
+ import { existsSync as existsSync86 } from "fs";
154597
154641
 
154598
154642
  // src/mcp/websearch.ts
154599
154643
  init_logger();
@@ -154625,15 +154669,6 @@ function createWebsearchConfig(config4) {
154625
154669
  }
154626
154670
  var websearch = createWebsearchConfig();
154627
154671
 
154628
- // src/mcp/context7.ts
154629
- var context7 = {
154630
- type: "remote",
154631
- url: "https://mcp.context7.com/mcp",
154632
- enabled: true,
154633
- headers: process.env.CONTEXT7_API_KEY ? { Authorization: `Bearer ${process.env.CONTEXT7_API_KEY}` } : undefined,
154634
- oauth: false
154635
- };
154636
-
154637
154672
  // src/mcp/grep-app.ts
154638
154673
  var grep_app = {
154639
154674
  type: "remote",
@@ -154651,19 +154686,11 @@ function createBuiltinMcps(disabledMcps = [], config4) {
154651
154686
  mcps.websearch = websearchConfig;
154652
154687
  }
154653
154688
  }
154654
- if (!disabledMcps.includes("context7")) {
154655
- mcps.context7 = context7;
154656
- }
154657
154689
  if (!disabledMcps.includes("grep_app")) {
154658
154690
  mcps.grep_app = grep_app;
154659
154691
  }
154660
154692
  return mcps;
154661
154693
  }
154662
- // src/mcp/index.ts
154663
- import { join as join96 } from "path";
154664
- var __dirname = "C:\\hiai\\hiai-opencode-public\\src\\mcp";
154665
- var ASSETS_DIR = join96(import.meta.dirname || __dirname, "..", "assets", "mcp");
154666
-
154667
154694
  // src/shared/runtime-plugin-config.ts
154668
154695
  function mergeRecords(base, override) {
154669
154696
  if (!base && !override)
@@ -154763,7 +154790,7 @@ function hasUsableLocalMcpRuntime(name, entry) {
154763
154790
  return false;
154764
154791
  }
154765
154792
  if (binary2 === "node" && typeof args[0] === "string" && args[0].endsWith(".mjs")) {
154766
- if (!existsSync85(args[0])) {
154793
+ if (!existsSync86(args[0])) {
154767
154794
  return false;
154768
154795
  }
154769
154796
  const probe2 = spawnSync5(binary2, ["--version"], {
@@ -155237,19 +155264,30 @@ async function createSkillContext(args) {
155237
155264
  }
155238
155265
  return true;
155239
155266
  });
155240
- const includeClaudeSkills = pluginConfig.claude_code?.skills !== false;
155241
- const [configSourceSkills, userSkills, globalSkills, projectSkills, opencodeProjectSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
155242
- discoverConfigSourceSkills({
155267
+ const discovery2 = resolveSkillDiscoveryConfig(pluginConfig);
155268
+ const [
155269
+ managedPluginSkills,
155270
+ configSourceSkills,
155271
+ userSkills,
155272
+ globalSkills,
155273
+ projectSkills,
155274
+ opencodeProjectSkills,
155275
+ agentsProjectSkills,
155276
+ agentsGlobalSkills
155277
+ ] = await Promise.all([
155278
+ discoverManagedPluginSkills(),
155279
+ discovery2.config_sources ? discoverConfigSourceSkills({
155243
155280
  config: pluginConfig.skills,
155244
155281
  configDir: directory
155245
- }),
155246
- includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
155247
- discoverOpencodeGlobalSkills(),
155248
- includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
155249
- discoverOpencodeProjectSkills(directory),
155250
- discoverProjectAgentsSkills(directory),
155251
- discoverGlobalAgentsSkills()
155282
+ }) : Promise.resolve([]),
155283
+ discovery2.global_claude ? discoverUserClaudeSkills() : Promise.resolve([]),
155284
+ discovery2.global_opencode ? discoverOpencodeGlobalSkills() : Promise.resolve([]),
155285
+ discovery2.project_claude ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
155286
+ discovery2.project_opencode ? discoverOpencodeProjectSkills(directory) : Promise.resolve([]),
155287
+ discovery2.project_agents ? discoverProjectAgentsSkills(directory) : Promise.resolve([]),
155288
+ discovery2.global_agents ? discoverGlobalAgentsSkills() : Promise.resolve([])
155252
155289
  ]);
155290
+ const filteredManagedPluginSkills = filterProviderGatedSkills(managedPluginSkills, browserProvider);
155253
155291
  const filteredConfigSourceSkills = filterProviderGatedSkills(configSourceSkills, browserProvider);
155254
155292
  const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
155255
155293
  const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
@@ -155257,7 +155295,7 @@ async function createSkillContext(args) {
155257
155295
  const filteredOpencodeProjectSkills = filterProviderGatedSkills(opencodeProjectSkills, browserProvider);
155258
155296
  const filteredAgentsProjectSkills = filterProviderGatedSkills(agentsProjectSkills, browserProvider);
155259
155297
  const filteredAgentsGlobalSkills = filterProviderGatedSkills(agentsGlobalSkills, browserProvider);
155260
- const mergedSkills = mergeSkills(builtinSkills, pluginConfig.skills, filteredConfigSourceSkills, [...filteredUserSkills, ...filteredAgentsGlobalSkills], filteredGlobalSkills, [...filteredProjectSkills, ...filteredAgentsProjectSkills], filteredOpencodeProjectSkills, { configDir: directory });
155298
+ const mergedSkills = mergeSkills(builtinSkills, pluginConfig.skills, [...filteredManagedPluginSkills, ...filteredConfigSourceSkills], [...filteredUserSkills, ...filteredAgentsGlobalSkills], filteredGlobalSkills, [...filteredProjectSkills, ...filteredAgentsProjectSkills], filteredOpencodeProjectSkills, { configDir: directory });
155261
155299
  const availableSkills = mergedSkills.map((skill2) => ({
155262
155300
  name: skill2.name,
155263
155301
  description: skill2.definition.description ?? "",
@@ -155747,10 +155785,10 @@ init_agent_display_names();
155747
155785
 
155748
155786
  // src/plugin/ultrawork-db-model-override.ts
155749
155787
  import { Database } from "bun:sqlite";
155750
- import { join as join97 } from "path";
155751
- import { existsSync as existsSync86 } from "fs";
155788
+ import { join as join96 } from "path";
155789
+ import { existsSync as existsSync87 } from "fs";
155752
155790
  function getDbPath() {
155753
- return join97(getDataDir(), "opencode", "opencode.db");
155791
+ return join96(getDataDir(), "opencode", "opencode.db");
155754
155792
  }
155755
155793
  var MAX_MICROTASK_RETRIES = 10;
155756
155794
  function tryUpdateMessageModel(db, messageId, targetModel, variant) {
@@ -155827,7 +155865,7 @@ function retryViaMicrotask(db, messageId, targetModel, variant, attempt) {
155827
155865
  function scheduleDeferredModelOverride(messageId, targetModel, variant) {
155828
155866
  queueMicrotask(() => {
155829
155867
  const dbPath = getDbPath();
155830
- if (!existsSync86(dbPath)) {
155868
+ if (!existsSync87(dbPath)) {
155831
155869
  log("[ultrawork-db-override] DB not found, skipping deferred override");
155832
155870
  return;
155833
155871
  }
@@ -157169,6 +157207,163 @@ function createFirstMessageVariantGate() {
157169
157207
  // src/index.ts
157170
157208
  init_plugin_identity();
157171
157209
 
157210
+ // src/shared/startup-diagnostics.ts
157211
+ import { existsSync as existsSync88, readFileSync as readFileSync60 } from "fs";
157212
+ import { join as join98 } from "path";
157213
+
157214
+ // src/mcp/registry.ts
157215
+ import { join as join97 } from "path";
157216
+ function resolveAssetScript(...segments) {
157217
+ return join97(import.meta.dirname, "..", "assets", ...segments);
157218
+ }
157219
+ function createNpmPackageCommand(pkg, ...args) {
157220
+ return ["node", resolveAssetScript("runtime", "npm-package-runner.mjs"), pkg, ...args];
157221
+ }
157222
+ var HIAI_MCP_REGISTRY = {
157223
+ playwright: {
157224
+ name: "playwright",
157225
+ enabledByDefault: true,
157226
+ install: "npm",
157227
+ optionalEnv: ["HIAI_PLAYWRIGHT_INSTALL_BROWSERS"],
157228
+ config: {
157229
+ enabled: true,
157230
+ command: ["node", resolveAssetScript("mcp", "playwright.mjs")],
157231
+ timeout: 600000
157232
+ }
157233
+ },
157234
+ stitch: {
157235
+ name: "stitch",
157236
+ enabledByDefault: true,
157237
+ install: "remote",
157238
+ requiredEnv: ["STITCH_AI_API_KEY"],
157239
+ config: {
157240
+ enabled: true,
157241
+ type: "remote",
157242
+ url: "https://stitch.googleapis.com/mcp",
157243
+ headers: { "X-Goog-Api-Key": "{env:STITCH_AI_API_KEY}" },
157244
+ timeout: 600000
157245
+ }
157246
+ },
157247
+ "sequential-thinking": {
157248
+ name: "sequential-thinking",
157249
+ enabledByDefault: true,
157250
+ install: "npm",
157251
+ config: {
157252
+ enabled: true,
157253
+ command: createNpmPackageCommand("@modelcontextprotocol/server-sequential-thinking"),
157254
+ timeout: 600000
157255
+ }
157256
+ },
157257
+ firecrawl: {
157258
+ name: "firecrawl",
157259
+ enabledByDefault: true,
157260
+ install: "npm",
157261
+ requiredEnv: ["FIRECRAWL_API_KEY"],
157262
+ config: {
157263
+ enabled: true,
157264
+ command: createNpmPackageCommand("firecrawl-mcp"),
157265
+ timeout: 600000,
157266
+ environment: { FIRECRAWL_API_KEY: "{env:FIRECRAWL_API_KEY}" }
157267
+ }
157268
+ },
157269
+ rag: {
157270
+ name: "rag",
157271
+ enabledByDefault: true,
157272
+ install: "user-service",
157273
+ optionalEnv: ["OPENCODE_RAG_URL"],
157274
+ config: {
157275
+ enabled: true,
157276
+ type: "local",
157277
+ command: ["node", resolveAssetScript("mcp", "rag.mjs")],
157278
+ environment: {
157279
+ OPENCODE_RAG_URL: "{env:OPENCODE_RAG_URL:-http://localhost:9002/tools/search}"
157280
+ },
157281
+ timeout: 600000
157282
+ }
157283
+ },
157284
+ context7: {
157285
+ name: "context7",
157286
+ enabledByDefault: true,
157287
+ install: "remote",
157288
+ optionalEnv: ["CONTEXT7_API_KEY"],
157289
+ config: {
157290
+ enabled: true,
157291
+ type: "remote",
157292
+ url: "https://mcp.context7.com/mcp",
157293
+ headers: { "X-API-KEY": "{env:CONTEXT7_API_KEY}" },
157294
+ timeout: 600000
157295
+ }
157296
+ },
157297
+ mempalace: {
157298
+ name: "mempalace",
157299
+ enabledByDefault: true,
157300
+ install: "python",
157301
+ optionalEnv: ["MEMPALACE_PYTHON", "MEMPALACE_PALACE_PATH", "HIAI_MCP_AUTO_INSTALL"],
157302
+ config: {
157303
+ enabled: true,
157304
+ type: "local",
157305
+ command: ["node", resolveAssetScript("mcp", "mempalace.mjs"), "--palace", "./.opencode/palace"],
157306
+ timeout: 600000
157307
+ }
157308
+ }
157309
+ };
157310
+
157311
+ // src/shared/startup-diagnostics.ts
157312
+ init_plugin_identity();
157313
+ function readPlugins(configPath) {
157314
+ if (!existsSync88(configPath))
157315
+ return [];
157316
+ try {
157317
+ const content = readFileSync60(configPath, "utf-8");
157318
+ const parsed = parseJsoncSafe(content);
157319
+ return (parsed.data?.plugin ?? []).map((entry) => typeof entry === "string" ? entry : Array.isArray(entry) ? entry[0] : "").filter((entry) => typeof entry === "string" && entry.trim().length > 0);
157320
+ } catch {
157321
+ return [];
157322
+ }
157323
+ }
157324
+ function warnIfListPluginEntry(directory) {
157325
+ const globalPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
157326
+ const candidates = [
157327
+ join98(directory, ".opencode", "opencode.json"),
157328
+ join98(directory, ".opencode", "opencode.jsonc"),
157329
+ globalPaths.configJson,
157330
+ globalPaths.configJsonc
157331
+ ];
157332
+ for (const configPath of candidates) {
157333
+ const plugins = readPlugins(configPath);
157334
+ if (!plugins.includes("list"))
157335
+ continue;
157336
+ console.warn(`[hiai-opencode] WARNING: ${configPath} contains plugin: ["list"].`);
157337
+ console.warn("[hiai-opencode] This can prevent hiai-opencode MCP servers from loading from that config scope.");
157338
+ console.warn(`[hiai-opencode] Update it to: plugin: ["${PLUGIN_NAME}"]`);
157339
+ }
157340
+ }
157341
+ function hasConfigAuthFallback(pluginConfig, envName) {
157342
+ if (envName === "FIRECRAWL_API_KEY")
157343
+ return !!pluginConfig.auth?.firecrawl?.trim();
157344
+ if (envName === "STITCH_AI_API_KEY")
157345
+ return !!pluginConfig.auth?.stitch?.trim();
157346
+ if (envName === "CONTEXT7_API_KEY")
157347
+ return !!pluginConfig.auth?.context7?.trim();
157348
+ return false;
157349
+ }
157350
+ function warnMissingRequiredMcpEnv(args) {
157351
+ const disabled = new Set(args.pluginConfig.disabled_mcps ?? []);
157352
+ const mcpConfig = args.platformConfig.mcp ?? {};
157353
+ for (const [name, entry] of Object.entries(HIAI_MCP_REGISTRY)) {
157354
+ if (disabled.has(name))
157355
+ continue;
157356
+ if (mcpConfig[name]?.enabled === false)
157357
+ continue;
157358
+ if (!entry.requiredEnv || entry.requiredEnv.length === 0)
157359
+ continue;
157360
+ const missing = entry.requiredEnv.filter((envName) => !process.env[envName]?.trim() && !hasConfigAuthFallback(args.pluginConfig, envName));
157361
+ if (missing.length === 0)
157362
+ continue;
157363
+ 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.");
157364
+ }
157365
+ }
157366
+
157172
157367
  // src/internals/plugins/subtask2/core/state.ts
157173
157368
  var configs = {};
157174
157369
  var pluginConfig = { replace_generic: true };
@@ -157484,7 +157679,7 @@ function resolveResultReferences(text, sessionID) {
157484
157679
 
157485
157680
  // src/internals/plugins/subtask2/utils/config.ts
157486
157681
  import { mkdirSync as mkdirSync18 } from "fs";
157487
- import { dirname as dirname29, join as join98 } from "path";
157682
+ import { dirname as dirname30, join as join99 } from "path";
157488
157683
 
157489
157684
  // src/internals/plugins/subtask2/utils/prompts.ts
157490
157685
  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.";
@@ -157550,15 +157745,15 @@ async function getAutoWorkflowPrompt() {
157550
157745
  var AUTO_WORKFLOW_PROMPT = AUTO_WORKFLOW_PROMPT_TEMPLATE.replace(README_PLACEHOLDER, "[Use getAutoWorkflowPrompt() to get full documentation]");
157551
157746
 
157552
157747
  // src/internals/plugins/subtask2/utils/config.ts
157553
- var CONFIG_PATH = join98(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
157748
+ var CONFIG_PATH = join99(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
157554
157749
  var cachedReadmeContent = null;
157555
157750
  async function loadReadmeContent() {
157556
157751
  if (cachedReadmeContent !== null) {
157557
157752
  return cachedReadmeContent;
157558
157753
  }
157559
157754
  try {
157560
- const pluginRoot = join98(dirname29(import.meta.path), "..", "..");
157561
- const readmePath = join98(pluginRoot, "README.md");
157755
+ const pluginRoot = join99(dirname30(import.meta.path), "..", "..");
157756
+ const readmePath = join99(pluginRoot, "README.md");
157562
157757
  const file3 = Bun.file(readmePath);
157563
157758
  if (await file3.exists()) {
157564
157759
  cachedReadmeContent = await file3.text();
@@ -157593,7 +157788,7 @@ async function loadConfig2() {
157593
157788
  }
157594
157789
  }
157595
157790
  } catch {}
157596
- mkdirSync18(dirname29(CONFIG_PATH), { recursive: true });
157791
+ mkdirSync18(dirname30(CONFIG_PATH), { recursive: true });
157597
157792
  await Bun.write(CONFIG_PATH, `{
157598
157793
  // Replace OpenCode's generic "Summarize..." prompt when no return is specified
157599
157794
  "replace_generic": true,
@@ -157665,7 +157860,7 @@ function clearLog() {
157665
157860
  }
157666
157861
 
157667
157862
  // src/internals/plugins/subtask2/commands/manifest.ts
157668
- import { join as join100 } from "path";
157863
+ import { join as join101 } from "path";
157669
157864
 
157670
157865
  // src/internals/plugins/subtask2/parsing/frontmatter.ts
157671
157866
  var import_yaml = __toESM(require_dist2(), 1);
@@ -157921,8 +158116,8 @@ function parseAutoWorkflowOutput(text) {
157921
158116
  async function buildManifest() {
157922
158117
  const manifest = {};
157923
158118
  const dirs = [
157924
- join100(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
157925
- join100(Bun.env.PWD ?? ".", ".opencode", "command")
158119
+ join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158120
+ join101(Bun.env.PWD ?? ".", ".opencode", "command")
157926
158121
  ];
157927
158122
  for (const dir of dirs) {
157928
158123
  try {
@@ -158085,11 +158280,11 @@ async function resolveTurnReferences(text, sessionID) {
158085
158280
  }
158086
158281
 
158087
158282
  // src/internals/plugins/subtask2/commands/loader.ts
158088
- import { join as join101 } from "path";
158283
+ import { join as join102 } from "path";
158089
158284
  async function loadCommandFile(name) {
158090
158285
  const dirs = [
158091
- join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158092
- join101(Bun.env.PWD ?? ".", ".opencode", "command")
158286
+ join102(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158287
+ join102(Bun.env.PWD ?? ".", ".opencode", "command")
158093
158288
  ];
158094
158289
  for (const dir of dirs) {
158095
158290
  const directPath = `${dir}/${name}.md`;
@@ -159369,14 +159564,14 @@ init_websearch_cited();
159369
159564
  // src/features/builtin-skills/materialize.ts
159370
159565
  import {
159371
159566
  cpSync,
159372
- existsSync as existsSync88,
159567
+ existsSync as existsSync90,
159373
159568
  mkdirSync as mkdirSync20,
159374
159569
  readdirSync as readdirSync26,
159375
- readFileSync as readFileSync59,
159570
+ readFileSync as readFileSync61,
159376
159571
  rmSync as rmSync4,
159377
159572
  writeFileSync as writeFileSync22
159378
159573
  } from "fs";
159379
- import { join as join102 } from "path";
159574
+ import { join as join103 } from "path";
159380
159575
  var GENERATED_MARKER = "<!-- Generated by hiai-opencode builtin skill materializer. -->";
159381
159576
  var MANAGED_SKILL_METADATA = ".hiai-skill.json";
159382
159577
  var LEGACY_MANAGED_DIR_MARKER = ".hiai-plugin-skill";
@@ -159403,10 +159598,10 @@ function buildSkillFrontmatter(skill2) {
159403
159598
  `);
159404
159599
  }
159405
159600
  function shouldWriteSkillFile(skillFilePath) {
159406
- if (!existsSync88(skillFilePath))
159601
+ if (!existsSync90(skillFilePath))
159407
159602
  return true;
159408
159603
  try {
159409
- const existing = readFileSync59(skillFilePath, "utf-8");
159604
+ const existing = readFileSync61(skillFilePath, "utf-8");
159410
159605
  return existing.includes(GENERATED_MARKER);
159411
159606
  } catch {
159412
159607
  return false;
@@ -159414,10 +159609,10 @@ function shouldWriteSkillFile(skillFilePath) {
159414
159609
  }
159415
159610
  function getSkillLayout() {
159416
159611
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
159417
- const assembledSkillsDir = join102(configDir, "skills");
159418
- const sourceRootDir = join102(configDir, ".hiai", "skills");
159419
- const builtinSourceDir = join102(sourceRootDir, "builtin");
159420
- const pluginSourceDir = join102(sourceRootDir, "plugin");
159612
+ const assembledSkillsDir = join103(configDir, "skills");
159613
+ const sourceRootDir = join103(configDir, ".hiai", "skills");
159614
+ const builtinSourceDir = join103(sourceRootDir, "builtin");
159615
+ const pluginSourceDir = join103(sourceRootDir, "plugin");
159421
159616
  mkdirSync20(assembledSkillsDir, { recursive: true });
159422
159617
  mkdirSync20(builtinSourceDir, { recursive: true });
159423
159618
  mkdirSync20(pluginSourceDir, { recursive: true });
@@ -159430,31 +159625,31 @@ function getSkillLayout() {
159430
159625
  };
159431
159626
  }
159432
159627
  function writeManagedSkillMetadata(targetDir, metadata) {
159433
- writeFileSync22(join102(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
159628
+ writeFileSync22(join103(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
159434
159629
  `, "utf-8");
159435
159630
  }
159436
159631
  function readManagedSkillMetadata(targetDir) {
159437
- const metadataPath = join102(targetDir, MANAGED_SKILL_METADATA);
159438
- if (!existsSync88(metadataPath)) {
159632
+ const metadataPath = join103(targetDir, MANAGED_SKILL_METADATA);
159633
+ if (!existsSync90(metadataPath)) {
159439
159634
  return null;
159440
159635
  }
159441
159636
  try {
159442
- return JSON.parse(readFileSync59(metadataPath, "utf-8"));
159637
+ return JSON.parse(readFileSync61(metadataPath, "utf-8"));
159443
159638
  } catch {
159444
159639
  return null;
159445
159640
  }
159446
159641
  }
159447
159642
  function isLegacyManagedSkillDir(targetDir, origin) {
159448
- if (origin === "plugin" && existsSync88(join102(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
159643
+ if (origin === "plugin" && existsSync90(join103(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
159449
159644
  return true;
159450
159645
  }
159451
159646
  if (origin === "builtin") {
159452
- const skillFilePath = join102(targetDir, "SKILL.md");
159453
- if (!existsSync88(skillFilePath)) {
159647
+ const skillFilePath = join103(targetDir, "SKILL.md");
159648
+ if (!existsSync90(skillFilePath)) {
159454
159649
  return false;
159455
159650
  }
159456
159651
  try {
159457
- return readFileSync59(skillFilePath, "utf-8").includes(GENERATED_MARKER);
159652
+ return readFileSync61(skillFilePath, "utf-8").includes(GENERATED_MARKER);
159458
159653
  } catch {
159459
159654
  return false;
159460
159655
  }
@@ -159462,7 +159657,7 @@ function isLegacyManagedSkillDir(targetDir, origin) {
159462
159657
  return false;
159463
159658
  }
159464
159659
  function shouldSyncManagedSkillDir(targetDir, origin) {
159465
- if (!existsSync88(targetDir))
159660
+ if (!existsSync90(targetDir))
159466
159661
  return true;
159467
159662
  const metadata = readManagedSkillMetadata(targetDir);
159468
159663
  if (metadata?.generatedBy === "hiai-opencode" && metadata.origin === origin) {
@@ -159478,7 +159673,7 @@ function shouldCleanupManagedSkillDir(targetDir, origin) {
159478
159673
  return isLegacyManagedSkillDir(targetDir, origin);
159479
159674
  }
159480
159675
  function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
159481
- if (!existsSync88(rootDir)) {
159676
+ if (!existsSync90(rootDir)) {
159482
159677
  return;
159483
159678
  }
159484
159679
  for (const entry of readdirSync26(rootDir, { withFileTypes: true })) {
@@ -159486,15 +159681,15 @@ function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
159486
159681
  continue;
159487
159682
  if (expectedSkillNames.has(entry.name))
159488
159683
  continue;
159489
- const targetDir = join102(rootDir, entry.name);
159684
+ const targetDir = join103(rootDir, entry.name);
159490
159685
  if (shouldCleanupManagedSkillDir(targetDir, origin)) {
159491
159686
  rmSync4(targetDir, { recursive: true, force: true });
159492
159687
  }
159493
159688
  }
159494
159689
  }
159495
159690
  function writeSkillRegistry(configDir, entries) {
159496
- const registryDir = join102(configDir, ".hiai");
159497
- const assembledSkillsDir = join102(configDir, "skills");
159691
+ const registryDir = join103(configDir, ".hiai");
159692
+ const assembledSkillsDir = join103(configDir, "skills");
159498
159693
  mkdirSync20(registryDir, { recursive: true });
159499
159694
  mkdirSync20(assembledSkillsDir, { recursive: true });
159500
159695
  const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
@@ -159508,12 +159703,12 @@ function writeSkillRegistry(configDir, entries) {
159508
159703
  },
159509
159704
  layout: {
159510
159705
  assembledSkillsDir,
159511
- builtinSourceDir: join102(registryDir, "skills", "builtin"),
159512
- pluginSourceDir: join102(registryDir, "skills", "plugin")
159706
+ builtinSourceDir: join103(registryDir, "skills", "builtin"),
159707
+ pluginSourceDir: join103(registryDir, "skills", "plugin")
159513
159708
  },
159514
159709
  entries: sortedEntries
159515
159710
  };
159516
- writeFileSync22(join102(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
159711
+ writeFileSync22(join103(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
159517
159712
  `, "utf-8");
159518
159713
  const readme = [
159519
159714
  "# Hiai Skill Layout",
@@ -159528,16 +159723,16 @@ function writeSkillRegistry(configDir, entries) {
159528
159723
  ""
159529
159724
  ].join(`
159530
159725
  `);
159531
- writeFileSync22(join102(assembledSkillsDir, "README.md"), readme, "utf-8");
159726
+ writeFileSync22(join103(assembledSkillsDir, "README.md"), readme, "utf-8");
159532
159727
  }
159533
159728
  function materializeBuiltinSkills(skills) {
159534
159729
  const { assembledSkillsDir, builtinSourceDir } = getSkillLayout();
159535
159730
  const expectedSkillNames = new Set(skills.map((skill2) => skill2.name));
159536
159731
  for (const skill2 of skills) {
159537
- const sourceSkillDir = join102(builtinSourceDir, skill2.name);
159538
- const sourceSkillFilePath = join102(sourceSkillDir, "SKILL.md");
159539
- const assembledSkillDir = join102(assembledSkillsDir, skill2.name);
159540
- const assembledSkillFilePath = join102(assembledSkillDir, "SKILL.md");
159732
+ const sourceSkillDir = join103(builtinSourceDir, skill2.name);
159733
+ const sourceSkillFilePath = join103(sourceSkillDir, "SKILL.md");
159734
+ const assembledSkillDir = join103(assembledSkillsDir, skill2.name);
159735
+ const assembledSkillFilePath = join103(assembledSkillDir, "SKILL.md");
159541
159736
  const content = buildSkillFrontmatter(skill2);
159542
159737
  mkdirSync20(sourceSkillDir, { recursive: true });
159543
159738
  mkdirSync20(assembledSkillDir, { recursive: true });
@@ -159565,8 +159760,8 @@ function materializeBuiltinSkills(skills) {
159565
159760
  cleanupRemovedManagedSkillDirs(assembledSkillsDir, "builtin", expectedSkillNames);
159566
159761
  }
159567
159762
  function materializePluginSkillDirectories(pluginRootDir) {
159568
- const sourceSkillsDir = join102(pluginRootDir, "skills");
159569
- if (!existsSync88(sourceSkillsDir)) {
159763
+ const sourceSkillsDir = join103(pluginRootDir, "skills");
159764
+ if (!existsSync90(sourceSkillsDir)) {
159570
159765
  return;
159571
159766
  }
159572
159767
  const { assembledSkillsDir, pluginSourceDir, configDir } = getSkillLayout();
@@ -159578,9 +159773,9 @@ function materializePluginSkillDirectories(pluginRootDir) {
159578
159773
  if (entry.name === "tmp")
159579
159774
  continue;
159580
159775
  expectedSkillNames.add(entry.name);
159581
- const sourceDir = join102(sourceSkillsDir, entry.name);
159582
- const mirroredSourceDir = join102(pluginSourceDir, entry.name);
159583
- const assembledDir = join102(assembledSkillsDir, entry.name);
159776
+ const sourceDir = join103(sourceSkillsDir, entry.name);
159777
+ const mirroredSourceDir = join103(pluginSourceDir, entry.name);
159778
+ const assembledDir = join103(assembledSkillsDir, entry.name);
159584
159779
  if (!shouldSyncManagedSkillDir(mirroredSourceDir, "plugin") || !shouldSyncManagedSkillDir(assembledDir, "plugin")) {
159585
159780
  continue;
159586
159781
  }
@@ -159614,7 +159809,7 @@ function materializePluginSkillDirectories(pluginRootDir) {
159614
159809
  for (const builtinEntry of readdirSync26(assembledSkillsDir, { withFileTypes: true })) {
159615
159810
  if (!builtinEntry.isDirectory())
159616
159811
  continue;
159617
- const assembledDir = join102(assembledSkillsDir, builtinEntry.name);
159812
+ const assembledDir = join103(assembledSkillsDir, builtinEntry.name);
159618
159813
  const metadata = readManagedSkillMetadata(assembledDir);
159619
159814
  if (metadata?.generatedBy !== "hiai-opencode" || metadata.origin !== "builtin") {
159620
159815
  continue;
@@ -159637,10 +159832,11 @@ function configureBundledBunPtyLibrary() {
159637
159832
  }
159638
159833
  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";
159639
159834
  const candidates = [
159640
- join104(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
159641
- join104(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
159835
+ join105(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
159836
+ join105(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName),
159837
+ join105(import.meta.dirname, "..", "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
159642
159838
  ];
159643
- const resolved = candidates.find((candidate) => existsSync90(candidate));
159839
+ const resolved = candidates.find((candidate) => existsSync92(candidate));
159644
159840
  if (resolved) {
159645
159841
  process.env.BUN_PTY_LIB = resolved;
159646
159842
  }
@@ -159649,6 +159845,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
159649
159845
  log("[HiaiOpenCodePlugin] ENTRY - plugin loading", {
159650
159846
  directory: ctx.directory
159651
159847
  });
159848
+ warnIfListPluginEntry(ctx.directory);
159652
159849
  const skillPluginCheck = detectExternalSkillPlugin(ctx.directory);
159653
159850
  if (skillPluginCheck.detected && skillPluginCheck.pluginName) {
159654
159851
  console.warn(getSkillPluginConflictWarning(skillPluginCheck.pluginName));
@@ -159657,11 +159854,15 @@ var HiaiOpenCodePlugin = async (ctx) => {
159657
159854
  await activePluginDispose?.();
159658
159855
  const internalConfig = loadConfig(ctx.directory);
159659
159856
  const pluginConfig2 = hydratePluginConfigWithPlatformDefaults(loadPluginConfig(ctx.directory, ctx), internalConfig);
159857
+ warnMissingRequiredMcpEnv({
159858
+ pluginConfig: pluginConfig2,
159859
+ platformConfig: internalConfig
159860
+ });
159660
159861
  materializeBuiltinSkills(createBuiltinSkills({
159661
159862
  browserProvider: pluginConfig2.browser_automation_engine?.provider ?? "playwright",
159662
159863
  disabledSkills: new Set(pluginConfig2.disabled_skills ?? [])
159663
159864
  }));
159664
- materializePluginSkillDirectories(join104(import.meta.dirname, ".."));
159865
+ materializePluginSkillDirectories(join105(import.meta.dirname, ".."));
159665
159866
  const { initializeModelRequirements: initializeModelRequirements2 } = await Promise.resolve().then(() => (init_model_requirements(), exports_model_requirements));
159666
159867
  initializeModelRequirements2(internalConfig);
159667
159868
  const { initializeModelHeuristics: initializeModelHeuristics2 } = await Promise.resolve().then(() => (init_model_capability_heuristics(), exports_model_capability_heuristics));
@@ -159761,30 +159962,25 @@ var HiaiOpenCodePlugin = async (ctx) => {
159761
159962
  auth: {
159762
159963
  provider: "hiai-opencode",
159763
159964
  methods: [
159764
- { type: "api", label: "Google API key" },
159765
- { type: "api", label: "OpenAI API key" },
159766
- { type: "api", label: "OpenRouter API key" }
159965
+ { type: "api", label: "Google Search API key" }
159767
159966
  ],
159768
159967
  loader: async (getAuth) => {
159769
159968
  const authData = await getAuth();
159770
159969
  const { registerGetAuth: registerGetAuth2, GOOGLE_PROVIDER_ID: GOOGLE_PROVIDER_ID2, OPENAI_PROVIDER_ID: OPENAI_PROVIDER_ID2, OPENROUTER_PROVIDER_ID: OPENROUTER_PROVIDER_ID2 } = await Promise.resolve().then(() => (init_websearch_cited(), exports_websearch_cited));
159771
- const getKey = (label, configKey) => {
159772
- const fromAuth = authData[label];
159773
- if (fromAuth)
159774
- return fromAuth;
159970
+ const getConfiguredKey = (configKey) => {
159775
159971
  if (configKey)
159776
159972
  return resolveEnvVars(configKey);
159777
159973
  return;
159778
159974
  };
159779
- const googleKey = getKey("Google API key", internalConfig.auth?.googleSearch);
159780
- const openaiKey = getKey("OpenAI API key", internalConfig.auth?.openai);
159781
- const openRouterKey = getKey("OpenRouter API key", internalConfig.auth?.openrouter);
159975
+ const googleKey = authData["Google Search API key"] || getConfiguredKey(internalConfig.auth?.googleSearch);
159976
+ const openaiKey = getConfiguredKey(internalConfig.auth?.openai);
159977
+ const openRouterKey = getConfiguredKey(internalConfig.auth?.openrouter);
159782
159978
  if (googleKey)
159783
- registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve(googleKey));
159979
+ registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: googleKey }));
159784
159980
  if (openaiKey)
159785
- registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve(openaiKey));
159981
+ registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openaiKey }));
159786
159982
  if (openRouterKey)
159787
- registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve(openRouterKey));
159983
+ registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openRouterKey }));
159788
159984
  return {};
159789
159985
  }
159790
159986
  },