11/// <reference types="bun-types" />
22
33import { afterEach , beforeEach , describe , expect , spyOn , test } from "bun:test" ;
4+ import type { OhMyOpenCodeConfig } from "../config" ;
45import * as builtinCommands from "../features/builtin-commands" ;
56import * as commandLoader from "../features/claude-code-command-loader" ;
67import * as skillLoader from "../features/opencode-skill-loader" ;
7- import type { OhMyOpenCodeConfig } from "../config" ;
8- import type { PluginComponents } from "./plugin-components-loader" ;
9- import { applyCommandConfig } from "./command-config-handler" ;
108import {
119 getAgentDisplayName ,
1210 getAgentListDisplayName ,
1311} from "../shared/agent-display-names" ;
12+ import { applyCommandConfig } from "./command-config-handler" ;
13+ import type { PluginComponents } from "./plugin-components-loader" ;
1414
1515function createPluginComponents ( ) : PluginComponents {
1616 return {
@@ -24,13 +24,14 @@ function createPluginComponents(): PluginComponents {
2424 } ;
2525}
2626
27- function createPluginConfig ( ) : OhMyOpenCodeConfig {
27+ function createPluginConfig ( overrides : Partial < OhMyOpenCodeConfig > = { } ) : OhMyOpenCodeConfig {
2828 return {
2929 git_master : {
3030 commit_footer : true ,
3131 include_co_authored_by : true ,
3232 git_env_prefix : "GIT_MASTER=1" ,
3333 } ,
34+ ...overrides ,
3435 } ;
3536}
3637
@@ -78,6 +79,156 @@ describe("applyCommandConfig", () => {
7879 loadGlobalAgentsSkillsSpy . mockRestore ( ) ;
7980 } ) ;
8081
82+ test ( "includes builtin skills in command config" , async ( ) => {
83+ // given
84+ const config : Record < string , unknown > = { command : { } } ;
85+
86+ // when
87+ await applyCommandConfig ( {
88+ config,
89+ pluginConfig : createPluginConfig ( ) ,
90+ ctx : { directory : "/tmp" } ,
91+ pluginComponents : createPluginComponents ( ) ,
92+ } ) ;
93+
94+ // then
95+ const commandConfig = config . command as Record < string , { description ?: string ; template ?: string } > ;
96+ expect ( commandConfig [ "init-deep" ] ?. description ) . toContain ( "hierarchical AGENTS.md" ) ;
97+ expect ( commandConfig [ "init-deep" ] ?. template ) . toContain ( "Generate hierarchical AGENTS.md files" ) ;
98+ } ) ;
99+
100+ test ( "excludes disabled builtin skills from command config" , async ( ) => {
101+ // given
102+ const config : Record < string , unknown > = { command : { } } ;
103+
104+ // when
105+ await applyCommandConfig ( {
106+ config,
107+ pluginConfig : createPluginConfig ( { disabled_skills : [ "init-deep" ] } ) ,
108+ ctx : { directory : "/tmp" } ,
109+ pluginComponents : createPluginComponents ( ) ,
110+ } ) ;
111+
112+ // then
113+ const commandConfig = config . command as Record < string , unknown > ;
114+ expect ( commandConfig [ "init-deep" ] ) . toBeUndefined ( ) ;
115+ } ) ;
116+
117+ test ( "keeps builtin command precedence over same-name builtin skills" , async ( ) => {
118+ // given
119+ loadBuiltinCommandsSpy . mockReturnValue ( {
120+ "remove-ai-slops" : {
121+ name : "remove-ai-slops" ,
122+ description : "Builtin command wins" ,
123+ template : "command template" ,
124+ } ,
125+ } ) ;
126+ const config : Record < string , unknown > = { command : { } } ;
127+
128+ // when
129+ await applyCommandConfig ( {
130+ config,
131+ pluginConfig : createPluginConfig ( ) ,
132+ ctx : { directory : "/tmp" } ,
133+ pluginComponents : createPluginComponents ( ) ,
134+ } ) ;
135+
136+ // then
137+ const commandConfig = config . command as Record < string , { description ?: string ; template ?: string } > ;
138+ expect ( commandConfig [ "remove-ai-slops" ] ?. description ) . toBe ( "Builtin command wins" ) ;
139+ expect ( commandConfig [ "remove-ai-slops" ] ?. template ) . toBe ( "command template" ) ;
140+ } ) ;
141+
142+ test ( "allows higher-precedence project skills to override builtin skill commands" , async ( ) => {
143+ // given
144+ loadProjectSkillsSpy . mockResolvedValue ( {
145+ "init-deep" : {
146+ description : "Project init-deep skill" ,
147+ template : "project template" ,
148+ } ,
149+ } ) ;
150+ const config : Record < string , unknown > = { command : { } } ;
151+
152+ // when
153+ await applyCommandConfig ( {
154+ config,
155+ pluginConfig : createPluginConfig ( ) ,
156+ ctx : { directory : "/tmp" } ,
157+ pluginComponents : createPluginComponents ( ) ,
158+ } ) ;
159+
160+ // then
161+ const commandConfig = config . command as Record < string , { description ?: string ; template ?: string } > ;
162+ expect ( commandConfig [ "init-deep" ] ?. description ) . toBe ( "Project init-deep skill" ) ;
163+ expect ( commandConfig [ "init-deep" ] ?. template ) . toBe ( "project template" ) ;
164+ } ) ;
165+
166+ test ( "uses browser provider gating for builtin skill commands" , async ( ) => {
167+ // given
168+ const defaultConfig : Record < string , unknown > = { command : { } } ;
169+ const agentBrowserConfig : Record < string , unknown > = { command : { } } ;
170+
171+ // when
172+ await applyCommandConfig ( {
173+ config : defaultConfig ,
174+ pluginConfig : createPluginConfig ( ) ,
175+ ctx : { directory : "/tmp" } ,
176+ pluginComponents : createPluginComponents ( ) ,
177+ } ) ;
178+ await applyCommandConfig ( {
179+ config : agentBrowserConfig ,
180+ pluginConfig : createPluginConfig ( { browser_automation_engine : { provider : "agent-browser" } } ) ,
181+ ctx : { directory : "/tmp" } ,
182+ pluginComponents : createPluginComponents ( ) ,
183+ } ) ;
184+
185+ // then
186+ const defaultCommands = defaultConfig . command as Record < string , unknown > ;
187+ const agentBrowserCommands = agentBrowserConfig . command as Record < string , unknown > ;
188+ expect ( defaultCommands . playwright ) . toBeDefined ( ) ;
189+ expect ( defaultCommands [ "agent-browser" ] ) . toBeUndefined ( ) ;
190+ expect ( agentBrowserCommands [ "agent-browser" ] ) . toBeDefined ( ) ;
191+ expect ( agentBrowserCommands . playwright ) . toBeUndefined ( ) ;
192+ } ) ;
193+
194+ test ( "uses team-mode gating for builtin skill commands" , async ( ) => {
195+ // given
196+ const defaultConfig : Record < string , unknown > = { command : { } } ;
197+ const teamModeConfig : Record < string , unknown > = { command : { } } ;
198+ const disabledTeamModeConfig : Record < string , unknown > = { command : { } } ;
199+
200+ // when
201+ await applyCommandConfig ( {
202+ config : defaultConfig ,
203+ pluginConfig : createPluginConfig ( ) ,
204+ ctx : { directory : "/tmp" } ,
205+ pluginComponents : createPluginComponents ( ) ,
206+ } ) ;
207+ await applyCommandConfig ( {
208+ config : teamModeConfig ,
209+ pluginConfig : createPluginConfig ( { team_mode : { enabled : true } } ) ,
210+ ctx : { directory : "/tmp" } ,
211+ pluginComponents : createPluginComponents ( ) ,
212+ } ) ;
213+ await applyCommandConfig ( {
214+ config : disabledTeamModeConfig ,
215+ pluginConfig : createPluginConfig ( {
216+ disabled_skills : [ "team-mode" ] ,
217+ team_mode : { enabled : true } ,
218+ } ) ,
219+ ctx : { directory : "/tmp" } ,
220+ pluginComponents : createPluginComponents ( ) ,
221+ } ) ;
222+
223+ // then
224+ const defaultCommands = defaultConfig . command as Record < string , unknown > ;
225+ const teamModeCommands = teamModeConfig . command as Record < string , unknown > ;
226+ const disabledTeamModeCommands = disabledTeamModeConfig . command as Record < string , unknown > ;
227+ expect ( defaultCommands [ "team-mode" ] ) . toBeUndefined ( ) ;
228+ expect ( teamModeCommands [ "team-mode" ] ) . toBeDefined ( ) ;
229+ expect ( disabledTeamModeCommands [ "team-mode" ] ) . toBeUndefined ( ) ;
230+ } ) ;
231+
81232 test ( "includes .agents skills in command config" , async ( ) => {
82233 // given
83234 loadProjectAgentsSkillsSpy . mockResolvedValue ( {
0 commit comments