Skip to content

refactor(7.1): consolidate 23 packages → 8 (the 7.x Phase 1)#2

Merged
codeweiz merged 9 commits into
mainfrom
feat/7.1-consolidation
Jun 3, 2026
Merged

refactor(7.1): consolidate 23 packages → 8 (the 7.x Phase 1)#2
codeweiz merged 9 commits into
mainfrom
feat/7.1-consolidation

Conversation

@codeweiz
Copy link
Copy Markdown
Owner

@codeweiz codeweiz commented Jun 3, 2026

Phase 1 of the 7.x program (docs/7.0-design.md / docs/tasks/01-consolidation-task.md). Zero runtime behavior change — the published @chances-ai/cli binary behaves identically; this is internal restructuring. Major version because the workspace package surface (names SDK consumers import) changed.

23 libraries → 7 (+ design-system reserved = 8 target)

client · engine · native · runtime · tui · ui-core · wire

Step Merge Commit
Phase 0 A3 bun.lock registry CI guard b482cef
S1 config+telemetry+telemetry-otel → runtime (./config/./telemetry/./otel) 09d9a49
S2 ink-ext → tui ce31687
S3 client-core+web-ui → client (. / ./react) 561929c
S4 rpc+serve → wire (./rpc / ./serve) d820c8b
S5 11 domain packages → engine (granular subpath exports, no . barrel) af2be79
S6 depcruise 8-tier rewrite + 2 new structural rules 54d656d
S7 changeset + publint/smoke-release finalize 9d71e50

