Skip to content

Commit 22cb039

Browse files
authored
refactor(flags): migrate external skills flag (#27685)
1 parent 2d6bede commit 22cb039

5 files changed

Lines changed: 85 additions & 3 deletions

File tree

packages/core/src/flag/flag.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export const Flag = {
3030
OPENCODE_DISABLE_MOUSE: truthy("OPENCODE_DISABLE_MOUSE"),
3131
OPENCODE_DISABLE_CLAUDE_CODE,
3232
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT: OPENCODE_DISABLE_CLAUDE_CODE || truthy("OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"),
33-
OPENCODE_DISABLE_EXTERNAL_SKILLS: truthy("OPENCODE_DISABLE_EXTERNAL_SKILLS"),
3433
OPENCODE_FAKE_VCS: process.env["OPENCODE_FAKE_VCS"],
3534
OPENCODE_SERVER_PASSWORD: process.env["OPENCODE_SERVER_PASSWORD"],
3635
OPENCODE_SERVER_USERNAME: process.env["OPENCODE_SERVER_USERNAME"],

packages/opencode/src/effect/runtime-flags.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class Service extends ConfigService.Service<Service>()("@opencode/Runtime
1717
disableDefaultPlugins: bool("OPENCODE_DISABLE_DEFAULT_PLUGINS"),
1818
disableChannelDb: bool("OPENCODE_DISABLE_CHANNEL_DB"),
1919
disableEmbeddedWebUi: bool("OPENCODE_DISABLE_EMBEDDED_WEB_UI"),
20+
disableExternalSkills: bool("OPENCODE_DISABLE_EXTERNAL_SKILLS"),
2021
disableClaudeCodeSkills: Config.all({
2122
broad: bool("OPENCODE_DISABLE_CLAUDE_CODE"),
2223
direct: bool("OPENCODE_DISABLE_CLAUDE_CODE_SKILLS"),

packages/opencode/src/skill/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { NamedError } from "@opencode-ai/core/util/error"
55
import type { Agent } from "@/agent/agent"
66
import { Bus } from "@/bus"
77
import { InstanceState } from "@/effect/instance-state"
8-
import { Flag } from "@opencode-ai/core/flag/flag"
98
import { Global } from "@opencode-ai/core/global"
109
import { Permission } from "@/permission"
1110
import { AppFileSystem } from "@opencode-ai/core/filesystem"
@@ -166,14 +165,15 @@ const discoverSkills = Effect.fnUntraced(function* (
166165
discovery: Discovery.Interface,
167166
fsys: AppFileSystem.Interface,
168167
global: Global.Interface,
168+
disableExternalSkills: boolean,
169169
disableClaudeCodeSkills: boolean,
170170
directory: string,
171171
worktree: string,
172172
) {
173173
const state: ScanState = { matches: new Set(), dirs: new Set() }
174174

175175
const externalDirs: string[] = []
176-
if (!Flag.OPENCODE_DISABLE_EXTERNAL_SKILLS) {
176+
if (!disableExternalSkills) {
177177
if (!disableClaudeCodeSkills) externalDirs.push(CLAUDE_EXTERNAL_DIR)
178178
externalDirs.push(AGENTS_EXTERNAL_DIR)
179179

@@ -249,6 +249,7 @@ export const layer = Layer.effect(
249249
discovery,
250250
fsys,
251251
global,
252+
flags.disableExternalSkills,
252253
flags.disableClaudeCodeSkills,
253254
ctx.directory,
254255
ctx.worktree,

packages/opencode/test/effect/runtime-flags.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe("RuntimeFlags", () => {
2727
OPENCODE_DISABLE_CHANNEL_DB: "true",
2828
OPENCODE_AUTO_SHARE: "true",
2929
OPENCODE_DISABLE_EMBEDDED_WEB_UI: "true",
30+
OPENCODE_DISABLE_EXTERNAL_SKILLS: "true",
3031
OPENCODE_EXPERIMENTAL: "true",
3132
OPENCODE_ENABLE_EXA: "true",
3233
OPENCODE_ENABLE_PARALLEL: "true",
@@ -42,6 +43,7 @@ describe("RuntimeFlags", () => {
4243
expect(flags.disableDefaultPlugins).toBe(true)
4344
expect(flags.disableChannelDb).toBe(true)
4445
expect(flags.disableEmbeddedWebUi).toBe(true)
46+
expect(flags.disableExternalSkills).toBe(true)
4547
expect(flags.enableExa).toBe(true)
4648
expect(flags.enableParallel).toBe(true)
4749
expect(flags.enableExperimentalModels).toBe(true)
@@ -84,6 +86,7 @@ describe("RuntimeFlags", () => {
8486
expect(flags.disableDefaultPlugins).toBe(true)
8587
expect(flags.disableChannelDb).toBe(false)
8688
expect(flags.disableEmbeddedWebUi).toBe(false)
89+
expect(flags.disableExternalSkills).toBe(false)
8790
expect(flags.disableClaudeCodeSkills).toBe(false)
8891
expect(flags.enableExa).toBe(false)
8992
expect(flags.experimentalIconDiscovery).toBe(false)
@@ -103,6 +106,22 @@ describe("RuntimeFlags", () => {
103106
}),
104107
)
105108

109+
it.effect("disableExternalSkills defaults to false", () =>
110+
Effect.gen(function* () {
111+
const flags = yield* readFlags.pipe(Effect.provide(fromConfig({})))
112+
113+
expect(flags.disableExternalSkills).toBe(false)
114+
}),
115+
)
116+
117+
it.effect("disableExternalSkills reads OPENCODE_DISABLE_EXTERNAL_SKILLS", () =>
118+
Effect.gen(function* () {
119+
const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_DISABLE_EXTERNAL_SKILLS: "true" })))
120+
121+
expect(flags.disableExternalSkills).toBe(true)
122+
}),
123+
)
124+
106125
it.effect("experimentalIconDiscovery reads OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", () =>
107126
Effect.gen(function* () {
108127
const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_EXPERIMENTAL_ICON_DISCOVERY: "true" })))
@@ -222,6 +241,7 @@ describe("RuntimeFlags", () => {
222241
ConfigProvider.fromUnknown({
223242
OPENCODE_PURE: "true",
224243
OPENCODE_DISABLE_DEFAULT_PLUGINS: "true",
244+
OPENCODE_DISABLE_EXTERNAL_SKILLS: "true",
225245
OPENCODE_EXPERIMENTAL: "true",
226246
OPENCODE_ENABLE_EXA: "true",
227247
OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1234",
@@ -235,6 +255,7 @@ describe("RuntimeFlags", () => {
235255
expect(flags.disableDefaultPlugins).toBe(false)
236256
expect(flags.disableChannelDb).toBe(false)
237257
expect(flags.disableEmbeddedWebUi).toBe(false)
258+
expect(flags.disableExternalSkills).toBe(false)
238259
expect(flags.disableClaudeCodeSkills).toBe(false)
239260
expect(flags.enableExa).toBe(false)
240261
expect(flags.experimentalIconDiscovery).toBe(false)

packages/opencode/test/skill/skill.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ const itWithoutClaudeCodeSkills = testEffect(
2929
node,
3030
),
3131
)
32+
const itWithoutExternalSkills = testEffect(
33+
Layer.mergeAll(
34+
Skill.layer.pipe(
35+
Layer.provide(Discovery.defaultLayer),
36+
Layer.provide(Config.defaultLayer),
37+
Layer.provide(Bus.layer),
38+
Layer.provide(AppFileSystem.defaultLayer),
39+
Layer.provide(Global.layer),
40+
Layer.provide(RuntimeFlags.layer({ disableExternalSkills: true })),
41+
),
42+
node,
43+
),
44+
)
3245

3346
async function createGlobalSkill(homeDir: string) {
3447
const skillDir = path.join(homeDir, ".claude", "skills", "global-test-skill")
@@ -420,6 +433,53 @@ description: A skill in the .agents/skills directory.
420433
),
421434
)
422435

436+
itWithoutExternalSkills.live("skips external skill directories when disabled", () =>
437+
provideTmpdirInstance(
438+
(dir) =>
439+
Effect.gen(function* () {
440+
yield* Effect.promise(() =>
441+
Promise.all([
442+
Bun.write(
443+
path.join(dir, ".claude", "skills", "claude-skill", "SKILL.md"),
444+
`---
445+
name: claude-skill
446+
description: A skill in the .claude/skills directory.
447+
---
448+
449+
# Claude Skill
450+
`,
451+
),
452+
Bun.write(
453+
path.join(dir, ".agents", "skills", "agent-skill", "SKILL.md"),
454+
`---
455+
name: agent-skill
456+
description: A skill in the .agents/skills directory.
457+
---
458+
459+
# Agent Skill
460+
`,
461+
),
462+
Bun.write(
463+
path.join(dir, ".opencode", "skill", "opencode-skill", "SKILL.md"),
464+
`---
465+
name: opencode-skill
466+
description: A skill in the .opencode/skill directory.
467+
---
468+
469+
# OpenCode Skill
470+
`,
471+
),
472+
]),
473+
)
474+
475+
const skill = yield* Skill.Service
476+
const list = (yield* skill.all()).filter((s) => s.location !== "<built-in>")
477+
expect(list.map((s) => s.name)).toEqual(["opencode-skill"])
478+
}),
479+
{ git: true },
480+
),
481+
)
482+
423483
it.live("properly resolves directories that skills live in", () =>
424484
provideTmpdirInstance(
425485
(dir) =>

0 commit comments

Comments
 (0)