@hiai-gg/hiai-opencode 0.1.3 → 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 (51) hide show
  1. package/.env.example +14 -18
  2. package/AGENTS.md +75 -23
  3. package/ARCHITECTURE.md +11 -14
  4. package/LICENSE.md +1 -0
  5. package/README.md +177 -94
  6. package/assets/cli/hiai-opencode.mjs +276 -0
  7. package/assets/mcp/playwright.mjs +7 -0
  8. package/config/hiai-opencode.schema.json +113 -1
  9. package/dist/config/defaults.d.ts +0 -3
  10. package/dist/config/index.d.ts +0 -1
  11. package/dist/config/platform-schema.d.ts +70 -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 +692 -541
  23. package/dist/plugin/skill-discovery-config.d.ts +4 -0
  24. package/dist/shared/startup-diagnostics.d.ts +6 -0
  25. package/hiai-opencode.json +191 -35
  26. package/package.json +4 -1
  27. package/src/agents/AGENTS.md +3 -4
  28. package/src/config/defaults.ts +60 -81
  29. package/src/config/index.ts +0 -1
  30. package/src/config/platform-schema.ts +17 -2
  31. package/src/config/schema/agent-overrides.ts +2 -0
  32. package/src/config/schema/commands.ts +1 -0
  33. package/src/config/schema/fast-apply.ts +4 -4
  34. package/src/config/schema/index.ts +2 -0
  35. package/src/config/schema/oh-my-opencode-config.ts +3 -0
  36. package/src/config/schema/skill-discovery.ts +25 -0
  37. package/src/config/types.ts +16 -0
  38. package/src/features/builtin-commands/commands.ts +7 -0
  39. package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
  40. package/src/features/builtin-commands/types.ts +1 -1
  41. package/src/features/builtin-skills/skills/playwright.ts +24 -2
  42. package/src/features/opencode-skill-loader/loader.ts +11 -0
  43. package/src/index.ts +14 -13
  44. package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
  45. package/src/plugin/skill-context.ts +31 -13
  46. package/src/plugin/skill-discovery-config.ts +32 -0
  47. package/src/plugin-handlers/agent-config-handler.ts +20 -13
  48. package/src/plugin-handlers/command-config-handler.ts +22 -12
  49. package/src/shared/migration/agent-names.ts +5 -5
  50. package/src/shared/startup-diagnostics.ts +77 -0
  51. 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
@@ -114235,6 +114269,17 @@ var SkillsConfigSchema = exports_external.union([
114235
114269
  }).catchall(SkillEntrySchema)
114236
114270
  ]);
114237
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
+
114238
114283
  // src/config/schema/bob.ts
