Reported by Ben Matthews on Discord against v1.14.45: a `skills:` field
shaped as an array (rather than the schema's `{paths?, urls?}` object)
caused the entire config load to fail with ConfigInvalidError, the
server returned 500, and the desktop app couldn't start.
Per Kit:
> for all of these things that we load from the user's computer, they
> should be kind of tolerant. We can have warnings that we log
> somewhere, but Jesus. It shouldn't break opencode.
This makes `ConfigParse.effectSchema` field-tolerant:
- Unknown top-level keys are stripped (with a warning log) instead of
throwing `unrecognized_keys`.
- Top-level fields whose value fails decoding are dropped (with a
warning log naming the field + the issue summary), the rest of the
config decodes normally.
- Root-level errors (e.g. data is not an object at all) and post-strip
failures still throw the original `InvalidError` so we don't silently
swallow truly broken configs.
Three new tests cover the reported shape (skills as array), unknown
keys, and multi-bad-field cases. Two existing tests that asserted the
strict-throw behavior were updated to the new tolerant contract.
Pre-fix: opencode unstartable for users with malformed configs.
Post-fix: opencode starts, the bad field is ignored, the user sees a
warning in the log naming what was dropped.
The cross-spawn-spawner module has been moved from src/effect/ to src/
to simplify the core package structure. The src/types.d.ts file which
contained unused type declarations has also been removed. All imports
throughout the codebase have been updated to reflect the new location.
This change reduces the package's internal complexity by flattening the
module hierarchy and removing dead code, making future maintenance easier.
Moved the cross-spawn-spawner module from packages/opencode to packages/core
to enable code sharing across the monorepo. This consolidates the process
spawning infrastructure into the core package so other packages can use
cross-platform child process spawning without duplicating the implementation.
Updated all import statements across the codebase to reference the new
location (@opencode-ai/core/effect/cross-spawn-spawner). Removed the
local copy from the opencode package along with its tests.
Move the Global module from packages/opencode/src/global to packages/core/src/global
to provide a unified location for managing XDG directories and application paths.
This eliminates duplicate path definitions across packages and ensures consistent
access to data, config, cache, state, log, and bin directories throughout the codebase.
Extract error handling, parsing logic, and variable substitution into dedicated
modules. This reduces duplication between tui.json and opencode.json parsing
and makes the config system easier to extend for future config formats.
Fixes potential plugin resolution issues when switching between projects by wrapping
plugin loading in Instance.provide(). This ensures each plugin resolves dependencies
relative to its correct project directory instead of inheriting context from whatever
instance happened to be active.
Also reorganizes config loading code into focused modules (command.ts, managed.ts,
plugin.ts) to make the codebase easier to maintain and test.