Skip to content

Commit cccdeef

Browse files
authored
refactor(flags): migrate claude code skills flag to RuntimeFlags (anomalyco#27605)
1 parent 83c145f commit cccdeef

5 files changed

Lines changed: 102 additions & 5 deletions

File tree

packages/core/src/flag/flag.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ function number(key: string) {
1414

1515
const OPENCODE_EXPERIMENTAL = truthy("OPENCODE_EXPERIMENTAL")
1616
const OPENCODE_DISABLE_CLAUDE_CODE = truthy("OPENCODE_DISABLE_CLAUDE_CODE")
17-
const OPENCODE_DISABLE_CLAUDE_CODE_SKILLS =
18-
OPENCODE_DISABLE_CLAUDE_CODE || truthy("OPENCODE_DISABLE_CLAUDE_CODE_SKILLS")
1917
const copy = process.env["OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT"]
2018

2119
export const Flag = {
@@ -41,7 +39,6 @@ export const Flag = {
4139
OPENCODE_DISABLE_MOUSE: truthy("OPENCODE_DISABLE_MOUSE"),
4240
OPENCODE_DISABLE_CLAUDE_CODE,
4341
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT: OPENCODE_DISABLE_CLAUDE_CODE || truthy("OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"),
44-
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS,
4542
OPENCODE_DISABLE_EXTERNAL_SKILLS: truthy("OPENCODE_DISABLE_EXTERNAL_SKILLS"),
4643
OPENCODE_FAKE_VCS: process.env["OPENCODE_FAKE_VCS"],
4744
OPENCODE_SERVER_PASSWORD: process.env["OPENCODE_SERVER_PASSWORD"],

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ const enabledByExperimental = (name: string) =>
99
export class Service extends ConfigService.Service<Service>()("@opencode/RuntimeFlags", {
1010
pure: bool("OPENCODE_PURE"),
1111
disableDefaultPlugins: bool("OPENCODE_DISABLE_DEFAULT_PLUGINS"),
12+
disableClaudeCodeSkills: Config.all({
13+
broad: bool("OPENCODE_DISABLE_CLAUDE_CODE"),
14+
direct: bool("OPENCODE_DISABLE_CLAUDE_CODE_SKILLS"),
15+
}).pipe(Config.map((flags) => flags.broad || flags.direct)),
1216
enableExa: Config.all({
1317
experimental,
1418
enabled: bool("OPENCODE_ENABLE_EXA"),

packages/opencode/src/skill/index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Permission } from "@/permission"
1111
import { AppFileSystem } from "@opencode-ai/core/filesystem"
1212
import { Config } from "@/config/config"
1313
import { ConfigMarkdown } from "@/config/markdown"
14+
import { RuntimeFlags } from "@/effect/runtime-flags"
1415
import { Glob } from "@opencode-ai/core/util/glob"
1516
import * as Log from "@opencode-ai/core/util/log"
1617
import { Discovery } from "./discovery"
@@ -165,14 +166,15 @@ const discoverSkills = Effect.fnUntraced(function* (
165166
discovery: Discovery.Interface,
166167
fsys: AppFileSystem.Interface,
167168
global: Global.Interface,
169+
disableClaudeCodeSkills: boolean,
168170
directory: string,
169171
worktree: string,
170172
) {
171173
const state: ScanState = { matches: new Set(), dirs: new Set() }
172174

173175
const externalDirs: string[] = []
174176
if (!Flag.OPENCODE_DISABLE_EXTERNAL_SKILLS) {
175-
if (!Flag.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS) externalDirs.push(CLAUDE_EXTERNAL_DIR)
177+
if (!disableClaudeCodeSkills) externalDirs.push(CLAUDE_EXTERNAL_DIR)
176178
externalDirs.push(AGENTS_EXTERNAL_DIR)
177179

178180
for (const dir of externalDirs) {
@@ -239,9 +241,18 @@ export const layer = Layer.effect(
239241
const bus = yield* Bus.Service
240242
const fsys = yield* AppFileSystem.Service
241243
const global = yield* Global.Service
244+
const flags = yield* RuntimeFlags.Service
242245
const discovered = yield* InstanceState.make(
243246
Effect.fn("Skill.discovery")(function* (ctx) {
244-
return yield* discoverSkills(config, discovery, fsys, global, ctx.directory, ctx.worktree)
247+
return yield* discoverSkills(
248+
config,
249+
discovery,
250+
fsys,
251+
global,
252+
flags.disableClaudeCodeSkills,
253+
ctx.directory,
254+
ctx.worktree,
255+
)
245256
}),
246257
)
247258
const state = yield* InstanceState.make(
@@ -291,6 +302,7 @@ export const defaultLayer = layer.pipe(
291302
Layer.provide(Bus.layer),
292303
Layer.provide(AppFileSystem.defaultLayer),
293304
Layer.provide(Global.layer),
305+
Layer.provide(RuntimeFlags.defaultLayer),
294306
)
295307

296308
export function fmt(list: Info[], opts: { verbose: boolean }) {

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ describe("RuntimeFlags", () => {
4646

4747
expect(flags.pure).toBe(false)
4848
expect(flags.disableDefaultPlugins).toBe(true)
49+
expect(flags.disableClaudeCodeSkills).toBe(false)
4950
expect(flags.enableExa).toBe(false)
5051
expect(flags.client).toBe("cli")
5152
}),
@@ -70,8 +71,35 @@ describe("RuntimeFlags", () => {
7071

7172
expect(flags.pure).toBe(false)
7273
expect(flags.disableDefaultPlugins).toBe(false)
74+
expect(flags.disableClaudeCodeSkills).toBe(false)
7375
expect(flags.enableExa).toBe(false)
7476
expect(flags.client).toBe("cli")
7577
}),
7678
)
79+
80+
it.effect("disableClaudeCodeSkills defaults to false", () =>
81+
Effect.gen(function* () {
82+
const flags = yield* readFlags.pipe(Effect.provide(fromConfig({})))
83+
84+
expect(flags.disableClaudeCodeSkills).toBe(false)
85+
}),
86+
)
87+
88+
it.effect("disableClaudeCodeSkills reads OPENCODE_DISABLE_CLAUDE_CODE_SKILLS", () =>
89+
Effect.gen(function* () {
90+
const flags = yield* readFlags.pipe(
91+
Effect.provide(fromConfig({ OPENCODE_DISABLE_CLAUDE_CODE_SKILLS: "true" })),
92+
)
93+
94+
expect(flags.disableClaudeCodeSkills).toBe(true)
95+
}),
96+
)
97+
98+
it.effect("disableClaudeCodeSkills inherits OPENCODE_DISABLE_CLAUDE_CODE", () =>
99+
Effect.gen(function* () {
100+
const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_DISABLE_CLAUDE_CODE: "true" })))
101+
102+
expect(flags.disableClaudeCodeSkills).toBe(true)
103+
}),
104+
)
77105
})

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { describe, expect } from "bun:test"
22
import { Effect, Layer } from "effect"
33
import { Skill } from "../../src/skill"
4+
import { Discovery } from "../../src/skill/discovery"
5+
import { RuntimeFlags } from "../../src/effect/runtime-flags"
6+
import { Bus } from "../../src/bus"
7+
import { Config } from "../../src/config/config"
48
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
9+
import { AppFileSystem } from "@opencode-ai/core/filesystem"
10+
import { Global } from "@opencode-ai/core/global"
511
import { provideInstance, provideTmpdirInstance, tmpdir } from "../fixture/fixture"
612
import { testEffect } from "../lib/effect"
713
import path from "path"
@@ -10,6 +16,19 @@ import fs from "fs/promises"
1016
const node = CrossSpawnSpawner.defaultLayer
1117

1218
const it = testEffect(Layer.mergeAll(Skill.defaultLayer, node))
19+
const itWithoutClaudeCodeSkills = testEffect(
20+
Layer.mergeAll(
21+
Skill.layer.pipe(
22+
Layer.provide(Discovery.defaultLayer),
23+
Layer.provide(Config.defaultLayer),
24+
Layer.provide(Bus.layer),
25+
Layer.provide(AppFileSystem.defaultLayer),
26+
Layer.provide(Global.layer),
27+
Layer.provide(RuntimeFlags.layer({ disableClaudeCodeSkills: true })),
28+
),
29+
node,
30+
),
31+
)
1332

1433
async function createGlobalSkill(homeDir: string) {
1534
const skillDir = path.join(homeDir, ".claude", "skills", "global-test-skill")
@@ -364,6 +383,43 @@ description: A skill in the .agents/skills directory.
364383
),
365384
)
366385

386+
itWithoutClaudeCodeSkills.live("skips Claude Code skills when disabled", () =>
387+
provideTmpdirInstance(
388+
(dir) =>
389+
Effect.gen(function* () {
390+
yield* Effect.promise(() =>
391+
Promise.all([
392+
Bun.write(
393+
path.join(dir, ".claude", "skills", "claude-skill", "SKILL.md"),
394+
`---
395+
name: claude-skill
396+
description: A skill in the .claude/skills directory.
397+
---
398+
399+
# Claude Skill
400+
`,
401+
),
402+
Bun.write(
403+
path.join(dir, ".agents", "skills", "agent-skill", "SKILL.md"),
404+
`---
405+
name: agent-skill
406+
description: A skill in the .agents/skills directory.
407+
---
408+
409+
# Agent Skill
410+
`,
411+
),
412+
]),
413+
)
414+
415+
const skill = yield* Skill.Service
416+
const list = (yield* skill.all()).filter((s) => s.location !== "<built-in>")
417+
expect(list.map((s) => s.name)).toEqual(["agent-skill"])
418+
}),
419+
{ git: true },
420+
),
421+
)
422+
367423
it.live("properly resolves directories that skills live in", () =>
368424
provideTmpdirInstance(
369425
(dir) =>

0 commit comments

Comments
 (0)