Skip to content

feat(core): expose config changes stream - #39131

Merged
kitlangton merged 1 commit into
v2from
config-changes
Jul 27, 2026
Merged

kitlangton merged 1 commit into
v2from
config-changes

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

What

Adds config.changes() to the Config service: a stream of raw filesystem updates under config roots. This is the seam that lets domain owners (commands, agents, plugins) observe edits to the source files they parse — without overloading config.updated, which stays reserved for structured config and topology changes.

Second slice of the config source reload series, after #38983 (read-barrier event ordering). Design doc: docs/design/config-source-reload.md on the config-source-reload branch.

How

Config already owns everything this needs: reconcileWatches keeps deduplicated recursive subscriptions aligned with entries, and every Watcher.Update under every root already funnels into one internal PubSub (packages/core/src/config.ts). This PR exposes that existing feed:

readonly changes: () => Stream.Stream<Watcher.Update>

implemented as Stream.fromPubSub(updates) — one line of runtime code. Because Config reconciles watches on reload, subscribers also receive updates from roots added later, without resubscribing.

Consumers will compose filtering and debounce at the call site:

config.changes().pipe(
  Stream.filter(isCommandPath),
  Stream.debounce("100 millis"),
  Stream.runForEach(() => command.reload()),
)

The remaining diff is mechanical: 24 Config.Service.of test stubs across 16 files gain changes: () => Stream.empty.

Scope

Deliberately not here, coming as follow-up PRs:

Testing

  • New test: Config > exposes filesystem updates under config roots through changes — written red first (config.changes is not a function), green after.
  • bun test over all 13 touched test files: 102 pass, 0 fail.
  • bun typecheck in packages/core: clean.
  • test/session-runner.test.ts fails identically (24) with and without this change — the pre-existing Unbound layer node: @opencode/Location set from the tool consolidation refactor, unrelated to this PR.

@kitlangton

Copy link
Copy Markdown
Contributor Author

Unit failures are the pre-existing v2 base set (Unbound layer node: @opencode/Location from the tool consolidation refactor, plus the pre-existing PluginSupervisor auto-discovered reload failure) — verified identical on clean base. Typecheck and both e2e jobs green.

@kitlangton
kitlangton merged commit 02c37c4 into v2 Jul 27, 2026
6 of 8 checks passed
@kitlangton
kitlangton deleted the config-changes branch July 27, 2026 17:38
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant