refactor: migrate selected runtime schemas to Effect Schema#268
refactor: migrate selected runtime schemas to Effect Schema#268Astro-Han wants to merge 3 commits into
Conversation
Pure mechanical rename of the workspace package. packages/shared is moved to packages/core; all consumers update imports from @opencode-ai/shared/* to @opencode-ai/core/*. No file content changes beyond the package rename. PawWork-local consumers (packages/util, packages/ui, packages/opencode, packages/desktop-electron runtime-import-guard test) updated. This is the first half of upstream's "shared → core" refactor; the follow-up commits that move modules (Global, log, flag, cross-spawn, npm) into core land in a separate PR (#209 PR2). Refs: #209
Pulls upstream PR follow-ups to the shared→core rename: - 1a734adb4d core: consolidate shared infrastructure into core package - 705f792e87 core: move Global module to @opencode-ai/core - 3eee2f6afa core: move cross-spawn-spawner from opencode to core - 1e98167b0e core: move cross-spawn-spawner to root and remove unused types - f5dce6d960 core: move npm service to core package Also pulls the npm-config snapshot from upstream HEAD (Stage C of #209 intake plan): packages/core/src/npm.ts, npm-config.ts, npm-config.test.ts. The pre-existing packages/opencode/test/npm.test.ts is removed. PawWork carve-outs: - packages/core/src/global.ts uses Runtime.appName() instead of hardcoded "opencode" so the pawwork-namespace data dir is preserved. - packages/opencode/src/global/index.ts is kept as PawWork's local Runtime-aware Global module; upstream's auto-rewritten @opencode-ai/core/global imports flow through to the carve-out. - packages/core/src/effect/logger.ts uses PawWork's namespace-style Log API (Log.create / Log.Default / Log.init) rather than upstream HEAD's flat-export style. PawWork callers expect the namespace shape. Mechanical cleanup: - packages/opencode/src/installation/meta.ts is removed; callers use @opencode-ai/core/installation/version (InstallationVersion / InstallationChannel) directly. - All ../util/log, ../flag/flag, @/effect/* and similar local imports rewritten to @opencode-ai/core/* equivalents (~120 files). - @effect/opentelemetry catalog entry added to root package.json (4.0.0-beta.46, matching the rest of the effect ecosystem). Verified: typecheck clean across packages/{core, opencode, util, ui, desktop-electron}. Refs: #209
Squashes upstream PRs #23716, #23740, #23744, #23745, #23747, #23749,
#23752, #23754, #23756, #23757, #23763, #24005, #24040, #24169, #24213
into a single PawWork commit. Ranges over 16 upstream commits in
date order from upstream's Effect Schema migration batch.
What landed:
- Config.Info, ConfigPermission.Info, ConfigAgent.Info schema definitions
migrated to Effect Schema canonical form. PawWork callers use
Config.Info.zod accessor where Hono validators or Zod-style decoders
are still needed.
- Schema definition files in control-plane, permission, project, pty,
question, sync, tool, session migrated to Effect Schema.
- packages/opencode/src/util/effect-zod.ts walker enhanced to derive
.zod from Effect Schema at runtime, plus tests.
- packages/sdk/js/v2/gen/types.gen.ts regenerated to reflect schema
shape changes.
What was preserved (PawWork divergence kept on Zod / namespace API):
- packages/opencode/src/session/{session,message-v2,prompt,export,message,revert,summary,todo,status,compaction,projectors}.ts
— PawWork's session domain stays Zod-shaped to keep MessageV2
PawWork-only types (FileSource/SymbolSource/ResourceSource carry
PawWork attachment metadata) compatible with current callers.
- packages/opencode/src/bus/bus-event.ts — PawWork keeps Zod-typed
BusEvent.define so the 30+ PawWork test fixtures and divergent
consumers (server/instance/*, acp/agent.ts, file/watcher.ts) keep
reading evt.properties as their schema's inferred type rather than
unknown.
- packages/opencode/src/{snapshot,permission,mcp,provider}/index.ts —
these modules use a PawWork "namespace + XValue alias" pattern that
upstream redesigned. Keeping HEAD here preserves Snapshot.track,
Permission.ask, Mcp.add, Provider.list etc. for PawWork callers.
- packages/opencode/src/provider/* — PawWork's volcengine/zen
integration carries divergent code paths (VOLCENGINE_PLAN constants,
HTTP-Referer/X-Title carve-out per project_rename_blockers.md).
- packages/opencode/src/{file,project,pty,sync,ide,lsp/client,command,
control-plane/workspace,worktree,question,util/schema}/{index,*}.ts
— kept PawWork API surface for callers.
Skipped commits in this range (no PawWork-applicable change after
carve-outs): 93940a1859 (provider domain) — provider.ts is a PawWork
permanent carve-out; the migration is reapplied to PawWork's local
provider only when divergence settles.
Verified: typecheck clean across packages/{core, opencode, util, ui,
desktop-electron}.
Refs: #209
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request migrates configuration and identifier schemas to use Effect Schema as the source of truth, deriving Zod schemas for compatibility. It removes the ZodPreprocess utility and the __originalKeys hack in favor of native Effect transformations. Feedback was provided regarding the isZodType utility, which incorrectly checks for a non-standard _zod property instead of using instanceof z.ZodType.
| function isZodType(value: unknown): value is z.ZodTypeAny { | ||
| return typeof value === "object" && value !== null && "_zod" in value | ||
| } |
There was a problem hiding this comment.
The isZodType guard checks for a _zod property, which is not a standard property on Zod type instances (they typically use _def internally). This will cause zodObject to always fall back to walk(schema.ast), bypassing any hand-crafted or refined Zod schemas attached via .zod statics (such as the .strict() and .meta() calls in config.ts). Using instanceof z.ZodType is the standard approach and ensures compatibility with Zod v4 patterns, where refinements are common.
| function isZodType(value: unknown): value is z.ZodTypeAny { | |
| return typeof value === "object" && value !== null && "_zod" in value | |
| } | |
| function isZodType(value: unknown): value is z.ZodTypeAny { | |
| return value instanceof z.ZodType | |
| } |
References
- In Zod v4, it is a valid pattern to call .omit() on a schema after applying .refine(). This strips the refinement and returns a ZodObject.
- Adhere to established codebase conventions for error handling (e.g., using instanceof Error for same-process errors) to maintain consistency, rather than introducing new patterns like type guards.
6f1633f to
5e335cb
Compare
|
Superseded by #280 (rebased onto current dev — actual change is 24 files, the 225 here was inflated by PR1+PR2 merge-commit SHA mismatch). |
Summary
Squashes upstream's Effect Schema migration batch (16 PRs, dated Apr 21–24 2026) into one PawWork commit. Selectively adopts the schema-definition-layer changes while preserving PawWork's namespace-API and Zod-typed BusEvent layers where divergence is too deep.
Upstream PRs included: #23716, #23740, #23744, #23745, #23747, #23749, #23752, #23754, #23756, #23757, #23763, #24005, #24040, #24169, #24213
Why
Stage D of the foundation sync (#209). The schema-definition layer (Config.Info, ConfigPermission.Info, ConfigAgent.Info, several
*/schema.tsfiles,util/effect-zodwalker) is core runtime work — this PR adopts those. Per @yuhan: "Effect Schema is core runtime work."The consumer layer (session, bus, provider, snapshot, permission, mcp namespaces) has too much PawWork divergence to take upstream's redesign wholesale. Those stay on PawWork's existing Zod / namespace API; the schema layer changes still flow through via the
.zodaccessor pattern.What landed (24 files)
Config.Info.zod(server/instance/{config,global}.ts,script/schema.ts).control-plane,permission,project,pty,question,sync,tool/schema.ts,session/schema.ts,tool/edit.ts,tool/todo.ts.util/effect-zod.tswalker enhanced to derive.zodfrom Effect Schema at runtime, plus walker tests.packages/sdk/js/src/v2/gen/types.gen.tsregenerated to reflect schema shape changes (Stage I would've done this anyway).config.test.ts,permission/next.test.ts,compaction.test.ts,session.test.ts,effect-zod.test.ts).What was preserved (PawWork divergence)
session/{session,message-v2,prompt,export,message,revert,summary,todo,status,compaction,projectors}.ts— PawWork's session domain stays Zod-shaped. MessageV2'sFileSource/SymbolSource/ResourceSourcecarry PawWork-only attachment metadata that upstream's Effect Schema variants drop.bus/bus-event.ts— PawWork keeps Zod-typedBusEvent.define. ~30 PawWork tests + divergent consumers (server/instance/*,acp/agent.ts,file/watcher.ts) readevt.propertiesas inferred type, notunknown.{snapshot,permission,mcp,provider}/index.ts— PawWork uses a "namespace + XValue alias" pattern that upstream redesigned to flat exports. Keeping HEAD preservesSnapshot.track,Permission.ask,Mcp.add,Provider.list.provider/{provider,auth,models}.ts— PawWork's volcengine/zen integration carries divergent code paths (VOLCENGINE_PLAN_*constants, HTTP-Referer/X-Title carve-out perproject_rename_blockers.md).{file,project,pty,sync,ide,lsp/client,command,control-plane/workspace,worktree,question,util/schema}/{index,*}.ts— kept PawWork API surface for callers.Skipped commit: 93940a1859 (provider domain Effect Schema migration) — entire diff sat on PawWork carve-out files; reapplied through PawWork-local provider when divergence settles.
Related Issue
#209
How To Verify
All 5 packages typecheck clean.
Stacked on
Base is
claude/upstream-sync-209-pr2-moves(#266). Will auto-rebase todevafter #265 → #266 chain merges.Checklist
packages/sdk/js/v2/gen/types.gen.tsregenerated; no new depsdev(via stacked PR), Conventional Commits English title