114239
114284
  var BobTasksConfigSchema = exports_external.object({
114240
114285
  storage_path: exports_external.string().optional(),
@@ -114293,7 +114338,8 @@ var AuthConfigSchema = exports_external.object({
114293
114338
  openai: exports_external.string().optional(),
114294
114339
  openrouter: exports_external.string().optional(),
114295
114340
  stitch: exports_external.string().optional(),
114296
- firecrawl: exports_external.string().optional()
114341
+ firecrawl: exports_external.string().optional(),
114342
+ context7: exports_external.string().optional()
114297
114343
  }).optional();
114298
114344
  var HiaiOpenCodeConfigSchema = exports_external.object({
114299
114345
  $schema: exports_external.string().optional(),
@@ -114317,6 +114363,7 @@ var HiaiOpenCodeConfigSchema = exports_external.object({
114317
114363
  experimental: ExperimentalConfigSchema.optional(),
114318
114364
  auto_update: exports_external.boolean().optional(),
114319
114365
  skills: SkillsConfigSchema.optional(),
114366
+ skill_discovery: SkillDiscoveryConfigSchema.optional(),
114320
114367
  ralph_loop: RalphLoopConfigSchema.optional(),
114321
114368
  runtime_fallback: exports_external.union([exports_external.boolean(), RuntimeFallbackConfigSchema]).optional(),
114322
114369
  background_task: BackgroundTaskConfigSchema.optional(),
@@ -116004,6 +116051,44 @@ If any issues are found during critical review:
116004
116051
  - ALWAYS preserve test coverage
116005
116052
  - If uncertain about a change, err on the side of keeping the original code`;
116006
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
+
116007
116092
  // src/features/builtin-commands/commands.ts
116008
116093
  function resolveStartWorkAgent(options) {
116009
116094
  if (options?.useRegisteredAgents) {
@@ -116107,6 +116192,12 @@ Timestamp: $TIMESTAMP
116107
116192
  $ARGUMENTS
116108
116193
  </user-request>`,
116109
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>`
116110
116201
  }
116111
116202
  };
116112
116203
  }
@@ -120443,8 +120534,8 @@ import * as fs12 from "fs";
120443
120534
  import * as path6 from "path";
120444
120535
 
120445
120536
  // src/config/loader.ts
120446
- import { existsSync as existsSync56, readFileSync as readFileSync42 } from "fs";
120447
- import { join as join67 } from "path";
120537
+ import { existsSync as existsSync57, readFileSync as readFileSync43 } from "fs";
120538
+ import { join as join66 } from "path";
120448
120539
 
120449
120540
  // src/config/platform-schema.ts
120450
120541
  var AgentConfigSchema = exports_external.object({
@@ -120499,6 +120590,15 @@ var SkillsConfigSchema2 = exports_external.object({
120499
120590
  enabled: exports_external.boolean().optional(),
120500
120591
  disabled: exports_external.array(exports_external.string()).optional()
120501
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
+ });
120502
120602
  var PermissionsConfigSchema = exports_external.object({
120503
120603
  read: exports_external.record(exports_external.string(), exports_external.string()).optional(),
120504
120604
  edit: exports_external.record(exports_external.string(), exports_external.string()).optional(),
@@ -120530,8 +120630,8 @@ var AuthKeysSchema = exports_external.object({
120530
120630
  });
120531
120631
  var OllamaConfigSchema = exports_external.object({
120532
120632
  enabled: exports_external.boolean().default(false),
120533
- model: exports_external.string().default("qwen3.5:4b"),
120534
- baseUrl: exports_external.string().default("http://localhost:11434"),
120633
+ model: exports_external.string().default(""),
120634
+ baseUrl: exports_external.string().default(""),
120535
120635
  purpose: exports_external.enum(["verification", "helper", "fallback"]).default("helper")
120536
120636
  });
120537
120637
  var ModelFamilySchema = exports_external.object({
@@ -120560,6 +120660,8 @@ var AgentsConfigSchema = exports_external.object({
120560
120660
  zoe: AgentConfigSchema.optional(),
120561
120661
  build: AgentConfigSchema.optional(),
120562
120662
  "pre-plan": AgentConfigSchema.optional(),
120663
+ manager: AgentConfigSchema.optional(),
120664
+ vision: AgentConfigSchema.optional(),
120563
120665
  logician: AgentConfigSchema.optional(),
120564
120666
  librarian: AgentConfigSchema.optional(),
120565
120667
  explore: AgentConfigSchema.optional(),
@@ -120589,6 +120691,8 @@ var AgentRequirementsConfigSchema = exports_external.object({
120589
120691
  zoe: ModelRequirementSchema.optional(),
120590
120692
  build: ModelRequirementSchema.optional(),
120591
120693
  "pre-plan": ModelRequirementSchema.optional(),
120694
+ manager: ModelRequirementSchema.optional(),
120695
+ vision: ModelRequirementSchema.optional(),
120592
120696
  logician: ModelRequirementSchema.optional(),
120593
120697
  librarian: ModelRequirementSchema.optional(),
120594
120698
  explore: ModelRequirementSchema.optional(),
@@ -120611,205 +120715,54 @@ var HiaiOpencodeConfigSchema = exports_external.object({
120611
120715
  lsp: exports_external.record(exports_external.string(), LspServerConfigSchema).optional(),
120612
120716
  subtask2: Subtask2ConfigSchema.optional(),
120613
120717
  skills: SkillsConfigSchema2.optional(),
120718
+ skill_discovery: SkillDiscoveryConfigSchema2.optional(),
120614
120719
  permissions: PermissionsConfigSchema.optional(),
120615
120720
  auth: AuthKeysSchema.optional(),
120616
120721
  ollama: OllamaConfigSchema.optional()
120617
120722
  });
120618
120723
 
120619
- // src/config/models.ts
120620
- var MODEL_PRESETS = {
120621
- fast: "openrouter/google/gemini-2.0-flash",
120622
- mid: "openrouter/anthropic/claude-3.5-sonnet",
120623
- high: "openrouter/anthropic/claude-3.5-opus",
120624
- ultrahigh: "openrouter/openai/gpt-4o",
120625
- vision: "openrouter/google/gemini-2.0-pro-exp-02-05",
120626
- reasoning: "openrouter/openai/o1",
120627
- strategist: "openrouter/z-ai/glm-5.1",
120628
- critic: "openrouter/qwen/qwen2.5-72b-instruct",
120629
- writing: "openrouter/kimi/kimi-latest"
120630
- };
120631
-
120632
- // src/mcp/registry.ts
120633
- import { join as join65 } from "path";
120634
- function resolveAssetScript(...segments) {
120635
- return join65(import.meta.dirname, "..", "assets", ...segments);
120636
- }
120637
- function createNpmPackageCommand(pkg, ...args) {
120638
- return ["node", resolveAssetScript("runtime", "npm-package-runner.mjs"), pkg, ...args];
120639
- }
120640
- var HIAI_MCP_REGISTRY = {
120641
- playwright: {
120642
- name: "playwright",
120643
- enabledByDefault: true,
120644
- install: "npm",
120645
- optionalEnv: ["HIAI_PLAYWRIGHT_INSTALL_BROWSERS"],
120646
- config: {
120647
- enabled: true,
120648
- command: ["node", resolveAssetScript("mcp", "playwright.mjs")],
120649
- timeout: 600000
120650
- }
120651
- },
120652
- stitch: {
120653
- name: "stitch",
120654
- enabledByDefault: true,
120655
- install: "remote",
120656
- requiredEnv: ["STITCH_AI_API_KEY"],
120657
- config: {
120658
- enabled: true,
120659
- type: "remote",
120660
- url: "https://stitch.googleapis.com/mcp",
120661
- headers: { "X-Goog-Api-Key": "{env:STITCH_AI_API_KEY}" },
120662
- timeout: 600000
120663
- }
120664
- },
120665
- "sequential-thinking": {
120666
- name: "sequential-thinking",
120667
- enabledByDefault: true,
120668
- install: "npm",
120669
- config: {
120670
- enabled: true,
120671
- command: createNpmPackageCommand("@modelcontextprotocol/server-sequential-thinking"),
120672
- timeout: 600000
120673
- }
120674
- },
120675
- firecrawl: {
120676
- name: "firecrawl",
120677
- enabledByDefault: true,
120678
- install: "npm",
120679
- requiredEnv: ["FIRECRAWL_API_KEY"],
120680
- config: {
120681
- enabled: true,
120682
- command: createNpmPackageCommand("firecrawl-mcp"),
120683
- timeout: 600000,
120684
- environment: { FIRECRAWL_API_KEY: "{env:FIRECRAWL_API_KEY}" }
120685
- }
120686
- },
120687
- rag: {
120688
- name: "rag",
120689
- enabledByDefault: true,
120690
- install: "user-service",
120691
- optionalEnv: ["OPENCODE_RAG_URL"],
120692
- config: {
120693
- enabled: true,
120694
- type: "local",
120695
- command: ["node", resolveAssetScript("mcp", "rag.mjs")],
120696
- environment: {
120697
- OPENCODE_RAG_URL: "{env:OPENCODE_RAG_URL:-http://localhost:9002/tools/search}"
120698
- },
120699
- timeout: 600000
120700
- }
120701
- },
120702
- context7: {
120703
- name: "context7",
120704
- enabledByDefault: true,
120705
- install: "remote",
120706
- optionalEnv: ["CONTEXT7_API_KEY"],
120707
- config: {
120708
- enabled: true,
120709
- type: "remote",
120710
- url: "https://mcp.context7.com/mcp",
120711
- headers: { "X-API-KEY": "{env:CONTEXT7_API_KEY}" },
120712
- timeout: 600000
120713
- }
120714
- },
120715
- mempalace: {
120716
- name: "mempalace",
120717
- enabledByDefault: true,
120718
- install: "python",
120719
- optionalEnv: ["MEMPALACE_PYTHON", "MEMPALACE_PALACE_PATH", "HIAI_MCP_AUTO_INSTALL"],
120720
- config: {
120721
- enabled: true,
120722
- type: "local",
120723
- command: ["node", resolveAssetScript("mcp", "mempalace.mjs"), "--palace", "./.opencode/palace"],
120724
- timeout: 600000
120724
+ // src/config/defaults.ts
120725
+ import { existsSync as existsSync56, readFileSync as readFileSync42 } from "fs";
120726
+ import { dirname as dirname18, join as join65, normalize as normalize2 } from "path";
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;
120725
120739
  }
120726
120740
  }
120727
- };
120728
- function createDefaultMcpConfig() {
120729
- return Object.fromEntries(Object.entries(HIAI_MCP_REGISTRY).map(([name, entry]) => [
120730
- name,
120731
- { ...entry.config, enabled: entry.enabledByDefault }
120732
- ]));
120741
+ throw new Error("[hiai-opencode] Cannot find bundled hiai-opencode.json. The package is incomplete.");
120733
120742
  }
120734
-
120735
- // src/config/defaults.ts
120736
- import { join as join66 } from "path";
120737
- var defaultConfig = {
120738
- agents: {
120739
- bob: { model: MODEL_PRESETS.high },
120740
- guard: { model: MODEL_PRESETS.ultrahigh },
120741
- strategist: { model: MODEL_PRESETS.strategist },
120742
- critic: { model: MODEL_PRESETS.critic },
120743
- coder: { model: MODEL_PRESETS.mid },
120744
- designer: {
120745
- model: "openrouter/google/gemini-3.1-pro",
120746
- description: "Creative visual problem-solver for high-touch UI, interaction, and brand-level interface direction. Best used when the task needs taste, composition, and design judgment rather than plain implementation. (Designer - HiaiOpenCode)"
120747
- },
120748
- sub: { model: MODEL_PRESETS.fast },
120749
- researcher: { model: MODEL_PRESETS.fast },
120750
- multimodal: { model: MODEL_PRESETS.vision },
120751
- "quality-guardian": { model: MODEL_PRESETS.mid },
120752
- "platform-manager": { model: MODEL_PRESETS.fast },
120753
- brainstormer: { model: MODEL_PRESETS.fast },
120754
- "agent-skills": { model: MODEL_PRESETS.fast }
120755
- },
120756
- agentRequirements: {},
120757
- categories: {
120758
- "visual-engineering": { model: MODEL_PRESETS.vision, variant: "high" },
120759
- artistry: { model: MODEL_PRESETS.vision, variant: "high" },
120760
- ultrabrain: { model: MODEL_PRESETS.ultrahigh, variant: "xhigh" },
120761
- deep: { model: MODEL_PRESETS.reasoning, variant: "medium" },
120762
- quick: { model: MODEL_PRESETS.fast },
120763
- writing: { model: MODEL_PRESETS.writing },
120764
- git: { model: MODEL_PRESETS.fast },
120765
- "unspecified-low": { model: MODEL_PRESETS.mid },
120766
- "unspecified-high": { model: MODEL_PRESETS.high, variant: "max" }
120767
- },
120768
- categoryRequirements: {},
120769
- mcp: createDefaultMcpConfig(),
120770
- lsp: {
120771
- typescript: {
120772
- command: ["typescript-language-server", "--stdio"],
120773
- extensions: [".ts", ".tsx", ".mts", ".cts"]
120774
- },
120775
- svelte: {
120776
- command: ["svelteserver", "--stdio"],
120777
- extensions: [".svelte"]
120778
- },
120779
- eslint: {
120780
- command: ["node", join66(import.meta.dirname, "..", "assets", "runtime", "npm-package-runner.mjs"), "eslint-lsp", "--stdio"],
120781
- extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
120782
- },
120783
- bash: {
120784
- command: ["node", join66(import.meta.dirname, "..", "assets", "runtime", "npm-package-runner.mjs"), "bash-language-server", "start"],
120785
- extensions: [".sh", ".bash"]
120786
- },
120787
- pyright: {
120788
- command: ["pyright-langserver", "--stdio"],
120789
- extensions: [".py"]
120790
- }
120791
- },
120792
- subtask2: {
120793
- replace_generic: true,
120794
- generic_return: null
120795
- },
120796
- skills: {
120797
- enabled: true,
120798
- disabled: []
120799
- },
120800
- permissions: {
120801
- read: { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" },
120802
- edit: { "*": "allow" },
120803
- bash: { "*": "allow" },
120804
- deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"]
120805
- },
120806
- ollama: {
120807
- enabled: false,
120808
- model: "{env:OLLAMA_MODEL:-qwen3.5:4b}",
120809
- baseUrl: "http://localhost:11434",
120810
- purpose: "helper"
120743
+ function expandPluginRootPlaceholders(value, pluginRoot) {
120744
+ if (typeof value === "string") {
120745
+ return value.replaceAll("{pluginRoot}", pluginRoot);
120811
120746
  }
120812
- };
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();
120813
120766
 
120814
120767
  // src/config/types.ts
120815
120768
  var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
@@ -120817,6 +120770,8 @@ var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
120817
120770
  zoe: "bob",
120818
120771
  build: "bob",
120819
120772
  "pre-plan": "strategist",
120773
+ manager: "platform-manager",
120774
+ vision: "multimodal",
120820
120775
  logician: "strategist",
120821
120776
  librarian: "researcher",
120822
120777
  explore: "researcher",
@@ -120854,8 +120809,8 @@ function deepMerge2(base, override) {
120854
120809
  function findConfigFile(searchDirs) {
120855
120810
  for (const dir of searchDirs) {
120856
120811
  for (const filename of CONFIG_FILENAMES) {
120857
- const candidate = join67(dir, filename);
120858
- if (existsSync56(candidate))
120812
+ const candidate = join66(dir, filename);
120813
+ if (existsSync57(candidate))
120859
120814
  return candidate;
120860
120815
  }
120861
120816
  }
@@ -120927,13 +120882,13 @@ function normalizeCompactLspConfig(rawConfig) {
120927
120882
  function loadConfig(projectDir) {
120928
120883
  const searchDirs = [
120929
120884
  projectDir,
120930
- join67(projectDir, ".opencode"),
120931
- join67(process.env.HOME || "", ".config", "opencode")
120885
+ join66(projectDir, ".opencode"),
120886
+ join66(process.env.HOME || "", ".config", "opencode")
120932
120887
  ];
120933
120888
  const configPath = findConfigFile(searchDirs);
120934
120889
  if (!configPath)
120935
120890
  return BASE_CONFIG;
120936
- const raw = readFileSync42(configPath, "utf-8");
120891
+ const raw = readFileSync43(configPath, "utf-8");
120937
120892
  const parsed = parse2(raw);
120938
120893
  const normalizedParsed = normalizeCompactLspConfig(parsed);
120939
120894
  const validated = HiaiOpencodeConfigSchema.parse(normalizedParsed);
@@ -120949,12 +120904,12 @@ function resolveEnvVars(value) {
120949
120904
  // src/shared/migrate-legacy-config-file.ts
120950
120905
  init_logger();
120951
120906
  init_plugin_identity();
120952
- import { existsSync as existsSync57, readFileSync as readFileSync43, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
120953
- import { join as join68, dirname as dirname18, basename as basename9 } from "path";
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";
120954
120909
  function buildCanonicalPath(legacyPath) {
120955
- const dir = dirname18(legacyPath);
120910
+ const dir = dirname19(legacyPath);
120956
120911
  const ext = basename9(legacyPath).includes(".jsonc") ? ".jsonc" : ".json";
120957
- return join68(dir, `${CONFIG_BASENAME}${ext}`);
120912
+ return join67(dir, `${CONFIG_BASENAME}${ext}`);
120958
120913
  }
120959
120914
  function archiveLegacyConfigFile(legacyPath) {
120960
120915
  const backupPath = `${legacyPath}.bak`;
@@ -120986,15 +120941,15 @@ function archiveLegacyConfigFile(legacyPath) {
120986
120941
  }
120987
120942
  }
120988
120943
  function migrateLegacyConfigFile(legacyPath) {
120989
- if (!existsSync57(legacyPath))
120944
+ if (!existsSync58(legacyPath))
120990
120945
  return false;
120991
120946
  if (!basename9(legacyPath).startsWith(LEGACY_CONFIG_BASENAME))
120992
120947
  return false;
120993
120948
  const canonicalPath = buildCanonicalPath(legacyPath);
120994
- if (existsSync57(canonicalPath))
120949
+ if (existsSync58(canonicalPath))
120995
120950
  return false;
120996
120951
  try {
120997
- const content = readFileSync43(legacyPath, "utf-8");
120952
+ const content = readFileSync44(legacyPath, "utf-8");
120998
120953
  writeFileAtomically(canonicalPath, content);
120999
120954
  const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath);
121000
120955
  log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
@@ -122514,11 +122469,11 @@ function createRuntimeFallbackHook(ctx, options) {
122514
122469
  };
122515
122470
  }
122516
122471
  // src/hooks/write-existing-file-guard/hook.ts
122517
- import { existsSync as existsSync60, realpathSync as realpathSync6 } from "fs";
122518
- import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute11, join as join70, normalize as normalize2, relative as relative8, resolve as resolve14 } from "path";
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";
122519
122474
 
122520
122475
  // src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
122521
- import { existsSync as existsSync59 } from "fs";
122476
+ import { existsSync as existsSync60 } from "fs";
122522
122477
 
122523
122478
  // src/hooks/write-existing-file-guard/session-read-permissions.ts
122524
122479
  function touchSession(sessionLastAccess, sessionID) {
@@ -122606,7 +122561,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
122606
122561
  return;
122607
122562
  }
122608
122563
  if (toolName === "read") {
122609
- if (!existsSync59(resolvedPath) || !input.sessionID) {
122564
+ if (!existsSync60(resolvedPath) || !input.sessionID) {
122610
122565
  return;
122611
122566
  }
122612
122567
  registerReadPermission({
@@ -122622,7 +122577,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
122622
122577
  if (argsRecord && "overwrite" in argsRecord) {
122623
122578
  delete argsRecord.overwrite;
122624
122579
  }
122625
- if (!existsSync59(resolvedPath)) {
122580
+ if (!existsSync60(resolvedPath)) {
122626
122581
  return;
122627
122582
  }
122628
122583
  const isBobPath2 = canonicalPath.includes("/.bob/");
@@ -122673,7 +122628,7 @@ function getPathFromArgs(args) {
122673
122628
  return args?.filePath ?? args?.path ?? args?.file_path;
122674
122629
  }
122675
122630
  function resolveInputPath(ctx, inputPath) {
122676
- return normalize2(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
122631
+ return normalize3(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
122677
122632
  }
122678
122633
  function isPathInsideDirectory(pathToCheck, directory) {
122679
122634
  const relativePath = relative8(directory, pathToCheck);
@@ -122681,18 +122636,18 @@ function isPathInsideDirectory(pathToCheck, directory) {
122681
122636
  }
122682
122637
  function toCanonicalPath2(absolutePath) {
122683
122638
  let canonicalPath = absolutePath;
122684
- if (existsSync60(absolutePath)) {
122639
+ if (existsSync61(absolutePath)) {
122685
122640
  try {
122686
122641
  canonicalPath = realpathSync6.native(absolutePath);
122687
122642
  } catch {
122688
122643
  canonicalPath = absolutePath;
122689
122644
  }
122690
122645
  } else {
122691
- const absoluteDir = dirname20(absolutePath);
122692
- const resolvedDir = existsSync60(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
122693
- canonicalPath = join70(resolvedDir, basename11(absolutePath));
122646
+ const absoluteDir = dirname21(absolutePath);
122647
+ const resolvedDir = existsSync61(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
122648
+ canonicalPath = join69(resolvedDir, basename11(absolutePath));
122694
122649
  }
122695
- return normalize2(canonicalPath);
122650
+ return normalize3(canonicalPath);
122696
122651
  }
122697
122652
  function isOverwriteEnabled(value) {
122698
122653
  if (value === true) {
@@ -123966,23 +123921,23 @@ init_logger();
123966
123921
  init_plugin_identity();
123967
123922
 
123968
123923
  // src/hooks/legacy-plugin-toast/auto-migrate.ts
123969
- import { existsSync as existsSync61, readFileSync as readFileSync45 } from "fs";
123970
- import { join as join71 } from "path";
123924
+ import { existsSync as existsSync62, readFileSync as readFileSync46 } from "fs";
123925
+ import { join as join70 } from "path";
123971
123926
  init_plugin_identity();
123972
123927
  function detectOpenCodeConfigPath(overrideConfigDir) {
123973
123928
  if (overrideConfigDir) {
123974
- const jsoncPath = join71(overrideConfigDir, "opencode.jsonc");
123975
- const jsonPath = join71(overrideConfigDir, "opencode.json");
123976
- if (existsSync61(jsoncPath))
123929
+ const jsoncPath = join70(overrideConfigDir, "opencode.jsonc");
123930
+ const jsonPath = join70(overrideConfigDir, "opencode.json");
123931
+ if (existsSync62(jsoncPath))
123977
123932
  return jsoncPath;
123978
- if (existsSync61(jsonPath))
123933
+ if (existsSync62(jsonPath))
123979
123934
  return jsonPath;
123980
123935
  return null;
123981
123936
  }
123982
123937
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
123983
- if (existsSync61(paths.configJsonc))
123938
+ if (existsSync62(paths.configJsonc))
123984
123939
  return paths.configJsonc;
123985
- if (existsSync61(paths.configJson))
123940
+ if (existsSync62(paths.configJson))
123986
123941
  return paths.configJson;
123987
123942
  return null;
123988
123943
  }
@@ -123991,7 +123946,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
123991
123946
  if (!configPath)
123992
123947
  return { migrated: false, from: null, to: null, configPath: null };
123993
123948
  try {
123994
- const content = readFileSync45(configPath, "utf-8");
123949
+ const content = readFileSync46(configPath, "utf-8");
123995
123950
  const parseResult = parseJsoncSafe(content);
123996
123951
  if (!parseResult.data?.plugin)
123997
123952
  return { migrated: false, from: null, to: null, configPath };
@@ -124109,7 +124064,7 @@ async function queryOllama(args) {
124109
124064
  }
124110
124065
 
124111
124066
  // src/hooks/fast-apply/tool-execute-before-handler.ts
124112
- import { existsSync as existsSync62, readFileSync as readFileSync46 } from "fs";
124067
+ import { existsSync as existsSync63, readFileSync as readFileSync47 } from "fs";
124113
124068
  async function handleFastApplyToolExecuteBefore(args) {
124114
124069
  const { input, output, config: config2 } = args;
124115
124070
  const normalizedTool = input.tool.toLowerCase();
@@ -124128,7 +124083,7 @@ async function handleFastApplyToolExecuteBefore(args) {
124128
124083
  });
124129
124084
  return;
124130
124085
  }
124131
- if (!existsSync62(filePath)) {
124086
+ if (!existsSync63(filePath)) {
124132
124087
  log("[fast-apply] Skipping: file does not exist (new file)", {
124133
124088
  sessionID: input.sessionID,
124134
124089
  callID: input.callID,
@@ -124138,7 +124093,7 @@ async function handleFastApplyToolExecuteBefore(args) {
124138
124093
  }
124139
124094
  let originalContent;
124140
124095
  try {
124141
- originalContent = readFileSync46(filePath, "utf-8");
124096
+ originalContent = readFileSync47(filePath, "utf-8");
124142
124097
  } catch (err) {
124143
124098
  log("[fast-apply] Failed to read file, falling back to default", {
124144
124099
  sessionID: input.sessionID,
@@ -124517,13 +124472,13 @@ var DEFAULT_MAX_SYMBOLS = 200;
124517
124472
  var DEFAULT_MAX_DIAGNOSTICS = 200;
124518
124473
  var DEFAULT_MAX_DIRECTORY_FILES = 50;
124519
124474
  // src/tools/lsp/server-config-loader.ts
124520
- import { existsSync as existsSync63, readFileSync as readFileSync47 } from "fs";
124521
- import { join as join72 } from "path";
124475
+ import { existsSync as existsSync64, readFileSync as readFileSync48 } from "fs";
124476
+ import { join as join71 } from "path";
124522
124477
  function loadJsonFile(path7) {
124523
- if (!existsSync63(path7))
124478
+ if (!existsSync64(path7))
124524
124479
  return null;
124525
124480
  try {
124526
- return parseJsonc(readFileSync47(path7, "utf-8"));
124481
+ return parseJsonc(readFileSync48(path7, "utf-8"));
124527
124482
  } catch {
124528
124483
  return null;
124529
124484
  }
@@ -124532,9 +124487,9 @@ function getConfigPaths2() {
124532
124487
  const cwd = process.cwd();
124533
124488
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
124534
124489
  return {
124535
- project: detectPluginConfigFile(join72(cwd, ".opencode")).path,
124490
+ project: detectPluginConfigFile(join71(cwd, ".opencode")).path,
124536
124491
  user: detectPluginConfigFile(configDir).path,
124537
- opencode: detectConfigFile(join72(configDir, "opencode")).path
124492
+ opencode: detectConfigFile(join71(configDir, "opencode")).path
124538
124493
  };
124539
124494
  }
124540
124495
  function loadAllConfigs() {
@@ -124603,20 +124558,20 @@ function getMergedServers() {
124603
124558
  }
124604
124559
 
124605
124560
  // src/tools/lsp/server-installation.ts
124606
- import { existsSync as existsSync64 } from "fs";
124607
- import { delimiter, join as join74 } from "path";
124561
+ import { existsSync as existsSync65 } from "fs";
124562
+ import { delimiter, join as join73 } from "path";
124608
124563
 
124609
124564
  // src/tools/lsp/server-path-bases.ts
124610
- import { join as join73 } from "path";
124565
+ import { join as join72 } from "path";
124611
124566
  function getLspServerAdditionalPathBases(workingDirectory) {
124612
124567
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
124613
- const dataDir = join73(getDataDir(), "opencode");
124568
+ const dataDir = join72(getDataDir(), "opencode");
124614
124569
  return [
124615
- join73(workingDirectory, "node_modules", ".bin"),
124616
- join73(configDir, "bin"),
124617
- join73(configDir, "node_modules", ".bin"),
124618
- join73(dataDir, "bin"),
124619
- join73(dataDir, "bin", "node_modules", ".bin")
124570
+ join72(workingDirectory, "node_modules", ".bin"),
124571
+ join72(configDir, "bin"),
124572
+ join72(configDir, "node_modules", ".bin"),
124573
+ join72(dataDir, "bin"),
124574
+ join72(dataDir, "bin", "node_modules", ".bin")
124620
124575
  ];
124621
124576
  }
124622
124577
 
@@ -124626,7 +124581,7 @@ function isServerInstalled(command) {
124626
124581
  return false;
124627
124582
  const cmd = command[0];
124628
124583
  if (cmd.includes("/") || cmd.includes("\\")) {
124629
- if (existsSync64(cmd))
124584
+ if (existsSync65(cmd))
124630
124585
  return true;
124631
124586
  }
124632
124587
  const isWindows2 = process.platform === "win32";
@@ -124647,14 +124602,14 @@ function isServerInstalled(command) {
124647
124602
  const paths = pathEnv.split(delimiter);
124648
124603
  for (const p of paths) {
124649
124604
  for (const suffix of exts) {
124650
- if (existsSync64(join74(p, cmd + suffix))) {
124605
+ if (existsSync65(join73(p, cmd + suffix))) {
124651
124606
  return true;
124652
124607
  }
124653
124608
  }
124654
124609
  }
124655
124610
  for (const base of getLspServerAdditionalPathBases(process.cwd())) {
124656
124611
  for (const suffix of exts) {
124657
- if (existsSync64(join74(base, cmd + suffix))) {
124612
+ if (existsSync65(join73(base, cmd + suffix))) {
124658
124613
  return true;
124659
124614
  }
124660
124615
  }
@@ -124712,13 +124667,13 @@ function getLanguageId(ext) {
124712
124667
  init_logger();
124713
124668
  var {spawn: bunSpawn2 } = globalThis.Bun;
124714
124669
  import { spawn as nodeSpawn2 } from "child_process";
124715
- import { existsSync as existsSync65, statSync as statSync7 } from "fs";
124670
+ import { existsSync as existsSync66, statSync as statSync7 } from "fs";
124716
124671
  function shouldUseNodeSpawn() {
124717
124672
  return process.platform === "win32";
124718
124673
  }
124719
124674
  function validateCwd(cwd) {
124720
124675
  try {
124721
- if (!existsSync65(cwd)) {
124676
+ if (!existsSync66(cwd)) {
124722
124677
  return { valid: false, error: `Working directory does not exist: ${cwd}` };
124723
124678
  }
124724
124679
  const stats = statSync7(cwd);
@@ -124850,7 +124805,7 @@ function spawnProcess(command, options) {
124850
124805
  return proc;
124851
124806
  }
124852
124807
  // src/tools/lsp/lsp-client.ts
124853
- import { readFileSync as readFileSync48 } from "fs";
124808
+ import { readFileSync as readFileSync49 } from "fs";
124854
124809
  import { extname as extname4, resolve as resolve15 } from "path";
124855
124810
  import { pathToFileURL as pathToFileURL2 } from "url";
124856
124811
 
@@ -125122,7 +125077,7 @@ class LSPClient extends LSPClientConnection {
125122
125077
  async openFile(filePath) {
125123
125078
  const absPath = resolve15(filePath);
125124
125079
  const uri = pathToFileURL2(absPath).href;
125125
- const text = readFileSync48(absPath, "utf-8");
125080
+ const text = readFileSync49(absPath, "utf-8");
125126
125081
  if (!this.openedFiles.has(absPath)) {
125127
125082
  const ext = extname4(absPath);
125128
125083
  const languageId = getLanguageId(ext);
@@ -125480,10 +125435,10 @@ var lspManager = LSPServerManager.getInstance();
125480
125435
  // src/tools/lsp/lsp-client-wrapper.ts
125481
125436
  import { extname as extname5, resolve as resolve16 } from "path";
125482
125437
  import { fileURLToPath as fileURLToPath2 } from "url";
125483
- import { existsSync as existsSync66, statSync as statSync8 } from "fs";
125438
+ import { existsSync as existsSync67, statSync as statSync8 } from "fs";
125484
125439
  init_plugin_identity();
125485
125440
  function isDirectoryPath(filePath) {
125486
- if (!existsSync66(filePath)) {
125441
+ if (!existsSync67(filePath)) {
125487
125442
  return false;
125488
125443
  }
125489
125444
  return statSync8(filePath).isDirectory();
@@ -125493,14 +125448,14 @@ function uriToPath(uri) {
125493
125448
  }
125494
125449
  function findWorkspaceRoot(filePath) {
125495
125450
  let dir = resolve16(filePath);
125496
- if (!existsSync66(dir) || !isDirectoryPath(dir)) {
125451
+ if (!existsSync67(dir) || !isDirectoryPath(dir)) {
125497
125452
  dir = __require("path").dirname(dir);
125498
125453
  }
125499
125454
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
125500
125455
  let prevDir = "";
125501
125456
  while (dir !== prevDir) {
125502
125457
  for (const marker of markers) {
125503
- if (existsSync66(__require("path").join(dir, marker))) {
125458
+ if (existsSync67(__require("path").join(dir, marker))) {
125504
125459
  return dir;
125505
125460
  }
125506
125461
  }
@@ -125675,10 +125630,10 @@ function formatApplyResult(result) {
125675
125630
  `);
125676
125631
  }
125677
125632
  // src/tools/lsp/workspace-edit.ts
125678
- import { readFileSync as readFileSync49, writeFileSync as writeFileSync17 } from "fs";
125633
+ import { readFileSync as readFileSync50, writeFileSync as writeFileSync17 } from "fs";
125679
125634
  function applyTextEditsToFile(filePath, edits) {
125680
125635
  try {
125681
- let content = readFileSync49(filePath, "utf-8");
125636
+ let content = readFileSync50(filePath, "utf-8");
125682
125637
  const lines = content.split(`
125683
125638
  `);
125684
125639
  const sortedEdits = [...edits].sort((a, b) => {
@@ -125744,7 +125699,7 @@ function applyWorkspaceEdit(edit) {
125744
125699
  try {
125745
125700
  const oldPath = uriToPath(change.oldUri);
125746
125701
  const newPath = uriToPath(change.newUri);
125747
- const content = readFileSync49(oldPath, "utf-8");
125702
+ const content = readFileSync50(oldPath, "utf-8");
125748
125703
  writeFileSync17(newPath, content, "utf-8");
125749
125704
  __require("fs").unlinkSync(oldPath);
125750
125705
  result.filesModified.push(newPath);
@@ -125910,8 +125865,8 @@ init_tool();
125910
125865
  import { resolve as resolve18 } from "path";
125911
125866
 
125912
125867
  // src/tools/lsp/directory-diagnostics.ts
125913
- import { existsSync as existsSync67, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
125914
- import { extname as extname6, join as join75, resolve as resolve17 } from "path";
125868
+ import { existsSync as existsSync68, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
125869
+ import { extname as extname6, join as join74, resolve as resolve17 } from "path";
125915
125870
  var SKIP_DIRECTORIES = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
125916
125871
  function collectFilesWithExtension(dir, extension, maxFiles) {
125917
125872
  const files = [];
@@ -125927,7 +125882,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
125927
125882
  for (const entry of entries) {
125928
125883
  if (files.length >= maxFiles)
125929
125884
  return;
125930
- const fullPath = join75(currentDir, entry);
125885
+ const fullPath = join74(currentDir, entry);
125931
125886
  let stat;
125932
125887
  try {
125933
125888
  stat = lstatSync2(fullPath);
@@ -125956,7 +125911,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
125956
125911
  throw new Error(`Extension must start with a dot (e.g., ".ts", not "${extension}"). ` + `Use ".${extension}" instead.`);
125957
125912
  }
125958
125913
  const absDir = resolve17(directory);
125959
- if (!existsSync67(absDir)) {
125914
+ if (!existsSync68(absDir)) {
125960
125915
  throw new Error(`Directory does not exist: ${absDir}`);
125961
125916
  }
125962
125917
  const serverResult = findServerForExtension(extension);
@@ -126030,7 +125985,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
126030
125985
 
126031
125986
  // src/tools/lsp/infer-extension.ts
126032
125987
  import { readdirSync as readdirSync20, lstatSync as lstatSync3 } from "fs";
126033
- import { extname as extname7, join as join76 } from "path";
125988
+ import { extname as extname7, join as join75 } from "path";
126034
125989
  var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
126035
125990
  var MAX_SCAN_ENTRIES = 500;
126036
125991
  function inferExtensionFromDirectory(directory) {
@@ -126048,7 +126003,7 @@ function inferExtensionFromDirectory(directory) {
126048
126003
  for (const entry of entries) {
126049
126004
  if (scanned >= MAX_SCAN_ENTRIES)
126050
126005
  return;
126051
- const fullPath = join76(dir, entry);
126006
+ const fullPath = join75(dir, entry);
126052
126007
  let stat;
126053
126008
  try {
126054
126009
  stat = lstatSync3(fullPath);
@@ -126217,12 +126172,12 @@ var DEFAULT_MAX_MATCHES = 500;
126217
126172
 
126218
126173
  // src/tools/ast-grep/sg-cli-path.ts
126219
126174
  import { createRequire as createRequire4 } from "module";
126220
- import { dirname as dirname21, join as join78 } from "path";
126221
- import { existsSync as existsSync69, statSync as statSync9 } from "fs";
126175
+ import { dirname as dirname22, join as join77 } from "path";
126176
+ import { existsSync as existsSync70, statSync as statSync9 } from "fs";
126222
126177
 
126223
126178
  // src/tools/ast-grep/downloader.ts
126224
- import { existsSync as existsSync68 } from "fs";
126225
- import { join as join77 } from "path";
126179
+ import { existsSync as existsSync69 } from "fs";
126180
+ import { join as join76 } from "path";
126226
126181
  import { homedir as homedir14 } from "os";
126227
126182
  import { createRequire as createRequire3 } from "module";
126228
126183
  init_logger();
@@ -126250,12 +126205,12 @@ var PLATFORM_MAP2 = {
126250
126205
  function getCacheDir3() {
126251
126206
  if (process.platform === "win32") {
126252
126207
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
126253
- const base2 = localAppData || join77(homedir14(), "AppData", "Local");
126254
- return join77(base2, CACHE_DIR_NAME, "bin");
126208
+ const base2 = localAppData || join76(homedir14(), "AppData", "Local");
126209
+ return join76(base2, CACHE_DIR_NAME, "bin");
126255
126210
  }
126256
126211
  const xdgCache = process.env.XDG_CACHE_HOME;
126257
- const base = xdgCache || join77(homedir14(), ".cache");
126258
- return join77(base, CACHE_DIR_NAME, "bin");
126212
+ const base = xdgCache || join76(homedir14(), ".cache");
126213
+ return join76(base, CACHE_DIR_NAME, "bin");
126259
126214
  }
126260
126215
  function getBinaryName3() {
126261
126216
  return process.platform === "win32" ? "sg.exe" : "sg";
@@ -126272,8 +126227,8 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
126272
126227
  }
126273
126228
  const cacheDir = getCacheDir3();
126274
126229
  const binaryName = getBinaryName3();
126275
- const binaryPath = join77(cacheDir, binaryName);
126276
- if (existsSync68(binaryPath)) {
126230
+ const binaryPath = join76(cacheDir, binaryName);
126231
+ if (existsSync69(binaryPath)) {
126277
126232
  return binaryPath;
126278
126233
  }
126279
126234
  const { arch, os: os4 } = platformInfo;
@@ -126281,7 +126236,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
126281
126236
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version3}/${assetName}`;
126282
126237
  log(`[${PUBLISHED_PACKAGE_NAME}] Downloading ast-grep binary...`);
126283
126238
  try {
126284
- const archivePath = join77(cacheDir, assetName);
126239
+ const archivePath = join76(cacheDir, assetName);
126285
126240
  ensureCacheDir(cacheDir);
126286
126241
  await downloadArchive(downloadUrl, archivePath);
126287
126242
  await extractZipArchive(archivePath, cacheDir);
@@ -126334,9 +126289,9 @@ function findSgCliPathSync() {
126334
126289
  try {
126335
126290
  const require2 = createRequire4(import.meta.url);
126336
126291
  const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
126337
- const cliDirectory = dirname21(cliPackageJsonPath);
126338
- const sgPath = join78(cliDirectory, binaryName);
126339
- if (existsSync69(sgPath) && isValidBinary(sgPath)) {
126292
+ const cliDirectory = dirname22(cliPackageJsonPath);
126293
+ const sgPath = join77(cliDirectory, binaryName);
126294
+ if (existsSync70(sgPath) && isValidBinary(sgPath)) {
126340
126295
  return sgPath;
126341
126296
  }
126342
126297
  } catch {}
@@ -126345,10 +126300,10 @@ function findSgCliPathSync() {
126345
126300
  try {
126346
126301
  const require2 = createRequire4(import.meta.url);
126347
126302
  const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
126348
- const packageDirectory = dirname21(packageJsonPath);
126303
+ const packageDirectory = dirname22(packageJsonPath);
126349
126304
  const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
126350
- const binaryPath = join78(packageDirectory, astGrepBinaryName);
126351
- if (existsSync69(binaryPath) && isValidBinary(binaryPath)) {
126305
+ const binaryPath = join77(packageDirectory, astGrepBinaryName);
126306
+ if (existsSync70(binaryPath) && isValidBinary(binaryPath)) {
126352
126307
  return binaryPath;
126353
126308
  }
126354
126309
  } catch {}
@@ -126356,7 +126311,7 @@ function findSgCliPathSync() {
126356
126311
  if (process.platform === "darwin") {
126357
126312
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
126358
126313
  for (const path7 of homebrewPaths) {
126359
- if (existsSync69(path7) && isValidBinary(path7)) {
126314
+ if (existsSync70(path7) && isValidBinary(path7)) {
126360
126315
  return path7;
126361
126316
  }
126362
126317
  }
@@ -126380,14 +126335,14 @@ function setSgCliPath(path7) {
126380
126335
  }
126381
126336
  // src/tools/ast-grep/cli.ts
126382
126337
  var {spawn: spawn17 } = globalThis.Bun;
126383
- import { existsSync as existsSync71 } from "fs";
126338
+ import { existsSync as existsSync72 } from "fs";
126384
126339
 
126385
126340
  // src/tools/ast-grep/cli-binary-path-resolution.ts
126386
- import { existsSync as existsSync70 } from "fs";
126341
+ import { existsSync as existsSync71 } from "fs";
126387
126342
  var resolvedCliPath3 = null;
126388
126343
  var initPromise3 = null;
126389
126344
  async function getAstGrepPath() {
126390
- if (resolvedCliPath3 !== null && existsSync70(resolvedCliPath3)) {
126345
+ if (resolvedCliPath3 !== null && existsSync71(resolvedCliPath3)) {
126391
126346
  return resolvedCliPath3;
126392
126347
  }
126393
126348
  if (initPromise3) {
@@ -126395,7 +126350,7 @@ async function getAstGrepPath() {
126395
126350
  }
126396
126351
  initPromise3 = (async () => {
126397
126352
  const syncPath = findSgCliPathSync();
126398
- if (syncPath && existsSync70(syncPath)) {
126353
+ if (syncPath && existsSync71(syncPath)) {
126399
126354
  resolvedCliPath3 = syncPath;
126400
126355
  setSgCliPath(syncPath);
126401
126356
  return syncPath;
@@ -126494,7 +126449,7 @@ async function runSg(options) {
126494
126449
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
126495
126450
  args.push(...paths);
126496
126451
  let cliPath = getSgCliPath();
126497
- if (!cliPath || !existsSync71(cliPath)) {
126452
+ if (!cliPath || !existsSync72(cliPath)) {
126498
126453
  const downloadedPath = await getAstGrepPath();
126499
126454
  if (downloadedPath) {
126500
126455
  cliPath = downloadedPath;
@@ -126749,20 +126704,20 @@ import { resolve as resolve19 } from "path";
126749
126704
  var {spawn: spawn18 } = globalThis.Bun;
126750
126705
 
126751
126706
  // src/tools/grep/constants.ts
126752
- import { existsSync as existsSync73 } from "fs";
126753
- import { join as join80, dirname as dirname22 } from "path";
126707
+ import { existsSync as existsSync74 } from "fs";
126708
+ import { join as join79, dirname as dirname23 } from "path";
126754
126709
  import { spawnSync as spawnSync4 } from "child_process";
126755
126710
 
126756
126711
  // src/tools/grep/downloader.ts
126757
- import { existsSync as existsSync72, readdirSync as readdirSync21 } from "fs";
126758
- import { join as join79 } from "path";
126712
+ import { existsSync as existsSync73, readdirSync as readdirSync21 } from "fs";
126713
+ import { join as join78 } from "path";
126759
126714
  init_plugin_identity();
126760
126715
  function findFileRecursive(dir, filename) {
126761
126716
  try {
126762
126717
  const entries = readdirSync21(dir, { withFileTypes: true, recursive: true });
126763
126718
  for (const entry of entries) {
126764
126719
  if (entry.isFile() && entry.name === filename) {
126765
- return join79(entry.parentPath ?? dir, entry.name);
126720
+ return join78(entry.parentPath ?? dir, entry.name);
126766
126721
  }
126767
126722
  }
126768
126723
  } catch {
@@ -126783,11 +126738,11 @@ function getPlatformKey() {
126783
126738
  }
126784
126739
  function getInstallDir() {
126785
126740
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
126786
- return join79(homeDir, ".cache", CACHE_DIR_NAME, "bin");
126741
+ return join78(homeDir, ".cache", CACHE_DIR_NAME, "bin");
126787
126742
  }
126788
126743
  function getRgPath() {
126789
126744
  const isWindows2 = process.platform === "win32";
126790
- return join79(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
126745
+ return join78(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
126791
126746
  }
126792
126747
  async function extractTarGz2(archivePath, destDir) {
126793
126748
  const platformKey = getPlatformKey();
@@ -126804,7 +126759,7 @@ async function extractZip2(archivePath, destDir) {
126804
126759
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
126805
126760
  const foundPath = findFileRecursive(destDir, binaryName);
126806
126761
  if (foundPath) {
126807
- const destPath = join79(destDir, binaryName);
126762
+ const destPath = join78(destDir, binaryName);
126808
126763
  if (foundPath !== destPath) {
126809
126764
  const { renameSync: renameSync4 } = await import("fs");
126810
126765
  renameSync4(foundPath, destPath);
@@ -126819,13 +126774,13 @@ async function downloadAndInstallRipgrep() {
126819
126774
  }
126820
126775
  const installDir = getInstallDir();
126821
126776
  const rgPath = getRgPath();
126822
- if (existsSync72(rgPath)) {
126777
+ if (existsSync73(rgPath)) {
126823
126778
  return rgPath;
126824
126779
  }
126825
126780
  ensureCacheDir(installDir);
126826
126781
  const filename = `ripgrep-${RG_VERSION}-${config4.platform}.${config4.extension}`;
126827
126782
  const url3 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
126828
- const archivePath = join79(installDir, filename);
126783
+ const archivePath = join78(installDir, filename);
126829
126784
  try {
126830
126785
  await downloadArchive(url3, archivePath);
126831
126786
  if (config4.extension === "tar.gz") {
@@ -126834,7 +126789,7 @@ async function downloadAndInstallRipgrep() {
126834
126789
  await extractZip2(archivePath, installDir);
126835
126790
  }
126836
126791
  ensureExecutable(rgPath);
126837
- if (!existsSync72(rgPath)) {
126792
+ if (!existsSync73(rgPath)) {
126838
126793
  throw new Error("ripgrep binary not found after extraction");
126839
126794
  }
126840
126795
  return rgPath;
@@ -126846,7 +126801,7 @@ async function downloadAndInstallRipgrep() {
126846
126801
  }
126847
126802
  function getInstalledRipgrepPath() {
126848
126803
  const rgPath = getRgPath();
126849
- return existsSync72(rgPath) ? rgPath : null;
126804
+ return existsSync73(rgPath) ? rgPath : null;
126850
126805
  }
126851
126806
 
126852
126807
  // src/tools/grep/constants.ts
@@ -126868,18 +126823,18 @@ function findExecutable(name) {
126868
126823
  }
126869
126824
  function getOpenCodeBundledRg() {
126870
126825
  const execPath = process.execPath;
126871
- const execDir = dirname22(execPath);
126826
+ const execDir = dirname23(execPath);
126872
126827
  const isWindows2 = process.platform === "win32";
126873
126828
  const rgName = isWindows2 ? "rg.exe" : "rg";
126874
126829
  const candidates = [
126875
- join80(getDataDir(), "opencode", "bin", rgName),
126876
- join80(execDir, rgName),
126877
- join80(execDir, "bin", rgName),
126878
- join80(execDir, "..", "bin", rgName),
126879
- join80(execDir, "..", "libexec", rgName)
126830
+ join79(getDataDir(), "opencode", "bin", rgName),
126831
+ join79(execDir, rgName),
126832
+ join79(execDir, "bin", rgName),
126833
+ join79(execDir, "..", "bin", rgName),
126834
+ join79(execDir, "..", "libexec", rgName)
126880
126835
  ];
126881
126836
  for (const candidate of candidates) {
126882
- if (existsSync73(candidate)) {
126837
+ if (existsSync74(candidate)) {
126883
126838
  return candidate;
126884
126839
  }
126885
126840
  }
@@ -127531,10 +127486,10 @@ Use this when a task matches an available skill's or command's description.
127531
127486
  `;
127532
127487
  // src/tools/skill/tools.ts
127533
127488
  init_dist();
127534
- import { dirname as dirname24 } from "path";
127489
+ import { dirname as dirname25 } from "path";
127535
127490
 
127536
127491
  // src/tools/slashcommand/command-output-formatter.ts
127537
- import { dirname as dirname23 } from "path";
127492
+ import { dirname as dirname24 } from "path";
127538
127493
  async function formatLoadedCommand(command, userMessage) {
127539
127494
  const sections = [];
127540
127495
  sections.push(`# /${command.name} Command
@@ -127573,7 +127528,7 @@ async function formatLoadedCommand(command, userMessage) {
127573
127528
  if (!content && command.lazyContentLoader) {
127574
127529
  content = await command.lazyContentLoader.load();
127575
127530
  }
127576
- const commandDir = command.path ? dirname23(command.path) : process.cwd();
127531
+ const commandDir = command.path ? dirname24(command.path) : process.cwd();
127577
127532
  const withFileReferences = await resolveFileReferencesInText(content, commandDir);
127578
127533
  const resolvedContent = await resolveCommandsInText(withFileReferences);
127579
127534
  let finalContent = resolvedContent.trim();
@@ -127963,7 +127918,7 @@ function createSkillTool(options = {}) {
127963
127918
  if (matchedSkill.name === "git-master") {
127964
127919
  body = injectGitMasterConfig(body, options.gitMasterConfig);
127965
127920
  }
127966
- const dir = matchedSkill.path ? dirname24(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
127921
+ const dir = matchedSkill.path ? dirname25(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
127967
127922
  const output = [
127968
127923
  `## Skill: ${matchedSkill.name}`,
127969
127924
  "",
@@ -128006,9 +127961,9 @@ var skill = createSkillTool();
128006
127961
  init_tool();
128007
127962
 
128008
127963
  // src/tools/session-manager/constants.ts
128009
- import { join as join81 } from "path";
128010
- var TODO_DIR2 = join81(getClaudeConfigDir(), "todos");
128011
- var TRANSCRIPT_DIR2 = join81(getClaudeConfigDir(), "transcripts");
127964
+ import { join as join80 } from "path";
127965
+ var TODO_DIR2 = join80(getClaudeConfigDir(), "todos");
127966
+ var TRANSCRIPT_DIR2 = join80(getClaudeConfigDir(), "transcripts");
128012
127967
  var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
128013
127968
 
128014
127969
  Returns a list of available session IDs with metadata including message count, date range, and agents used.
@@ -128081,11 +128036,11 @@ Has Todos: Yes (12 items, 8 completed)
128081
128036
  Has Transcript: Yes (234 entries)`;
128082
128037
 
128083
128038
  // src/tools/session-manager/file-storage.ts
128084
- import { existsSync as existsSync74 } from "fs";
128039
+ import { existsSync as existsSync75 } from "fs";
128085
128040
  import { readdir, readFile } from "fs/promises";
128086
- import { join as join82 } from "path";
128041
+ import { join as join81 } from "path";
128087
128042
  async function getFileMainSessions(directory) {
128088
- if (!existsSync74(SESSION_STORAGE))
128043
+ if (!existsSync75(SESSION_STORAGE))
128089
128044
  return [];
128090
128045
  const sessions = [];
128091
128046
  try {
@@ -128093,13 +128048,13 @@ async function getFileMainSessions(directory) {
128093
128048
  for (const projectDir of projectDirs) {
128094
128049
  if (!projectDir.isDirectory())
128095
128050
  continue;
128096
- const projectPath = join82(SESSION_STORAGE, projectDir.name);
128051
+ const projectPath = join81(SESSION_STORAGE, projectDir.name);
128097
128052
  const sessionFiles = await readdir(projectPath);
128098
128053
  for (const file3 of sessionFiles) {
128099
128054
  if (!file3.endsWith(".json"))
128100
128055
  continue;
128101
128056
  try {
128102
- const content = await readFile(join82(projectPath, file3), "utf-8");
128057
+ const content = await readFile(join81(projectPath, file3), "utf-8");
128103
128058
  const meta3 = JSON.parse(content);
128104
128059
  if (meta3.parentID)
128105
128060
  continue;
@@ -128117,7 +128072,7 @@ async function getFileMainSessions(directory) {
128117
128072
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
128118
128073
  }
128119
128074
  async function getFileAllSessions() {
128120
- if (!existsSync74(MESSAGE_STORAGE))
128075
+ if (!existsSync75(MESSAGE_STORAGE))
128121
128076
  return [];
128122
128077
  const sessions = [];
128123
128078
  async function scanDirectory(dir) {
@@ -128126,7 +128081,7 @@ async function getFileAllSessions() {
128126
128081
  for (const entry of entries) {
128127
128082
  if (!entry.isDirectory())
128128
128083
  continue;
128129
- const sessionPath = join82(dir, entry.name);
128084
+ const sessionPath = join81(dir, entry.name);
128130
128085
  const files = await readdir(sessionPath);
128131
128086
  if (files.some((file3) => file3.endsWith(".json"))) {
128132
128087
  sessions.push(entry.name);
@@ -128146,7 +128101,7 @@ async function fileSessionExists(sessionID) {
128146
128101
  }
128147
128102
  async function getFileSessionMessages(sessionID) {
128148
128103
  const messageDir = getMessageDir(sessionID);
128149
- if (!messageDir || !existsSync74(messageDir))
128104
+ if (!messageDir || !existsSync75(messageDir))
128150
128105
  return [];
128151
128106
  const messages = [];
128152
128107
  try {
@@ -128155,7 +128110,7 @@ async function getFileSessionMessages(sessionID) {
128155
128110
  if (!file3.endsWith(".json"))
128156
128111
  continue;
128157
128112
  try {
128158
- const content = await readFile(join82(messageDir, file3), "utf-8");
128113
+ const content = await readFile(join81(messageDir, file3), "utf-8");
128159
128114
  const meta3 = JSON.parse(content);
128160
128115
  const parts = await readParts2(meta3.id);
128161
128116
  messages.push({
@@ -128181,8 +128136,8 @@ async function getFileSessionMessages(sessionID) {
128181
128136
  });
128182
128137
  }
128183
128138
  async function readParts2(messageID) {
128184
- const partDir = join82(PART_STORAGE, messageID);
128185
- if (!existsSync74(partDir))
128139
+ const partDir = join81(PART_STORAGE, messageID);
128140
+ if (!existsSync75(partDir))
128186
128141
  return [];
128187
128142
  const parts = [];
128188
128143
  try {
@@ -128191,7 +128146,7 @@ async function readParts2(messageID) {
128191
128146
  if (!file3.endsWith(".json"))
128192
128147
  continue;
128193
128148
  try {
128194
- const content = await readFile(join82(partDir, file3), "utf-8");
128149
+ const content = await readFile(join81(partDir, file3), "utf-8");
128195
128150
  parts.push(JSON.parse(content));
128196
128151
  } catch {
128197
128152
  continue;
@@ -128203,14 +128158,14 @@ async function readParts2(messageID) {
128203
128158
  return parts.sort((a, b) => a.id.localeCompare(b.id));
128204
128159
  }
128205
128160
  async function getFileSessionTodos(sessionID) {
128206
- if (!existsSync74(TODO_DIR2))
128161
+ if (!existsSync75(TODO_DIR2))
128207
128162
  return [];
128208
128163
  try {
128209
128164
  const allFiles = await readdir(TODO_DIR2);
128210
128165
  const todoFiles = allFiles.filter((file3) => file3 === `${sessionID}.json`);
128211
128166
  for (const file3 of todoFiles) {
128212
128167
  try {
128213
- const content = await readFile(join82(TODO_DIR2, file3), "utf-8");
128168
+ const content = await readFile(join81(TODO_DIR2, file3), "utf-8");
128214
128169
  const data = JSON.parse(content);
128215
128170
  if (!Array.isArray(data))
128216
128171
  continue;
@@ -128230,10 +128185,10 @@ async function getFileSessionTodos(sessionID) {
128230
128185
  return [];
128231
128186
  }
128232
128187
  async function getFileSessionTranscript(sessionID) {
128233
- if (!existsSync74(TRANSCRIPT_DIR2))
128188
+ if (!existsSync75(TRANSCRIPT_DIR2))
128234
128189
  return 0;
128235
- const transcriptFile = join82(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
128236
- if (!existsSync74(transcriptFile))
128190
+ const transcriptFile = join81(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
128191
+ if (!existsSync75(transcriptFile))
128237
128192
  return 0;
128238
128193
  try {
128239
128194
  const content = await readFile(transcriptFile, "utf-8");
@@ -130613,9 +130568,9 @@ async function resolveMultimodalLookerAgentMetadata(ctx) {
130613
130568
 
130614
130569
  // src/tools/look-at/image-converter.ts
130615
130570
  import * as childProcess from "child_process";
130616
- import { existsSync as existsSync75, mkdtempSync, readFileSync as readFileSync50, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
130571
+ import { existsSync as existsSync76, mkdtempSync, readFileSync as readFileSync51, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
130617
130572
  import { tmpdir as tmpdir7 } from "os";
130618
- import { dirname as dirname25, join as join83 } from "path";
130573
+ import { dirname as dirname26, join as join82 } from "path";
130619
130574
  var SUPPORTED_FORMATS = new Set([
130620
130575
  "image/jpeg",
130621
130576
  "image/png",
@@ -130653,11 +130608,11 @@ function needsConversion(mimeType) {
130653
130608
  return mimeType.startsWith("image/");
130654
130609
  }
130655
130610
  function convertImageToJpeg(inputPath, mimeType) {
130656
- if (!existsSync75(inputPath)) {
130611
+ if (!existsSync76(inputPath)) {
130657
130612
  throw new Error(`File not found: ${inputPath}`);
130658
130613
  }
130659
- const tempDir = mkdtempSync(join83(tmpdir7(), "opencode-img-"));
130660
- const outputPath = join83(tempDir, "converted.jpg");
130614
+ const tempDir = mkdtempSync(join82(tmpdir7(), "opencode-img-"));
130615
+ const outputPath = join82(tempDir, "converted.jpg");
130661
130616
  log(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
130662
130617
  try {
130663
130618
  if (process.platform === "darwin") {
@@ -130667,7 +130622,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130667
130622
  encoding: "utf-8",
130668
130623
  timeout: CONVERSION_TIMEOUT_MS
130669
130624
  });
130670
- if (existsSync75(outputPath)) {
130625
+ if (existsSync76(outputPath)) {
130671
130626
  log(`[image-converter] Converted using sips: ${outputPath}`);
130672
130627
  return outputPath;
130673
130628
  }
@@ -130682,7 +130637,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130682
130637
  encoding: "utf-8",
130683
130638
  timeout: CONVERSION_TIMEOUT_MS
130684
130639
  });
130685
- if (existsSync75(outputPath)) {
130640
+ if (existsSync76(outputPath)) {
130686
130641
  log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
130687
130642
  return outputPath;
130688
130643
  }
@@ -130695,7 +130650,7 @@ function convertImageToJpeg(inputPath, mimeType) {
130695
130650
  ` + ` RHEL/CentOS: sudo yum install ImageMagick`);
130696
130651
  } catch (error92) {
130697
130652
  try {
130698
- if (existsSync75(outputPath)) {
130653
+ if (existsSync76(outputPath)) {
130699
130654
  unlinkSync10(outputPath);
130700
130655
  }
130701
130656
  } catch {}
@@ -130708,12 +130663,12 @@ function convertImageToJpeg(inputPath, mimeType) {
130708
130663
  }
130709
130664
  function cleanupConvertedImage(filePath) {
130710
130665
  try {
130711
- const tempDirectory = dirname25(filePath);
130712
- if (existsSync75(filePath)) {
130666
+ const tempDirectory = dirname26(filePath);
130667
+ if (existsSync76(filePath)) {
130713
130668
  unlinkSync10(filePath);
130714
130669
  log(`[image-converter] Cleaned up temporary file: ${filePath}`);
130715
130670
  }
130716
- if (existsSync75(tempDirectory)) {
130671
+ if (existsSync76(tempDirectory)) {
130717
130672
  rmSync3(tempDirectory, { recursive: true, force: true });
130718
130673
  log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
130719
130674
  }
@@ -130722,9 +130677,9 @@ function cleanupConvertedImage(filePath) {
130722
130677
  }
130723
130678
  }
130724
130679
  function convertBase64ImageToJpeg(base64Data, mimeType) {
130725
- const tempDir = mkdtempSync(join83(tmpdir7(), "opencode-b64-"));
130680
+ const tempDir = mkdtempSync(join82(tmpdir7(), "opencode-b64-"));
130726
130681
  const inputExt = mimeType.split("/")[1] || "bin";
130727
- const inputPath = join83(tempDir, `input.${inputExt}`);
130682
+ const inputPath = join82(tempDir, `input.${inputExt}`);
130728
130683
  const tempFiles = [inputPath];
130729
130684
  try {
130730
130685
  const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
@@ -130733,14 +130688,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
130733
130688
  log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
130734
130689
  const outputPath = convertImageToJpeg(inputPath, mimeType);
130735
130690
  tempFiles.push(outputPath);
130736
- const convertedBuffer = readFileSync50(outputPath);
130691
+ const convertedBuffer = readFileSync51(outputPath);
130737
130692
  const convertedBase64 = convertedBuffer.toString("base64");
130738
130693
  log(`[image-converter] Base64 conversion successful`);
130739
130694
  return { base64: convertedBase64, tempFiles };
130740
130695
  } catch (error92) {
130741
130696
  tempFiles.forEach((file3) => {
130742
130697
  try {
130743
- if (existsSync75(file3))
130698
+ if (existsSync76(file3))
130744
130699
  unlinkSync10(file3);
130745
130700
  } catch {}
130746
130701
  });
@@ -132921,22 +132876,22 @@ function applyFallbackEntrySettings(input) {
132921
132876
  // src/tools/delegate-task/subagent-discovery.ts
132922
132877
  init_agent_display_names();
132923
132878
  // src/features/claude-code-agent-loader/loader.ts
132924
- import { existsSync as existsSync78, readdirSync as readdirSync22 } from "fs";
132925
- import { join as join84 } from "path";
132879
+ import { existsSync as existsSync79, readdirSync as readdirSync22 } from "fs";
132880
+ import { join as join83 } from "path";
132926
132881
 
132927
132882
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
132928
- import { existsSync as existsSync77, readFileSync as readFileSync52 } from "fs";
132883
+ import { existsSync as existsSync78, readFileSync as readFileSync53 } from "fs";
132929
132884
  import { basename as basename13, extname as extname8 } from "path";
132930
132885
  init_logger();
132931
132886
 
132932
132887
  // src/features/claude-code-agent-loader/json-agent-loader.ts
132933
- import { existsSync as existsSync76, readFileSync as readFileSync51 } from "fs";
132888
+ import { existsSync as existsSync77, readFileSync as readFileSync52 } from "fs";
132934
132889
  function parseJsonAgentFile(filePath, scope) {
132935
132890
  try {
132936
- if (!existsSync76(filePath)) {
132891
+ if (!existsSync77(filePath)) {
132937
132892
  return null;
132938
132893
  }
132939
- const content = readFileSync51(filePath, "utf-8");
132894
+ const content = readFileSync52(filePath, "utf-8");
132940
132895
  const { data } = parseJsoncSafe(content);
132941
132896
  if (!data) {
132942
132897
  return null;
@@ -132972,10 +132927,10 @@ function parseJsonAgentFile(filePath, scope) {
132972
132927
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
132973
132928
  function parseMarkdownAgentFile(filePath, scope) {
132974
132929
  try {
132975
- if (!existsSync77(filePath)) {
132930
+ if (!existsSync78(filePath)) {
132976
132931
  return null;
132977
132932
  }
132978
- const content = readFileSync52(filePath, "utf-8");
132933
+ const content = readFileSync53(filePath, "utf-8");
132979
132934
  const { data, body } = parseFrontmatter(content);
132980
132935
  const fileName = basename13(filePath);
132981
132936
  const agentName = fileName.replace(/\.md$/i, "");
@@ -133007,7 +132962,7 @@ function parseMarkdownAgentFile(filePath, scope) {
133007
132962
  function loadAgentDefinitions(paths, scope) {
133008
132963
  const result = Object.create(null);
133009
132964
  for (const filePath of paths) {
133010
- if (!existsSync77(filePath)) {
132965
+ if (!existsSync78(filePath)) {
133011
132966
  log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
133012
132967
  continue;
133013
132968
  }
@@ -133032,7 +132987,7 @@ function loadAgentDefinitions(paths, scope) {
133032
132987
 
133033
132988
  // src/features/claude-code-agent-loader/loader.ts
133034
132989
  function loadAgentsFromDir(agentsDir, scope) {
133035
- if (!existsSync78(agentsDir)) {
132990
+ if (!existsSync79(agentsDir)) {
133036
132991
  return [];
133037
132992
  }
133038
132993
  const entries = readdirSync22(agentsDir, { withFileTypes: true });
@@ -133040,7 +132995,7 @@ function loadAgentsFromDir(agentsDir, scope) {
133040
132995
  for (const entry of entries) {
133041
132996
  if (!isMarkdownFile(entry))
133042
132997
  continue;
133043
- const agentPath = join84(agentsDir, entry.name);
132998
+ const agentPath = join83(agentsDir, entry.name);
133044
132999
  const agent = parseMarkdownAgentFile(agentPath, scope);
133045
133000
  if (agent) {
133046
133001
  agents.push(agent);
@@ -133049,7 +133004,7 @@ function loadAgentsFromDir(agentsDir, scope) {
133049
133004
  return agents;
133050
133005
  }
133051
133006
  function loadUserAgents() {
133052
- const userAgentsDir = join84(getClaudeConfigDir(), "agents");
133007
+ const userAgentsDir = join83(getClaudeConfigDir(), "agents");
133053
133008
  const agents = loadAgentsFromDir(userAgentsDir, "user");
133054
133009
  const result = Object.create(null);
133055
133010
  for (const agent of agents) {
@@ -133058,7 +133013,7 @@ function loadUserAgents() {
133058
133013
  return result;
133059
133014
  }
133060
133015
  function loadProjectAgents(directory) {
133061
- const projectAgentsDir = join84(directory ?? process.cwd(), ".claude", "agents");
133016
+ const projectAgentsDir = join83(directory ?? process.cwd(), ".claude", "agents");
133062
133017
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
133063
133018
  const result = Object.create(null);
133064
133019
  for (const agent of agents) {
@@ -133068,7 +133023,7 @@ function loadProjectAgents(directory) {
133068
133023
  }
133069
133024
  function loadOpencodeGlobalAgents() {
133070
133025
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
133071
- const opencodeAgentsDir = join84(configDir, "agents");
133026
+ const opencodeAgentsDir = join83(configDir, "agents");
133072
133027
  const agents = loadAgentsFromDir(opencodeAgentsDir, "opencode");
133073
133028
  const result = Object.create(null);
133074
133029
  for (const agent of agents) {
@@ -133077,7 +133032,7 @@ function loadOpencodeGlobalAgents() {
133077
133032
  return result;
133078
133033
  }
133079
133034
  function loadOpencodeProjectAgents(directory) {
133080
- const opencodeProjectDir = join84(directory ?? process.cwd(), ".opencode", "agents");
133035
+ const opencodeProjectDir = join83(directory ?? process.cwd(), ".opencode", "agents");
133081
133036
  const agents = loadAgentsFromDir(opencodeProjectDir, "opencode-project");
133082
133037
  const result = Object.create(null);
133083
133038
  for (const agent of agents) {
@@ -133620,7 +133575,7 @@ function createDelegateTask(options) {
133620
133575
  init_constants();
133621
133576
  // src/tools/task/task-create.ts
133622
133577
  init_tool();
133623
- import { join as join87 } from "path";
133578
+ import { join as join86 } from "path";
133624
133579
 
133625
133580
  // src/tools/task/types.ts
133626
133581
  var TaskStatusSchema = exports_external.enum(["pending", "in_progress", "completed", "deleted"]);
@@ -133674,18 +133629,18 @@ var TaskDeleteInputSchema = exports_external.object({
133674
133629
  });
133675
133630
 
133676
133631
  // src/features/claude-tasks/storage.ts
133677
- import { join as join86, dirname as dirname27, basename as basename14, isAbsolute as isAbsolute12 } from "path";
133678
- import { existsSync as existsSync80, mkdirSync as mkdirSync16, readFileSync as readFileSync54, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
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";
133679
133634
  import { randomUUID as randomUUID2 } from "crypto";
133680
133635
  function getTaskDir(config4 = {}) {
133681
133636
  const tasksConfig = config4.bob?.tasks;
133682
133637
  const storagePath = tasksConfig?.storage_path;
133683
133638
  if (storagePath) {
133684
- return isAbsolute12(storagePath) ? storagePath : join86(process.cwd(), storagePath);
133639
+ return isAbsolute12(storagePath) ? storagePath : join85(process.cwd(), storagePath);
133685
133640
  }
133686
133641
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
133687
133642
  const listId = resolveTaskListId(config4);
133688
- return join86(configDir, "tasks", listId);
133643
+ return join85(configDir, "tasks", listId);
133689
133644
  }
133690
133645
  function sanitizePathSegment(value) {
133691
133646
  return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
@@ -133703,16 +133658,16 @@ function resolveTaskListId(config4 = {}) {
133703
133658
  return sanitizePathSegment(basename14(process.cwd()));
133704
133659
  }
133705
133660
  function ensureDir(dirPath) {
133706
- if (!existsSync80(dirPath)) {
133661
+ if (!existsSync81(dirPath)) {
133707
133662
  mkdirSync16(dirPath, { recursive: true });
133708
133663
  }
133709
133664
  }
133710
133665
  function readJsonSafe(filePath, schema2) {
133711
133666
  try {
133712
- if (!existsSync80(filePath)) {
133667
+ if (!existsSync81(filePath)) {
133713
133668
  return null;
133714
133669
  }
133715
- const content = readFileSync54(filePath, "utf-8");
133670
+ const content = readFileSync55(filePath, "utf-8");
133716
133671
  const parsed = JSON.parse(content);
133717
133672
  const result = schema2.safeParse(parsed);
133718
133673
  if (!result.success) {
@@ -133724,7 +133679,7 @@ function readJsonSafe(filePath, schema2) {
133724
133679
  }
133725
133680
  }
133726
133681
  function writeJsonAtomic(filePath, data) {
133727
- const dir = dirname27(filePath);
133682
+ const dir = dirname28(filePath);
133728
133683
  ensureDir(dir);
133729
133684
  const tempPath = `${filePath}.tmp.${Date.now()}`;
133730
133685
  try {
@@ -133732,7 +133687,7 @@ function writeJsonAtomic(filePath, data) {
133732
133687
  renameSync4(tempPath, filePath);
133733
133688
  } catch (error92) {
133734
133689
  try {
133735
- if (existsSync80(tempPath)) {
133690
+ if (existsSync81(tempPath)) {
133736
133691
  unlinkSync11(tempPath);
133737
133692
  }
133738
133693
  } catch {}
@@ -133744,7 +133699,7 @@ function generateTaskId() {
133744
133699
  return `T-${randomUUID2()}`;
133745
133700
  }
133746
133701
  function acquireLock(dirPath) {
133747
- const lockPath = join86(dirPath, ".lock");
133702
+ const lockPath = join85(dirPath, ".lock");
133748
133703
  const lockId = randomUUID2();
133749
133704
  const createLock = (timestamp2) => {
133750
133705
  writeFileSync19(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
@@ -133754,7 +133709,7 @@ function acquireLock(dirPath) {
133754
133709
  };
133755
133710
  const isStale = () => {
133756
133711
  try {
133757
- const lockContent = readFileSync54(lockPath, "utf-8");
133712
+ const lockContent = readFileSync55(lockPath, "utf-8");
133758
133713
  const lockData = JSON.parse(lockContent);
133759
133714
  const lockAge = Date.now() - lockData.timestamp;
133760
133715
  return lockAge > STALE_LOCK_THRESHOLD_MS;
@@ -133792,9 +133747,9 @@ function acquireLock(dirPath) {
133792
133747
  acquired: true,
133793
133748
  release: () => {
133794
133749
  try {
133795
- if (!existsSync80(lockPath))
133750
+ if (!existsSync81(lockPath))
133796
133751
  return;
133797
- const lockContent = readFileSync54(lockPath, "utf-8");
133752
+ const lockContent = readFileSync55(lockPath, "utf-8");
133798
133753
  const lockData = JSON.parse(lockContent);
133799
133754
  if (lockData.id !== lockId)
133800
133755
  return;
@@ -133957,7 +133912,7 @@ async function handleCreate(args, config4, ctx, context) {
133957
133912
  threadID: context.sessionID
133958
133913
  };
133959
133914
  const validatedTask = TaskObjectSchema.parse(task);
133960
- writeJsonAtomic(join87(taskDir, `${taskId}.json`), validatedTask);
133915
+ writeJsonAtomic(join86(taskDir, `${taskId}.json`), validatedTask);
133961
133916
  await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
133962
133917
  return JSON.stringify({
133963
133918
  task: {
@@ -133980,7 +133935,7 @@ async function handleCreate(args, config4, ctx, context) {
133980
133935
  }
133981
133936
  // src/tools/task/task-get.ts
133982
133937
  init_tool();
133983
- import { join as join88 } from "path";
133938
+ import { join as join87 } from "path";
133984
133939
  var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
133985
133940
  function parseTaskId(id) {
133986
133941
  if (!TASK_ID_PATTERN.test(id))
@@ -134005,7 +133960,7 @@ Returns null if the task does not exist or the file is invalid.`,
134005
133960
  return JSON.stringify({ error: "invalid_task_id" });
134006
133961
  }
134007
133962
  const taskDir = getTaskDir(config4);
134008
- const taskPath = join88(taskDir, `${taskId}.json`);
133963
+ const taskPath = join87(taskDir, `${taskId}.json`);
134009
133964
  const task = readJsonSafe(taskPath, TaskObjectSchema);
134010
133965
  return JSON.stringify({ task: task ?? null });
134011
133966
  } catch (error92) {
@@ -134019,8 +133974,8 @@ Returns null if the task does not exist or the file is invalid.`,
134019
133974
  }
134020
133975
  // src/tools/task/task-list.ts
134021
133976
  init_tool();
134022
- import { join as join89 } from "path";
134023
- import { existsSync as existsSync81, readdirSync as readdirSync24 } from "fs";
133977
+ import { join as join88 } from "path";
133978
+ import { existsSync as existsSync82, readdirSync as readdirSync24 } from "fs";
134024
133979
  function createTaskList(config4) {
134025
133980
  return tool({
134026
133981
  description: `List all active tasks with summary information.
@@ -134031,7 +133986,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
134031
133986
  args: {},
134032
133987
  execute: async () => {
134033
133988
  const taskDir = getTaskDir(config4);
134034
- if (!existsSync81(taskDir)) {
133989
+ if (!existsSync82(taskDir)) {
134035
133990
  return JSON.stringify({ tasks: [] });
134036
133991
  }
134037
133992
  const files = readdirSync24(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
@@ -134040,7 +133995,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
134040
133995
  }
134041
133996
  const allTasks = [];
134042
133997
  for (const fileId of files) {
134043
- const task = readJsonSafe(join89(taskDir, `${fileId}.json`), TaskObjectSchema);
133998
+ const task = readJsonSafe(join88(taskDir, `${fileId}.json`), TaskObjectSchema);
134044
133999
  if (task) {
134045
134000
  allTasks.push(task);
134046
134001
  }
@@ -134069,7 +134024,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
134069
134024
  }
134070
134025
  // src/tools/task/task-update.ts
134071
134026
  init_tool();
134072
- import { join as join90 } from "path";
134027
+ import { join as join89 } from "path";
134073
134028
  var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
134074
134029
  function parseTaskId2(id) {
134075
134030
  if (!TASK_ID_PATTERN2.test(id))
@@ -134117,7 +134072,7 @@ async function handleUpdate(args, config4, ctx, context) {
134117
134072
  return JSON.stringify({ error: "task_lock_unavailable" });
134118
134073
  }
134119
134074
  try {
134120
- const taskPath = join90(taskDir, `${taskId}.json`);
134075
+ const taskPath = join89(taskDir, `${taskId}.json`);
134121
134076
  const task = readJsonSafe(taskPath, TaskObjectSchema);
134122
134077
  if (!task) {
134123
134078
  return JSON.stringify({ error: "task_not_found" });
@@ -134987,7 +134942,7 @@ Diff.prototype = {
134987
134942
  tokenize: function tokenize(value) {
134988
134943
  return Array.from(value);
134989
134944
  },
134990
- join: function join91(chars) {
134945
+ join: function join90(chars) {
134991
134946
  return chars.join("");
134992
134947
  },
134993
134948
  postProcess: function postProcess(changeObjects) {
@@ -136334,7 +136289,7 @@ function createToolGuardHooks(args) {
136334
136289
  const readImageResizer = isHookEnabled("read-image-resizer") ? safeHook("read-image-resizer", () => createReadImageResizerHook(ctx)) : null;
136335
136290
  const todoDescriptionOverride = isHookEnabled("todo-description-override") ? safeHook("todo-description-override", () => createTodoDescriptionOverrideHook()) : null;
136336
136291
  const webfetchRedirectGuard = isHookEnabled("webfetch-redirect-guard") ? safeHook("webfetch-redirect-guard", () => createWebFetchRedirectGuardHook(ctx)) : null;
136337
- const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "http://localhost:11434", model: "qwen3.5:9b", timeout: 30000 })) : null;
136292
+ const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "", model: "", timeout: 30000 })) : null;
136338
136293
  return {
136339
136294
  commentChecker,
136340
136295
  toolOutputTruncator,
@@ -137247,8 +137202,8 @@ function unregisterManagerForCleanup(manager) {
137247
137202
  }
137248
137203
 
137249
137204
  // src/features/background-agent/compaction-aware-message-resolver.ts
137250
- import { readdirSync as readdirSync25, readFileSync as readFileSync55 } from "fs";
137251
- import { join as join92 } from "path";
137205
+ import { readdirSync as readdirSync25, readFileSync as readFileSync56 } from "fs";
137206
+ import { join as join91 } from "path";
137252
137207
  function hasFullAgentAndModel(message) {
137253
137208
  return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
137254
137209
  }
@@ -137327,7 +137282,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
137327
137282
  const messages = [];
137328
137283
  for (const file3 of files) {
137329
137284
  try {
137330
- const content = readFileSync55(join92(messageDir, file3), "utf-8");
137285
+ const content = readFileSync56(join91(messageDir, file3), "utf-8");
137331
137286
  const parsed = JSON.parse(content);
137332
137287
  if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
137333
137288
  continue;
@@ -137417,7 +137372,7 @@ function handleSessionIdleBackgroundEvent(args) {
137417
137372
  }
137418
137373
 
137419
137374
  // src/features/background-agent/manager.ts
137420
- import { join as join93 } from "path";
137375
+ import { join as join92 } from "path";
137421
137376
 
137422
137377
  // src/features/background-agent/task-poller.ts
137423
137378
  init_plugin_identity();
@@ -139093,7 +139048,7 @@ ${originalText}`;
139093
139048
  parentSessionID: task.parentSessionID
139094
139049
  });
139095
139050
  }
139096
- const messageDir = join93(MESSAGE_STORAGE, task.parentSessionID);
139051
+ const messageDir = join92(MESSAGE_STORAGE, task.parentSessionID);
139097
139052
  const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionID) : null;
139098
139053
  agent = currentMessage?.agent ?? task.parentAgent;
139099
139054
  model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
@@ -139424,11 +139379,11 @@ ${originalText}`;
139424
139379
  }
139425
139380
  }
139426
139381
  // src/features/mcp-oauth/storage.ts
139427
- import { chmodSync as chmodSync2, existsSync as existsSync82, mkdirSync as mkdirSync17, readFileSync as readFileSync56, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
139428
- import { dirname as dirname28, join as join94 } from "path";
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";
139429
139384
  var STORAGE_FILE_NAME = "mcp-oauth.json";
139430
139385
  function getMcpOauthStoragePath() {
139431
- return join94(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
139386
+ return join93(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
139432
139387
  }
139433
139388
  function normalizeHost(serverHost) {
139434
139389
  let host = serverHost.trim();
@@ -139465,11 +139420,11 @@ function buildKey(serverHost, resource) {
139465
139420
  }
139466
139421
  function readStore() {
139467
139422
  const filePath = getMcpOauthStoragePath();
139468
- if (!existsSync82(filePath)) {
139423
+ if (!existsSync83(filePath)) {
139469
139424
  return null;
139470
139425
  }
139471
139426
  try {
139472
- const content = readFileSync56(filePath, "utf-8");
139427
+ const content = readFileSync57(filePath, "utf-8");
139473
139428
  return JSON.parse(content);
139474
139429
  } catch {
139475
139430
  return null;
@@ -139478,8 +139433,8 @@ function readStore() {
139478
139433
  function writeStore(store2) {
139479
139434
  const filePath = getMcpOauthStoragePath();
139480
139435
  try {
139481
- const dir = dirname28(filePath);
139482
- if (!existsSync82(dir)) {
139436
+ const dir = dirname29(filePath);
139437
+ if (!existsSync83(dir)) {
139483
139438
  mkdirSync17(dir, { recursive: true });
139484
139439
  }
139485
139440
  const tempPath = `${filePath}.tmp.${Date.now()}`;
@@ -146126,8 +146081,8 @@ class TmuxSessionManager {
146126
146081
  var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
146127
146082
  var MIN_STABILITY_TIME_MS4 = 10 * 1000;
146128
146083
  // src/features/claude-code-mcp-loader/loader.ts
146129
- import { existsSync as existsSync83, readFileSync as readFileSync57 } from "fs";
146130
- import { join as join95 } from "path";
146084
+ import { existsSync as existsSync84, readFileSync as readFileSync58 } from "fs";
146085
+ import { join as join94 } from "path";
146131
146086
  import { homedir as homedir15 } from "os";
146132
146087
  init_logger();
146133
146088
  function getMcpConfigPaths() {
@@ -146135,10 +146090,10 @@ function getMcpConfigPaths() {
146135
146090
  const cwd = process.cwd();
146136
146091
  const explicitClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || process.env.OPENCODE_CONFIG_DIR?.trim();
146137
146092
  const candidates = [
146138
- ...explicitClaudeConfigDir ? [] : [{ path: join95(homedir15(), ".claude.json"), scope: "user" }],
146139
- { path: join95(claudeConfigDir, ".mcp.json"), scope: "user" },
146140
- { path: join95(cwd, ".mcp.json"), scope: "project" },
146141
- { path: join95(cwd, ".claude", ".mcp.json"), scope: "local" }
146093
+ ...explicitClaudeConfigDir ? [] : [{ path: join94(homedir15(), ".claude.json"), scope: "user" }],
146094
+ { path: join94(claudeConfigDir, ".mcp.json"), scope: "user" },
146095
+ { path: join94(cwd, ".mcp.json"), scope: "project" },
146096
+ { path: join94(cwd, ".claude", ".mcp.json"), scope: "local" }
146142
146097
  ];
146143
146098
  const seen = new Set;
146144
146099
  return candidates.filter(({ path: path9 }) => {
@@ -146149,7 +146104,7 @@ function getMcpConfigPaths() {
146149
146104
  });
146150
146105
  }
146151
146106
  async function loadMcpConfigFile(filePath) {
146152
- if (!existsSync83(filePath)) {
146107
+ if (!existsSync84(filePath)) {
146153
146108
  return null;
146154
146109
  }
146155
146110
  try {
@@ -146165,10 +146120,10 @@ function getSystemMcpServerNames() {
146165
146120
  const paths = getMcpConfigPaths();
146166
146121
  const cwd = process.cwd();
146167
146122
  for (const { path: path9 } of paths) {
146168
- if (!existsSync83(path9))
146123
+ if (!existsSync84(path9))
146169
146124
  continue;
146170
146125
  try {
146171
- const content = readFileSync57(path9, "utf-8");
146126
+ const content = readFileSync58(path9, "utf-8");
146172
146127
  const config4 = JSON.parse(content);
146173
146128
  if (!config4?.mcpServers)
146174
146129
  continue;
@@ -150513,7 +150468,7 @@ var researcherPromptMetadata = {
150513
150468
  };
150514
150469
 
150515
150470
  // src/agents/builtin-agents/resolve-file-uri.ts
150516
- import { existsSync as existsSync84, readFileSync as readFileSync58 } from "fs";
150471
+ import { existsSync as existsSync85, readFileSync as readFileSync59 } from "fs";
150517
150472
  import { homedir as homedir16 } from "os";
150518
150473
  import { isAbsolute as isAbsolute13, resolve as resolve22 } from "path";
150519
150474
  init_logger();
@@ -150538,11 +150493,11 @@ function resolvePromptAppend(promptAppend, configDir) {
150538
150493
  });
150539
150494
  return `[WARNING: Path rejected: ${promptAppend}]`;
150540
150495
  }
150541
- if (!existsSync84(filePath)) {
150496
+ if (!existsSync85(filePath)) {
150542
150497
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
150543
150498
  }
150544
150499
  try {
150545
- return readFileSync58(filePath, "utf8");
150500
+ return readFileSync59(filePath, "utf8");
150546
150501
  } catch {
150547
150502
  return `[WARNING: Could not read file: ${promptAppend}]`;
150548
150503
  }
@@ -154176,6 +154131,28 @@ async function buildStrategistAgentConfig(params) {
154176
154131
  return merged;
154177
154132
  }
154178
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
+
154179
154156
  // src/plugin-handlers/agent-config-handler.ts
154180
154157
  var CANONICAL_VISIBLE_AGENT_NAMES = [
154181
154158
  "Bob",
@@ -154238,8 +154215,9 @@ async function applyAgentConfig(params) {
154238
154215
  const migratedDisabledAgents = (params.pluginConfig.disabled_agents ?? []).map((agent) => {
154239
154216
  return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
154240
154217
  });
154241
- const includeClaudeSkillsForAwareness = params.pluginConfig.claude_code?.skills ?? true;
154218
+ const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
154242
154219
  const [
154220
+ discoveredManagedPluginSkills,
154243
154221
  discoveredConfigSourceSkills,
154244
154222
  discoveredUserSkills,
154245
154223
  discoveredProjectSkills,
@@ -154248,18 +154226,20 @@ async function applyAgentConfig(params) {
154248
154226
  discoveredOpencodeProjectSkills,
154249
154227
  discoveredGlobalAgentsSkills
154250
154228
  ] = await Promise.all([
154251
- discoverConfigSourceSkills({
154229
+ discoverManagedPluginSkills(),
154230
+ discovery2.config_sources ? discoverConfigSourceSkills({
154252
154231
  config: params.pluginConfig.skills,
154253
154232
  configDir: params.ctx.directory
154254
- }),
154255
- includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]),
154256
- includeClaudeSkillsForAwareness ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]),
154257
- includeClaudeSkillsForAwareness ? discoverProjectAgentsSkills(params.ctx.directory) : Promise.resolve([]),
154258
- discoverOpencodeGlobalSkills(),
154259
- discoverOpencodeProjectSkills(params.ctx.directory),
154260
- includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([])
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([])
154261
154240
  ]);
154262
154241
  const allDiscoveredSkills = [
154242
+ ...discoveredManagedPluginSkills,
154263
154243
  ...discoveredConfigSourceSkills,
154264
154244
  ...discoveredOpencodeProjectSkills,
154265
154245
  ...discoveredProjectSkills,
@@ -154468,7 +154448,7 @@ async function applyAgentConfig(params) {
154468
154448
  init_agent_display_names();
154469
154449
  // src/features/claude-code-command-loader/loader.ts
154470
154450
  import { promises as fs14 } from "fs";
154471
- import { join as join96, basename as basename15 } from "path";
154451
+ import { join as join95, basename as basename15 } from "path";
154472
154452
  init_logger();
154473
154453
  async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
154474
154454
  try {
@@ -154499,7 +154479,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
154499
154479
  if (entry.isDirectory()) {
154500
154480
  if (entry.name.startsWith("."))
154501
154481
  continue;
154502
- const subDirPath = join96(commandsDir, entry.name);
154482
+ const subDirPath = join95(commandsDir, entry.name);
154503
154483
  const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
154504
154484
  const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
154505
154485
  commands2.push(...subCommands);
@@ -154507,7 +154487,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
154507
154487
  }
154508
154488
  if (!isMarkdownFile(entry))
154509
154489
  continue;
154510
- const commandPath = join96(commandsDir, entry.name);
154490
+ const commandPath = join95(commandsDir, entry.name);
154511
154491
  const baseCommandName = basename15(entry.name, ".md");
154512
154492
  const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
154513
154493
  try {
@@ -154566,12 +154546,12 @@ function commandsToRecord(commands2) {
154566
154546
  return result;
154567
154547
  }
154568
154548
  async function loadUserCommands() {
154569
- const userCommandsDir = join96(getClaudeConfigDir(), "commands");
154549
+ const userCommandsDir = join95(getClaudeConfigDir(), "commands");
154570
154550
  const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
154571
154551
  return commandsToRecord(commands2);
154572
154552
  }
154573
154553
  async function loadProjectCommands(directory) {
154574
- const projectCommandsDir = join96(directory ?? process.cwd(), ".claude", "commands");
154554
+ const projectCommandsDir = join95(directory ?? process.cwd(), ".claude", "commands");
154575
154555
  const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
154576
154556
  return commandsToRecord(commands2);
154577
154557
  }
@@ -154592,9 +154572,9 @@ async function applyCommandConfig(params) {
154592
154572
  });
154593
154573
  const systemCommands = params.config.command ?? {};
154594
154574
  const includeClaudeCommands = params.pluginConfig.claude_code?.commands ?? true;
154595
- const includeClaudeSkills = params.pluginConfig.claude_code?.skills ?? true;
154575
+ const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
154596
154576
  const externalSkillPlugin = detectExternalSkillPlugin(params.ctx.directory);
154597
- if (includeClaudeSkills && externalSkillPlugin.detected) {
154577
+ if ((discovery2.project_claude || discovery2.global_claude || discovery2.global_opencode) && externalSkillPlugin.detected) {
154598
154578
  log(getSkillPluginConflictWarning(externalSkillPlugin.pluginName));
154599
154579
  }
154600
154580
  const [
@@ -154603,6 +154583,7 @@ async function applyCommandConfig(params) {
154603
154583
  projectCommands,
154604
154584
  opencodeGlobalCommands,
154605
154585
  opencodeProjectCommands,
154586
+ managedPluginSkills,
154606
154587
  userSkills,
154607
154588
  globalAgentsSkills,
154608
154589
  projectSkills,
@@ -154610,23 +154591,25 @@ async function applyCommandConfig(params) {
154610
154591
  opencodeGlobalSkills,
154611
154592
  opencodeProjectSkills
154612
154593
  ] = await Promise.all([
154613
- discoverConfigSourceSkills({
154594
+ discovery2.config_sources ? discoverConfigSourceSkills({
154614
154595
  config: params.pluginConfig.skills,
154615
154596
  configDir: params.ctx.directory
154616
- }),
154597
+ }) : Promise.resolve([]),
154617
154598
  includeClaudeCommands ? loadUserCommands() : Promise.resolve({}),
154618
154599
  includeClaudeCommands ? loadProjectCommands(params.ctx.directory) : Promise.resolve({}),
154619
154600
  loadOpencodeGlobalCommands(),
154620
154601
  loadOpencodeProjectCommands(params.ctx.directory),
154621
- includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
154622
- includeClaudeSkills ? loadGlobalAgentsSkills() : Promise.resolve({}),
154623
- includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
154624
- includeClaudeSkills ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
154625
- loadOpencodeGlobalSkills(),
154626
- loadOpencodeProjectSkills(params.ctx.directory)
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({})
154627
154609
  ]);
154628
154610
  params.config.command = {
154629
154611
  ...builtinCommands,
154612
+ ...managedPluginSkills,
154630
154613
  ...skillsToCommandDefinitionRecord(configSourceSkills),
154631
154614
  ...userCommands,
154632
154615
  ...userSkills,
@@ -154654,7 +154637,7 @@ function remapCommandAgentFields(commands2) {
154654
154637
 
154655
154638
  // src/plugin-handlers/mcp-config-handler.ts
154656
154639
  import { spawnSync as spawnSync5 } from "child_process";
154657
- import { existsSync as existsSync85 } from "fs";
154640
+ import { existsSync as existsSync86 } from "fs";
154658
154641
 
154659
154642
  // src/mcp/websearch.ts
154660
154643
  init_logger();
@@ -154807,7 +154790,7 @@ function hasUsableLocalMcpRuntime(name, entry) {
154807
154790
  return false;
154808
154791
  }
154809
154792
  if (binary2 === "node" && typeof args[0] === "string" && args[0].endsWith(".mjs")) {
154810
- if (!existsSync85(args[0])) {
154793
+ if (!existsSync86(args[0])) {
154811
154794
  return false;
154812
154795
  }
154813
154796
  const probe2 = spawnSync5(binary2, ["--version"], {
@@ -155281,19 +155264,30 @@ async function createSkillContext(args) {
155281
155264
  }
155282
155265
  return true;
155283
155266
  });
155284
- const includeClaudeSkills = pluginConfig.claude_code?.skills !== false;
155285
- const [configSourceSkills, userSkills, globalSkills, projectSkills, opencodeProjectSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
155286
- 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({
155287
155280
  config: pluginConfig.skills,
155288
155281
  configDir: directory
155289
- }),
155290
- includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
155291
- discoverOpencodeGlobalSkills(),
155292
- includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
155293
- discoverOpencodeProjectSkills(directory),
155294
- discoverProjectAgentsSkills(directory),
155295
- 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([])
155296
155289
  ]);
155290
+ const filteredManagedPluginSkills = filterProviderGatedSkills(managedPluginSkills, browserProvider);
155297
155291
  const filteredConfigSourceSkills = filterProviderGatedSkills(configSourceSkills, browserProvider);
155298
155292
  const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
155299
155293
  const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
@@ -155301,7 +155295,7 @@ async function createSkillContext(args) {
155301
155295
  const filteredOpencodeProjectSkills = filterProviderGatedSkills(opencodeProjectSkills, browserProvider);
155302
155296
  const filteredAgentsProjectSkills = filterProviderGatedSkills(agentsProjectSkills, browserProvider);
155303
155297
  const filteredAgentsGlobalSkills = filterProviderGatedSkills(agentsGlobalSkills, browserProvider);
155304
- 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 });
155305
155299
  const availableSkills = mergedSkills.map((skill2) => ({
155306
155300
  name: skill2.name,
155307
155301
  description: skill2.definition.description ?? "",
@@ -155791,10 +155785,10 @@ init_agent_display_names();
155791
155785
 
155792
155786
  // src/plugin/ultrawork-db-model-override.ts
155793
155787
  import { Database } from "bun:sqlite";
155794
- import { join as join97 } from "path";
155795
- import { existsSync as existsSync86 } from "fs";
155788
+ import { join as join96 } from "path";
155789
+ import { existsSync as existsSync87 } from "fs";
155796
155790
  function getDbPath() {
155797
- return join97(getDataDir(), "opencode", "opencode.db");
155791
+ return join96(getDataDir(), "opencode", "opencode.db");
155798
155792
  }
155799
155793
  var MAX_MICROTASK_RETRIES = 10;
155800
155794
  function tryUpdateMessageModel(db, messageId, targetModel, variant) {
@@ -155871,7 +155865,7 @@ function retryViaMicrotask(db, messageId, targetModel, variant, attempt) {
155871
155865
  function scheduleDeferredModelOverride(messageId, targetModel, variant) {
155872
155866
  queueMicrotask(() => {
155873
155867
  const dbPath = getDbPath();
155874
- if (!existsSync86(dbPath)) {
155868
+ if (!existsSync87(dbPath)) {
155875
155869
  log("[ultrawork-db-override] DB not found, skipping deferred override");
155876
155870
  return;
155877
155871
  }
@@ -157213,6 +157207,163 @@ function createFirstMessageVariantGate() {
157213
157207
  // src/index.ts
157214
157208
  init_plugin_identity();
157215
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
+
157216
157367
  // src/internals/plugins/subtask2/core/state.ts
157217
157368
  var configs = {};
157218
157369
  var pluginConfig = { replace_generic: true };
@@ -157528,7 +157679,7 @@ function resolveResultReferences(text, sessionID) {
157528
157679
 
157529
157680
  // src/internals/plugins/subtask2/utils/config.ts
157530
157681
  import { mkdirSync as mkdirSync18 } from "fs";
157531
- import { dirname as dirname29, join as join98 } from "path";
157682
+ import { dirname as dirname30, join as join99 } from "path";
157532
157683
 
157533
157684
  // src/internals/plugins/subtask2/utils/prompts.ts
157534
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.";
@@ -157594,15 +157745,15 @@ async function getAutoWorkflowPrompt() {
157594
157745
  var AUTO_WORKFLOW_PROMPT = AUTO_WORKFLOW_PROMPT_TEMPLATE.replace(README_PLACEHOLDER, "[Use getAutoWorkflowPrompt() to get full documentation]");
157595
157746
 
157596
157747
  // src/internals/plugins/subtask2/utils/config.ts
157597
- var CONFIG_PATH = join98(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
157748
+ var CONFIG_PATH = join99(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
157598
157749
  var cachedReadmeContent = null;
157599
157750
  async function loadReadmeContent() {
157600
157751
  if (cachedReadmeContent !== null) {
157601
157752
  return cachedReadmeContent;
157602
157753
  }
157603
157754
  try {
157604
- const pluginRoot = join98(dirname29(import.meta.path), "..", "..");
157605
- const readmePath = join98(pluginRoot, "README.md");
157755
+ const pluginRoot = join99(dirname30(import.meta.path), "..", "..");
157756
+ const readmePath = join99(pluginRoot, "README.md");
157606
157757
  const file3 = Bun.file(readmePath);
157607
157758
  if (await file3.exists()) {
157608
157759
  cachedReadmeContent = await file3.text();
@@ -157637,7 +157788,7 @@ async function loadConfig2() {
157637
157788
  }
157638
157789
  }
157639
157790
  } catch {}
157640
- mkdirSync18(dirname29(CONFIG_PATH), { recursive: true });
157791
+ mkdirSync18(dirname30(CONFIG_PATH), { recursive: true });
157641
157792
  await Bun.write(CONFIG_PATH, `{
157642
157793
  // Replace OpenCode's generic "Summarize..." prompt when no return is specified
157643
157794
  "replace_generic": true,
@@ -157709,7 +157860,7 @@ function clearLog() {
157709
157860
  }
157710
157861
 
157711
157862
  // src/internals/plugins/subtask2/commands/manifest.ts
157712
- import { join as join100 } from "path";
157863
+ import { join as join101 } from "path";
157713
157864
 
157714
157865
  // src/internals/plugins/subtask2/parsing/frontmatter.ts
157715
157866
  var import_yaml = __toESM(require_dist2(), 1);
@@ -157965,8 +158116,8 @@ function parseAutoWorkflowOutput(text) {
157965
158116
  async function buildManifest() {
157966
158117
  const manifest = {};
157967
158118
  const dirs = [
157968
- join100(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
157969
- join100(Bun.env.PWD ?? ".", ".opencode", "command")
158119
+ join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158120
+ join101(Bun.env.PWD ?? ".", ".opencode", "command")
157970
158121
  ];
157971
158122
  for (const dir of dirs) {
157972
158123
  try {
@@ -158129,11 +158280,11 @@ async function resolveTurnReferences(text, sessionID) {
158129
158280
  }
158130
158281
 
158131
158282
  // src/internals/plugins/subtask2/commands/loader.ts
158132
- import { join as join101 } from "path";
158283
+ import { join as join102 } from "path";
158133
158284
  async function loadCommandFile(name) {
158134
158285
  const dirs = [
158135
- join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158136
- join101(Bun.env.PWD ?? ".", ".opencode", "command")
158286
+ join102(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
158287
+ join102(Bun.env.PWD ?? ".", ".opencode", "command")
158137
158288
  ];
158138
158289
  for (const dir of dirs) {
158139
158290
  const directPath = `${dir}/${name}.md`;
@@ -159413,14 +159564,14 @@ init_websearch_cited();
159413
159564
  // src/features/builtin-skills/materialize.ts
159414
159565
  import {
159415
159566
  cpSync,
159416
- existsSync as existsSync88,
159567
+ existsSync as existsSync90,
159417
159568
  mkdirSync as mkdirSync20,
159418
159569
  readdirSync as readdirSync26,
159419
- readFileSync as readFileSync59,
159570
+ readFileSync as readFileSync61,
159420
159571
  rmSync as rmSync4,
159421
159572
  writeFileSync as writeFileSync22
159422
159573
  } from "fs";
159423
- import { join as join102 } from "path";
159574
+ import { join as join103 } from "path";
159424
159575
  var GENERATED_MARKER = "<!-- Generated by hiai-opencode builtin skill materializer. -->";
159425
159576
  var MANAGED_SKILL_METADATA = ".hiai-skill.json";
159426
159577
  var LEGACY_MANAGED_DIR_MARKER = ".hiai-plugin-skill";
@@ -159447,10 +159598,10 @@ function buildSkillFrontmatter(skill2) {
159447
159598
  `);
159448
159599
  }
159449
159600
  function shouldWriteSkillFile(skillFilePath) {
159450
- if (!existsSync88(skillFilePath))
159601
+ if (!existsSync90(skillFilePath))
159451
159602
  return true;
159452
159603
  try {
159453
- const existing = readFileSync59(skillFilePath, "utf-8");
159604
+ const existing = readFileSync61(skillFilePath, "utf-8");
159454
159605
  return existing.includes(GENERATED_MARKER);
159455
159606
  } catch {
159456
159607
  return false;
@@ -159458,10 +159609,10 @@ function shouldWriteSkillFile(skillFilePath) {
159458
159609
  }
159459
159610
  function getSkillLayout() {
159460
159611
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
159461
- const assembledSkillsDir = join102(configDir, "skills");
159462
- const sourceRootDir = join102(configDir, ".hiai", "skills");
159463
- const builtinSourceDir = join102(sourceRootDir, "builtin");
159464
- const pluginSourceDir = join102(sourceRootDir, "plugin");
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");
159465
159616
  mkdirSync20(assembledSkillsDir, { recursive: true });
159466
159617
  mkdirSync20(builtinSourceDir, { recursive: true });
159467
159618
  mkdirSync20(pluginSourceDir, { recursive: true });
@@ -159474,31 +159625,31 @@ function getSkillLayout() {
159474
159625
  };
159475
159626
  }
159476
159627
  function writeManagedSkillMetadata(targetDir, metadata) {
159477
- writeFileSync22(join102(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
159628
+ writeFileSync22(join103(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
159478
159629
  `, "utf-8");
159479
159630
  }
159480
159631
  function readManagedSkillMetadata(targetDir) {
159481
- const metadataPath = join102(targetDir, MANAGED_SKILL_METADATA);
159482
- if (!existsSync88(metadataPath)) {
159632
+ const metadataPath = join103(targetDir, MANAGED_SKILL_METADATA);
159633
+ if (!existsSync90(metadataPath)) {
159483
159634
  return null;
159484
159635
  }
159485
159636
  try {
159486
- return JSON.parse(readFileSync59(metadataPath, "utf-8"));
159637
+ return JSON.parse(readFileSync61(metadataPath, "utf-8"));
159487
159638
  } catch {
159488
159639
  return null;
159489
159640
  }
159490
159641
  }
159491
159642
  function isLegacyManagedSkillDir(targetDir, origin) {
159492
- if (origin === "plugin" && existsSync88(join102(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
159643
+ if (origin === "plugin" && existsSync90(join103(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
159493
159644
  return true;
159494
159645
  }
159495
159646
  if (origin === "builtin") {
159496
- const skillFilePath = join102(targetDir, "SKILL.md");
159497
- if (!existsSync88(skillFilePath)) {
159647
+ const skillFilePath = join103(targetDir, "SKILL.md");
159648
+ if (!existsSync90(skillFilePath)) {
159498
159649
  return false;
159499
159650
  }
159500
159651
  try {
159501
- return readFileSync59(skillFilePath, "utf-8").includes(GENERATED_MARKER);
159652
+ return readFileSync61(skillFilePath, "utf-8").includes(GENERATED_MARKER);
159502
159653
  } catch {
159503
159654
  return false;
159504
159655
  }
@@ -159506,7 +159657,7 @@ function isLegacyManagedSkillDir(targetDir, origin) {
159506
159657
  return false;
159507
159658
  }
159508
159659
  function shouldSyncManagedSkillDir(targetDir, origin) {
159509
- if (!existsSync88(targetDir))
159660
+ if (!existsSync90(targetDir))
159510
159661
  return true;
159511
159662
  const metadata = readManagedSkillMetadata(targetDir);
159512
159663
  if (metadata?.generatedBy === "hiai-opencode" && metadata.origin === origin) {
@@ -159522,7 +159673,7 @@ function shouldCleanupManagedSkillDir(targetDir, origin) {
159522
159673
  return isLegacyManagedSkillDir(targetDir, origin);
159523
159674
  }
159524
159675
  function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
159525
- if (!existsSync88(rootDir)) {
159676
+ if (!existsSync90(rootDir)) {
159526
159677
  return;
159527
159678
  }
159528
159679
  for (const entry of readdirSync26(rootDir, { withFileTypes: true })) {
@@ -159530,15 +159681,15 @@ function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
159530
159681
  continue;
159531
159682
  if (expectedSkillNames.has(entry.name))
159532
159683
  continue;
159533
- const targetDir = join102(rootDir, entry.name);
159684
+ const targetDir = join103(rootDir, entry.name);
159534
159685
  if (shouldCleanupManagedSkillDir(targetDir, origin)) {
159535
159686
  rmSync4(targetDir, { recursive: true, force: true });
159536
159687
  }
159537
159688
  }
159538
159689
  }
159539
159690
  function writeSkillRegistry(configDir, entries) {
159540
- const registryDir = join102(configDir, ".hiai");
159541
- const assembledSkillsDir = join102(configDir, "skills");
159691
+ const registryDir = join103(configDir, ".hiai");
159692
+ const assembledSkillsDir = join103(configDir, "skills");
159542
159693
  mkdirSync20(registryDir, { recursive: true });
159543
159694
  mkdirSync20(assembledSkillsDir, { recursive: true });
159544
159695
  const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
@@ -159552,12 +159703,12 @@ function writeSkillRegistry(configDir, entries) {
159552
159703
  },
159553
159704
  layout: {
159554
159705
  assembledSkillsDir,
159555
- builtinSourceDir: join102(registryDir, "skills", "builtin"),
159556
- pluginSourceDir: join102(registryDir, "skills", "plugin")
159706
+ builtinSourceDir: join103(registryDir, "skills", "builtin"),
159707
+ pluginSourceDir: join103(registryDir, "skills", "plugin")
159557
159708
  },
159558
159709
  entries: sortedEntries
159559
159710
  };
159560
- writeFileSync22(join102(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
159711
+ writeFileSync22(join103(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
159561
159712
  `, "utf-8");
159562
159713
  const readme = [
159563
159714
  "# Hiai Skill Layout",
@@ -159572,16 +159723,16 @@ function writeSkillRegistry(configDir, entries) {
159572
159723
  ""
159573
159724
  ].join(`
159574
159725
  `);
159575
- writeFileSync22(join102(assembledSkillsDir, "README.md"), readme, "utf-8");
159726
+ writeFileSync22(join103(assembledSkillsDir, "README.md"), readme, "utf-8");
159576
159727
  }
159577
159728
  function materializeBuiltinSkills(skills) {
159578
159729
  const { assembledSkillsDir, builtinSourceDir } = getSkillLayout();
159579
159730
  const expectedSkillNames = new Set(skills.map((skill2) => skill2.name));
159580
159731
  for (const skill2 of skills) {
159581
- const sourceSkillDir = join102(builtinSourceDir, skill2.name);
159582
- const sourceSkillFilePath = join102(sourceSkillDir, "SKILL.md");
159583
- const assembledSkillDir = join102(assembledSkillsDir, skill2.name);
159584
- const assembledSkillFilePath = join102(assembledSkillDir, "SKILL.md");
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");
159585
159736
  const content = buildSkillFrontmatter(skill2);
159586
159737
  mkdirSync20(sourceSkillDir, { recursive: true });
159587
159738
  mkdirSync20(assembledSkillDir, { recursive: true });
@@ -159609,8 +159760,8 @@ function materializeBuiltinSkills(skills) {
159609
159760
  cleanupRemovedManagedSkillDirs(assembledSkillsDir, "builtin", expectedSkillNames);
159610
159761
  }
159611
159762
  function materializePluginSkillDirectories(pluginRootDir) {
159612
- const sourceSkillsDir = join102(pluginRootDir, "skills");
159613
- if (!existsSync88(sourceSkillsDir)) {
159763
+ const sourceSkillsDir = join103(pluginRootDir, "skills");
159764
+ if (!existsSync90(sourceSkillsDir)) {
159614
159765
  return;
159615
159766
  }
159616
159767
  const { assembledSkillsDir, pluginSourceDir, configDir } = getSkillLayout();
@@ -159622,9 +159773,9 @@ function materializePluginSkillDirectories(pluginRootDir) {
159622
159773
  if (entry.name === "tmp")
159623
159774
  continue;
159624
159775
  expectedSkillNames.add(entry.name);
159625
- const sourceDir = join102(sourceSkillsDir, entry.name);
159626
- const mirroredSourceDir = join102(pluginSourceDir, entry.name);
159627
- const assembledDir = join102(assembledSkillsDir, entry.name);
159776
+ const sourceDir = join103(sourceSkillsDir, entry.name);
159777
+ const mirroredSourceDir = join103(pluginSourceDir, entry.name);
159778
+ const assembledDir = join103(assembledSkillsDir, entry.name);
159628
159779
  if (!shouldSyncManagedSkillDir(mirroredSourceDir, "plugin") || !shouldSyncManagedSkillDir(assembledDir, "plugin")) {
159629
159780
  continue;
159630
159781
  }
@@ -159658,7 +159809,7 @@ function materializePluginSkillDirectories(pluginRootDir) {
159658
159809
  for (const builtinEntry of readdirSync26(assembledSkillsDir, { withFileTypes: true })) {
159659
159810
  if (!builtinEntry.isDirectory())
159660
159811
  continue;
159661
- const assembledDir = join102(assembledSkillsDir, builtinEntry.name);
159812
+ const assembledDir = join103(assembledSkillsDir, builtinEntry.name);
159662
159813
  const metadata = readManagedSkillMetadata(assembledDir);
159663
159814
  if (metadata?.generatedBy !== "hiai-opencode" || metadata.origin !== "builtin") {
159664
159815
  continue;
@@ -159681,11 +159832,11 @@ function configureBundledBunPtyLibrary() {
159681
159832
  }
159682
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";
159683
159834
  const candidates = [
159684
- join104(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
159685
- join104(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName),
159686
- join104(import.meta.dirname, "..", "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
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)
159687
159838
  ];
159688
- const resolved = candidates.find((candidate) => existsSync90(candidate));
159839
+ const resolved = candidates.find((candidate) => existsSync92(candidate));
159689
159840
  if (resolved) {
159690
159841
  process.env.BUN_PTY_LIB = resolved;
159691
159842
  }
@@ -159694,6 +159845,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
159694
159845
  log("[HiaiOpenCodePlugin] ENTRY - plugin loading", {
159695
159846
  directory: ctx.directory
159696
159847
  });
159848
+ warnIfListPluginEntry(ctx.directory);
159697
159849
  const skillPluginCheck = detectExternalSkillPlugin(ctx.directory);
159698
159850
  if (skillPluginCheck.detected && skillPluginCheck.pluginName) {
159699
159851
  console.warn(getSkillPluginConflictWarning(skillPluginCheck.pluginName));
@@ -159702,11 +159854,15 @@ var HiaiOpenCodePlugin = async (ctx) => {
159702
159854
  await activePluginDispose?.();
159703
159855
  const internalConfig = loadConfig(ctx.directory);
159704
159856
  const pluginConfig2 = hydratePluginConfigWithPlatformDefaults(loadPluginConfig(ctx.directory, ctx), internalConfig);
159857
+ warnMissingRequiredMcpEnv({
159858
+ pluginConfig: pluginConfig2,
159859
+ platformConfig: internalConfig
159860
+ });
159705
159861
  materializeBuiltinSkills(createBuiltinSkills({
159706
159862
  browserProvider: pluginConfig2.browser_automation_engine?.provider ?? "playwright",
159707
159863
  disabledSkills: new Set(pluginConfig2.disabled_skills ?? [])
159708
159864
  }));
159709
- materializePluginSkillDirectories(join104(import.meta.dirname, ".."));
159865
+ materializePluginSkillDirectories(join105(import.meta.dirname, ".."));
159710
159866
  const { initializeModelRequirements: initializeModelRequirements2 } = await Promise.resolve().then(() => (init_model_requirements(), exports_model_requirements));
159711
159867
  initializeModelRequirements2(internalConfig);
159712
159868
  const { initializeModelHeuristics: initializeModelHeuristics2 } = await Promise.resolve().then(() => (init_model_capability_heuristics(), exports_model_capability_heuristics));
@@ -159806,30 +159962,25 @@ var HiaiOpenCodePlugin = async (ctx) => {
159806
159962
  auth: {
159807
159963
  provider: "hiai-opencode",
159808
159964
  methods: [
159809
- { type: "api", label: "Google API key" },
159810
- { type: "api", label: "OpenAI API key" },
159811
- { type: "api", label: "OpenRouter API key" }
159965
+ { type: "api", label: "Google Search API key" }
159812
159966
  ],
159813
159967
  loader: async (getAuth) => {
159814
159968
  const authData = await getAuth();
159815
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));
159816
- const getKey = (label, configKey) => {
159817
- const fromAuth = authData[label];
159818
- if (fromAuth)
159819
- return fromAuth;
159970
+ const getConfiguredKey = (configKey) => {
159820
159971
  if (configKey)
159821
159972
  return resolveEnvVars(configKey);
159822
159973
  return;
159823
159974
  };
159824
- const googleKey = getKey("Google API key", internalConfig.auth?.googleSearch);
159825
- const openaiKey = getKey("OpenAI API key", internalConfig.auth?.openai);
159826
- const openRouterKey = getKey("OpenRouter API key", internalConfig.auth?.openrouter);
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);
159827
159978
  if (googleKey)
159828
- registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve(googleKey));
159979
+ registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: googleKey }));
159829
159980
  if (openaiKey)
159830
- registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve(openaiKey));
159981
+ registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openaiKey }));
159831
159982
  if (openRouterKey)
159832
- registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve(openRouterKey));
159983
+ registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openRouterKey }));
159833
159984
  return {};
159834
159985
  }
159835
159986
  },