How it stays honest

  • Granular subpath exports are the lazy-peer + tree-shake boundary; no . barrel on engine/wire (forces explicit subpath imports).
  • no-static-optional-peer depcruise rule structurally enforces the lazy optional-peer contract (mcp-sdk / vscode-jsonrpc / @napi-rs/keyring / acp-sdk / @opentelemetry/* loaded only via computed-specifier dynamic import).
  • no-deep-cross-package-src — apps import via package exports, never reach into src/.
  • browser-safe tier (ui-core/client/design-system) stays node-free + type-only on engine/wire (the LocalEventBus indirection).
  • happy-dom isolation preserved for client (split test: real-WebSocket client-core without happy-dom; DOM web-ui with --preload).

Gates (all green, every step)

bun run check · bun run test (engine 1070 tests/74 files 0 fail; full suite green) · bun run boundaries (1057 modules, 0 violations) · all 6 smoke-compile-* · publint (8 pkgs) · smoke-release.

Review

codex R1 (design) + R2 (implementation) both run; R2 findings verified as false positives (codex ran root bun test vs canonical bun run test; test-file peer imports are excluded by design). No real blockers. Migration table in .changeset/7-1-consolidation.md.

🤖 Generated with Claude Code

codeweiz and others added 9 commits June 2, 2026 23:36
The 3 docs/7.0-*.md (design + 132 decisions + resolved) are the locked single source of truth. Derived an ordered task backlog into docs/tasks/ (00-index with the 3 working principles + phase-0 + 14 task files mapping to per-phase design docs 7.1-7.14). docs/7.1-design.md = the consolidation (23->8 pkg) design, codex-R1 folded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (Phase 0 A3)

A contributor behind a regional mirror (~/.npmrc=npmmirror) can bun-install a lockfile pinned to that mirror, which then fails CI's bun --compile on GitHub runners (the v1.0.0 root cause, see bunfig.toml). Guard the typescript job (pre-install): fail fast if bun.lock records any non-npmjs registry host.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…runtime (consolidation Step 1)

Phase 1 / Step 1 of the 23->8 package consolidation (docs/7.1-design.md). Zero behavior change. config+telemetry+telemetry-otel src moved to runtime/src/{config,telemetry,telemetry-otel}/; runtime now exports ./config, ./telemetry, ./otel (subpaths -> dist) and absorbs the @opentelemetry/* optional peer+dev deps. Internal imports relativized; 23 external consumers rewritten @chances-ai/{config,telemetry,telemetry-otel} -> @chances-ai/runtime/{config,telemetry,otel} (incl. the load-runtime computed specifier). Removed stale dep+tsconfig refs (root + apps/cli + tools/mcp/lsp/core; lsp's config dep was dead). depcruise rules 1/4/6 dead-name cleanup. smoke-compile-otel redefined: optional-absence surface shrinks from (sub-package + peer) to @opentelemetry/* only (the sub-package now ships inside runtime). bun.lock is host-agnostic after bun install (bunfig pins npmjs.org).

Gates: check 45/45 · test 45/45 (runtime now 291 tests/18 files incl 8 moved) · boundaries 1061 modules 0 violations · smoke otel/oauth/lsp all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dation Step 2)

Phase 1 / Step 2 of the 23->8 consolidation (lowest-risk merge). Zero behavior change. ink-ext/src moved to tui/src/ink-ext/ (ink-ext was imported ONLY by tui, and is a leaf — imports no workspace pkg). 15 tui files rewritten @chances-ai/ink-ext -> ./ink-ext/index.js; removed tui dep + tui/root tsconfig refs; deleted the depcruise ink-ext-is-a-leaf rule and dropped ink-ext from rules 1/2 (tui now covers the folded path). bun.lock normalized to npmjs.org (a local bun install re-pinned npmmirror via ~/.npmrc; sed'd back — the ci.yml A3 guard enforces this).

Gates: check 43/43 · test 43/43 (tui now 190 tests/20 files incl 5 moved ink-ext) · boundaries 1061 modules 0 violations · smoke-compile-tui green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nsolidation Step 3)

Phase 1 / Step 3 of the 23->8 consolidation. Zero behavior change. New @chances-ai/client: '.' = client-core (browser-safe RPC client, React-free), './react' = web-ui (HeroUI/React DOM components). client-core/src + web-ui/src moved under client/src/{client-core,web-ui}/; 18 web-ui files rewritten @chances-ai/client-core -> ../client-core/index.js; react/react-dom/@heroui made OPTIONAL peers (only ./react needs them, per design [2.4]). apps/web: @chances-ai/client-core -> @chances-ai/client, @chances-ai/web-ui -> @chances-ai/client/react. depcruise browser-safe rules (1/2/3/4) renamed client-core|web-ui -> client; root tsconfig merged. browser-safe.test made RECURSIVE over the whole client/src tree (R1 #8); boundaries.test fixture paths re-depthed (one extra nesting level).

happy-dom isolation: client-core's transport.test drives a REAL loopback WebSocket (Bun.serve) that happy-dom clobbers, while web-ui's *.dom.test.tsx NEED happy-dom — so the client 'test' script runs TWO separate bun-test processes (src/client-core WITHOUT happy-dom; src/web-ui WITH --preload ./happydom.ts). No global preload in bunfig.

Gates: check 41/41 · test 41/41 (client-core 77 tests/5 files incl real-WS transport + recursive browser-safe; web-ui 83 tests/11 files DOM) · boundaries 1059 modules 0 violations · apps/web vite build node-free.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Step 4)

Phase 1 / Step 4 of the 23->8 consolidation. Zero behavior change; driver.ts EngineHost seam byte-identical. New @chances-ai/wire: './rpc' (ACP/RPC core over the EngineHost) + './serve' (relay/replay-hub/tls/auth/pairing). rpc/src + serve/src moved under wire/src/{rpc,serve}/; serve's 8 @chances-ai/rpc imports relativized to ../rpc/index.js; @agentclientprotocol/sdk stays an optional peer (computed-specifier lazy load in acp/load-sdk.ts); ws/selfsigned stay hard deps reachable only via ./serve. Consumers (apps/cli, apps/desktop, client) rewritten @chances-ai/rpc -> @chances-ai/wire/rpc, @chances-ai/serve -> @chances-ai/wire/serve. wire is the SERVER tier: it legitimately imports ui-core (server-side view-model projection), so it's governed by depcruise no-client-to-tui (rules 2), NOT no-domain-to-ui (rule 1) — rpc removed from rule 1 from-list; serve->wire in rules 1/2/4/6; boundaries.test now asserts no-client-to-tui. smoke-compile-rpc ACP stash path -> packages/wire.

Gates: check 39/39 · test 39/39 (wire 272 tests/22 files incl driver/cross-transport/boundaries) · boundaries 1057 modules 0 violations · smoke-compile-rpc (acp-sdk present+absent) · smoke-compile-serve (compile + start + /health + WS /acp initialize).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lidation Step 5, XL)

Phase 1 / Step 5 — the big merge. Zero behavior change. ai+agents+tools+plugin-api+plugin-logger+memory+local-vault+lsp+mcp+session+core folded into @chances-ai/engine with granular subpath exports (./ai ./agents ./tools ./plugin-api ./plugin-logger ./memory ./local-vault ./lsp ./mcp ./session ./core), NO '.' barrel (subpath = the lazy-peer + tree-shake boundary). Intra-engine cross-domain imports relativized depth-aware (core/mcp have nested subdirs, so core/compaction/*->../../ vs core/*->../, via a throwaway script). mcp->local-vault is now a plain relative dynamic import (local-vault always ships in engine; keyring stays lazy). Optional peers consolidated onto engine: ai+@ai-sdk/* + @modelcontextprotocol/sdk + @napi-rs/keyring + vscode-jsonrpc (all computed-specifier lazy). External consumers (apps/cli, tui, ui-core, wire, scripts/benchmark, root devDeps) rewritten @chances-ai/<domain> -> @chances-ai/engine/<domain>; apps/cli's 11 domain deps collapse to one @chances-ai/engine. depcruise rules 1/4/6 domain names -> engine; lsp boundaries.test re-depthed (still no-domain-to-ui). load-runtime loadLsp computed specifier -> ["@chances-ai","engine","lsp"]. smoke-compile-oauth/lsp redefined: optional-absence surface shrinks from (sub-package + peer) to external-peer-only (sub-packages now always ship in engine); stash paths -> packages/engine/node_modules.

Gates: check 19/19 · test 19/19 (engine now 1069 tests/74 files, 2 skip, 0 fail — no cross-test interference) · boundaries 1057 modules 0 violations · all 6 smokes green (otel/oauth/lsp/rpc/serve/tui).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uctural rules (consolidation Step 6)

Phase 1 / Step 6. Clean rewrite of .dependency-cruiser.cjs for the consolidated 8-package tiers (apps -> ui[tui] -> client[ui-core/client/design-system, browser-safe] -> server[wire] -> domain[engine] -> infra[runtime] -> native), with refreshed comments (dropped the stale web-ui/client-core/serve/ink-ext/config/telemetry names). design-system pre-listed in the browser-safe tier rules (reserved for task 03). TWO new structural rules: no-static-optional-peer ([2.1]) — engine/wire/runtime may load mcp-sdk/vscode-jsonrpc/@napi-rs/keyring/acp-sdk/@opentelemetry/* ONLY via computed-specifier dynamic import (dependencyTypes:[import,require] catches a static value import; computed/dynamic/type-only allowed; @ai-sdk excluded as bundled); no-deep-cross-package-src ([2.8]) — apps must import packages via their exports, never reach into src/. Added a committed no-static-optional-peer regression fixture to engine/src/lsp/boundaries.test.ts. Both new rules verified to FIRE (ad-hoc negative fixtures).

Gates: engine test 1070 tests/74 files 0 fail (incl the new rule-7 fixture) · boundaries 1057 modules 0 violations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (Step 7)

Phase 1 / Step 7 (finalize). turbo.json needs no change (build graph auto-derived from package.json deps; no hardcoded package names). publint: all 8 consolidated packages 'All good!' (incl the no-'.'-barrel engine/wire subpath-only packages). smoke-release (Node out-of-bun) green. Added the 7.1 major changeset with the full old->new import-specifier migration table (fixed-group anchors @chances-ai/cli). Ticked Steps 3-7 in docs/tasks/01-consolidation-task.md.

CONSOLIDATION COMPLETE: 23 packages -> 7 libs (client/engine/native/runtime/tui/ui-core/wire) + design-system reserved = 8 target. Final gate all green: check + test + boundaries (1057 modules, 0 violations) + publint + smoke-release + all 6 compile smokes. Zero behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codeweiz codeweiz merged commit f096b4c into main Jun 3, 2026
2 checks passed
@codeweiz codeweiz deleted the feat/7.1-consolidation branch June 3, 2026 00:15
codeweiz added a commit that referenced this pull request Jun 3, 2026
… (Step 3)

Focused port of oh-my-pi pi-natives grep.rs: a #[napi] async grep() on the
libuv pool (so a serve fan-out can't freeze the event loop), keeping the
load-bearing pieces and the facade's option set, dropping pi's context
lines / type filters / output modes / in-memory search+has_match (no
consumer yet — R1 #5).

Native (src/grep.rs):
- ripgrep stack: grep-regex + grep-searcher + globset filter + ignore
  parallel walker (gitignore-aware, hidden included, node_modules/.git
  pruned); per-128 heartbeat; mmap for files > 128 KiB, skip > 4 MiB.
- two-step sanitize: sanitize_braces (`${x}`→`$\{x\}`, valid quantifiers
  and \p{}/\x{}/\u{} pass through) + escape_unescaped_parentheses retry on
  a group-syntax error (so `fn(` searches literally instead of erroring).
- matched line text trimmed both ends to match jsGrep; results sorted by
  (path, line) then truncated to maxResults.

Facade (breaking, async flip): grep(pattern, root, opts) is now
Promise<GrepMatch[]>; the native addon returns {path,lineNumber,line} and
the facade adapts to the UNCHANGED {file,line,text} contract (R1 #2). Added
addonOrForced() — the unified CHANCES_NATIVE_FORCE_FALLBACK switch (R1 #8).
Repoint: grep.ts awaits; native package grep tests await + go async.

Tests: 7 Rust unit (sanitize/paren-recovery/relative+line/per-file-limit/
glob/gitignore) + 4 native↔JS facade equivalence (literal / regex+case+glob
/ perFileLimit+maxResults / sanitized brace; non-multiline on a clean tree
where both walkers agree — §9 #1/R1 #22). Multiline divergence documented:
the native stack coalesces ADJACENT multiline match-blocks (ripgrep
semantics, verified) — the "multiple matches" test spaces blocks out; the
grep-tool invalid-regex test now uses an unclosed char class (malformed on
both backends) since bare parens are recovered.

Gates: cargo fmt + clippy -D warnings clean + cargo test 47/0 · native
61/0 · check 19/19 · boundaries 1057/0 · full test 19/19. .node 752 KiB →
2.3 MiB (ripgrep stack). deps: globset/grep-matcher/grep-regex/
grep-searcher/memmap2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant