feat(3.1.1): drop build shims, add publint to CI verify#1
Merged
Conversation
Two scripts deleted (`build-cli.ts` 12 lines, `build-native.ts` 9 lines) — both were `spawnSync` wrappers around a single command. `build:native` was already inlined in package.json#scripts; `build:cli` is now too. publint added to .github/workflows/release.yml verify job. The script iterates `packages/*` and `apps/*` via shell glob — same shape bun resolves workspaces — so new packages get manifest-lint coverage without editing a list. The 3.1.0 verify regression was exactly the class of bug this catches at this layer (missing-from-publish-list shows up as a pack/manifest issue). Baseline: all 14 workspace packages pass publint clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
codeweiz
added a commit
that referenced
this pull request
May 28, 2026
When the model's context fills up, chances-cli now transparently
shrinks it. Three triggers (manual `/compact` + threshold + Anthropic-
only reactive overflow), two-stage (allowlist tool-output pruning
first then LLM summary). NO idle (pi + claude-code both skip;
oh-my-pi recommends v1 skip too).
`Compactor` (~270 LoC) in `packages/core/src/compaction/`:
- `shouldCompact({ lastRequestInputTokens, model })` — pure
predicate, threshold = `contextWindow − max(16384, floor(window
× 0.10))`. Signal source is per-stream `lastRequestInputTokens`,
NOT the turn aggregate (a multi-step tool loop would otherwise
trip threshold too early; codex Round-1 MUST-FIX #1).
- `compact(reason, signal)` — two-stage. Stage 1 prunes
`tool-result.output` for allowlisted tools (default
`compactableTools = ["bash", "grep"]`), preserving `callId` /
`name` / `ok` / `type` so Anthropic `tool_use ↔ tool_result`
pairing survives (codex Round-1 MUST-FIX #2). Stage 2 runs
`summarizeConversation` + `SessionManager.compactTurns(summary,
keepLastN=5)`.
- 3-strike circuit breaker. Manual `/compact` + Anthropic-overflow
bypass `enabled:false` AND tripped breaker (a 413 is a hard
signal we must try; codex Round-2 MUST-FIX #1). Manual additionally
resets the breaker on success.
- Cancellation classification via `signal.aborted` (the AI-SDK
wraps `AbortError` as a `provider:error` event, so naive
`AppError(Cancelled)` matching silently absorbed user Ctrl-C
as a compactor fault; codex Round-2 MUST-FIX #2).
- CJK-aware token estimator `max(char/4, cjk/2)` so Doubao 32K /
Kimi 32K / DeepSeek 65K windows stay sane (codex Round-1
SHOULD-FIX #1).
Engine wiring (`packages/core/src/engine.ts`):
- Per provider-stream-call, tracks `attemptLastInputTokens` (reset
per attempt, captured on success). After the outer loop,
`lastRequestInputTokens` holds the LAST successful stream's last
`usage.inputTokens`.
- New emit order: `appendTurn` → `ack notifications` → `usage:turn`
→ `await compact("threshold")` → `token.throwIfCancelled()` →
`turn:end`. TUI subscribers never see "turn over" while session
is still mutating; a cancelled compaction propagates to the
caller (codex Round-1 MUST-FIX #4 + Round-2 MUST-FIX #2).
- Anthropic-only reactive overflow recovery: detects `prompt is
too long` / `request_too_large` / `maximum.*context.*length`
AND `route.adapter.id === "anthropic"`, runs `compact("overflow")`,
retries the inner stream once. `recoveredFromOverflow` per-turn
flag prevents loops. Other 10 providers stay deferred (codex
Round-1 SHOULD-FIX #4).
- `suppressLifecycleEvents` (set by subagent engines) suppresses
`usage:turn` too — child engines stay invisible on the parent
bus's lifecycle channel.
New `SessionManager.pruneTurns(keepRecentTurns, transform)` for
in-place per-turn rewriting. Honors keep-recent at turn-boundary
granularity. Idempotent if the transform is.
New bus events: `usage:turn` (carries `lastRequestInputTokens` —
3.6 OTel will consume this), `compaction:start`, `compaction:end`.
`apps/cli/src/boot/create-app.ts` — `buildEngine` constructs the
`Compactor` only when `ctx.backgroundTasks` is set (interactive
chat gating proxy: `-p` one-shot mode has no "next turn" for
threshold compaction). Exposes via `ctx.compactor`. Subagent
engines never receive one.
`apps/cli/src/slash/compact.ts` — refactored to route through
`ctx.compactor.compact("manual", ...)` when present. Defensive
direct-summarizer fallback preserved for test setups that build
`BuiltinSlashDeps` without going through `buildEngine`. Slash
signal plumbing deferred to 3.x.later (codex Round-1 MUST-FIX #3:
`SlashCommand.run` has no `AbortSignal`).
New `CompactionConfig` under `AgentConfig`: 5 knobs (`enabled`,
`reserveTokens`, `keepRecentTurns`, `pruneMinSavings`,
`compactableTools`) + 4 env overrides (`compactableTools` is
config-only — comma-parsing of tool names invites quoting bugs).
Prune marker sanitizes the display name (controls stripped,
64-char cap) so a malicious plugin tool name can't corrupt the
synthetic marker sent back to the model — `part.name` itself
preserved unchanged for provider tool_use pairing (codex Round-2
SHOULD-FIX #3).
Codex review folded into the same commit:
- Round-1 (design, 4 MUST-FIX + 4 SHOULD-FIX + 2 NICE): idle
deferred; `lastRequestInputTokens` not turn-aggregate; prune
output-field-only; slash uncancellable; usage:turn → await
compact → turn:end ordering; CJK estimator; allowlist not
denylist; circuit-breaker scope honest + manual bypasses;
Anthropic-only overflow; module layout OK; single-huge-turn
+ second-compaction edge tests.
- Round-2 (impl, 2 MUST-FIX + 3 SHOULD-FIX + 2 NICE):
`enabled:false` was disabling manual too; cancellation via
`signal.aborted` because AI-SDK wraps AbortError as provider
error; stats/doctor metrics promised but unimplemented —
explicitly deferred to 3.x.later; overflow test wasn't
pinning `lastRequestInputTokens` semantics; prune marker
leaked raw plugin tool names; stale "denylist" wording fixed;
single-huge-turn test was vanity, strengthened.
`@chances-ai/core` promoted `@chances-ai/config` from devDep to
runtime dep (compactor `import type { CompactionConfig }`).
`.dependency-cruiser.cjs` allows `core → config`.
843 tests / 0 fail / 2107 expect calls. 29/29 typecheck. 405
boundary modules / 0 violations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
codeweiz
added a commit
that referenced
this pull request
May 31, 2026
…, serve skeleton Phase A (M0 foundations) of the unified multi-platform client (docs/6.1). v17 ships M0+M1 together as one major; this lands the M0 half (staged for the eventual v17.0.0 release with M1). - ui-core: browser-safe extraction of the 6 pure view modules from tui (highlight-to-segments/diff-model/view-model/frame-scheduler/tool-line/theme); process.*/node:os injected; tui re-exports via a thin theme shim — zero behavior change, apps/cli untouched. - design-system: Tamagui (@tamagui/core 2.1.0) skeleton; tokens/themes derived from ui-core (single source, res #1); compiles on Bun + tsc -b + React 19 and runs createTamagui in a no-DOM runtime (TOP RISK resolved). - serve: `chances serve` relay skeleton — loopback-only (no 0.0.0.0 until M3 auth) + GET /health; reuses ui-core highlightToSegments so clients ship no highlighter (res #2). - cruiser: no-client-to-tui (covers apps/{web,desktop,mobile}) + ui-core-is-browser-safe (dependencyTypes:core + grep-based global scan) + design-system-consumers, all with regression fixtures. - AppEvent: compile-time-exhaustive serialization fixtures (satisfies Record<AppEventType, AppEvent>) + round-trip + golden snapshot. - docs: STATUS/ROADMAP reflect v17 M0 progress (Phase A done, Phase B next). codex R1 folded: 2 MUST (loopback-only bind; ChatViewModel home injection to preserve ~-folding) + 3 SHOULD (browser-safe globals scan; apps/{web,desktop, mobile} cruiser coverage; AppEvent edge fixtures). Gates: test 46, typecheck 44, boundaries 829/0, cargo fmt clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
3.1.1 release-pipeline cleanup. Two pieces:
scripts/build-cli.ts(12 lines) andscripts/build-native.ts(9 lines) were each a singlespawnSyncwrapping one command.build:nativewas already inlined as apackage.jsonscript;build:cliis now too. Net -21 lines.packages/*andapps/*via shell glob — same shape bun resolves workspaces — so new packages get manifest-lint coverage without editing a list. The 3.1.0 verify regression was exactly the class of bug this catches at this layer.Deliberately not doing in this PR (covered in the design discussion):
release-publish-npm.tswithbunx changeset publish—@changesets/cli@2.31.0callsnpm publish, which does not rewriteworkspace:*references in our manifests.bun publish(current) does. Documented atdocs/STATUS.md:266.changesets/action— would still need a separate Cargo.toml lockstep step, so layering it on top ofrelease.tsadds complexity rather than removes it.workspace-packages.ts— algorithmically derived, not hand-maintained, and keeps publish window safe against half-published states. Codex review endorsed keeping it.Test plan
🤖 Generated with Claude Code