| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
brand: retire the old traced marks, sync the canonical vector family The repo's brand/mark.svg + wordmark traces were an earlier lower-fidelity trace of the C-curl whale (black currentColor instead of the navy family), and crates/tui/src/runtime_web/codewhale-192.png was still the retired diving-whale tile served by the embedded runtime web client. - brand/ and web/public/brand/ now carry byte-identical copies of the canonical family (codewhale-apps/packages/brand/svg/), adding the missing mark-mono and mark-reversed variants. - extensions/vscode/media/codewhale.svg uses the family mono mark. - runtime_web/codewhale-192.png is the canonical 192 tile (same bytes as codewhale-apps apps/web/public/icons/codewhale-192.png). - opengraph-image.tsx reads mark-reversed.svg (the family's white-on-navy variant) instead of string-replacing currentColor, which the family mark.svg does not contain; wordmark aspect corrected to the family's 1024x160 viewBox. - Deleted brand/mark-navy.svg (duplicate of the family navy mark), brand/wordmark0901.png + wordmarkinverted.png (only consumer was the retired generator; founder rasters preserved in codewhale-apps/packages/brand/source/), and scripts/brand/trace-brand.py (regenerated the retired trace; not referenced by CI). The founder brand sheet brand/codewhalemarkfinal.png stays as scripts/brand/braille-mark.py's input. - PRODUCT.md and the public-auth-routes provenance comment updated to name the canonical family home. Checks: npx tsc --noEmit (web) exit 0. Asset swap + comments; runtime_web route tests reference the icon path, not bytes. (cherry picked from commit 116a57b8143167265e48a8c48b10d35828031cf3) | 1 天前 | |
ci(cnb): post shadow GitHub check runs from linux rust gates (#5746) Import the codewhale-cnb-bridge GitHub App credentials from the CNB KeyStore (codewhale.net/codewhale-ci-secrets, github-bridge.yml) via the documented imports mechanism, and add an endStages bridge step to the linux rust gates pipeline that mints an installation token and posts a non-required 'linux rust gates -cnb' Check Run on the exact GitHub SHA being built, with the conclusion mapped from CNB_PIPELINE_STATUS. Per the shadow-parity protocol in the CNB-primary CI design: GitHub Actions stays canonical and required, no GitHub gate flips, and the bridge runs in endStages so a bridge outage can never fail the CNB pipeline itself. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> | 16 天前 | |
fix(release): give the Windows installer a Terminal-aware Start Menu shortcut The zip already shipped codewhale.bat (where wt, then the exe). NSIS only copied the exes, so a Start Menu launch still used the raw binary (#1854). Install the same launcher into bin, pin a current-user shortcut at it, and delete both on uninstall. Verified: node --test scripts/release/assemble-release-assets.test.js (7/7) and makensis compiled a test installer. | 29 天前 | |
feat(media): executable capture harness for the v0.9.2 real session The media plan (#4906, docs/releases/v0.9.2-media-plan.md) already specifies the procedure and references a tape at docs/evidence/v092-first-fleet-session.tape. That tape did not exist, and the acceptance checklist was prose. This supplies both, so the only thing left is the part that genuinely needs a human: running it and judging whether the take is worth showing. The tape replays the plan's four beats at 120x32. It sets a plain dark terminal theme rather than a hand-written "Blue Stage" palette: Blue Stage is a Codewhale theme and the TUI paints its own cells, so an emulator palette imitating it would be invented colors fighting the real ones. The product theme is selected from the sealed config instead. record-session.sh exists because a recording is published footage, and the failure mode is not a bad take — it is a take containing a home directory or a credential. It refuses rather than producing something that must be scrubbed: it checks the installed binary embeds this exact HEAD, refuses a dirty tree, scans the environment for anything key-shaped, seals HOME/CODEWHALE_HOME, and writes a capture.json naming the source commit and asset digests so the asset can be re-shot instead of aging into a lie about the UI. check-media-assets.py turns the mechanical half of the checklist into a command. It parses MEDIA_BUDGETS out of web/lib/media-manifest.ts rather than duplicating the numbers, so it cannot drift from the contract the web tests already enforce, and it reports rather than fails on the issue's stricter ~3 MB README target since that is a different budget from the site fallback. Neither script judges the take, and the validator says so on success: whether the session is worth showing, whether every frame is real, and whether the caption cues match remain human calls. | 1 个月前 | |
fix(ohos): re-quote Windows linker arguments containing spaces cmd's %* expansion strips the quotes rustc puts around link arguments that contain spaces, so an SDK path like "D:\DevEco Studio\...\sysroot" arrived at the clang launcher split on the space and the final Rust link failed. Walk the arguments with %~1 and re-wrap each in quotes before forwarding to the PowerShell wrapper, and extend the no-SDK release guard to keep the re-quoting contract. Assisted by Claude Code. Signed-off-by: shenjackyuanjie <54507071+shenjackyuanjie@users.noreply.github.com> (cherry picked from commit 6a3837cd48dc937bfaff6288750ac79f7f9cd2fd) | 1 个月前 | |
fix(release): do not fail prepare-release when a doc has no source-candidate line The two source-candidate rewrites I added exited non-zero unless they matched exactly once. That is wrong for a helper that must work on any checkout: `prepare-release.test.sh` drives the script over a fixture at 0.8.68 whose INSTALL.md and facts matrix never carried those sentences, so the helper aborted and the `Check release helper contracts` step went red on main and on every PR branch rebased onto it. Now they rewrite when the sentence is present and are silent when it is not, failing only on more than one occurrence, which would be genuinely ambiguous. Nothing is lost by tolerating zero: `web/lib/public-surface-contract.test.ts` already asserts both sentences exist and match `FACTS.version`, so a deletion is caught by a stronger gate than this one. The pointer rewrite immediately above has always been written this way. Verified both directions: `bash scripts/release/prepare-release.test.sh` → "prepare-release tests passed"; and an idempotent `./scripts/release/prepare-release.sh 0.9.14` against the real tree still leaves the checkout clean with "Version state OK: workspace=0.9.14, npm=0.9.14, npm-binary=0.9.14, lockfile in sync". Ten of the eleven `scripts/release/*.test.sh` now pass. The eleventh, `validate-crate-publish-order.test.sh`, fails on its live-workspace block for a different and pre-existing reason — #6287, `codewhale-tui` depending on the unpublishable `codewhale-memory` — which is a decision, not a fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 12 小时前 | |
chore(release): prepare v0.9.14 Opens the `## [0.9.14] - 2026-09-16` section — the accumulated `[Unreleased]` body becomes the release entry, a fresh empty `[Unreleased]` opens above it, and the compare links gain `v0.9.13...v0.9.14` with `[Unreleased]` re-pointed at `v0.9.14...HEAD`. Then `scripts/release/prepare-release.sh 0.9.14` bumped every version-bearing file in one transaction: the workspace version, every `codewhale-*` dependency pin, the npm wrapper (`version` and `codewhaleBinaryVersion`), the Runtime SDK, the VS Code extension and its lock, the root npm lock, the remote-smoke default tag, the public fact matrix, and both Cargo and npm locks. It also regenerated `crates/tui/CHANGELOG.md`, `web/lib/facts.generated.ts` and `web/lib/changelog.generated.ts`. The generated facts refresh matters beyond the version string: the committed crate roster had gone stale against the vendored `crates/memory`, which would have reddened the Web Frontend job on the next push. `npm/deepseek-tui` stays at 0.8.49 — compatibility-only, not bumped, not published (checklist §2). Gates run by the script and re-verified: Feature release-note receipts OK: 17 linked issue reference(s) in v0.9.13..HEAD Version state OK: workspace=0.9.14, npm=0.9.14, npm-binary=0.9.14, lockfile in sync OHOS Windows linker wrapper contract OK OHOS dependency graph OK for codewhale-tui on aarch64-unknown-linux-ohos OHOS rquickjs-sys bindgen feature edge OK for codewhale-workflow-js **No tag is pushed.** The version bump is a commit; creating and pushing `v0.9.14` is the irreversible act that publishes the GitHub Release, GHCR images and npm, and it stays a human decision. Contributor credits for the release entry are still being assembled and land before any tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 13 小时前 | |
fix(release): promote tested v0.9.11 nonbenchmark candidate Promotes the fully gated non-benchmark candidate while preserving the benchmark tree exactly from the prior release-PR head. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 25 天前 | |
fix(ci): close the CodeQL cache-poisoning Highs in the release workflows All 19 open actions/cache-poisoning/poisonable-step alerts (#88-#106) sit in release.yml, release-candidate.yml and release-artifacts.yml: jobs interpolated the caller SHA into ref/caches and let setup-node's implicit npm cache key on run identity. Now caller source_sha is pinned against github.sha by a pin job (refusing any retarget), checkout and build identity use GITHUB_SHA through env indirection instead of template interpolation, rust-cache keys use stable prefix-key values, and setup-node's implicit package cache is off where it cannot be keyed safely. Also carries the CodeQL #107 fix from the same lane: catalog_models_dev.py prints remote limit values as numbers/null/redacted only and drops query and fragment material from source URLs before logging. Harvested from #5401 (workflow+script files; CHANGELOG edit intentionally excluded here and lands with the release branch; GHSA advisory text split to a later PR as advised). No-Issue: CodeQL alert remediation (alerts #88-#107); no single user-facing issue tracks these Signed-off-by: Hunter Bown <hunter@hmbown.com> | 1 个月前 | |
fix(ci): close the CodeQL cache-poisoning Highs in the release workflows All 19 open actions/cache-poisoning/poisonable-step alerts (#88-#106) sit in release.yml, release-candidate.yml and release-artifacts.yml: jobs interpolated the caller SHA into ref/caches and let setup-node's implicit npm cache key on run identity. Now caller source_sha is pinned against github.sha by a pin job (refusing any retarget), checkout and build identity use GITHUB_SHA through env indirection instead of template interpolation, rust-cache keys use stable prefix-key values, and setup-node's implicit package cache is off where it cannot be keyed safely. Also carries the CodeQL #107 fix from the same lane: catalog_models_dev.py prints remote limit values as numbers/null/redacted only and drops query and fragment material from source URLs before logging. Harvested from #5401 (workflow+script files; CHANGELOG edit intentionally excluded here and lands with the release branch; GHSA advisory text split to a later PR as advised). No-Issue: CodeQL alert remediation (alerts #88-#107); no single user-facing issue tracks these Signed-off-by: Hunter Bown <hunter@hmbown.com> | 1 个月前 | |
fix(ci): stop the blocking-call ratchet taxing extracted test files, and unred main `Lint` is failing on `origin/main` at "Check blocking-calls budget" (run 35126167644, sha 9a674f47f). The check is `continue-on-error` on `pull_request` and fatal on `push`, so #6096 went green as a PR and turned `main` red the moment it merged — the exact asymmetry that lets a red `main` go unnoticed. Two separate things were wrong, and only one of them was a budget question. **The ratchet could not see whole-file test modules.** Its docstring says it skips test code, and `file_counts` does recognise `#[test]`, `mod tests` and `fn test_*` — but a file that is *entirely* a test module knows nothing about it, because that fact lives in the parent's `#[cfg(test)] mod foo;` declaration. So extracting a test suite into its own file made untouched call sites look new. `session_export_regression_tests.rs` and `session_export_surface_tests.rs` are declared `#[cfg(test)]` at `commands/mod.rs:36-41`; they were counted anyway. `cfg_test_module_files()` now resolves those declarations and excludes the files they name. That is a tightening, not a loosening. Six existing test files (`telemetry/src/tests.rs`, `dsh/tests.rs`, `skills/tests.rs`, `test_support.rs`, `subagent/tests.rs`, `golden_harness.rs`) were carrying budgets totalling 27 sites that the ratchet should never have been counting. Those entries are gone, so 27 sites can no longer hide inside an allowance. **The remaining two sites are a relocation, not new debt.** `commands/groups/session/export.rs` was budgeted `std_fs: 4`; #6096 moved those four verbatim into `commands/session_export_host.rs`, which had no entry. Same four calls, same synchronous callers — `SessionExportAdapter`'s trait methods at `contract.rs:1549/1563/1567` are `fn`, not `async fn`. The budget moves with the code. `crates/memory/src/main.rs:371` is one `std::fs::canonicalize` inside `fn main()`, which the ratchet's own docstring names as fine ("synchronous entry points"). Audited the regenerated JSON rather than trusting `--update`: two entries added (both verified above), seven removed, **zero existing budgets raised**, 181 files down to 176. Two tests pin the new behaviour — a `#[cfg(test)] mod` declaration excludes the file it names, and a plain `mod` declaration does not, so the exclusion cannot quietly widen to production code. Tests: `python3 scripts/test_check_blocking_calls_budget.py` — Ran 11 tests, OK (9 before). `python3 scripts/check-blocking-calls-budget.py` — "600 sites across 176 files, within budget", exit 0, where it exited 1 with four offenders before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 13 小时前 | |
fix(ci): stop the blocking-call ratchet taxing extracted test files, and unred main `Lint` is failing on `origin/main` at "Check blocking-calls budget" (run 35126167644, sha 9a674f47f). The check is `continue-on-error` on `pull_request` and fatal on `push`, so #6096 went green as a PR and turned `main` red the moment it merged — the exact asymmetry that lets a red `main` go unnoticed. Two separate things were wrong, and only one of them was a budget question. **The ratchet could not see whole-file test modules.** Its docstring says it skips test code, and `file_counts` does recognise `#[test]`, `mod tests` and `fn test_*` — but a file that is *entirely* a test module knows nothing about it, because that fact lives in the parent's `#[cfg(test)] mod foo;` declaration. So extracting a test suite into its own file made untouched call sites look new. `session_export_regression_tests.rs` and `session_export_surface_tests.rs` are declared `#[cfg(test)]` at `commands/mod.rs:36-41`; they were counted anyway. `cfg_test_module_files()` now resolves those declarations and excludes the files they name. That is a tightening, not a loosening. Six existing test files (`telemetry/src/tests.rs`, `dsh/tests.rs`, `skills/tests.rs`, `test_support.rs`, `subagent/tests.rs`, `golden_harness.rs`) were carrying budgets totalling 27 sites that the ratchet should never have been counting. Those entries are gone, so 27 sites can no longer hide inside an allowance. **The remaining two sites are a relocation, not new debt.** `commands/groups/session/export.rs` was budgeted `std_fs: 4`; #6096 moved those four verbatim into `commands/session_export_host.rs`, which had no entry. Same four calls, same synchronous callers — `SessionExportAdapter`'s trait methods at `contract.rs:1549/1563/1567` are `fn`, not `async fn`. The budget moves with the code. `crates/memory/src/main.rs:371` is one `std::fs::canonicalize` inside `fn main()`, which the ratchet's own docstring names as fine ("synchronous entry points"). Audited the regenerated JSON rather than trusting `--update`: two entries added (both verified above), seven removed, **zero existing budgets raised**, 181 files down to 176. Two tests pin the new behaviour — a `#[cfg(test)] mod` declaration excludes the file it names, and a plain `mod` declaration does not, so the exclusion cannot quietly widen to production code. Tests: `python3 scripts/test_check_blocking_calls_budget.py` — Ran 11 tests, OK (9 before). `python3 scripts/check-blocking-calls-budget.py` — "600 sites across 176 files, within budget", exit 0, where it exited 1 with four offenders before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 13 小时前 | |
test(FEAT-025): pin the export slice with baseline-captured goldens and gates Behaviour preservation is proven rather than claimed. Four goldens were captured from the pre-refactor implementation at `3f3aa9ed7` by dispatching frozen fixtures through the baseline public `/export` seam in a scratch worktree: - authoritative transcript with no restore repository (header, every content variant, D9 omission markers, redaction, ANSI stripping), - the turn handoff, - the visible-history fallback over a workspace with recorded restore points, - correlation against recorded restore points (table, newest-first order, `tool` snapshots listed but not correlated, the ambiguous double match, and the no-match line). Only genuinely clock-derived fields are normalised (the export stamp, the turn header stamp, and - for the recorded states - the snapshot id and `Recorded (UTC)` cell, because `git commit-tree` uses a wall-clock date). A unit test pins the normaliser so it cannot quietly widen. Everything else is byte-compared. Also here: the exhaustive `ContextParts` assertion that makes "no unrelated facet" a compile-time guarantee, the shared host-bound test-support module, the token-aware extraction audits plus their own unit test, and the boundary gate extension that keeps `codewhale-secrets` free of any TUI edge. Carries one unrelated, disclosed repair: a bounded retry for a fork/exec `ETXTBSY` race in the `wl-paste` regression, kept because the configured workspace gate was intermittently red without it. Generated with CodeWhale | 22 小时前 | |
fix(ci): qualify native image tests and preserve main migration history Keep the real sips resize integration assertions on macOS; Linux has no sips. When main equals origin/main, compare migration topology with its first parent instead of treating an existing frontier as initialization. Preserve feature-branch merge-base checks and reject arbitrary growth. Validation: native Computer Use 196 passed, 15 platform skips; migration regressions 60 passed; live manifest gate passed. npm test: 66 wrapper + 9 SDK + 446 web passed. npm run check:web passed (0 errors, 2 existing image warnings). git diff --check passed. | 5 天前 | |
chore: land the bounded dead-code slice and stop the wall regrowing #4785 asks for a 481-attribute sweep. This is not that sweep — it is the part that can land without judgment calls, plus the gate that makes the sweep worth doing. The measurements are why the gate comes first: issue filed 464 attributes / 143 files 2026-07-26 426 / 111 2026-07-28 481 / 155 The sweep was working and the total still rose, because two large landings this week added state whose accessors only their own tests read. A sweep is a snapshot; a budget is a direction. scripts/check-dead-code-budget.py counts `allow(dead_code)` across crates/ and fails when the total exceeds a committed ceiling. Lowering it is free; raising it needs `--update` and a sentence in the PR, so growth becomes a visible decision rather than an accident. On failure it prints per-crate now-vs-budget and marks which crate grew. Wired into Lint next to the other check-*.py gates. This covers a real blind spot: CI's clippy runs without `--all-targets`, so it never lints cfg(test) or integration-test code — and a prior strip-and-check measured 197 attributes alive *only* because a test references them. The three zero-risk removals from the issue's cluster list: - `codew_legacy_shim.rs` -> `codew.rs`. The issue calls this out as a rename, not a deletion: it is the live `codew` binary and its own docs call it permanent. Every sweep flags the filename; the binary name is unchanged. - `clap` dropped from app-server and `thiserror` from lane — no source in either crate references them. Cargo.lock loses exactly those two edges and no package versions move. The budget baseline is recorded at today's 482, not at an aspirational number, so the gate starts truthful and the sweep can ratchet it down. | 1 个月前 | |
test(tui): preserve persistence baseline evidence Commit the raw clean-SHA macOS receipt behind the persistence backlog budget, require it to match every recorded metric and provenance field, and close Python boolean/integer alias plus impossible zero-retention gaps on the budget side. | 1 个月前 | |
providers: retire Antigravity to a non-runnable tombstone Harvested from PR #5739, which had gone stale against main (45 conflicts across 54 files, most of them the branch dragging in files main has since moved past). Per AGENTS.md the change was re-applied to current main rather than hand-merged. Antigravity could not run an agentic turn: the cloud-code request builder bailed on any request carrying tools. ACP cannot rescue it either — `session/new` takes only `cwd` and the route comes from the server's own config, so ACP carries no provider selection and an ACP client expects a full tool-using agent. Two independent reviews (grok-4.6, deepseek-v4- flash) agreed with retiring it. What is gone: the private OAuth reader (`agy_credentials.rs`, the `state.vscdb` import and `AGY_ADC_AUTH` precedence), the private cloud-code transport (`client/cloud_code.rs`, `/v1internal`), `WireDialect::GoogleCloudCode`, and every Antigravity branch in `client.rs`, `credential_resolve.rs`, and the doctor. What remains: `ProviderKind::Antigravity` as a deserialize-only tombstone (serde alias `agy`), out of `ProviderKind::ALL` (43 -> 42), out of the catalog export and both route goldens. `ProviderKind::parse` is now gated through `ALL` so no selection surface can resolve a tombstone back into a route, while `parse_config_identity` gains `parse_retired_alias` so a surface can still *name* it and refuse — otherwise `agy` would go unrecognized and mint a fresh `[providers.agy]` table that serde folds right back onto the legacy one. The one accepted path is `codewhale auth clear --provider antigravity|agy`, which clears only Codewhale-owned config, consent, selection, fallback entries and secret slot, with secret rollback on save failure. It resolves no external path and never touches a Google or Antigravity session; a test plants an external-session trap file and asserts it is byte-identical afterwards. Two things I got wrong and the compiler caught. Excising the cloud-code seam from `client.rs` first swallowed the general request-binding path every provider uses (`bind_request_to_protocol` / `clamp_output_cap` / the DS4 strict-tool fixup) — the "never used" errors on those helpers were the real signal, not noise. And hardening the drift guard to discover hand-written providers by shape pulled in `Custom`, which the script deliberately treats as a meta provider; that was fixed in the guard rather than by bending the docs around it. `scripts/check-provider-registry.py` (+757) now enforces all of this, and discovers hand-written `impl Provider` blocks by shape — its hand-kept roster had already gone stale and had never heard of `concentrate`. cargo nextest: codewhale-tui 11931 passed, codewhale-config 636 passed, codewhale-cli 370 passed, codewhale-core 1092 passed. 0 failures. clippy -p tui -p config -p cli --all-targets --all-features: 0 errors. check-provider-registry: passed. check-tui-locale-parity: PASS. dead-code budget: PASS at 420. web: 386 passed, check:facts/check:docs PASS. Harvested-from: PR #5739 by @Hmbown Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 12 天前 | |
feat(i18n): define localization matrix with locale registry and drift checks (#3090) - docs/LOCALIZATION.md: canonical tracking document for shipped, planned, and deferred locales across website and README surfaces. Includes Russian as next-priority and Arabic as RTL deferred. - web/lib/i18n/config.ts: expand locale config with ALL_LOCALES registry (9 tracked locales, 2 shipped) and LocaleStatus types. Active `locales` array now derived from shipped status, enabling >2 locale support without hard-coded arrays. - web/components/locale-switcher.tsx: rewrite from hard-coded en↔zh toggle to support any number of shipped locales (2 = toggle, 3+ = dropdown). Reads from ALL_LOCALES. - web/middleware.ts: Accept-Language detection now matches against all shipped locales instead of hard-coding Chinese-only detection. - scripts/check-readme-locales.sh: symmetry check verifying main README links all locale READMEs and no orphaned locale files exist. Harvested from PR #3763 by @idling11 Co-authored-by: idling11 <8055620+idling11@users.noreply.github.com> | 2 个月前 | |
docs(i18n): add fr/de/zh-TW/hi/tr/it/pl/ar README translations Ship README translations for the TUI packs that had no README, plus Turkish, Italian, Polish, and Arabic. Include Catalan as the remaining shipped TUI pack. Cross-link every language switcher, restamp all translations against the updated English README, and register the new files in both check-readme-translations.py lists. | 1 个月前 | |
fix: route every reqwest client through codewhale_release::tls (#6153) Bare Client::builder()/new() under rustls-no-provider panics before the first provider install. Add a Lint gate (scripts/check-reqwest-builders.py + hermetic test, wired into ci.yml) and sweep the 17 remaining call sites onto tls/platform builders, dropping the hand-installed providers. Gate: test_check_reqwest_builders.py 5/5 ok; check fails with 17 hits before the sweep, passes after. clippy workspace clean. | 3 天前 | |
Pin the runtime tool metric to an explicit shell profile The ignored tool-catalog metric inherited SHELL, so the same signed8fbd binary measured14,701 active bytes under /bin/zsh and15,151 under pwsh. Pin existing SHELL=bash after the fixture's empty PATH; no interpreter is executed or installed. Record the actual detected binary in a versioned profile, fail if an already-initialized dispatcher defeats the pin, and reject missing or mismatched shell evidence in the existing budget checker. A fresh-process regression compares complete metrics under two inherited shells. Production tool selection, dispatch and permission code is unchanged. Reconcile only the intentional hidden tts identity/count already measured on signed8fbd and explained by d8e8ecf5a1. No byte/token ceiling is raised. Final numeric reconciliation remains pending root's fresh merged artifact. Validation: measurement harness3pass0fail; checker harness19pass0fail; cargo fmt --all -- --check and git diff --check pass. Five exact metric processes on signed8fbd prove ambient-shell divergence and byte-identical metrics when the proposed bare-bash setting is applied externally. These are old-binary input-setting proofs, not compiled-new-fixture evidence. New Rust fixture regression/full Cargo compilation explicitly UNRUN here; root owns the fresh signed build and final measurement. | 8 天前 | |
refactor: extract localization into codewhale-localization First crate out of the TUI monolith. 7,087 lines and 16 locale packs leave `crates/tui`, which drops from 973,442 to 966,355 lines. The founder's read was right and worth recording, because it is the thing that kept this from happening: it looks far scarier than it is. `localization` appeared to depend on the rest of the crate, but the single `crate::` reference in all 6,797 lines was **inside a doc comment** — prose, not an edge. It was already a standalone crate wearing a module's clothes, consumed by 145 files and depending on none of them. The subsystem is cohesive and moves whole: the registry, its rust-i18n backend, the `generate_localization` half of `build.rs`, and `locales/`. `localization` is the only module in the workspace that touches `rust_i18n::t!`, so the entire i18n coupling left with it — `crates/tui` no longer depends on rust-i18n at all, and its `build.rs` loses a build-dependency and a code generator. 165 consumers were repointed from `crate::localization::` to `codewhale_localization::`. No re-export shim was left behind: per `docs/design/TUI_DECONSTRUCTION.md:176,185-186` a shim with deferred consumers is the state this work exists to remove, and there is no external contract to protect. Gate paths moved with the packs: `check-tui-locale-parity.py`, `check-tui-product-vocabulary.sh`, and the live docs. `docs/CHANGELOG_ARCHIVE.md` keeps its old paths deliberately — it is a historical record, not a pointer. Verified, not assumed: cargo check --workspace --all-targets 0 errors, 0 unused warnings cargo test -p codewhale-localization 51 passed; 0 failed cargo test -p codewhale-tui --lib -- tui::views tui::widgets commands:: 1610 passed; 0 failed scripts/check-tui-locale-parity.py PASS, 2203/2203 in 15 packs scripts/check-tui-product-vocabulary.sh exit 0 No new tests: 51 existing ones moved with the code and prove the extraction by passing unchanged, which is the only assertion that matters for a move. What this buys beyond the line count: the localization suite now runs in 3.56s against a small crate instead of waiting on the TUI crate's build, and TUI edits no longer recompile the string registry. C00 measured a warmed one-line locale edit at 30.22s / 8,728 MB RSS inside the monolith. Refs: Linear C03-C10 / SHA-6179, docs/design/TUI_DECONSTRUCTION.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL | 7 天前 | |
refactor: extract localization into codewhale-localization First crate out of the TUI monolith. 7,087 lines and 16 locale packs leave `crates/tui`, which drops from 973,442 to 966,355 lines. The founder's read was right and worth recording, because it is the thing that kept this from happening: it looks far scarier than it is. `localization` appeared to depend on the rest of the crate, but the single `crate::` reference in all 6,797 lines was **inside a doc comment** — prose, not an edge. It was already a standalone crate wearing a module's clothes, consumed by 145 files and depending on none of them. The subsystem is cohesive and moves whole: the registry, its rust-i18n backend, the `generate_localization` half of `build.rs`, and `locales/`. `localization` is the only module in the workspace that touches `rust_i18n::t!`, so the entire i18n coupling left with it — `crates/tui` no longer depends on rust-i18n at all, and its `build.rs` loses a build-dependency and a code generator. 165 consumers were repointed from `crate::localization::` to `codewhale_localization::`. No re-export shim was left behind: per `docs/design/TUI_DECONSTRUCTION.md:176,185-186` a shim with deferred consumers is the state this work exists to remove, and there is no external contract to protect. Gate paths moved with the packs: `check-tui-locale-parity.py`, `check-tui-product-vocabulary.sh`, and the live docs. `docs/CHANGELOG_ARCHIVE.md` keeps its old paths deliberately — it is a historical record, not a pointer. Verified, not assumed: cargo check --workspace --all-targets 0 errors, 0 unused warnings cargo test -p codewhale-localization 51 passed; 0 failed cargo test -p codewhale-tui --lib -- tui::views tui::widgets commands:: 1610 passed; 0 failed scripts/check-tui-locale-parity.py PASS, 2203/2203 in 15 packs scripts/check-tui-product-vocabulary.sh exit 0 No new tests: 51 existing ones moved with the code and prove the extraction by passing unchanged, which is the only assertion that matters for a move. What this buys beyond the line count: the localization suite now runs in 3.56s against a small crate instead of waiting on the TUI crate's build, and TUI edits no longer recompile the string registry. C00 measured a warmed one-line locale edit at 30.22s / 8,728 MB RSS inside the monolith. Refs: Linear C03-C10 / SHA-6179, docs/design/TUI_DECONSTRUCTION.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL | 7 天前 | |
feat(FEAT-020): register /plugin through the portable bridge and shrink both frontiers - PluginsCmd implements contract RegisterCommand<CommandResult> with exact WORKSPACE | PRESENTATION | PLUGIN; PluginsCommands group registers via ContextualCommand::from_contract - plugins_contextual destructures facets with safe missing-facet errors; transitional App shell now test-only - Public dispatch tests: exact capability set, undeclared facets absent, public seam dispatch, no-panic matrix (3 tests) - Remove plugins from PENDING_GROUPS and scripts/command-migration-topology.json frontier (same commit) - Migration fixture updated for six-group frontier; feat015 legacy-assertion test adds plugin to MIGRATED - All gates green: contract 23/23, TUI lib 11397/0, migration/boundary/CI fixtures + live gates, fmt, diff hygiene Generated with Claude Code Signed-off-by: Paulo Aboim Pinto <paulo.aboim.pinto@gmail.com> | 13 天前 | |
feat(providers): Concentrate as a first-class opt-in BYOK Responses gateway (#5725) * feat(providers): Concentrate as a first-class opt-in BYOK Responses gateway Adds `concentrate` (aliases `concentrate-ai`, `concentrate_ai`, `concentrateai`) inside the existing provider authorities — no parallel secret store, router, or runtime: - Identity/metadata: `ProviderKind::Concentrate`, hand-written `impl Provider` with `WirePolicy::Fixed(WireFormat::Responses)` (the gateway documents the Responses API as its production surface), default base URL `https://api.concentrate.ai/v1`, default model `deepseek-v4-pro`, env `CONCENTRATE_API_KEY` (+ `CONCENTRATE_BASE_URL`, `CONCENTRATE_MODEL`), its own secret-store slot, credential help. - Routing: aggregator-class pass-through. A plain catalog id lets the gateway choose the upstream provider, `provider/model` pins one, and only the gateway's own `concentrate/` namespace is stripped so `concentrate/auto` reaches its `auto` router while Codewhale's bare `auto` stays the resolver sentinel (provider default). - Wire: the Responses body carries only documented fields — `model`, `input`, `stream`, `max_output_tokens`, `tools`/`tool_choice`/ `parallel_tool_calls`, `reasoning.effort` — with the system prompt as a leading `system` input item (`instructions`, `store`, `include`, and `reasoning.summary` are absent from the gateway's parameter reference). Streaming rides the existing typed `response.*` SSE parser and ends on `response.completed` without a `[DONE]` sentinel. - Catalog: the unauthenticated `GET /v1/models` (OpenAI list shape) joins the named-gateway live-catalog path; rows stay provider-scoped and unclaimed. - Errors (provider-neutral): a 402 "insufficient credits/funds" body now classifies as quota (RateLimit) instead of falling through, and a flat `{"error":"<class>","message":"<detail>"}` body surfaces both halves in the TUI sanitizer instead of the class alone. - Registry parity: `ProviderKind::ALL` 42→43, registry 47→48, golden route ids + providers-export golden regenerated, `scripts/check-provider-registry.py` manual-impl allowlist, web facts label maps + `facts.generated.ts` (providers 45→46), docs rows in PROVIDERS.md (+ a Concentrate Notes section) and CONFIGURATION.md, CHANGELOG. Commercial boundary, preserved in code and docs: BYOK only. Concentrate's Terms of Service forbid resale, white-label, and service-bureau use without written consent and its AUP forbids key sharing, so there is no Codewhale-owned key, no stored customer key, no default or managed routing, and no markup; any hosted lane is gated on written consent, terms, and billing approval (ops evidence concentrate-gateway-20260829/CHECKLIST.md). A saved or environment Concentrate key is bound to the official base URL and is never sent to any other endpoint — a custom endpoint receives a key only when `base_url` and `api_key` are both written into `[providers.concentrate]`. Keyless dogfood: `scripts/concentrate-selftest.sh` boots `scripts/concentrate-stub.py` (the documented contract on loopback: `/v1/responses/health`, unauthenticated `/v1/models`, typed-SSE `/v1/responses`, documented error bodies) and drives the real `codewhale exec --auto --output-format stream-json` path through it, asserting the URL, bearer header, verbatim model, only-documented fields, system item first, the completed-turn receipt, and the wrong-key 401. No network call leaves the machine; no account exists in the loop. Contract sources (fetched 2026-08-29): https://concentrate.ai/docs/api-reference/introduction https://concentrate.ai/docs/api-reference/endpoint/request-parameters https://concentrate.ai/docs/api-reference/endpoint/streaming https://concentrate.ai/docs/api-reference/endpoint/errors https://concentrate.ai/docs/api-reference/endpoint/list-models https://concentrate.ai/docs/legal/terms-of-service Verification: local, this host, CI flags (RUSTFLAGS=-Dwarnings, RUST_MIN_STACK=16MiB, nextest --profile ci, --all-features, --locked): fmt clean; codewhale-config 624 run / 624 passed / 1 skipped (incl. new concentrate_resolves_… and concentrate_passes_ids_through_and_strips_only_its_own_namespace, regenerated goldens); codewhale-secrets 62/62; codewhale-tui focused (concentrate + error_taxonomy + client::responses + llm_client + provider config + catalog filters) 440 run / 440 passed; debug CLI built; scripts/concentrate-selftest.sh PASS ×3 (concentrate/auto → wire `auto`, openai/gpt-5.6-sol, deepseek-v4-pro); scripts/check-provider-registry.py PASS; clippy config+secrets and tui (--all-targets --all-features, CI allow list) clean; web facts regenerated (providers 46) + check-facts OK; dead-code budget PASS; git diff --check clean. Not done: no live Concentrate canary (needs a key and founder-gated spend); Windows-target compile is hosted-CI-only on this host. No-Issue: provider addition requested by the founder; no tracking issue exists. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(cli): bump the provider registry counts for Concentrate (48 / 43) Hosted `Test (ubuntu-latest)` on #5725 failed exactly one test out of 13,958: `cli_provider_helpers_follow_config_metadata` still asserted the pre-Concentrate registry sizes (47 full / 42 catalog). The config crate's twin assertion was updated in the parent commit; this mirrors it. The rest of the test (env vars and secret-store slot per registry kind) already held for `concentrate`. Local: codewhale-cli 276 run / 276 passed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(providers): Concentrate review leftovers — alias, unauth 2xx, selftest [providers.concentrateai] was silently ignored on both config tables. GET /v1/models is unauthenticated, so a 2xx must not count as key proof — the probe is unobserved and health_check issues no request. Missing stub reply text now fails the selftest instead of exiting 0. Duplicate CONCENTRATE_BASE_URL assignment removed; retired launch_screen row dropped after the main merge. Proven: concentrate_resolves_named_responses_gateway_and_environment_overrides 1 passed; concentrate_health_check_does_not_treat_unauthenticated_models_as_key_proof plus two sibling Concentrate tests 3 passed; 0 failed. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 15 天前 | |
feat(providers): Concentrate as a first-class opt-in BYOK Responses gateway (#5725) * feat(providers): Concentrate as a first-class opt-in BYOK Responses gateway Adds `concentrate` (aliases `concentrate-ai`, `concentrate_ai`, `concentrateai`) inside the existing provider authorities — no parallel secret store, router, or runtime: - Identity/metadata: `ProviderKind::Concentrate`, hand-written `impl Provider` with `WirePolicy::Fixed(WireFormat::Responses)` (the gateway documents the Responses API as its production surface), default base URL `https://api.concentrate.ai/v1`, default model `deepseek-v4-pro`, env `CONCENTRATE_API_KEY` (+ `CONCENTRATE_BASE_URL`, `CONCENTRATE_MODEL`), its own secret-store slot, credential help. - Routing: aggregator-class pass-through. A plain catalog id lets the gateway choose the upstream provider, `provider/model` pins one, and only the gateway's own `concentrate/` namespace is stripped so `concentrate/auto` reaches its `auto` router while Codewhale's bare `auto` stays the resolver sentinel (provider default). - Wire: the Responses body carries only documented fields — `model`, `input`, `stream`, `max_output_tokens`, `tools`/`tool_choice`/ `parallel_tool_calls`, `reasoning.effort` — with the system prompt as a leading `system` input item (`instructions`, `store`, `include`, and `reasoning.summary` are absent from the gateway's parameter reference). Streaming rides the existing typed `response.*` SSE parser and ends on `response.completed` without a `[DONE]` sentinel. - Catalog: the unauthenticated `GET /v1/models` (OpenAI list shape) joins the named-gateway live-catalog path; rows stay provider-scoped and unclaimed. - Errors (provider-neutral): a 402 "insufficient credits/funds" body now classifies as quota (RateLimit) instead of falling through, and a flat `{"error":"<class>","message":"<detail>"}` body surfaces both halves in the TUI sanitizer instead of the class alone. - Registry parity: `ProviderKind::ALL` 42→43, registry 47→48, golden route ids + providers-export golden regenerated, `scripts/check-provider-registry.py` manual-impl allowlist, web facts label maps + `facts.generated.ts` (providers 45→46), docs rows in PROVIDERS.md (+ a Concentrate Notes section) and CONFIGURATION.md, CHANGELOG. Commercial boundary, preserved in code and docs: BYOK only. Concentrate's Terms of Service forbid resale, white-label, and service-bureau use without written consent and its AUP forbids key sharing, so there is no Codewhale-owned key, no stored customer key, no default or managed routing, and no markup; any hosted lane is gated on written consent, terms, and billing approval (ops evidence concentrate-gateway-20260829/CHECKLIST.md). A saved or environment Concentrate key is bound to the official base URL and is never sent to any other endpoint — a custom endpoint receives a key only when `base_url` and `api_key` are both written into `[providers.concentrate]`. Keyless dogfood: `scripts/concentrate-selftest.sh` boots `scripts/concentrate-stub.py` (the documented contract on loopback: `/v1/responses/health`, unauthenticated `/v1/models`, typed-SSE `/v1/responses`, documented error bodies) and drives the real `codewhale exec --auto --output-format stream-json` path through it, asserting the URL, bearer header, verbatim model, only-documented fields, system item first, the completed-turn receipt, and the wrong-key 401. No network call leaves the machine; no account exists in the loop. Contract sources (fetched 2026-08-29): https://concentrate.ai/docs/api-reference/introduction https://concentrate.ai/docs/api-reference/endpoint/request-parameters https://concentrate.ai/docs/api-reference/endpoint/streaming https://concentrate.ai/docs/api-reference/endpoint/errors https://concentrate.ai/docs/api-reference/endpoint/list-models https://concentrate.ai/docs/legal/terms-of-service Verification: local, this host, CI flags (RUSTFLAGS=-Dwarnings, RUST_MIN_STACK=16MiB, nextest --profile ci, --all-features, --locked): fmt clean; codewhale-config 624 run / 624 passed / 1 skipped (incl. new concentrate_resolves_… and concentrate_passes_ids_through_and_strips_only_its_own_namespace, regenerated goldens); codewhale-secrets 62/62; codewhale-tui focused (concentrate + error_taxonomy + client::responses + llm_client + provider config + catalog filters) 440 run / 440 passed; debug CLI built; scripts/concentrate-selftest.sh PASS ×3 (concentrate/auto → wire `auto`, openai/gpt-5.6-sol, deepseek-v4-pro); scripts/check-provider-registry.py PASS; clippy config+secrets and tui (--all-targets --all-features, CI allow list) clean; web facts regenerated (providers 46) + check-facts OK; dead-code budget PASS; git diff --check clean. Not done: no live Concentrate canary (needs a key and founder-gated spend); Windows-target compile is hosted-CI-only on this host. No-Issue: provider addition requested by the founder; no tracking issue exists. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(cli): bump the provider registry counts for Concentrate (48 / 43) Hosted `Test (ubuntu-latest)` on #5725 failed exactly one test out of 13,958: `cli_provider_helpers_follow_config_metadata` still asserted the pre-Concentrate registry sizes (47 full / 42 catalog). The config crate's twin assertion was updated in the parent commit; this mirrors it. The rest of the test (env vars and secret-store slot per registry kind) already held for `concentrate`. Local: codewhale-cli 276 run / 276 passed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(providers): Concentrate review leftovers — alias, unauth 2xx, selftest [providers.concentrateai] was silently ignored on both config tables. GET /v1/models is unauthenticated, so a 2xx must not count as key proof — the probe is unobserved and health_check issues no request. Missing stub reply text now fails the selftest instead of exiting 0. Duplicate CONCENTRATE_BASE_URL assignment removed; retired launch_screen row dropped after the main merge. Proven: concentrate_resolves_named_responses_gateway_and_environment_overrides 1 passed; concentrate_health_check_does_not_treat_unauthenticated_models_as_key_proof plus two sibling Concentrate tests 3 passed; 0 failed. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 15 天前 | |
feat(plugins): bundle-mode conversion for real dsh packages in convert-plugin.py --bundle <package-dir> consumes a real dsh npm bundle end to end: reads package.json -> dsh.bundle.patch -> parses cordis.patch.yml with !!js tags captured (never evaluated), applies the patch list with applyEntryPatches parity (insert, group inserts, keyed overrides), lowers the three !!js idioms (process.execPath -> node, process.env.X || 'literal', template paths), snapshots stdio arg host directories into mcp/<server>, imports dsh-skill-filesystem rows as customSkillDirs skills, and routes everything unportable into CONVERSION.md as named diagnostics instead of dropping it. Verified against our own codewhale-cu-plugin/integrations/dsh reference bundle (previously could not round-trip): 1 MCP declaration prepared, mcp/computer-use/server.mjs snapshotted from the installed app, tool timeout and version carried over. All 46 converter tests pass, including 6 new bundle-mode tests (patch evaluation, !!js lowering, group inserts, skill import, non-execution guarantees). Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 23 小时前 | |
chore(tui): normalize stale dead_code allows and ratchet budget (#5587) Strip 112 uncommented `#[allow(dead_code)]` across crates/tui/src and let the compiler re-adjudicate each under `-D warnings` in every target: - ~50 items are prod-dead but test-reached: `#[cfg_attr(not(test), expect(dead_code))]` asserts that and self-verifies against future callers. - ~33 items are dead in every build (documented wire captures, reserved enum variants, pre-wired seams): `#[expect(dead_code)]` keeps them honestly. - `install`/`update` (skills) and `log_exec`/`append_log_static` (shell_dispatcher) are used only from the `#[path]`-included integration crate: `#[cfg_attr(test, allow(dead_code))]` covers exactly those compiles. - `utils::ensure_dir` had zero callers and no stated intent: deleted. - `subagent_routing` one cfg_attr was fully stale (used in both builds): gone. Budget ratchets 369 -> 254. Verified: cargo check --all-targets --locked clean, fmt clean, integration 177 passed / 0 failed. | 2 天前 | |
chore(scripts): dev-cache warns before it fills a disk The #5465 wedge was dev-cache.sh putting ~6 GB build dirs on a volume with 6.5 GiB free and running it to ENOSPC. Add a free-space probe: warn when the volume holding the cache root has less than CODEWHALE_DEV_CACHE_MIN_FREE_GIB free, name the cold-build cost (~6 GB), and point at the escape hatches (CODEWHALE_CACHE_ROOT, the volume-preference envs). Dev tooling only; no product behavior changes. | 29 天前 | |
fix(dev-cache): isolate build-dir even when a stub ./target exists Cargo still writes CACHEDIR.TAG (and sometimes final artifacts) under ./target when build-dir is split, so the old auto-mode treated a freshly-isolated worktree as warm on the second command and recompiled everything into a second tree. auto now always isolates; CODEWHALE_DEV_CACHE=local is the explicit stay-in-./target opt-out. dev-cache.test.sh: all 22 checks pass on this tree. | 1 个月前 | |
fix(tests): adopt shared home isolation in test entry points Reuse the existing hermetic-home launcher for GitHub CI, release, CNB and dev-test. Preserve persistent Cargo caches, toolchain homes, migration fixtures, selectors and release authority. Validation: 8 synthetic launcher tests, 22 cache checks and 11 CI-wiring tests passed. Release workflow contracts passed, including 11 protected test invocations. Shell syntax, shellcheck -x, scoped actionlint and three-document YAML scope checks passed. Unfiltered actionlint retains pre-existing diagnostics in unchanged run blocks. No Cargo or Rust tests run in this slice. | 8 天前 | |
fix(tests): adopt shared home isolation in test entry points Reuse the existing hermetic-home launcher for GitHub CI, release, CNB and dev-test. Preserve persistent Cargo caches, toolchain homes, migration fixtures, selectors and release authority. Validation: 8 synthetic launcher tests, 22 cache checks and 11 CI-wiring tests passed. Release workflow contracts passed, including 11 protected test invocations. Shell syntax, shellcheck -x, scoped actionlint and three-document YAML scope checks passed. Unfiltered actionlint retains pre-existing diagnostics in unchanged run blocks. No Cargo or Rust tests run in this slice. | 8 天前 | |
refactor: extract palette into its own crate and move command_safety to execpolicy Two more modules out of the TUI monolith, on the same evidence as the localization extraction: a dependency census that counted `crate::` mentions inside doc comments and `#[cfg(test)]` blocks made these look entangled. With comments and test code excluded, both had **zero** real production dependencies on the rest of the crate. `palette` -> `codewhale-palette` (5,850 lines). Theming and colour tokens, with a wide but shallow consumer rewrite. No contrast or colour value changed while moving; `scripts/export-design-tokens.py` and the `check:tokens` gate follow the new path, and the gate passes with 64 tokens unchanged. Two OSC probes (`osc11::query_terminal`, used by `tui::mark` for the kitty graphics query) had to widen from `pub(crate)` to `pub` to cross the new crate line — a terminal capability query, not a trust boundary, and stated here rather than left for a reader to notice. `command_safety` -> `crates/execpolicy` (2,951 lines). Deliberately **not** a new crate: execpolicy already owns `ApprovalMode` and approval policy, and a `codewhale-command-safety` beside it would be a second authority for one concern. This is security-relevant code that classifies whether a shell command is safe to run, so it moved unchanged — not one classification rule, allowlist entry or matcher was touched. `crates/tui` already depended on execpolicy, so this move *removes* a dependency edge rather than adding one, which is the ideal shape for this work. The CI step that ran its tests under `codewhale-tui` now picks them up from the `codewhale-execpolicy` run on the line below it. crates/tui: 973,442 -> 957,746 lines across this session's three extractions. Verified: cargo check --workspace --all-targets 0 errors, 0 unused warnings cargo test -p codewhale-palette 81 passed; 0 failed cargo test -p codewhale-execpolicy 188 + 1 + 5 passed; 0 failed cargo test -p codewhale-localization 51 passed; 0 failed scripts/check-tui-locale-parity.py PASS scripts/export-design-tokens.py --check up to date, 64 tokens No new tests: the moved suites passing unchanged is the proof a move is correct. Refs: Linear C03-C10 / SHA-6179, docs/design/TUI_DECONSTRUCTION.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL | 7 天前 | |
scripts: report where Rust build output actually lives Read-only inventory of the three places build output accumulates. It never deletes, moves, or writes anything — reclaiming hundreds of gigabytes is a human decision, and this is the evidence for it. Prompted by a founder-shared article on multi-agent worktrees, whose Problem 5 is exactly this: agents build far more often than people do, `dev-cache.sh` already isolates a build dir per workspace so parallel agents do not share one Cargo lock, and nothing ever collects those directories when a worktree goes away. My first read of this workspace was wrong twice, which is why the tool exists rather than a one-off command: - I counted the cache by listing one directory level. Cargo expands `{workspace-path-hash}` to a TWO-level `XX/YYYYYYYYYYYYYY` path, so I counted 213 entries where there are 373 build roots, and concluded "zero build dirs match a live worktree" from what was really a name-matching artifact. - I left out per-checkout `target/` dirs entirely — 253 GiB, including the main checkout's own 153 GiB, the single largest object on the volume. Real total: 782 GiB (529 GiB across 373 cache build roots, 253 GiB in 13 checkout target dirs). Build roots are identified by their `CACHEDIR.TAG` signature rather than by directory name, because the name is a hash; the walk does not assume a depth, so a future Cargo layout change fails loudly instead of returning nothing. The cache root is asked of `dev-cache.sh` itself rather than re-derived, so the two cannot drift. Worktree classification is deliberately NOT reimplemented — `scripts/workspace-status.sh` already owns which worktrees exist, which are merged and which are dirty, and the report points at it rather than growing a second answer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 13 天前 | |
ci: stop the persistence RSS check rebuilding the workspace `check-persistence-backlog-budget.py` runs its measurement through `cargo test -p codewhale-tui --lib` with default features, but the step before it on the same runner is `cargo nextest run --workspace --all-features --locked`. This crate's `--all-features` adds `web` and `long-running-tests` on top of the default `tui,json,toml`, so the two are a different feature unification and Cargo rebuilds the crate and everything downstream of it rather than reusing what was just compiled. It is the second-largest step in the macOS leg: 10 minutes of a 71-minute job, for a test that runs in well under a second. Measured locally, the same command against a warm tree of the *other* feature set takes 9.5s when the features match and 132s when they do not — the delta is entirely the rebuild. Aligning the flag makes the measurement reuse the nextest artifacts. The measured test is unchanged and still runs `--exact --ignored --test-threads=1`, which is what the receipt's determinism depends on. | 29 天前 | |
fix(gates): measure the library runtime contract Run each ignored receipt test against its exact library path and reject Cargo's successful zero-test result explicitly. Keep the standalone tool-catalog measurement and current verification guidance on the same target, with hermetic command and failure regressions wired into CI. The repaired measurement exposed a real duplicate AGENTS.md injection from the bounded fragment importer. Keep canonical project-context sources single-owned while still importing additional rule formats through the typed, capped fragment boundary; this restores the checked-in prompt identity without raising the budget. Verified with the full 55-metric runtime-contract checker, focused core and TUI regressions, both Python harness suites, cargo fmt, and all-target clippy for codewhale-core and codewhale-tui. | 1 个月前 | |
fix(gates): measure the library runtime contract Run each ignored receipt test against its exact library path and reject Cargo's successful zero-test result explicitly. Keep the standalone tool-catalog measurement and current verification guidance on the same target, with hermetic command and failure regressions wired into CI. The repaired measurement exposed a real duplicate AGENTS.md injection from the bounded fragment importer. Keep canonical project-context sources single-owned while still importing additional rule formats through the typed, capped fragment boundary; this restores the checked-in prompt identity without raising the budget. Verified with the full 55-metric runtime-contract checker, focused core and TUI regressions, both Python harness suites, cargo fmt, and all-target clippy for codewhale-core and codewhale-tui. | 1 个月前 | |
test: bound the mobile non-loopback rejection probe Run the negative binding check with a ten-second deadline and a dedicated process group. If a regression starts a server, kill and reap the probe and count the timeout as a failure instead of accepting its nonzero status. Reuse Python, already required by the script's ephemeral port selection. Validation: real mobile smoke 9 passed, 0 failed; bash syntax and diff checks passed. A real-server negative control intentionally accepts the invalid request on loopback: 8 passed, 1 failed in bounded time, exit 1, and the probe process was reaped. Existing Rust source is unchanged. Root npm test and check:web scripts are unavailable; no npm gate or new hosted CI claimed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 12 天前 | |
fix(ohos): wrap Windows final links Point Cargo's Windows OHOS linker at a repository-local cmd launcher that delegates to the existing PowerShell clang wrapper. This keeps the target triple, SDK sysroot, and MUSL define on the final Rust link while preserving Cargo's arguments and the native linker exit status. Extend the no-SDK release gate and documentation to protect the full linker and rquickjs bindgen contract. Follow-up evidence from @shenjackyuanjie's PR #4470 completes the Windows linker path alongside @shenyongqing's original bindgen approach in PR #4384. Co-authored-by: shenjackyuanjie <54507071+shenjackyuanjie@users.noreply.github.com> Signed-off-by: Hunter B <hmbown@gmail.com> | 1 个月前 | |
add some fix for ohos | 1 个月前 | |
fix(custom): wire = responses|anthropic for openai-compatible + opencode-zen muse-spark (rescue of #5716) (#5719) * ci: add Windows x64 build workflow on push to main * fix: trigger build-windows on any push to main * fix(custom): support wire = "responses" | "anthropic" | "chat" for kind="openai-compatible" Custom provider was fixed to ChatCompletions, ignoring providers.<name>.wire. Now honors per-config wire in both client::provider_wire_format_for_config and config::provider_capability, keeping Custom::wire_policy default as Chat for compat. Aliases: responses/openai-responses/responses-api -> Responses; anthropic/messages/claude -> AnthropicMessages; default -> Chat. Fixes custom muse-spark-1.2 on opencode.ai/zen/v1 needing Responses. * fix(opencode-zen): route muse-spark over Responses API Muse Spark 1.2 contributor-free on https://opencode.ai/zen/v1 only supports POST /v1/responses (Responses API) and rejects Chat Completions. Previously the bundled offering roster and ModelAware resolver treated unknown muse-spark variants as chat or failed closed to unproven, so CodeWhale sent chat payloads that 404. - Add muse-spark-1.2, -contributor, -contributor-free to OPENCODE_ZEN_RESPONSES_MODELS (bundled_offerings) - Add resolver fallback: any muse-spark* under OpencodeZen resolves to endpoint_key responses even without exact catalog match - Update config.example.toml docs (GPT/Muse Spark -> Responses) and add muse-spark-1.2-contributor-free example - Add scripts/opencode-chat2responses-proxy.mjs as zero-Rust chat->responses shim for chat-only clients Custom gateways can already use wire="responses" (ff504585a); this fix makes the first-class opencode-zen provider work without hand-written wire config. * fix(client): keep codex env-token auth working on custom endpoints PR #5716 diverted OpenaiCodex credential resolution to the generic key resolver whenever provider_uses_custom_endpoint() is true, which dropped an explicit OPENAI_CODEX_ACCESS_TOKEN for custom-base-url setups. The shared-seam wiremock test proves the regression: the mock only answers Bearer test-token, so the request came back 404 on all three CI OSes (client::responses::tests::responses_stream_open_preserves_wire_headers_ through_shared_seam). The manual if-condition formatting also failed the Lint job's cargo fmt --check. Restore the pre-PR precedence by trying codex_credentials() first: env credentials still win on custom endpoints (codex_credentials checks env before the official-endpoint consent grant), the official endpoint keeps propagating OAuth errors, and only a custom endpoint with no env token falls back to deepseek_api_key() — preserving the contributor's goal of letting a custom endpoint authenticate with its own configured key. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * refactor(tui): route wire-dialect reads through one Config helper The wire= feature read providers.<id>.wire in two places (client wire resolution and the capability reporter), and provider_capability_with_ wire was exported but never called with a real value — a parallel entry point that reported Chat for custom providers the client actually speaks Responses/Messages to. - Add Config::provider_wire_dialect() as the single trimmed, non-empty wire reader; use it in provider_wire_format_for_config and the doctor capability report (provider_capability_with_wire). - Drop the over-broad '|| normalized.contains("responses")' from wire_config_prefers_responses in both modules: every listed alias except the singular 'response'/'response-api' spellings already contains the substring, so the fallback only admitted unintended values like 'not-responses'. - Remove the vestigial 'let _ = provider_kind;' marker in the resolver arm that now genuinely uses provider_kind. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * revert(ci): drop contributor-added build-windows workflow The PR added a Build Windows x64 workflow triggering on every push to main. That build is already covered: release-artifacts.yml builds both x86_64-pc-windows-msvc and aarch64-pc-windows-msvc release binaries, nightly.yml rebuilds them nightly, and ci.yml runs the full test matrix on windows-latest. A fourth always-on Windows build only spends CI minutes on every main push and grants the job an actions:write permission it does not need. Contributor CI-workflow additions are outside this feature's scope; restoring main's tree (no such file). Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: whp233 <whp233@users.noreply.github.com> Co-authored-by: CodeWhale Bot <bot@codewhale.net> | 16 天前 | |
chore(tui): tighten the persistence backlog budget to the coalesced shape (#6212) Re-baseline after the sender-side coalescing move: the paused-consumer fixture now retains 1 coalesced entry (66,625 bytes estimated) where the unbounded channel retained 128 requests (8,527,994 bytes). Ceilings drop from 128/8,529,280 to 4/96,256 — the fixture is single-session, so 4 covers the coalesced entry plus wake-epoch headroom; 96,256 bytes is ~45% above the observed sample and still bounds a second concurrent session's snapshot. check-persistence-backlog-budget.py: PASS (one-way ceilings respected, no further tightenings suggested) Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 天前 | |
chore(tui): tighten the persistence backlog budget to the coalesced shape (#6212) Re-baseline after the sender-side coalescing move: the paused-consumer fixture now retains 1 coalesced entry (66,625 bytes estimated) where the unbounded channel retained 128 requests (8,527,994 bytes). Ceilings drop from 128/8,529,280 to 4/96,256 — the fixture is single-session, so 4 covers the coalesced entry plus wake-epoch headroom; 96,256 bytes is ~45% above the observed sample and still bounds a second concurrent session's snapshot. check-persistence-backlog-budget.py: PASS (one-way ceilings respected, no further tightenings suggested) Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 天前 | |
fix(tui): complete Tideline shell integration | 16 天前 | |
fix(ci): green main's Lint and unblock the 0.9.14 release gates (#6268) * fix(ci): green main's Lint and unblock the 0.9.14 release gates Four gates that main currently fails. All four are advisory on pull requests (`continue-on-error: ${{ github.event_name == 'pull_request' }}`) and **fatal on push**, which is why `Lint` has been red on main since 04:08Z while every PR rollup looked green — CI runs 35054467418, 35054908721 and 35050587333 all failed `Lint` on exactly these. 1. Blocking-call budget: `crates/tui/src/tools/shell.rs` std_fs 2 -> 3. #6208's Q6 (e522e4f93c) replaced `if !path.exists()` with `std::fs::metadata(&path)` in `load_default_policy`. The checker counts the textual `std::fs::` form, so an equivalent stat that was previously uncounted became counted. Net blocking work went *down*: the same call now also carries the cache key that removed a full read plus TOML parse and regex recompile from every shell execution. `load_default_policy` is a synchronous fn, so the site cannot move to `spawn_blocking` without restructuring its callers — this is the "raise the budget if the site can only run on synchronous code" case the checker names. 2. Runtime contract budget: Act/Operate full catalogs gain `session_get` and `session_search` (50 -> 52 tools). #5715 (eefdcb42f507) added them as bounded read-only workspace-scoped recall. `--update` deliberately refuses identity changes, so this is the explicit maintainer edit the `_comment` history calls for, with a note appended in that style. Plan full is unchanged — the session tools are not offered there. 3. Feature release-note receipts: seven feature commits since v0.9.13 referenced six issues with no changelog entry, which is advisory in PR CI but **blocking on every release path** (check-versions.sh:33-38). Added entries for #5715, #6099, #6035 (Added) and #6033, #6085 (Changed), and attached #6151 to the two edit-gating entries whose commits carry that reference. 4. The `[Unreleased]` compare link still pointed at v0.9.12; check-versions only validates the link for the current workspace version, so it went unnoticed across a release. Verification on this machine (macOS aarch64, source 55a9e1b778fa): [runtime-contract-budget] PASS: all 55 metrics are exactly at budget. blocking-call budget: 626 sites across 181 files, within budget Feature release-note receipts OK: 16 linked issue reference(s) checked in v0.9.13..HEAD. Version state OK: workspace=0.9.13, npm=0.9.13, npm-binary=0.9.13, lockfile in sync. Ran 19 tests in 0.015s OK (test_check_runtime_contract_budget.py) Ran 3 tests in 0.000s OK (test_measure_runtime_contract.py) Not verified here: the runtime-contract byte/token ceilings are measured from macOS. The `_comment` history records that macOS measurements have under-counted before and had to be re-locked from a Linux Lint run (2026-09-13, after b4d48e9a4). If CI's Lint reports numeric drift on these values, re-lock them from that run rather than re-measuring locally; the name-set identities and digests are host-independent and will not move. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(web): regenerate the changelog module for the 0.9.14 entries `web/lib/changelog.generated.ts` is derived from CHANGELOG.md by `web/scripts/derive-changelog.mjs`, and `lib/changelog.test.ts` asserts the committed file matches a fresh derivation. The five release-note receipts added in 095f1ef62 changed the derivation, so the check failed: AssertionError: expected '// AUTO-GENERATED by web/scripts/deri…' to be '// AUTO-GENERATED by web/scripts/deri…' Test Files 1 failed | 50 passed (51) Tests 1 failed | 469 passed (470) Regenerated with the script rather than hand-edited. After: [derive-changelog] wrote 6 releases → lib/changelog.generated.ts Test Files 1 passed (1) Tests 6 passed (6) Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 天前 | |
fix(release): stop sync-changelog dropping a release for Unreleased (#3768) `scripts/sync-changelog.sh` regenerates the binary-embedded `crates/tui/CHANGELOG.md` as a rolling window of the most recent KEEP (15) `## [` sections. It counted `## [Unreleased]` as one of those sections, so whenever Unreleased had content the window silently dropped the oldest *released* version. Adding the `## [0.8.66]` entry on the release candidate is exactly what pushed `## [0.8.52]` out of the embedded changelog. Count only released versions toward the keep window; `## [Unreleased]` is always kept but never consumes a slot. The window now tracks a stable number of releases regardless of in-progress notes, so: - on `main` the embedded changelog regains the previously-dropped `0.8.51`; - on the release branch (where `0.8.66` is added) `0.8.52` is retained instead of being silently deleted. `check-versions.sh` runs `sync-changelog.sh --check`, which stays consistent because it uses the same script. Fixes #3768 | 2 个月前 | |
fix(tui): pin marketplace sources and keep transcript drags out of the composer Install sources in the bundled first-party marketplace snapshot pointed at the moving `refs/heads/main` archive while the catalog displayed a reviewed revision, so the bytes a user installed were not the bytes the snapshot described and `/plugin update` re-downloaded a whole-repository tarball that changed with every unrelated commit. Pin each source to the snapshot's revision; freshness comes from bumping the pin, which the marketplace-sync workflow already reports weekly, and `update` now finds no change until the pin moves. The store test and acceptance fixture contracts are unchanged. A transcript selection or scrollbar drag released over the composer was consumed by the composer handler: the caret moved, a composer selection started and the transcript drag flag never cleared. Let the surface that started the drag finish it. Document local-time and DST evaluation, missed-run coalescing, overlap protection and approval behavior for automations. Validation: tui::mouse_ui tests and plugins::marketplace tests passed (0 failed); the regenerated snapshot is byte-identical to the sync script's output for the pinned revision. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 4 天前 | |
ci: isolate Buildkite tests from personal Fleet state Reuse the TUI hermetic-home convention through one shared command wrapper. Seal nextest and doctests, including the existing unprivileged Linux path, without changing selected-Fleet validation or runner configuration. Remove inherited canonical/legacy home and config overrides so per-test fixtures keep precedence. Preserve the real toolchain homes and explicit stack settings, defaulting to the existing 16 MiB CI stack. Point the TUI runner at its actual library tests instead of the empty executable target. Validation on macOS, with Cargo offline and synthetic outer state: - Old representative Fleet invocation: 0 passed / 1 failed (expected). - Isolated identical invocation: 1 passed / 0 failed; outer hashes unchanged. - Full Buildkite script: 14,231 passed / 0 failed / 15 skipped; no LEAK. - Doctests: 3 passed / 0 failed / 8 ignored. - Focused Fleet/settings/log tests: 105 passed / 0 failed. - Boundary shell cases: 3 passed / 0 failed. - Migrated TUI config-panel golden test: 1 passed / 0 failed; nonzero asserted. - Shell syntax, ShellCheck, and git diff --check passed. Preserved initial full run: 14,187 passed / 44 failed / 15 skipped (43 config/home assertions and one unproven-cause plugin PTY timeout). The initial library-target smoke overflowed the default thread stack; it passes with the existing CI default. Full Buildkite already used 16 MiB. Root npm test and npm run check:web both exit 1: missing scripts, zero tests. Hosted CI and the Linux uid transition were not executed locally. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 12 天前 | |
fix(ci): stop the blocking-call ratchet taxing extracted test files, and unred main `Lint` is failing on `origin/main` at "Check blocking-calls budget" (run 35126167644, sha 9a674f47f). The check is `continue-on-error` on `pull_request` and fatal on `push`, so #6096 went green as a PR and turned `main` red the moment it merged — the exact asymmetry that lets a red `main` go unnoticed. Two separate things were wrong, and only one of them was a budget question. **The ratchet could not see whole-file test modules.** Its docstring says it skips test code, and `file_counts` does recognise `#[test]`, `mod tests` and `fn test_*` — but a file that is *entirely* a test module knows nothing about it, because that fact lives in the parent's `#[cfg(test)] mod foo;` declaration. So extracting a test suite into its own file made untouched call sites look new. `session_export_regression_tests.rs` and `session_export_surface_tests.rs` are declared `#[cfg(test)]` at `commands/mod.rs:36-41`; they were counted anyway. `cfg_test_module_files()` now resolves those declarations and excludes the files they name. That is a tightening, not a loosening. Six existing test files (`telemetry/src/tests.rs`, `dsh/tests.rs`, `skills/tests.rs`, `test_support.rs`, `subagent/tests.rs`, `golden_harness.rs`) were carrying budgets totalling 27 sites that the ratchet should never have been counting. Those entries are gone, so 27 sites can no longer hide inside an allowance. **The remaining two sites are a relocation, not new debt.** `commands/groups/session/export.rs` was budgeted `std_fs: 4`; #6096 moved those four verbatim into `commands/session_export_host.rs`, which had no entry. Same four calls, same synchronous callers — `SessionExportAdapter`'s trait methods at `contract.rs:1549/1563/1567` are `fn`, not `async fn`. The budget moves with the code. `crates/memory/src/main.rs:371` is one `std::fs::canonicalize` inside `fn main()`, which the ratchet's own docstring names as fine ("synchronous entry points"). Audited the regenerated JSON rather than trusting `--update`: two entries added (both verified above), seven removed, **zero existing budgets raised**, 181 files down to 176. Two tests pin the new behaviour — a `#[cfg(test)] mod` declaration excludes the file it names, and a plain `mod` declaration does not, so the exclusion cannot quietly widen to production code. Tests: `python3 scripts/test_check_blocking_calls_budget.py` — Ran 11 tests, OK (9 before). `python3 scripts/check-blocking-calls-budget.py` — "600 sites across 176 files, within budget", exit 0, where it exited 1 with four offenders before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 13 小时前 | |
test(FEAT-025): pin the export slice with baseline-captured goldens and gates Behaviour preservation is proven rather than claimed. Four goldens were captured from the pre-refactor implementation at `3f3aa9ed7` by dispatching frozen fixtures through the baseline public `/export` seam in a scratch worktree: - authoritative transcript with no restore repository (header, every content variant, D9 omission markers, redaction, ANSI stripping), - the turn handoff, - the visible-history fallback over a workspace with recorded restore points, - correlation against recorded restore points (table, newest-first order, `tool` snapshots listed but not correlated, the ambiguous double match, and the no-match line). Only genuinely clock-derived fields are normalised (the export stamp, the turn header stamp, and - for the recorded states - the snapshot id and `Recorded (UTC)` cell, because `git commit-tree` uses a wall-clock date). A unit test pins the normaliser so it cannot quietly widen. Everything else is byte-compared. Also here: the exhaustive `ContextParts` assertion that makes "no unrelated facet" a compile-time guarantee, the shared host-bound test-support module, the token-aware extraction audits plus their own unit test, and the boundary gate extension that keeps `codewhale-secrets` free of any TUI edge. Carries one unrelated, disclosed repair: a bounded retry for a fork/exec `ETXTBSY` race in the `wl-paste` regression, kept because the configured workspace gate was intermittently red without it. Generated with CodeWhale | 22 小时前 | |
fix(ci): qualify native image tests and preserve main migration history Keep the real sips resize integration assertions on macOS; Linux has no sips. When main equals origin/main, compare migration topology with its first parent instead of treating an existing frontier as initialization. Preserve feature-branch merge-base checks and reject arbitrary growth. Validation: native Computer Use 196 passed, 15 platform skips; migration regressions 60 passed; live manifest gate passed. npm test: 66 wrapper + 9 SDK + 446 web passed. npm run check:web passed (0 errors, 2 existing image warnings). git diff --check passed. | 5 天前 | |
test(tui): preserve persistence baseline evidence Commit the raw clean-SHA macOS receipt behind the persistence backlog budget, require it to match every recorded metric and provenance field, and close Python boolean/integer alias plus impossible zero-retention gaps on the budget side. | 1 个月前 | |
fix: route every reqwest client through codewhale_release::tls (#6153) Bare Client::builder()/new() under rustls-no-provider panics before the first provider install. Add a Lint gate (scripts/check-reqwest-builders.py + hermetic test, wired into ci.yml) and sweep the 17 remaining call sites onto tls/platform builders, dropping the hand-installed providers. Gate: test_check_reqwest_builders.py 5/5 ok; check fails with 17 hits before the sweep, passes after. clippy workspace clean. | 3 天前 | |
Pin the runtime tool metric to an explicit shell profile The ignored tool-catalog metric inherited SHELL, so the same signed8fbd binary measured14,701 active bytes under /bin/zsh and15,151 under pwsh. Pin existing SHELL=bash after the fixture's empty PATH; no interpreter is executed or installed. Record the actual detected binary in a versioned profile, fail if an already-initialized dispatcher defeats the pin, and reject missing or mismatched shell evidence in the existing budget checker. A fresh-process regression compares complete metrics under two inherited shells. Production tool selection, dispatch and permission code is unchanged. Reconcile only the intentional hidden tts identity/count already measured on signed8fbd and explained by d8e8ecf5a1. No byte/token ceiling is raised. Final numeric reconciliation remains pending root's fresh merged artifact. Validation: measurement harness3pass0fail; checker harness19pass0fail; cargo fmt --all -- --check and git diff --check pass. Five exact metric processes on signed8fbd prove ambient-shell divergence and byte-identical metrics when the proposed bare-bash setting is applied externally. These are old-binary input-setting proofs, not compiled-new-fixture evidence. New Rust fixture regression/full Cargo compilation explicitly UNRUN here; root owns the fresh signed build and final measurement. | 8 天前 | |
refactor: extract palette into its own crate and move command_safety to execpolicy Two more modules out of the TUI monolith, on the same evidence as the localization extraction: a dependency census that counted `crate::` mentions inside doc comments and `#[cfg(test)]` blocks made these look entangled. With comments and test code excluded, both had **zero** real production dependencies on the rest of the crate. `palette` -> `codewhale-palette` (5,850 lines). Theming and colour tokens, with a wide but shallow consumer rewrite. No contrast or colour value changed while moving; `scripts/export-design-tokens.py` and the `check:tokens` gate follow the new path, and the gate passes with 64 tokens unchanged. Two OSC probes (`osc11::query_terminal`, used by `tui::mark` for the kitty graphics query) had to widen from `pub(crate)` to `pub` to cross the new crate line — a terminal capability query, not a trust boundary, and stated here rather than left for a reader to notice. `command_safety` -> `crates/execpolicy` (2,951 lines). Deliberately **not** a new crate: execpolicy already owns `ApprovalMode` and approval policy, and a `codewhale-command-safety` beside it would be a second authority for one concern. This is security-relevant code that classifies whether a shell command is safe to run, so it moved unchanged — not one classification rule, allowlist entry or matcher was touched. `crates/tui` already depended on execpolicy, so this move *removes* a dependency edge rather than adding one, which is the ideal shape for this work. The CI step that ran its tests under `codewhale-tui` now picks them up from the `codewhale-execpolicy` run on the line below it. crates/tui: 973,442 -> 957,746 lines across this session's three extractions. Verified: cargo check --workspace --all-targets 0 errors, 0 unused warnings cargo test -p codewhale-palette 81 passed; 0 failed cargo test -p codewhale-execpolicy 188 + 1 + 5 passed; 0 failed cargo test -p codewhale-localization 51 passed; 0 failed scripts/check-tui-locale-parity.py PASS scripts/export-design-tokens.py --check up to date, 64 tokens No new tests: the moved suites passing unchanged is the proof a move is correct. Refs: Linear C03-C10 / SHA-6179, docs/design/TUI_DECONSTRUCTION.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL | 7 天前 | |
feat(plugins): bundle-mode conversion for real dsh packages in convert-plugin.py --bundle <package-dir> consumes a real dsh npm bundle end to end: reads package.json -> dsh.bundle.patch -> parses cordis.patch.yml with !!js tags captured (never evaluated), applies the patch list with applyEntryPatches parity (insert, group inserts, keyed overrides), lowers the three !!js idioms (process.execPath -> node, process.env.X || 'literal', template paths), snapshots stdio arg host directories into mcp/<server>, imports dsh-skill-filesystem rows as customSkillDirs skills, and routes everything unportable into CONVERSION.md as named diagnostics instead of dropping it. Verified against our own codewhale-cu-plugin/integrations/dsh reference bundle (previously could not round-trip): 1 MCP declaration prepared, mcp/computer-use/server.mjs snapshotted from the installed app, tool timeout and version carried over. All 46 converter tests pass, including 6 new bundle-mode tests (patch evaluation, !!js lowering, group inserts, skill import, non-execution guarantees). Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 23 小时前 | |
ci: give every main SHA a verdict and add a hermetic safety gate Test bankruptcy is a scheduling problem, not a rotten suite. With one concurrency group per branch, GitHub cancelled pending main runs when the next merge queued — 31 of the last 40 main CI runs never finished. Key non-PR runs by SHA so each commit actually gets a result. PRs still cancel superseded heads. Add a 15-minute Safety gate job for command_safety / auto_review / authority / sandbox / execpolicy. The 71-minute macOS Test job stays until a summary job exists for protect-main; nothing was deleted. Also align the persistence-backlog argv contract with the --all-features flag that stopped that check from rebuilding the workspace. | 29 天前 | |
fix(gates): measure the library runtime contract Run each ignored receipt test against its exact library path and reject Cargo's successful zero-test result explicitly. Keep the standalone tool-catalog measurement and current verification guidance on the same target, with hermetic command and failure regressions wired into CI. The repaired measurement exposed a real duplicate AGENTS.md injection from the bounded fragment importer. Keep canonical project-context sources single-owned while still importing additional rule formats through the typed, capped fragment boundary; this restores the checked-in prompt identity without raising the budget. Verified with the full 55-metric runtime-contract checker, focused core and TUI regressions, both Python harness suites, cargo fmt, and all-target clippy for codewhale-core and codewhale-tui. | 1 个月前 | |
fix(ci): give native Windows tests valid isolated home paths Translate Git Bash homes for native tools while retaining POSIX PATH semantics, provision isolated AppData folders, and keep cleanup bound to the original temporary path. Recovered Gemini donor reviewed and corrected by the coordinator. Validation: 9 hermetic-home shell tests and 22 dev-cache shell tests passed, 0 failures. These offline path fixtures do not prove execution on a native Windows runner; hosted Windows acceptance remains pending. | 8 天前 | |
fix(ci): give native Windows tests valid isolated home paths Translate Git Bash homes for native tools while retaining POSIX PATH semantics, provision isolated AppData folders, and keep cleanup bound to the original temporary path. Recovered Gemini donor reviewed and corrected by the coordinator. Validation: 9 hermetic-home shell tests and 22 dev-cache shell tests passed, 0 failures. These offline path fixtures do not prove execution on a native Windows runner; hosted Windows acceptance remains pending. | 8 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 天前 | ||
| 16 天前 | ||
| 29 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 12 小时前 | ||
| 13 小时前 | ||
| 25 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 13 小时前 | ||
| 13 小时前 | ||
| 22 小时前 | ||
| 5 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 12 天前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 3 天前 | ||
| 8 天前 | ||
| 7 天前 | ||
| 7 天前 | ||
| 13 天前 | ||
| 15 天前 | ||
| 15 天前 | ||
| 23 小时前 | ||
| 2 天前 | ||
| 29 天前 | ||
| 1 个月前 | ||
| 8 天前 | ||
| 8 天前 | ||
| 7 天前 | ||
| 13 天前 | ||
| 29 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 12 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 16 天前 | ||
| 1 天前 | ||
| 1 天前 | ||
| 16 天前 | ||
| 1 天前 | ||
| 2 个月前 | ||
| 4 天前 | ||
| 12 天前 | ||
| 13 小时前 | ||
| 22 小时前 | ||
| 5 天前 | ||
| 1 个月前 | ||
| 3 天前 | ||
| 8 天前 | ||
| 7 天前 | ||
| 23 小时前 | ||
| 29 天前 | ||
| 1 个月前 | ||
| 8 天前 | ||
| 8 天前 |