runtime-flags.test.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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.experimentalLspTool).toBe(true)
  34. expect(flags.experimentalPlanMode).toBe(true)
  35. expect(flags.experimentalEventSystem).toBe(true)
  36. expect(flags.experimentalWorkspaces).toBe(true)
  37. expect(flags.client).toBe("desktop")
  38. }),
  39. )
  40. it.effect("layer accepts partial test overrides and fills defaults from Config definitions", () =>
  41. Effect.gen(function* () {
  42. const flags = yield* readFlags.pipe(
  43. Effect.provide(RuntimeFlags.layer({ disableDefaultPlugins: true, bashDefaultTimeoutMs: 1_000 })),
  44. )
  45. expect(flags.pure).toBe(false)
  46. expect(flags.disableDefaultPlugins).toBe(true)
  47. expect(flags.disableClaudeCodeSkills).toBe(false)
  48. expect(flags.enableExa).toBe(false)
  49. expect(flags.bashDefaultTimeoutMs).toBe(1_000)
  50. expect(flags.enableExperimentalModels).toBe(false)
  51. expect(flags.client).toBe("cli")
  52. }),
  53. )
  54. for (const input of [
  55. { name: "absent", config: {}, expected: undefined },
  56. {
  57. name: "valid positive integer",
  58. config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1234" },
  59. expected: 1234,
  60. },
  61. {
  62. name: "invalid string",
  63. config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "nope" },
  64. expected: undefined,
  65. },
  66. { name: "zero", config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "0" }, expected: undefined },
  67. { name: "negative", config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "-1" }, expected: undefined },
  68. {
  69. name: "non-integer",
  70. config: { OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1.5" },
  71. expected: undefined,
  72. },
  73. ]) {
  74. it.effect(`parses bashDefaultTimeoutMs from config: ${input.name}`, () =>
  75. Effect.gen(function* () {
  76. const flags = yield* readFlags.pipe(Effect.provide(fromConfig(input.config)))
  77. expect(flags.bashDefaultTimeoutMs).toBe(input.expected)
  78. }),
  79. )
  80. }
  81. it.effect("layer ignores the active ConfigProvider for omitted test overrides", () =>
  82. Effect.gen(function* () {
  83. const flags = yield* readFlags.pipe(
  84. Effect.provide(RuntimeFlags.layer()),
  85. Effect.provide(
  86. ConfigProvider.layer(
  87. ConfigProvider.fromUnknown({
  88. OPENCODE_PURE: "true",
  89. OPENCODE_DISABLE_DEFAULT_PLUGINS: "true",
  90. OPENCODE_EXPERIMENTAL: "true",
  91. OPENCODE_ENABLE_EXA: "true",
  92. OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS: "1234",
  93. OPENCODE_CLIENT: "desktop",
  94. }),
  95. ),
  96. ),
  97. )
  98. expect(flags.pure).toBe(false)
  99. expect(flags.disableDefaultPlugins).toBe(false)
  100. expect(flags.disableClaudeCodeSkills).toBe(false)
  101. expect(flags.enableExa).toBe(false)
  102. expect(flags.bashDefaultTimeoutMs).toBeUndefined()
  103. expect(flags.client).toBe("cli")
  104. }),
  105. )
  106. it.effect("disableClaudeCodeSkills defaults to false", () =>
  107. Effect.gen(function* () {
  108. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({})))
  109. expect(flags.disableClaudeCodeSkills).toBe(false)
  110. }),
  111. )
  112. it.effect("disableClaudeCodeSkills reads OPENCODE_DISABLE_CLAUDE_CODE_SKILLS", () =>
  113. Effect.gen(function* () {
  114. const flags = yield* readFlags.pipe(
  115. Effect.provide(fromConfig({ OPENCODE_DISABLE_CLAUDE_CODE_SKILLS: "true" })),
  116. )
  117. expect(flags.disableClaudeCodeSkills).toBe(true)
  118. }),
  119. )
  120. it.effect("disableClaudeCodeSkills inherits OPENCODE_DISABLE_CLAUDE_CODE", () =>
  121. Effect.gen(function* () {
  122. const flags = yield* readFlags.pipe(Effect.provide(fromConfig({ OPENCODE_DISABLE_CLAUDE_CODE: "true" })))
  123. expect(flags.disableClaudeCodeSkills).toBe(true)
  124. }),
  125. )
  126. })