runtime-flags.test.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import { describe, expect } from "bun:test"
  2. import { ConfigProvider, Effect, Layer } from "effect"
  3. import { RuntimeFlags } from "../../src/effect/runtime-flags"
  4. import { it } from "../lib/effect"
  5. const fromConfig = (input: Record<string, unknown>) =>
  6. RuntimeFlags.defaultLayer.pipe(Layer.provide(ConfigProvider.layer(ConfigProvider.fromUnknown(input))))
  7. const readFlags = RuntimeFlags.Service.useSync((flags) => flags)
  8. describe("RuntimeFlags", () => {
  9. it.effect("defaultLayer parses plugin flags from the active ConfigProvider", () =>
  10. Effect.gen(function* () {
  11. const flags = yield* readFlags.pipe(
  12. Effect.provide(
  13. fromConfig({
  14. OPENCODE_PURE: "true",
  15. OPENCODE_DISABLE_DEFAULT_PLUGINS: "true",
  16. OPENCODE_EXPERIMENTAL: "true",
  17. OPENCODE_ENABLE_EXA: "true",
  18. OPENCODE_ENABLE_PARALLEL: "true",
  19. OPENCODE_ENABLE_EXPERIMENTAL_MODELS: "true",
  20. OPENCODE_ENABLE_QUESTION_TOOL: "true",
  21. OPENCODE_CLIENT: "desktop",
  22. }),
  23. ),
  24. )
  25. expect(flags.pure).toBe(true)
  26. expect(flags.disableDefaultPlugins).toBe(true)
  27. expect(flags.enableExa).toBe(true)
  28. expect(flags.enableParallel).toBe(true)
  29. expect(flags.enableExperimentalModels).toBe(true)
  30. expect(flags.enableQuestionTool).toBe(true)
  31. expect(flags.experimentalScout).toBe(true)
  32. expect(flags.experimentalBackgroundSubagents).toBe(true)
  33. expect(flags.experimentalLspTy).toBe(false)
  34. expect(flags.experimentalLspTool).toBe(true)
  35. expect(flags.experimentalOxfmt).toBe(true)
  36. expect(flags.experimentalPlanMode).toBe(true)
  37. expect(flags.experimentalEventSystem).toBe(true)
  38. expect(flags.experimentalWorkspaces).toBe(true)
  39. expect(flags.experimentalIconDiscovery).toBe(true)
  40. expect(flags.client).toBe("desktop")
  41. }),
  42. )
  43. it.effect("defaultLayer parses OPENCODE_EXPERIMENTAL_LSP_TY", () =>
  44. Effect.gen(function* () {
  45. const flags = yield* readFlags.pipe(
  46. Effect.provide(
  47. fromConfig({
  48. OPENCODE_EXPERIMENTAL_LSP_TY: "true",
  49. }),
  50. ),
  51. )
  52. expect(flags.experimentalLspTy).toBe(true)
  53. }),
  54. )
  55. it.effect("layer accepts partial test overrides and fills defaults from Config definitions", () =>
  56. Effect.gen(function* () {
  57. const flags = yield* readFlags.pipe(
  58. Effect.provide(RuntimeFlags.layer({ disableDefaultPlugins: true, bashDefaultTimeoutMs: 1_000 })),
  59. )
  60. expect(flags.pure).toBe(false)
  61. expect(flags.disableDefaultPlugins).toBe(true)
  62. expect(flags.disableClaudeCodeSkills).toBe(false)
  63. expect(flags.enableExa).toBe(false)
  64. expect(flags.experimentalIconDiscovery).toBe(false)
  65. expect(flags.experimentalOxfmt).toBe(false)
  66. expect(flags.bashDefaultTimeoutMs).toBe(1_000)
  67. expect(flags.enableExperimentalModels).toBe(false)
  68. expect(flags.client).toBe("cli")
  69. }),
  70. )
  71. it.effect("experimentalIconDiscovery defaults to false", () =>
  72. Effect.gen(function* () {
  73. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({})))
  74. expect(flags.experimentalIconDiscovery).toBe(false)
  75. }),
  76. )
  77. it.effect("experimentalIconDiscovery reads OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", () =>
  78. Effect.gen(function* () {
  79. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_EXPERIMENTAL_ICON_DISCOVERY: "true" })))
  80. expect(flags.experimentalIconDiscovery).toBe(true)
  81. }),
  82. )
  83. it.effect("experimentalIconDiscovery inherits OPENCODE_EXPERIMENTAL", () =>
  84. Effect.gen(function* () {
  85. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_EXPERIMENTAL: "true" })))
  86. expect(flags.experimentalIconDiscovery).toBe(true)
  87. }),
  88. )
  89. it.effect("experimentalOxfmt defaults to false", () =>
  90. Effect.gen(function* () {
  91. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({})))
  92. expect(flags.experimentalOxfmt).toBe(false)
  93. }),
  94. )
  95. it.effect("experimentalOxfmt is enabled by OPENCODE_EXPERIMENTAL_OXFMT", () =>
  96. Effect.gen(function* () {
  97. const flags = yield* readFlags.pipe(
  98. Effect.provide(
  99. fromConfig({
  100. OPENCODE_EXPERIMENTAL_OXFMT: "true",
  101. }),
  102. ),
  103. )
  104. expect(flags.experimentalOxfmt).toBe(true)
  105. }),
  106. )
  107. it.effect("experimentalOxfmt inherits OPENCODE_EXPERIMENTAL", () =>
  108. Effect.gen(function* () {
  109. const flags = yield* readFlags.pipe(
  110. Effect.provide(
  111. fromConfig({
  112. OPENCODE_EXPERIMENTAL: "true",
  113. }),
  114. ),
  115. )
  116. expect(flags.experimentalOxfmt).toBe(true)
  117. }),
  118. )
  119. for (const input of [
  120. { name: "absent", config: {}, expected: undefined },
  121. {
  122. name: "valid positive integer",
  123. config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1234" },
  124. expected: 1234,
  125. },
  126. {
  127. name: "invalid string",
  128. config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "nope" },
  129. expected: undefined,
  130. },
  131. { name: "zero", config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "0" }, expected: undefined },
  132. { name: "negative", config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "-1" }, expected: undefined },
  133. {
  134. name: "non-integer",
  135. config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1.5" },
  136. expected: undefined,
  137. },
  138. ]) {
  139. it.effect(`parses bashDefaultTimeoutMs from config: ${input.name}`, () =>
  140. Effect.gen(function* () {
  141. const flags = yield* readFlags.pipe(Effect.provide(fromConfig(input.config)))
  142. expect(flags.bashDefaultTimeoutMs).toBe(input.expected)
  143. }),
  144. )
  145. }
  146. it.effect("layer ignores the active ConfigProvider for omitted test overrides", () =>
  147. Effect.gen(function* () {
  148. const flags = yield* readFlags.pipe(
  149. Effect.provide(RuntimeFlags.layer()),
  150. Effect.provide(
  151. ConfigProvider.layer(
  152. ConfigProvider.fromUnknown({
  153. OPENCODE_PURE: "true",
  154. OPENCODE_DISABLE_DEFAULT_PLUGINS: "true",
  155. OPENCODE_EXPERIMENTAL: "true",
  156. OPENCODE_ENABLE_EXA: "true",
  157. OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1234",
  158. OPENCODE_CLIENT: "desktop",
  159. }),
  160. ),
  161. ),
  162. )
  163. expect(flags.pure).toBe(false)
  164. expect(flags.disableDefaultPlugins).toBe(false)
  165. expect(flags.disableClaudeCodeSkills).toBe(false)
  166. expect(flags.enableExa).toBe(false)
  167. expect(flags.experimentalIconDiscovery).toBe(false)
  168. expect(flags.experimentalOxfmt).toBe(false)
  169. expect(flags.bashDefaultTimeoutMs).toBeUndefined()
  170. expect(flags.client).toBe("cli")
  171. }),
  172. )
  173. it.effect("disableClaudeCodeSkills defaults to false", () =>
  174. Effect.gen(function* () {
  175. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({})))
  176. expect(flags.disableClaudeCodeSkills).toBe(false)
  177. }),
  178. )
  179. it.effect("disableClaudeCodeSkills reads OPENCODE_DISABLE_CLAUDE_CODE_SKILLS", () =>
  180. Effect.gen(function* () {
  181. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_DISABLE_CLAUDE_CODE_SKILLS: "true" })))
  182. expect(flags.disableClaudeCodeSkills).toBe(true)
  183. }),
  184. )
  185. it.effect("disableClaudeCodeSkills inherits OPENCODE_DISABLE_CLAUDE_CODE", () =>
  186. Effect.gen(function* () {
  187. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_DISABLE_CLAUDE_CODE: "true" })))
  188. expect(flags.disableClaudeCodeSkills).toBe(true)
  189. }),
  190. )
  191. })