oh-my-opencode 3.2.2 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -121,16 +121,6 @@
121
121
  - [アンインストール](#アンインストール)
122
122
  - [機能](#機能)
123
123
  - [設定](#設定)
124
- - [JSONC のサポート](#jsonc-のサポート)
125
- - [Google Auth](#google-auth)
126
- - [Agents](#agents)
127
- - [Permission オプション](#permission-オプション)
128
- - [Sisyphus Agent](#sisyphus-agent)
129
- - [Background Tasks](#background-tasks)
130
- - [Hooks](#hooks)
131
- - [MCPs](#mcps)
132
- - [LSP](#lsp)
133
- - [Experimental](#experimental)
134
124
  - [作者のノート](#作者のノート)
135
125
  - [注意](#注意)
136
126
  - [こちらの企業の専門家にご愛用いただいています](#こちらの企業の専門家にご愛用いただいています)
package/README.ko.md CHANGED
@@ -123,20 +123,6 @@
123
123
  - [제거](#제거)
124
124
  - [기능](#기능)
125
125
  - [구성](#구성)
126
- - [JSONC 지원](#jsonc-지원)
127
- - [Google 인증](#google-인증)
128
- - [에이전트](#에이전트)
129
- - [권한 옵션](#권한-옵션)
130
- - [내장 스킬](#내장-스킬)
131
- - [Git Master](#git-master)
132
- - [Sisyphus 에이전트](#sisyphus-에이전트)
133
- - [백그라운드 작업](#백그라운드-작업)
134
- - [카테고리](#카테고리)
135
- - [훅](#훅)
136
- - [MCP](#mcp)
137
- - [LSP](#lsp)
138
- - [실험적 기능](#실험적-기능)
139
- - [환경 변수](#환경-변수)
140
126
  - [작성자의 메모](#작성자의-메모)
141
127
  - [경고](#경고)
142
128
  - [다음 기업 전문가들이 사랑합니다](#다음-기업-전문가들이-사랑합니다)
package/README.md CHANGED
@@ -121,21 +121,7 @@ Yes, technically possible. But I cannot recommend using it.
121
121
  - [For LLM Agents](#for-llm-agents)
122
122
  - [Uninstallation](#uninstallation)
123
123
  - [Features](#features)
124
- - [Configuration](#configuration)
125
- - [JSONC Support](#jsonc-support)
126
- - [Google Auth](#google-auth)
127
- - [Agents](#agents)
128
- - [Permission Options](#permission-options)
129
- - [Built-in Skills](#built-in-skills)
130
- - [Git Master](#git-master)
131
- - [Sisyphus Agent](#sisyphus-agent)
132
- - [Background Tasks](#background-tasks)
133
- - [Categories](#categories)
134
- - [Hooks](#hooks)
135
- - [MCPs](#mcps)
136
- - [LSP](#lsp)
137
- - [Experimental](#experimental)
138
- - [Environment Variables](#environment-variables)
124
+ - [Configuration](#configuration)
139
125
  - [Author's Note](#authors-note)
140
126
  - [Warnings](#warnings)
141
127
  - [Loved by professionals at](#loved-by-professionals-at)
package/README.zh-cn.md CHANGED
@@ -122,20 +122,6 @@
122
122
  - [卸载](#卸载)
123
123
  - [功能特性](#功能特性)
124
124
  - [配置](#配置)
125
- - [JSONC 支持](#jsonc-支持)
126
- - [Google 认证](#google-认证)
127
- - [智能体](#智能体)
128
- - [权限选项](#权限选项)
129
- - [内置技能](#内置技能)
130
- - [Git Master](#git-master)
131
- - [Sisyphus 智能体](#sisyphus-智能体)
132
- - [后台任务](#后台任务)
133
- - [类别](#类别)
134
- - [钩子](#钩子)
135
- - [MCP](#mcp)
136
- - [LSP](#lsp)
137
- - [实验性功能](#实验性功能)
138
- - [环境变量](#环境变量)
139
125
  - [作者札记](#作者札记)
140
126
  - [警告](#警告)
141
127
  - [受到以下专业人士的喜爱](#受到以下专业人士的喜爱)
File without changes
@@ -4,7 +4,7 @@ import type { CategoriesConfig, GitMasterConfig } from "../config/schema";
4
4
  import type { LoadedSkill } from "../features/opencode-skill-loader/types";
5
5
  import type { BrowserAutomationProvider } from "../config/schema";
6
6
  type AgentSource = AgentFactory | AgentConfig;
7
- export declare function buildAgent(source: AgentSource, model: string, categories?: CategoriesConfig, gitMasterConfig?: GitMasterConfig, browserProvider?: BrowserAutomationProvider): AgentConfig;
7
+ export declare function buildAgent(source: AgentSource, model: string, categories?: CategoriesConfig, gitMasterConfig?: GitMasterConfig, browserProvider?: BrowserAutomationProvider, disabledSkills?: Set<string>): AgentConfig;
8
8
  /**
9
9
  * Creates OmO-specific environment context (time, timezone, locale).
10
10
  * Note: Working directory, platform, and date are already provided by OpenCode's system.ts,
@@ -12,5 +12,5 @@ export declare function buildAgent(source: AgentSource, model: string, categorie
12
12
  * See: https://github.com/code-yeongyu/oh-my-opencode/issues/379
13
13
  */
14
14
  export declare function createEnvContext(): string;
15
- export declare function createBuiltinAgents(disabledAgents?: string[], agentOverrides?: AgentOverrides, directory?: string, systemDefaultModel?: string, categories?: CategoriesConfig, gitMasterConfig?: GitMasterConfig, discoveredSkills?: LoadedSkill[], client?: any, browserProvider?: BrowserAutomationProvider, uiSelectedModel?: string): Promise<Record<string, AgentConfig>>;
15
+ export declare function createBuiltinAgents(disabledAgents?: string[], agentOverrides?: AgentOverrides, directory?: string, systemDefaultModel?: string, categories?: CategoriesConfig, gitMasterConfig?: GitMasterConfig, discoveredSkills?: LoadedSkill[], client?: any, browserProvider?: BrowserAutomationProvider, uiSelectedModel?: string, disabledSkills?: Set<string>): Promise<Record<string, AgentConfig>>;
16
16
  export {};
@@ -21,9 +21,12 @@ export interface ModelResolutionInfo {
21
21
  interface OmoConfig {
22
22
  agents?: Record<string, {
23
23
  model?: string;
24
+ variant?: string;
25
+ category?: string;
24
26
  }>;
25
27
  categories?: Record<string, {
26
28
  model?: string;
29
+ variant?: string;
27
30
  }>;
28
31
  }
29
32
  export declare function getModelResolutionInfo(): ModelResolutionInfo;
package/dist/cli/index.js CHANGED
@@ -6132,7 +6132,7 @@ var init_model_requirements = __esm(() => {
6132
6132
  oracle: {
6133
6133
  fallbackChain: [
6134
6134
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6135
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
6135
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
6136
6136
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }
6137
6137
  ]
6138
6138
  },
@@ -6176,14 +6176,14 @@ var init_model_requirements = __esm(() => {
6176
6176
  { providers: ["kimi-for-coding"], model: "k2p5" },
6177
6177
  { providers: ["opencode"], model: "kimi-k2.5-free" },
6178
6178
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6179
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
6179
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
6180
6180
  ]
6181
6181
  },
6182
6182
  momus: {
6183
6183
  fallbackChain: [
6184
6184
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
6185
6185
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6186
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
6186
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
6187
6187
  ]
6188
6188
  },
6189
6189
  atlas: {
@@ -6207,7 +6207,7 @@ var init_model_requirements = __esm(() => {
6207
6207
  ultrabrain: {
6208
6208
  fallbackChain: [
6209
6209
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
6210
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
6210
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
6211
6211
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }
6212
6212
  ]
6213
6213
  },
@@ -6215,13 +6215,13 @@ var init_model_requirements = __esm(() => {
6215
6215
  fallbackChain: [
6216
6216
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
6217
6217
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6218
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
6218
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
6219
6219
  ],
6220
6220
  requiresModel: "gpt-5.2-codex"
6221
6221
  },
6222
6222
  artistry: {
6223
6223
  fallbackChain: [
6224
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
6224
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
6225
6225
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6226
6226
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
6227
6227
  ],
@@ -6448,7 +6448,6 @@ var init_tmux = __esm(() => {
6448
6448
  var init_model_suggestion_retry = __esm(() => {
6449
6449
  init_logger();
6450
6450
  });
6451
-
6452
6451
  // src/shared/index.ts
6453
6452
  var init_shared = __esm(() => {
6454
6453
  init_model_resolution_pipeline();
@@ -8314,7 +8313,7 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
8314
8313
  // package.json
8315
8314
  var package_default = {
8316
8315
  name: "oh-my-opencode",
8317
- version: "3.2.2",
8316
+ version: "3.2.3",
8318
8317
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
8319
8318
  main: "dist/index.js",
8320
8319
  types: "dist/index.d.ts",
@@ -8388,13 +8387,13 @@ var package_default = {
8388
8387
  typescript: "^5.7.3"
8389
8388
  },
8390
8389
  optionalDependencies: {
8391
- "oh-my-opencode-darwin-arm64": "3.2.2",
8392
- "oh-my-opencode-darwin-x64": "3.2.2",
8393
- "oh-my-opencode-linux-arm64": "3.2.2",
8394
- "oh-my-opencode-linux-arm64-musl": "3.2.2",
8395
- "oh-my-opencode-linux-x64": "3.2.2",
8396
- "oh-my-opencode-linux-x64-musl": "3.2.2",
8397
- "oh-my-opencode-windows-x64": "3.2.2"
8390
+ "oh-my-opencode-darwin-arm64": "3.2.3",
8391
+ "oh-my-opencode-darwin-x64": "3.2.3",
8392
+ "oh-my-opencode-linux-arm64": "3.2.3",
8393
+ "oh-my-opencode-linux-arm64-musl": "3.2.3",
8394
+ "oh-my-opencode-linux-x64": "3.2.3",
8395
+ "oh-my-opencode-linux-x64-musl": "3.2.3",
8396
+ "oh-my-opencode-windows-x64": "3.2.3"
8398
8397
  },
8399
8398
  trustedDependencies: [
8400
8399
  "@ast-grep/cli",
@@ -24387,6 +24386,10 @@ var BrowserAutomationProviderSchema = exports_external.enum(["playwright", "agen
24387
24386
  var BrowserAutomationConfigSchema = exports_external.object({
24388
24387
  provider: BrowserAutomationProviderSchema.default("playwright")
24389
24388
  });
24389
+ var WebsearchProviderSchema = exports_external.enum(["exa", "tavily"]);
24390
+ var WebsearchConfigSchema = exports_external.object({
24391
+ provider: WebsearchProviderSchema.optional()
24392
+ });
24390
24393
  var TmuxLayoutSchema = exports_external.enum([
24391
24394
  "main-horizontal",
24392
24395
  "main-vertical",
@@ -24432,6 +24435,7 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
24432
24435
  babysitting: BabysittingConfigSchema.optional(),
24433
24436
  git_master: GitMasterConfigSchema.optional(),
24434
24437
  browser_automation_engine: BrowserAutomationConfigSchema.optional(),
24438
+ websearch: WebsearchConfigSchema.optional(),
24435
24439
  tmux: TmuxConfigSchema.optional(),
24436
24440
  sisyphus: SisyphusConfigSchema.optional()
24437
24441
  });
@@ -25423,11 +25427,36 @@ function getModelResolutionInfoWithOverrides(config2) {
25423
25427
  function formatModelWithVariant(model, variant) {
25424
25428
  return variant ? `${model} (${variant})` : model;
25425
25429
  }
25426
- function getEffectiveVariant(requirement) {
25430
+ function getAgentOverride(agentName, config2) {
25431
+ const agentOverrides = config2.agents;
25432
+ if (!agentOverrides)
25433
+ return;
25434
+ return agentOverrides[agentName] ?? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentName.toLowerCase())?.[1];
25435
+ }
25436
+ function getEffectiveVariant(name, requirement, config2) {
25437
+ const agentOverride = getAgentOverride(name, config2);
25438
+ if (agentOverride?.variant) {
25439
+ return agentOverride.variant;
25440
+ }
25441
+ const categoryName = agentOverride?.category;
25442
+ if (categoryName) {
25443
+ const categoryVariant = config2.categories?.[categoryName]?.variant;
25444
+ if (categoryVariant) {
25445
+ return categoryVariant;
25446
+ }
25447
+ }
25448
+ const firstEntry = requirement.fallbackChain[0];
25449
+ return firstEntry?.variant ?? requirement.variant;
25450
+ }
25451
+ function getCategoryEffectiveVariant(categoryName, requirement, config2) {
25452
+ const categoryVariant = config2.categories?.[categoryName]?.variant;
25453
+ if (categoryVariant) {
25454
+ return categoryVariant;
25455
+ }
25427
25456
  const firstEntry = requirement.fallbackChain[0];
25428
25457
  return firstEntry?.variant ?? requirement.variant;
25429
25458
  }
25430
- function buildDetailsArray(info, available) {
25459
+ function buildDetailsArray(info, available, config2) {
25431
25460
  const details = [];
25432
25461
  details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
25433
25462
  details.push("");
@@ -25447,14 +25476,14 @@ function buildDetailsArray(info, available) {
25447
25476
  details.push("Agents:");
25448
25477
  for (const agent of info.agents) {
25449
25478
  const marker = agent.userOverride ? "\u25CF" : "\u25CB";
25450
- const display = formatModelWithVariant(agent.effectiveModel, getEffectiveVariant(agent.requirement));
25479
+ const display = formatModelWithVariant(agent.effectiveModel, getEffectiveVariant(agent.name, agent.requirement, config2));
25451
25480
  details.push(` ${marker} ${agent.name}: ${display}`);
25452
25481
  }
25453
25482
  details.push("");
25454
25483
  details.push("Categories:");
25455
25484
  for (const category of info.categories) {
25456
25485
  const marker = category.userOverride ? "\u25CF" : "\u25CB";
25457
- const display = formatModelWithVariant(category.effectiveModel, getEffectiveVariant(category.requirement));
25486
+ const display = formatModelWithVariant(category.effectiveModel, getCategoryEffectiveVariant(category.name, category.requirement, config2));
25458
25487
  details.push(` ${marker} ${category.name}: ${display}`);
25459
25488
  }
25460
25489
  details.push("");
@@ -25476,7 +25505,7 @@ async function checkModelResolution() {
25476
25505
  name: CHECK_NAMES[CHECK_IDS.MODEL_RESOLUTION],
25477
25506
  status: available.cacheExists ? "pass" : "warn",
25478
25507
  message: `${agentCount} agents, ${categoryCount} categories${overrideNote}${cacheNote}`,
25479
- details: buildDetailsArray(info, available)
25508
+ details: buildDetailsArray(info, available, config2)
25480
25509
  };
25481
25510
  }
25482
25511
  function getModelResolutionCheckDefinition() {
@@ -1372,6 +1372,16 @@ export declare const BrowserAutomationConfigSchema: z.ZodObject<{
1372
1372
  "dev-browser": "dev-browser";
1373
1373
  }>>;
1374
1374
  }, z.core.$strip>;
1375
+ export declare const WebsearchProviderSchema: z.ZodEnum<{
1376
+ exa: "exa";
1377
+ tavily: "tavily";
1378
+ }>;
1379
+ export declare const WebsearchConfigSchema: z.ZodObject<{
1380
+ provider: z.ZodOptional<z.ZodEnum<{
1381
+ exa: "exa";
1382
+ tavily: "tavily";
1383
+ }>>;
1384
+ }, z.core.$strip>;
1375
1385
  export declare const TmuxLayoutSchema: z.ZodEnum<{
1376
1386
  "main-horizontal": "main-horizontal";
1377
1387
  "main-vertical": "main-vertical";
@@ -2581,6 +2591,12 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
2581
2591
  "dev-browser": "dev-browser";
2582
2592
  }>>;
2583
2593
  }, z.core.$strip>>;
2594
+ websearch: z.ZodOptional<z.ZodObject<{
2595
+ provider: z.ZodOptional<z.ZodEnum<{
2596
+ exa: "exa";
2597
+ tavily: "tavily";
2598
+ }>>;
2599
+ }, z.core.$strip>>;
2584
2600
  tmux: z.ZodOptional<z.ZodObject<{
2585
2601
  enabled: z.ZodDefault<z.ZodBoolean>;
2586
2602
  layout: z.ZodDefault<z.ZodEnum<{
@@ -2624,6 +2640,8 @@ export type BuiltinCategoryName = z.infer<typeof BuiltinCategoryNameSchema>;
2624
2640
  export type GitMasterConfig = z.infer<typeof GitMasterConfigSchema>;
2625
2641
  export type BrowserAutomationProvider = z.infer<typeof BrowserAutomationProviderSchema>;
2626
2642
  export type BrowserAutomationConfig = z.infer<typeof BrowserAutomationConfigSchema>;
2643
+ export type WebsearchProvider = z.infer<typeof WebsearchProviderSchema>;
2644
+ export type WebsearchConfig = z.infer<typeof WebsearchConfigSchema>;
2627
2645
  export type TmuxConfig = z.infer<typeof TmuxConfigSchema>;
2628
2646
  export type TmuxLayout = z.infer<typeof TmuxLayoutSchema>;
2629
2647
  export type SisyphusTasksConfig = z.infer<typeof SisyphusTasksConfigSchema>;
@@ -2,5 +2,6 @@ import type { BuiltinSkill } from "./types";
2
2
  import type { BrowserAutomationProvider } from "../../config/schema";
3
3
  export interface CreateBuiltinSkillsOptions {
4
4
  browserProvider?: BrowserAutomationProvider;
5
+ disabledSkills?: Set<string>;
5
6
  }
6
7
  export declare function createBuiltinSkills(options?: CreateBuiltinSkillsOptions): BuiltinSkill[];
@@ -3,6 +3,7 @@ import type { GitMasterConfig, BrowserAutomationProvider } from "../../config/sc
3
3
  export interface SkillResolutionOptions {
4
4
  gitMasterConfig?: GitMasterConfig;
5
5
  browserProvider?: BrowserAutomationProvider;
6
+ disabledSkills?: Set<string>;
6
7
  }
7
8
  declare function clearSkillCache(): void;
8
9
  declare function getAllSkills(options?: SkillResolutionOptions): Promise<LoadedSkill[]>;
package/dist/index.js CHANGED
@@ -4901,7 +4901,7 @@ var init_model_requirements = __esm(() => {
4901
4901
  oracle: {
4902
4902
  fallbackChain: [
4903
4903
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4904
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
4904
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
4905
4905
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }
4906
4906
  ]
4907
4907
  },
@@ -4945,14 +4945,14 @@ var init_model_requirements = __esm(() => {
4945
4945
  { providers: ["kimi-for-coding"], model: "k2p5" },
4946
4946
  { providers: ["opencode"], model: "kimi-k2.5-free" },
4947
4947
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4948
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
4948
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
4949
4949
  ]
4950
4950
  },
4951
4951
  momus: {
4952
4952
  fallbackChain: [
4953
4953
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
4954
4954
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4955
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
4955
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
4956
4956
  ]
4957
4957
  },
4958
4958
  atlas: {
@@ -4976,7 +4976,7 @@ var init_model_requirements = __esm(() => {
4976
4976
  ultrabrain: {
4977
4977
  fallbackChain: [
4978
4978
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
4979
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
4979
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
4980
4980
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }
4981
4981
  ]
4982
4982
  },
@@ -4984,13 +4984,13 @@ var init_model_requirements = __esm(() => {
4984
4984
  fallbackChain: [
4985
4985
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
4986
4986
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4987
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
4987
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
4988
4988
  ],
4989
4989
  requiresModel: "gpt-5.2-codex"
4990
4990
  },
4991
4991
  artistry: {
4992
4992
  fallbackChain: [
4993
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
4993
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
4994
4994
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4995
4995
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4996
4996
  ],
@@ -5206,6 +5206,18 @@ var init_agent_tool_restrictions = __esm(() => {
5206
5206
  task: false,
5207
5207
  delegate_task: false
5208
5208
  },
5209
+ metis: {
5210
+ write: false,
5211
+ edit: false,
5212
+ task: false,
5213
+ delegate_task: false
5214
+ },
5215
+ momus: {
5216
+ write: false,
5217
+ edit: false,
5218
+ task: false,
5219
+ delegate_task: false
5220
+ },
5209
5221
  "multimodal-looker": {
5210
5222
  read: true
5211
5223
  },
@@ -5382,6 +5394,15 @@ function fuzzyMatchModel(target, available, providers) {
5382
5394
  log("[fuzzyMatchModel] exact match found", { exactMatch });
5383
5395
  return exactMatch;
5384
5396
  }
5397
+ const exactModelIdMatches = matches.filter((model) => {
5398
+ const modelId = model.split("/").slice(1).join("/");
5399
+ return normalizeModelName(modelId) === targetNormalized;
5400
+ });
5401
+ if (exactModelIdMatches.length > 0) {
5402
+ const result2 = exactModelIdMatches.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
5403
+ log("[fuzzyMatchModel] exact model ID match found", { result: result2, candidateCount: exactModelIdMatches.length });
5404
+ return result2;
5405
+ }
5385
5406
  const result = matches.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
5386
5407
  log("[fuzzyMatchModel] shortest match", { result });
5387
5408
  return result;
@@ -6076,6 +6097,40 @@ var init_model_suggestion_retry = __esm(() => {
6076
6097
  init_logger();
6077
6098
  });
6078
6099
 
6100
+ // src/shared/opencode-server-auth.ts
6101
+ function getServerBasicAuthHeader() {
6102
+ const password = process.env.OPENCODE_SERVER_PASSWORD;
6103
+ if (!password) {
6104
+ return;
6105
+ }
6106
+ const username = process.env.OPENCODE_SERVER_USERNAME ?? "opencode";
6107
+ const token = Buffer.from(`${username}:${password}`, "utf8").toString("base64");
6108
+ return `Basic ${token}`;
6109
+ }
6110
+ function injectServerAuthIntoClient(client) {
6111
+ const auth = getServerBasicAuthHeader();
6112
+ if (!auth) {
6113
+ return;
6114
+ }
6115
+ try {
6116
+ if (typeof client !== "object" || client === null || !("_client" in client) || typeof client._client !== "object" || client._client === null) {
6117
+ throw new Error("[opencode-server-auth] OPENCODE_SERVER_PASSWORD is set but SDK client structure is incompatible. " + "This may indicate an OpenCode SDK version mismatch.");
6118
+ }
6119
+ const internal = client._client;
6120
+ if (typeof internal.setConfig !== "function") {
6121
+ throw new Error("[opencode-server-auth] OPENCODE_SERVER_PASSWORD is set but SDK client._client.setConfig is not a function. " + "This may indicate an OpenCode SDK version mismatch.");
6122
+ }
6123
+ internal.setConfig({
6124
+ headers: {
6125
+ Authorization: auth
6126
+ }
6127
+ });
6128
+ } catch (error) {
6129
+ const message = error instanceof Error ? error.message : String(error);
6130
+ console.warn(`[opencode-server-auth] Failed to inject server auth: ${message}`);
6131
+ }
6132
+ }
6133
+
6079
6134
  // src/shared/index.ts
6080
6135
  var init_shared = __esm(() => {
6081
6136
  init_model_resolution_pipeline();
@@ -11884,7 +11939,7 @@ var init_constants4 = __esm(() => {
11884
11939
  "visual-engineering": { model: "google/gemini-3-pro" },
11885
11940
  ultrabrain: { model: "openai/gpt-5.2-codex", variant: "xhigh" },
11886
11941
  deep: { model: "openai/gpt-5.2-codex", variant: "medium" },
11887
- artistry: { model: "google/gemini-3-pro", variant: "max" },
11942
+ artistry: { model: "google/gemini-3-pro", variant: "high" },
11888
11943
  quick: { model: "anthropic/claude-haiku-4-5" },
11889
11944
  "unspecified-low": { model: "anthropic/claude-sonnet-4-5" },
11890
11945
  "unspecified-high": { model: "anthropic/claude-opus-4-5", variant: "max" },
@@ -21919,7 +21974,7 @@ function getClaudeSettingsPaths(customPath) {
21919
21974
  if (customPath && existsSync20(customPath)) {
21920
21975
  paths.unshift(customPath);
21921
21976
  }
21922
- return paths;
21977
+ return [...new Set(paths)];
21923
21978
  }
21924
21979
  function mergeHooksConfig(base, override) {
21925
21980
  const result = { ...base };
@@ -24247,7 +24302,7 @@ function createKeywordDetectorHook(ctx, collector) {
24247
24302
  const currentAgent = getSessionAgent(input.sessionID) ?? input.agent;
24248
24303
  const cleanText = removeSystemReminders(promptText);
24249
24304
  const modelID = input.model?.modelID;
24250
- let detectedKeywords = detectKeywordsWithType(removeCodeBlocks2(cleanText), currentAgent, modelID);
24305
+ let detectedKeywords = detectKeywordsWithType(cleanText, currentAgent, modelID);
24251
24306
  if (isPlannerAgent(currentAgent)) {
24252
24307
  detectedKeywords = detectedKeywords.filter((k) => k.type !== "ultrawork");
24253
24308
  }
@@ -24398,8 +24453,7 @@ function createNonInteractiveEnvHook(_ctx) {
24398
24453
  if (!isGitCommand) {
24399
24454
  return;
24400
24455
  }
24401
- const shellType = "unix";
24402
- const envPrefix = buildEnvPrefix(NON_INTERACTIVE_ENV, shellType);
24456
+ const envPrefix = buildEnvPrefix(NON_INTERACTIVE_ENV, "unix");
24403
24457
  output.args.command = `${envPrefix} ${command}`;
24404
24458
  log(`[${HOOK_NAME2}] Prepended non-interactive env vars to git command`, {
24405
24459
  sessionID: input.sessionID,
@@ -25264,7 +25318,7 @@ var EXCLUDED_COMMANDS = new Set([
25264
25318
 
25265
25319
  // src/hooks/auto-slash-command/detector.ts
25266
25320
  var CODE_BLOCK_PATTERN3 = /```[\s\S]*?```/g;
25267
- function removeCodeBlocks3(text) {
25321
+ function removeCodeBlocks4(text) {
25268
25322
  return text.replace(CODE_BLOCK_PATTERN3, "");
25269
25323
  }
25270
25324
  function parseSlashCommand(text) {
@@ -25287,7 +25341,7 @@ function isExcludedCommand(command) {
25287
25341
  return EXCLUDED_COMMANDS.has(command.toLowerCase());
25288
25342
  }
25289
25343
  function detectSlashCommand(text) {
25290
- const textWithoutCodeBlocks = removeCodeBlocks3(text);
25344
+ const textWithoutCodeBlocks = removeCodeBlocks4(text);
25291
25345
  const trimmed = textWithoutCodeBlocks.trim();
25292
25346
  if (!trimmed.startsWith("/")) {
25293
25347
  return null;
@@ -26514,14 +26568,15 @@ function parseAllowedTools(allowedTools) {
26514
26568
  }
26515
26569
  return allowedTools.split(/\s+/).filter(Boolean);
26516
26570
  }
26517
- async function loadSkillFromPath(skillPath, resolvedPath, defaultName, scope) {
26571
+ async function loadSkillFromPath(skillPath, resolvedPath, defaultName, scope, namePrefix = "") {
26518
26572
  try {
26519
26573
  const content = await fs9.readFile(skillPath, "utf-8");
26520
26574
  const { data, body } = parseFrontmatter(content);
26521
26575
  const frontmatterMcp = parseSkillMcpConfigFromFrontmatter(content);
26522
26576
  const mcpJsonMcp = await loadMcpJsonFromDir(resolvedPath);
26523
26577
  const mcpConfig = mcpJsonMcp || frontmatterMcp;
26524
- const skillName = data.name || defaultName;
26578
+ const baseName = data.name || defaultName;
26579
+ const skillName = namePrefix ? `${namePrefix}/${baseName}` : baseName;
26525
26580
  const originalDescription = data.description || "";
26526
26581
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
26527
26582
  const formattedDescription = `(${scope} - Skill) ${originalDescription}`;
@@ -26566,42 +26621,52 @@ $ARGUMENTS
26566
26621
  return null;
26567
26622
  }
26568
26623
  }
26569
- async function loadSkillsFromDir(skillsDir, scope) {
26624
+ async function loadSkillsFromDir(skillsDir, scope, namePrefix = "", depth = 0, maxDepth = 2) {
26570
26625
  const entries = await fs9.readdir(skillsDir, { withFileTypes: true }).catch(() => []);
26571
- const skills = [];
26572
- for (const entry of entries) {
26573
- if (entry.name.startsWith("."))
26574
- continue;
26626
+ const skillMap = new Map;
26627
+ const directories = entries.filter((e) => !e.name.startsWith(".") && (e.isDirectory() || e.isSymbolicLink()));
26628
+ const files = entries.filter((e) => !e.name.startsWith(".") && !e.isDirectory() && !e.isSymbolicLink() && isMarkdownFile(e));
26629
+ for (const entry of directories) {
26575
26630
  const entryPath = join41(skillsDir, entry.name);
26576
- if (entry.isDirectory() || entry.isSymbolicLink()) {
26577
- const resolvedPath = await resolveSymlinkAsync(entryPath);
26578
- const dirName = entry.name;
26579
- const skillMdPath = join41(resolvedPath, "SKILL.md");
26580
- try {
26581
- await fs9.access(skillMdPath);
26582
- const skill = await loadSkillFromPath(skillMdPath, resolvedPath, dirName, scope);
26583
- if (skill)
26584
- skills.push(skill);
26585
- continue;
26586
- } catch {}
26587
- const namedSkillMdPath = join41(resolvedPath, `${dirName}.md`);
26588
- try {
26589
- await fs9.access(namedSkillMdPath);
26590
- const skill = await loadSkillFromPath(namedSkillMdPath, resolvedPath, dirName, scope);
26591
- if (skill)
26592
- skills.push(skill);
26593
- continue;
26594
- } catch {}
26631
+ const resolvedPath = await resolveSymlinkAsync(entryPath);
26632
+ const dirName = entry.name;
26633
+ const skillMdPath = join41(resolvedPath, "SKILL.md");
26634
+ try {
26635
+ await fs9.access(skillMdPath);
26636
+ const skill = await loadSkillFromPath(skillMdPath, resolvedPath, dirName, scope, namePrefix);
26637
+ if (skill && !skillMap.has(skill.name)) {
26638
+ skillMap.set(skill.name, skill);
26639
+ }
26595
26640
  continue;
26641
+ } catch {}
26642
+ const namedSkillMdPath = join41(resolvedPath, `${dirName}.md`);
26643
+ try {
26644
+ await fs9.access(namedSkillMdPath);
26645
+ const skill = await loadSkillFromPath(namedSkillMdPath, resolvedPath, dirName, scope, namePrefix);
26646
+ if (skill && !skillMap.has(skill.name)) {
26647
+ skillMap.set(skill.name, skill);
26648
+ }
26649
+ continue;
26650
+ } catch {}
26651
+ if (depth < maxDepth) {
26652
+ const newPrefix = namePrefix ? `${namePrefix}/${dirName}` : dirName;
26653
+ const nestedSkills = await loadSkillsFromDir(resolvedPath, scope, newPrefix, depth + 1, maxDepth);
26654
+ for (const nestedSkill of nestedSkills) {
26655
+ if (!skillMap.has(nestedSkill.name)) {
26656
+ skillMap.set(nestedSkill.name, nestedSkill);
26657
+ }
26658
+ }
26596
26659
  }
26597
- if (isMarkdownFile(entry)) {
26598
- const skillName = basename(entry.name, ".md");
26599
- const skill = await loadSkillFromPath(entryPath, skillsDir, skillName, scope);
26600
- if (skill)
26601
- skills.push(skill);
26660
+ }
26661
+ for (const entry of files) {
26662
+ const entryPath = join41(skillsDir, entry.name);
26663
+ const baseName = basename(entry.name, ".md");
26664
+ const skill = await loadSkillFromPath(entryPath, skillsDir, baseName, scope, namePrefix);
26665
+ if (skill && !skillMap.has(skill.name)) {
26666
+ skillMap.set(skill.name, skill);
26602
26667
  }
26603
26668
  }
26604
- return skills;
26669
+ return Array.from(skillMap.values());
26605
26670
  }
26606
26671
  function skillsToRecord(skills) {
26607
26672
  const result = {};
@@ -28600,9 +28665,13 @@ EOF
28600
28665
  };
28601
28666
  // src/features/builtin-skills/skills.ts
28602
28667
  function createBuiltinSkills(options = {}) {
28603
- const { browserProvider = "playwright" } = options;
28668
+ const { browserProvider = "playwright", disabledSkills } = options;
28604
28669
  const browserSkill = browserProvider === "agent-browser" ? agentBrowserSkill : playwrightSkill;
28605
- return [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill];
28670
+ const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill];
28671
+ if (!disabledSkills) {
28672
+ return skills;
28673
+ }
28674
+ return skills.filter((skill) => !disabledSkills.has(skill.name));
28606
28675
  }
28607
28676
 
28608
28677
  // src/features/opencode-skill-loader/skill-content.ts
@@ -28611,12 +28680,18 @@ import { readFileSync as readFileSync21 } from "fs";
28611
28680
  var cachedSkillsByProvider = new Map;
28612
28681
  async function getAllSkills(options) {
28613
28682
  const cacheKey = options?.browserProvider ?? "playwright";
28614
- const cached = cachedSkillsByProvider.get(cacheKey);
28615
- if (cached)
28616
- return cached;
28683
+ const hasDisabledSkills = options?.disabledSkills && options.disabledSkills.size > 0;
28684
+ if (!hasDisabledSkills) {
28685
+ const cached = cachedSkillsByProvider.get(cacheKey);
28686
+ if (cached)
28687
+ return cached;
28688
+ }
28617
28689
  const [discoveredSkills, builtinSkillDefs] = await Promise.all([
28618
28690
  discoverSkills({ includeClaudeCodePaths: true }),
28619
- Promise.resolve(createBuiltinSkills({ browserProvider: options?.browserProvider }))
28691
+ Promise.resolve(createBuiltinSkills({
28692
+ browserProvider: options?.browserProvider,
28693
+ disabledSkills: options?.disabledSkills
28694
+ }))
28620
28695
  ]);
28621
28696
  const builtinSkillsAsLoaded = builtinSkillDefs.map((skill) => ({
28622
28697
  name: skill.name,
@@ -28637,8 +28712,12 @@ async function getAllSkills(options) {
28637
28712
  }));
28638
28713
  const discoveredNames = new Set(discoveredSkills.map((s) => s.name));
28639
28714
  const uniqueBuiltins = builtinSkillsAsLoaded.filter((s) => !discoveredNames.has(s.name));
28640
- const allSkills = [...discoveredSkills, ...uniqueBuiltins];
28641
- cachedSkillsByProvider.set(cacheKey, allSkills);
28715
+ let allSkills = [...discoveredSkills, ...uniqueBuiltins];
28716
+ if (hasDisabledSkills) {
28717
+ allSkills = allSkills.filter((s) => !options.disabledSkills.has(s.name));
28718
+ } else {
28719
+ cachedSkillsByProvider.set(cacheKey, allSkills);
28720
+ }
28642
28721
  return allSkills;
28643
28722
  }
28644
28723
  async function extractSkillTemplate(skill) {
@@ -28702,7 +28781,10 @@ function injectGitMasterConfig(template, config) {
28702
28781
  ` + injection;
28703
28782
  }
28704
28783
  function resolveMultipleSkills(skillNames, options) {
28705
- const skills = createBuiltinSkills({ browserProvider: options?.browserProvider });
28784
+ const skills = createBuiltinSkills({
28785
+ browserProvider: options?.browserProvider,
28786
+ disabledSkills: options?.disabledSkills
28787
+ });
28706
28788
  const skillMap = new Map(skills.map((s) => [s.name, s.template]));
28707
28789
  const resolved = new Map;
28708
28790
  const notFound = [];
@@ -29067,7 +29149,7 @@ function getAgentDisplayName(configKey) {
29067
29149
  var HOOK_NAME4 = "prometheus-md-only";
29068
29150
  var PROMETHEUS_AGENT = "prometheus";
29069
29151
  var ALLOWED_EXTENSIONS = [".md"];
29070
- var BLOCKED_TOOLS = ["Write", "Edit", "write", "edit"];
29152
+ var BLOCKED_TOOLS = ["Write", "Edit", "write", "edit", "bash"];
29071
29153
  var PLANNING_CONSULT_WARNING = `
29072
29154
 
29073
29155
  ---
@@ -29198,6 +29280,14 @@ function createPrometheusMdOnlyHook(ctx) {
29198
29280
  if (!BLOCKED_TOOLS.includes(toolName)) {
29199
29281
  return;
29200
29282
  }
29283
+ if (toolName === "bash") {
29284
+ log(`[${HOOK_NAME4}] Blocked: Prometheus cannot execute bash commands`, {
29285
+ sessionID: input.sessionID,
29286
+ tool: toolName,
29287
+ agent: agentName
29288
+ });
29289
+ throw new Error(`[${HOOK_NAME4}] ${getAgentDisplayName("prometheus")} cannot execute bash commands. ` + `${getAgentDisplayName("prometheus")} is a READ-ONLY planner. Use /start-work to execute the plan. ` + `APOLOGIZE TO THE USER, REMIND OF YOUR PLAN WRITING PROCESSES, TELL USER WHAT YOU WILL GOING TO DO AS THE PROCESS, WRITE THE PLAN`);
29290
+ }
29201
29291
  const filePath = output.args.filePath ?? output.args.path ?? output.args.file;
29202
29292
  if (!filePath) {
29203
29293
  return;
@@ -31906,6 +31996,8 @@ class LSPClient {
31906
31996
  proc = null;
31907
31997
  connection = null;
31908
31998
  openedFiles = new Set;
31999
+ documentVersions = new Map;
32000
+ lastSyncedText = new Map;
31909
32001
  stderrBuffer = [];
31910
32002
  processExited = false;
31911
32003
  diagnosticsStore = new Map;
@@ -32110,21 +32202,41 @@ recent stderr: ${stderr}` : "")));
32110
32202
  }
32111
32203
  async openFile(filePath) {
32112
32204
  const absPath = resolve8(filePath);
32113
- if (this.openedFiles.has(absPath))
32114
- return;
32205
+ const uri = pathToFileURL(absPath).href;
32115
32206
  const text = readFileSync26(absPath, "utf-8");
32116
- const ext = extname(absPath);
32117
- const languageId = getLanguageId(ext);
32118
- this.sendNotification("textDocument/didOpen", {
32119
- textDocument: {
32120
- uri: pathToFileURL(absPath).href,
32121
- languageId,
32122
- version: 1,
32123
- text
32124
- }
32207
+ if (!this.openedFiles.has(absPath)) {
32208
+ const ext = extname(absPath);
32209
+ const languageId = getLanguageId(ext);
32210
+ const version = 1;
32211
+ this.sendNotification("textDocument/didOpen", {
32212
+ textDocument: {
32213
+ uri,
32214
+ languageId,
32215
+ version,
32216
+ text
32217
+ }
32218
+ });
32219
+ this.openedFiles.add(absPath);
32220
+ this.documentVersions.set(uri, version);
32221
+ this.lastSyncedText.set(uri, text);
32222
+ await new Promise((r) => setTimeout(r, 1000));
32223
+ return;
32224
+ }
32225
+ const prevText = this.lastSyncedText.get(uri);
32226
+ if (prevText === text) {
32227
+ return;
32228
+ }
32229
+ const nextVersion = (this.documentVersions.get(uri) ?? 1) + 1;
32230
+ this.documentVersions.set(uri, nextVersion);
32231
+ this.lastSyncedText.set(uri, text);
32232
+ this.sendNotification("textDocument/didChange", {
32233
+ textDocument: { uri, version: nextVersion },
32234
+ contentChanges: [{ text }]
32235
+ });
32236
+ this.sendNotification("textDocument/didSave", {
32237
+ textDocument: { uri },
32238
+ text
32125
32239
  });
32126
- this.openedFiles.add(absPath);
32127
- await new Promise((r) => setTimeout(r, 1000));
32128
32240
  }
32129
32241
  async definition(filePath, line, character) {
32130
32242
  const absPath = resolve8(filePath);
@@ -45924,10 +46036,11 @@ var grep = tool({
45924
46036
  include: tool.schema.string().optional().describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'),
45925
46037
  path: tool.schema.string().optional().describe("The directory to search in. Defaults to the current working directory.")
45926
46038
  },
45927
- execute: async (args) => {
46039
+ execute: async (args, ctx) => {
45928
46040
  try {
45929
46041
  const globs = args.include ? [args.include] : undefined;
45930
- const paths = args.path ? [args.path] : undefined;
46042
+ const searchPath = args.path ?? ctx.directory;
46043
+ const paths = [searchPath];
45931
46044
  const result = await runRg({
45932
46045
  pattern: args.pattern,
45933
46046
  paths,
@@ -46121,10 +46234,11 @@ var glob = tool({
46121
46234
  pattern: tool.schema.string().describe("The glob pattern to match files against"),
46122
46235
  path: tool.schema.string().optional().describe("The directory to search in. If not specified, the current working directory will be used. " + 'IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - ' + "simply omit it for the default behavior. Must be a valid directory path if provided.")
46123
46236
  },
46124
- execute: async (args) => {
46237
+ execute: async (args, ctx) => {
46125
46238
  try {
46126
46239
  const cli = await resolveGrepCliWithAutoInstall();
46127
- const paths = args.path ? [args.path] : undefined;
46240
+ const searchPath = args.path ?? ctx.directory;
46241
+ const paths = [searchPath];
46128
46242
  const result = await runRgFiles({
46129
46243
  pattern: args.pattern,
46130
46244
  paths
@@ -47190,7 +47304,7 @@ function createSkillTool(options = {}) {
47190
47304
  return options.skills;
47191
47305
  if (cachedSkills)
47192
47306
  return cachedSkills;
47193
- cachedSkills = await getAllSkills();
47307
+ cachedSkills = await getAllSkills({ disabledSkills: options?.disabledSkills });
47194
47308
  return cachedSkills;
47195
47309
  };
47196
47310
  const getDescription = async () => {
@@ -47345,7 +47459,7 @@ function createSkillMcpTool(options) {
47345
47459
  tool_name: tool.schema.string().optional().describe("MCP tool to call"),
47346
47460
  resource_name: tool.schema.string().optional().describe("MCP resource URI to read"),
47347
47461
  prompt_name: tool.schema.string().optional().describe("MCP prompt to get"),
47348
- arguments: tool.schema.union([tool.schema.string(), tool.schema.record(tool.schema.string(), tool.schema.unknown())]).optional().describe("JSON string or object of arguments"),
47462
+ arguments: tool.schema.union([tool.schema.string(), tool.schema.object({})]).optional().describe("JSON string or object of arguments"),
47349
47463
  grep: tool.schema.string().optional().describe("Regex pattern to filter output lines (only matching lines returned)")
47350
47464
  },
47351
47465
  async execute(args) {
@@ -49332,15 +49446,16 @@ async function resolveCategoryExecution(args, executorCtx, inheritedModel, syste
49332
49446
  let modelInfo;
49333
49447
  let categoryModel;
49334
49448
  const overrideModel = sisyphusJuniorModel;
49449
+ const explicitCategoryModel = userCategories?.[args.category]?.model;
49335
49450
  if (!requirement) {
49336
- actualModel = overrideModel ?? resolved.model;
49451
+ actualModel = explicitCategoryModel ?? overrideModel ?? resolved.model;
49337
49452
  if (actualModel) {
49338
- modelInfo = overrideModel ? { model: actualModel, type: "user-defined", source: "override" } : { model: actualModel, type: "system-default", source: "system-default" };
49453
+ modelInfo = explicitCategoryModel || overrideModel ? { model: actualModel, type: "user-defined", source: "override" } : { model: actualModel, type: "system-default", source: "system-default" };
49339
49454
  }
49340
49455
  } else {
49341
49456
  const resolution = resolveModelPipeline({
49342
49457
  intent: {
49343
- userModel: overrideModel ?? userCategories?.[args.category]?.model,
49458
+ userModel: explicitCategoryModel ?? overrideModel,
49344
49459
  categoryDefaultModel: resolved.model
49345
49460
  },
49346
49461
  constraints: { availableModels },
@@ -49532,7 +49647,8 @@ Prompts MUST be in English.`;
49532
49647
  const runInBackground = args.run_in_background === true;
49533
49648
  const { content: skillContent, error: skillError } = await resolveSkillContent(args.load_skills, {
49534
49649
  gitMasterConfig: options.gitMasterConfig,
49535
- browserProvider: options.browserProvider
49650
+ browserProvider: options.browserProvider,
49651
+ disabledSkills: options.disabledSkills
49536
49652
  });
49537
49653
  if (skillError) {
49538
49654
  return skillError;
@@ -64017,6 +64133,9 @@ class BackgroundManager {
64017
64133
  this.concurrencyManager.release(existingTask.concurrencyKey);
64018
64134
  existingTask.concurrencyKey = undefined;
64019
64135
  }
64136
+ this.client.session.abort({
64137
+ path: { id: sessionID }
64138
+ }).catch(() => {});
64020
64139
  this.markForNotification(existingTask);
64021
64140
  this.notifyParentSession(existingTask).catch((err) => {
64022
64141
  log("[background-agent] Failed to notify on error:", err);
@@ -64206,6 +64325,11 @@ class BackgroundManager {
64206
64325
  this.concurrencyManager.release(existingTask.concurrencyKey);
64207
64326
  existingTask.concurrencyKey = undefined;
64208
64327
  }
64328
+ if (existingTask.sessionID) {
64329
+ this.client.session.abort({
64330
+ path: { id: existingTask.sessionID }
64331
+ }).catch(() => {});
64332
+ }
64209
64333
  this.markForNotification(existingTask);
64210
64334
  this.notifyParentSession(existingTask).catch((err) => {
64211
64335
  log("[background-agent] Failed to notify on resume error:", err);
@@ -70918,6 +71042,10 @@ var BrowserAutomationProviderSchema = exports_external2.enum(["playwright", "age
70918
71042
  var BrowserAutomationConfigSchema = exports_external2.object({
70919
71043
  provider: BrowserAutomationProviderSchema.default("playwright")
70920
71044
  });
71045
+ var WebsearchProviderSchema = exports_external2.enum(["exa", "tavily"]);
71046
+ var WebsearchConfigSchema = exports_external2.object({
71047
+ provider: WebsearchProviderSchema.optional()
71048
+ });
70921
71049
  var TmuxLayoutSchema = exports_external2.enum([
70922
71050
  "main-horizontal",
70923
71051
  "main-vertical",
@@ -70963,6 +71091,7 @@ var OhMyOpenCodeConfigSchema = exports_external2.object({
70963
71091
  babysitting: BabysittingConfigSchema.optional(),
70964
71092
  git_master: GitMasterConfigSchema.optional(),
70965
71093
  browser_automation_engine: BrowserAutomationConfigSchema.optional(),
71094
+ websearch: WebsearchConfigSchema.optional(),
70966
71095
  tmux: TmuxConfigSchema.optional(),
70967
71096
  sisyphus: SisyphusConfigSchema.optional()
70968
71097
  });
@@ -74416,7 +74545,7 @@ function createHephaestusAgent(model, availableAgents, availableToolNames, avail
74416
74545
  model,
74417
74546
  maxTokens: 32000,
74418
74547
  prompt,
74419
- color: "#FF4500",
74548
+ color: "#D97706",
74420
74549
  permission: { question: "allow", call_omo_agent: "deny" },
74421
74550
  reasoningEffort: "medium"
74422
74551
  };
@@ -74449,7 +74578,7 @@ var agentMetadata = {
74449
74578
  function isFactory(source) {
74450
74579
  return typeof source === "function";
74451
74580
  }
74452
- function buildAgent(source, model, categories, gitMasterConfig, browserProvider) {
74581
+ function buildAgent(source, model, categories, gitMasterConfig, browserProvider, disabledSkills) {
74453
74582
  const base = isFactory(source) ? source(model) : source;
74454
74583
  const categoryConfigs = categories ? { ...DEFAULT_CATEGORIES, ...categories } : DEFAULT_CATEGORIES;
74455
74584
  const agentWithCategory = base;
@@ -74468,7 +74597,7 @@ function buildAgent(source, model, categories, gitMasterConfig, browserProvider)
74468
74597
  }
74469
74598
  }
74470
74599
  if (agentWithCategory.skills?.length) {
74471
- const { resolved } = resolveMultipleSkills(agentWithCategory.skills, { gitMasterConfig, browserProvider });
74600
+ const { resolved } = resolveMultipleSkills(agentWithCategory.skills, { gitMasterConfig, browserProvider, disabledSkills });
74472
74601
  if (resolved.size > 0) {
74473
74602
  const skillContent = Array.from(resolved.values()).join(`
74474
74603
 
@@ -74563,7 +74692,8 @@ function applyOverrides(config4, override, mergedCategories) {
74563
74692
  return result;
74564
74693
  }
74565
74694
  function mergeAgentConfig(base, override) {
74566
- const { prompt_append, ...rest } = override;
74695
+ const migratedOverride = migrateAgentConfig(override);
74696
+ const { prompt_append, ...rest } = migratedOverride;
74567
74697
  const merged = deepMerge(base, rest);
74568
74698
  if (prompt_append && merged.prompt) {
74569
74699
  merged.prompt = merged.prompt + `
@@ -74578,7 +74708,7 @@ function mapScopeToLocation(scope) {
74578
74708
  return "project";
74579
74709
  return "plugin";
74580
74710
  }
74581
- async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory, systemDefaultModel, categories, gitMasterConfig, discoveredSkills = [], client2, browserProvider, uiSelectedModel) {
74711
+ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory, systemDefaultModel, categories, gitMasterConfig, discoveredSkills = [], client2, browserProvider, uiSelectedModel, disabledSkills) {
74582
74712
  const connectedProviders = readConnectedProvidersCache();
74583
74713
  const availableModels = await fetchAvailableModels(undefined, {
74584
74714
  connectedProviders: connectedProviders ?? undefined
@@ -74591,7 +74721,7 @@ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, dir
74591
74721
  name,
74592
74722
  description: categories?.[name]?.description ?? CATEGORY_DESCRIPTIONS[name] ?? "General tasks"
74593
74723
  }));
74594
- const builtinSkills = createBuiltinSkills({ browserProvider });
74724
+ const builtinSkills = createBuiltinSkills({ browserProvider, disabledSkills });
74595
74725
  const builtinSkillNames = new Set(builtinSkills.map((s) => s.name));
74596
74726
  const builtinAvailable = builtinSkills.map((skill2) => ({
74597
74727
  name: skill2.name,
@@ -74633,7 +74763,7 @@ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, dir
74633
74763
  if (!resolution)
74634
74764
  continue;
74635
74765
  const { model, variant: resolvedVariant } = resolution;
74636
- let config4 = buildAgent(source, model, mergedCategories, gitMasterConfig, browserProvider);
74766
+ let config4 = buildAgent(source, model, mergedCategories, gitMasterConfig, browserProvider, disabledSkills);
74637
74767
  if (resolvedVariant) {
74638
74768
  config4 = { ...config4, variant: resolvedVariant };
74639
74769
  }
@@ -76966,13 +77096,32 @@ async function loadAllPluginComponents(options) {
76966
77096
  };
76967
77097
  }
76968
77098
  // src/mcp/websearch.ts
76969
- var websearch = {
76970
- type: "remote",
76971
- url: "https://mcp.exa.ai/mcp?tools=web_search_exa",
76972
- enabled: true,
76973
- headers: process.env.EXA_API_KEY ? { "x-api-key": process.env.EXA_API_KEY } : undefined,
76974
- oauth: false
76975
- };
77099
+ function createWebsearchConfig(config4) {
77100
+ const provider = config4?.provider || "exa";
77101
+ if (provider === "tavily") {
77102
+ const tavilyKey = process.env.TAVILY_API_KEY;
77103
+ if (!tavilyKey) {
77104
+ throw new Error("TAVILY_API_KEY environment variable is required for Tavily provider");
77105
+ }
77106
+ return {
77107
+ type: "remote",
77108
+ url: "https://mcp.tavily.com/mcp/",
77109
+ enabled: true,
77110
+ headers: {
77111
+ Authorization: `Bearer ${tavilyKey}`
77112
+ },
77113
+ oauth: false
77114
+ };
77115
+ }
77116
+ return {
77117
+ type: "remote",
77118
+ url: "https://mcp.exa.ai/mcp?tools=web_search_exa",
77119
+ enabled: true,
77120
+ headers: process.env.EXA_API_KEY ? { "x-api-key": process.env.EXA_API_KEY } : undefined,
77121
+ oauth: false
77122
+ };
77123
+ }
77124
+ var websearch = createWebsearchConfig();
76976
77125
 
76977
77126
  // src/mcp/context7.ts
76978
77127
  var context7 = {
@@ -76992,17 +77141,16 @@ var grep_app = {
76992
77141
  };
76993
77142
 
76994
77143
  // src/mcp/index.ts
76995
- var allBuiltinMcps = {
76996
- websearch,
76997
- context7,
76998
- grep_app
76999
- };
77000
- function createBuiltinMcps(disabledMcps = []) {
77144
+ function createBuiltinMcps(disabledMcps = [], config4) {
77001
77145
  const mcps = {};
77002
- for (const [name, config4] of Object.entries(allBuiltinMcps)) {
77003
- if (!disabledMcps.includes(name)) {
77004
- mcps[name] = config4;
77005
- }
77146
+ if (!disabledMcps.includes("websearch")) {
77147
+ mcps.websearch = createWebsearchConfig(config4?.websearch);
77148
+ }
77149
+ if (!disabledMcps.includes("context7")) {
77150
+ mcps.context7 = context7;
77151
+ }
77152
+ if (!disabledMcps.includes("grep_app")) {
77153
+ mcps.grep_app = grep_app;
77006
77154
  }
77007
77155
  return mcps;
77008
77156
  }
@@ -77093,7 +77241,8 @@ function createConfigHandler(deps) {
77093
77241
  ];
77094
77242
  const browserProvider = pluginConfig.browser_automation_engine?.provider ?? "playwright";
77095
77243
  const currentModel = config4.model;
77096
- const builtinAgents = await createBuiltinAgents(migratedDisabledAgents, pluginConfig.agents, ctx.directory, undefined, pluginConfig.categories, pluginConfig.git_master, allDiscoveredSkills, ctx.client, browserProvider, currentModel);
77244
+ const disabledSkills = new Set(pluginConfig.disabled_skills ?? []);
77245
+ const builtinAgents = await createBuiltinAgents(migratedDisabledAgents, pluginConfig.agents, ctx.directory, undefined, pluginConfig.categories, pluginConfig.git_master, allDiscoveredSkills, ctx.client, browserProvider, currentModel, disabledSkills);
77097
77246
  const userAgents = pluginConfig.claude_code?.agents ?? true ? loadUserAgents() : {};
77098
77247
  const projectAgents = pluginConfig.claude_code?.agents ?? true ? loadProjectAgents() : {};
77099
77248
  const rawPluginAgents = pluginComponents.agents;
@@ -77159,7 +77308,7 @@ function createConfigHandler(deps) {
77159
77308
  prompt: PROMETHEUS_SYSTEM_PROMPT,
77160
77309
  permission: PROMETHEUS_PERMISSION,
77161
77310
  description: `${configAgent?.plan?.description ?? "Plan agent"} (Prometheus - OhMyOpenCode)`,
77162
- color: configAgent?.plan?.color ?? "#9D4EDD",
77311
+ color: configAgent?.plan?.color ?? "#FF5722",
77163
77312
  ...temperatureToUse !== undefined ? { temperature: temperatureToUse } : {},
77164
77313
  ...topPToUse !== undefined ? { top_p: topPToUse } : {},
77165
77314
  ...maxTokensToUse !== undefined ? { maxTokens: maxTokensToUse } : {},
@@ -77193,7 +77342,9 @@ function createConfigHandler(deps) {
77193
77342
  value ? migrateAgentConfig(value) : value
77194
77343
  ])) : {};
77195
77344
  const migratedBuild = configAgent?.build ? migrateAgentConfig(configAgent.build) : {};
77196
- const planDemoteConfig = shouldDemotePlan ? { mode: "subagent" } : undefined;
77345
+ const planDemoteConfig = shouldDemotePlan ? {
77346
+ mode: "subagent"
77347
+ } : undefined;
77197
77348
  config4.agent = {
77198
77349
  ...agentConfig,
77199
77350
  ...Object.fromEntries(Object.entries(builtinAgents).filter(([k]) => k !== "sisyphus")),
@@ -77265,7 +77416,7 @@ function createConfigHandler(deps) {
77265
77416
  };
77266
77417
  const mcpResult = pluginConfig.claude_code?.mcp ?? true ? await loadMcpConfigs() : { servers: {} };
77267
77418
  config4.mcp = {
77268
- ...createBuiltinMcps(pluginConfig.disabled_mcps),
77419
+ ...createBuiltinMcps(pluginConfig.disabled_mcps, pluginConfig),
77269
77420
  ...config4.mcp,
77270
77421
  ...mcpResult.servers,
77271
77422
  ...pluginComponents.mcpServers
@@ -77314,6 +77465,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
77314
77465
  log("[OhMyOpenCodePlugin] ENTRY - plugin loading", {
77315
77466
  directory: ctx.directory
77316
77467
  });
77468
+ injectServerAuthIntoClient(ctx.client);
77317
77469
  startBackgroundCheck2();
77318
77470
  const pluginConfig = loadPluginConfig(ctx.directory, ctx);
77319
77471
  const disabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
@@ -77469,6 +77621,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
77469
77621
  const isMultimodalLookerEnabled = !(pluginConfig.disabled_agents ?? []).some((agent) => agent.toLowerCase() === "multimodal-looker");
77470
77622
  const lookAt = isMultimodalLookerEnabled ? createLookAt(ctx) : null;
77471
77623
  const browserProvider = pluginConfig.browser_automation_engine?.provider ?? "playwright";
77624
+ const disabledSkills = new Set(pluginConfig.disabled_skills ?? []);
77472
77625
  const delegateTask = createDelegateTask({
77473
77626
  manager: backgroundManager,
77474
77627
  client: ctx.client,
@@ -77477,6 +77630,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
77477
77630
  gitMasterConfig: pluginConfig.git_master,
77478
77631
  sisyphusJuniorModel: pluginConfig.agents?.["sisyphus-junior"]?.model,
77479
77632
  browserProvider,
77633
+ disabledSkills,
77480
77634
  onSyncSessionCreated: async (event) => {
77481
77635
  log("[index] onSyncSessionCreated callback", {
77482
77636
  sessionID: event.sessionID,
@@ -77495,11 +77649,8 @@ var OhMyOpenCodePlugin = async (ctx) => {
77495
77649
  });
77496
77650
  }
77497
77651
  });
77498
- const disabledSkills = new Set(pluginConfig.disabled_skills ?? []);
77499
77652
  const systemMcpNames = getSystemMcpServerNames();
77500
- const builtinSkills = createBuiltinSkills({ browserProvider }).filter((skill2) => {
77501
- if (disabledSkills.has(skill2.name))
77502
- return false;
77653
+ const builtinSkills = createBuiltinSkills({ browserProvider, disabledSkills }).filter((skill2) => {
77503
77654
  if (skill2.mcpConfig) {
77504
77655
  for (const mcpName of Object.keys(skill2.mcpConfig)) {
77505
77656
  if (systemMcpNames.has(mcpName))
@@ -77522,7 +77673,8 @@ var OhMyOpenCodePlugin = async (ctx) => {
77522
77673
  skills: mergedSkills,
77523
77674
  mcpManager: skillMcpManager,
77524
77675
  getSessionID: getSessionIDForMcp,
77525
- gitMasterConfig: pluginConfig.git_master
77676
+ gitMasterConfig: pluginConfig.git_master,
77677
+ disabledSkills
77526
77678
  });
77527
77679
  const skillMcpTool = createSkillMcpTool({
77528
77680
  manager: skillMcpManager,
@@ -1,3 +1,4 @@
1
+ import type { OhMyOpenCodeConfig } from "../config/schema";
1
2
  export { McpNameSchema, type McpName } from "./types";
2
3
  type RemoteMcpConfig = {
3
4
  type: "remote";
@@ -6,4 +7,4 @@ type RemoteMcpConfig = {
6
7
  headers?: Record<string, string>;
7
8
  oauth?: false;
8
9
  };
9
- export declare function createBuiltinMcps(disabledMcps?: string[]): Record<string, RemoteMcpConfig>;
10
+ export declare function createBuiltinMcps(disabledMcps?: string[], config?: OhMyOpenCodeConfig): Record<string, RemoteMcpConfig>;
@@ -1,9 +1,11 @@
1
- export declare const websearch: {
1
+ import type { WebsearchConfig } from "../config/schema";
2
+ type RemoteMcpConfig = {
2
3
  type: "remote";
3
4
  url: string;
4
5
  enabled: boolean;
5
- headers: {
6
- "x-api-key": string;
7
- } | undefined;
8
- oauth: false;
6
+ headers?: Record<string, string>;
7
+ oauth?: false;
9
8
  };
9
+ export declare function createWebsearchConfig(config?: WebsearchConfig): RemoteMcpConfig;
10
+ export declare const websearch: RemoteMcpConfig;
11
+ export {};
@@ -34,3 +34,4 @@ export * from "./connected-providers-cache";
34
34
  export * from "./session-utils";
35
35
  export * from "./tmux";
36
36
  export * from "./model-suggestion-retry";
37
+ export * from "./opencode-server-auth";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Builds HTTP Basic Auth header from environment variables.
3
+ *
4
+ * @returns Basic Auth header string, or undefined if OPENCODE_SERVER_PASSWORD is not set
5
+ */
6
+ export declare function getServerBasicAuthHeader(): string | undefined;
7
+ /**
8
+ * Injects HTTP Basic Auth header into the OpenCode SDK client.
9
+ *
10
+ * This function accesses the SDK's internal `_client.setConfig()` method.
11
+ * While `_client` has an underscore prefix (suggesting internal use), this is actually
12
+ * a stable public API from `@hey-api/openapi-ts` generated client:
13
+ * - `setConfig()` MERGES headers (does not replace existing ones)
14
+ * - This is the documented way to update client config at runtime
15
+ *
16
+ * @see https://github.com/sst/opencode/blob/main/packages/sdk/js/src/gen/client/client.gen.ts
17
+ * @throws {Error} If OPENCODE_SERVER_PASSWORD is set but client structure is incompatible
18
+ */
19
+ export declare function injectServerAuthIntoClient(client: unknown): void;
@@ -29,6 +29,7 @@ export interface ParentContext {
29
29
  export declare function resolveSkillContent(skills: string[], options: {
30
30
  gitMasterConfig?: GitMasterConfig;
31
31
  browserProvider?: BrowserAutomationProvider;
32
+ disabledSkills?: Set<string>;
32
33
  }): Promise<{
33
34
  content: string | undefined;
34
35
  error: string | null;
@@ -39,6 +39,7 @@ export interface DelegateTaskToolOptions {
39
39
  gitMasterConfig?: GitMasterConfig;
40
40
  sisyphusJuniorModel?: string;
41
41
  browserProvider?: BrowserAutomationProvider;
42
+ disabledSkills?: Set<string>;
42
43
  onSyncSessionCreated?: (event: SyncSessionCreatedEvent) => Promise<void>;
43
44
  }
44
45
  export interface BuildSystemContentInput {
@@ -24,6 +24,8 @@ export declare class LSPClient {
24
24
  private proc;
25
25
  private connection;
26
26
  private openedFiles;
27
+ private documentVersions;
28
+ private lastSyncedText;
27
29
  private stderrBuffer;
28
30
  private processExited;
29
31
  private diagnosticsStore;
@@ -25,4 +25,5 @@ export interface SkillLoadOptions {
25
25
  getSessionID?: () => string;
26
26
  /** Git master configuration for watermark/co-author settings */
27
27
  gitMasterConfig?: GitMasterConfig;
28
+ disabledSkills?: Set<string>;
28
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -74,13 +74,13 @@
74
74
  "typescript": "^5.7.3"
75
75
  },
76
76
  "optionalDependencies": {
77
- "oh-my-opencode-darwin-arm64": "3.2.2",
78
- "oh-my-opencode-darwin-x64": "3.2.2",
79
- "oh-my-opencode-linux-arm64": "3.2.2",
80
- "oh-my-opencode-linux-arm64-musl": "3.2.2",
81
- "oh-my-opencode-linux-x64": "3.2.2",
82
- "oh-my-opencode-linux-x64-musl": "3.2.2",
83
- "oh-my-opencode-windows-x64": "3.2.2"
77
+ "oh-my-opencode-darwin-arm64": "3.2.3",
78
+ "oh-my-opencode-darwin-x64": "3.2.3",
79
+ "oh-my-opencode-linux-arm64": "3.2.3",
80
+ "oh-my-opencode-linux-arm64-musl": "3.2.3",
81
+ "oh-my-opencode-linux-x64": "3.2.3",
82
+ "oh-my-opencode-linux-x64-musl": "3.2.3",
83
+ "oh-my-opencode-windows-x64": "3.2.3"
84
84
  },
85
85
  "trustedDependencies": [
86
86
  "@ast-grep/cli",