refactor(tui): adopt command shapes in plugins group (FEAT-020) - #5657
Merged
Conversation
added 7 commits
August 27, 2026 01:34
…es to command contract - CommandPluginContext: object-safe synchronous facet covering registry reads/mutations, async-bridged install/update/uninstall with sync receipts (D11), export, legacy scan, kimi managed import, and marketplace - Portable DTOs: PluginSummary/Detail/Diagnostic/McpServerDetail, mutation outcome+receipt, export receipt, legacy tool+scan, managed candidate+scan, marketplace catalog/candidate/add/state, suggestion - PLUGIN = 1 << 10 capability bit and one plugin envelope slot with with_plugin builder - Contract tests: object safety, field/variant closure, sync receipt outcomes, exact-hash mismatch, managed/marketplace portability, envelope transport, duplicate-slot rejection, bit stability - Contract boundary gate green; workspace compiles; fmt clean; 23/23 contract tests pass Generated with Claude Code
…misleading receipts Code-review finding: trust/enable/disable/revoke_trust returned a PluginMutationReceipt with outcome always NoChange, which is semantically wrong (NoChange means 'already up to date' in the install/update path). The host registry returns Result<(), String>; the handler renders the action word from its own dispatch arm and re-reads detail for post-mutation state. Return Result<(), String> — the exact-minimum typed surface. Generated with Claude Code
…tricted exposure - PluginAdapter implements CommandPluginContext against App: registry reads (summaries/detail/diagnostics/validation/suggest), registry mutations (trust/enable/disable/revoke with skill-cache + active-skill side effects), async-bridged install/update/uninstall with synchronous receipts (D11), export, legacy scan, kimi managed scan/install, marketplace state/add/remove/install (incl. builtin official catalog) - CommandContextBundle grows to eleven slots with plugin; contexts() exposes plugin only for PLUGIN capability - Portable conversion helpers: summary/detail/mcp server/diagnostic/marketplace diagnostic/mutation receipt/export receipt/legacy tool/marketplace candidate/catalog - kimi_import: scan_managed_plugins_portable wrapper; group modules made pub(crate); plugin_network_policy/run_async exposed - Adapter tests: host-data projection, registry mutation + suggest behavior, restricted exposure (3 tests) - Full TUI lib suite 11395/0; boundary gate green; fmt clean Generated with Claude Code
…acet parity - mod.rs: portable plugins() dispatch consuming workspace/presentation/plugin facets; legacy shell builds bundle and delegates (Phase 6 replaces with from_contract) - render.rs: render_bundle_detail/escape helpers consume portable PluginDetail + presentation facet - legacy.rs: consumes PluginLegacyScan; kimi_import.rs: consumes PluginManagedScan; marketplace.rs: consumes PluginMarketplaceState with localized plan text - Presentation facet: key_to_plugin_message_id maps all 52 plugin keys; source_path carried for marketplace provenance - Contract: PluginSuggestion.state_label, PluginDetail.inventory_summary, PluginMarketplaceCatalog.source_path, reload() facet method - Tests: 18 plugin tests converted to the portable shell path; full parity preserved - Full TUI lib 11394/0; contract 23/23; boundary gates green Generated with Claude Code
…nk 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
- Fix clippy findings in FEAT-020 plugin files: identical if blocks (contract.rs), useless as_ref/map (marketplace.rs), useless format + redundant closure (render.rs), manual unwrap_or_default (mod.rs), collapsible if (contract tests) - Boy Scout: repair pre-existing lints outside FEAT-020 scope (computer-use linux.rs &PathBuf->&Path, config catalog tests contains()/type_complexity) - cargo clippy --workspace --all-targets --locked -- -D warnings exits 0 with zero warnings Generated with Claude Code
rollback_hash_mismatch called crate::plugins::install::uninstall directly from the portable handler, a TUI-owned executable dependency that violates the D1 boundary and would break the FEAT-040 physical move. Add CommandPluginContext::uninstall_path(name, plugins_dir) - a file-level rollback removal with no registry resolution or skill side effects - and route the content-hash-mismatch rollback through it. The host adapter owns the crate::plugins call. Verified: contract 23/23, plugins group 18/18, plugin-scoped TUI suite 205/0, clippy -D warnings clean.
Owner
|
Landing into Rebase onto Verified on
Merging with a merge commit to keep Paulo's authorship. |
Hmbown
merged commit Aug 27, 2026
ece99d5
into
Hmbown:codex/v0912-integration-20260823
6 checks passed
Hmbown
pushed a commit
that referenced
this pull request
Aug 29, 2026
…ntities Twenty external contributions landed after the v0.9.11 band closed and none were credited: the newest band in docs/CONTRIBUTORS.md was still v0.9.11 while main shipped 0.9.12 work. Adds the v0.9.12 band covering all twenty (#5591, #5599, #5604, #5610, #5613, #5621-#5624, #5629, #5650, #5657, #5669, #5682, #5683, #5685, #5687, #5688, #5689, #5692) and demotes v0.9.11 so only the newest band stays expanded. AUTHOR_MAP gains numeric-noreply entries for musichen, M-Maciej, and serephus so future harvested credit is graph-mappable, plus a comment recording that wangfengcsu@qq.com (21 commits on main via #704) has no resolved login yet. AUTHOR_MAP is a project convention consumed by scripts/check-coauthor-trailers.py for new commits; GitHub does not read it, so it grants no retroactive contribution-graph credit for history already on main. No-Issue: contributor credit hygiene; no issue tracks it Signed-off-by: CodeWhale Bot <bot@codewhale.net>
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
FEAT-020 converts the TUI plugins command group (
/plugin, aliasplugins) to the external command shapes introduced by FEAT-014 and hosted by FEAT-015, following the pattern FEAT-018 (utility) and FEAT-019 (memory) established. The command files remain undercodewhale-tui; this PR changes their execution boundary without physically moving them.Baseline: the implementation is built on the v0.9.12 integration branch (
codex/v0912-integration-20260823,96bc9e79c), where FEAT-019 landed and the plugins group gained the marketplace and Kimi managed-import verbs. Those verbs joined the FEAT-020 scope per the migration rule ("every production command then present in that group joins the FEAT-020 scope").This PR:
CommandPluginContextfacet with exact-minimum typed delegates: registry reads (summaries,detail,registry_diagnostics,validation_is_clean,len,is_empty,state_path,suggest), registry mutations (reload/rediscover + skill-cache,trust/enable/disable/revoke_trust), async-bridged bundle mutations returning synchronous portable receipts (install,update,uninstall,uninstall_pathrollback,export,legacy_scan, Kimimanaged_scan/managed_install, marketplacemarketplace_state/marketplace_add/marketplace_remove/marketplace_install) and thePLUGIN = 1 << 10capability bit with one envelope slot;/plugindispatch,renderhelpers, legacy-tools scan, Kimi managed import, and marketplace operations to portable contract values — 19 structured DTOs, byte-identical output preserved;/pluginviaContextualCommand::from_contractwith the exactWORKSPACE | PRESENTATION | PLUGINcapability set (noSKILLS: skill-cache refresh and active-skill resets happen host-side in the adapter);key_to_plugin_message_id), withdescription_key: "cmd_plugin_description"and authoritative English fallback;pluginsfrom both migration-frontier representations atomically;Tracking: EPIC-006 / FEAT-020 in umbrella Hmbown/CodeWhale#5316.
Dependency boundary
The intended dependency direction remains acyclic:
/pluginhandlers no longer name or call concreteApp,PluginRegistry,crate::plugins, orConfig; the plugin facet delegates to the TUI-owned services through the adapter. The capability-driven dispatcher populates only declared slots.Review hardening (PR #5525 lessons + post-completion audit)
Command capability unavailable: <facet>— zero.expect()in production handlers.crate::plugins::install::uninstalldirectly from the portable handler; it now crosses the boundary through the newCommandPluginContext::uninstall_pathfacet method, and the host adapter owns thecrate::pluginscall.Scope and behavior
groups/pluginsis migrated (one production command:/plugin).codewhale-tui; no shared result/action ownership moves (FEAT-037);CommandResultandAppActionremain bounded temporary data references.MessageIds.Testing
cargo fmt --all -- --checkcargo test -p codewhale-command-contract --lib --locked— 23 passedcargo test -p codewhale-tui --lib --lockedplugins-scoped — 205 passed; full TUI lib 11,394 passed / 0 failed at completionpython3 scripts/test_check_command_crate_boundaries.py— 8 passedpython3 scripts/check-command-migration-manifest.py --baseline-ref origin/codex/v0912-integration-20260823— PASS (pluginsabsent from both frontier representations)python3 scripts/test_check_command_migration_manifest.py— 54 passed-D warnings— 0 warningsgit diff --checkChecklist
/pluginmigrated; zero concrete-App/PluginRegistry/crate::plugins/Confighandler dependenciesCommandPluginContextis the only new plugin-specific host facet;PLUGIN=1 << 10/plugindeclares exactlyWORKSPACE | PRESENTATION | PLUGIN; no other facetspluginsremoved from both migration-frontier representationsCI status
The base is the
codex/v0912-integration-20260823branch (where FEAT-019 landed and the pluginsgroup's marketplace/Kimi verbs live); the repo's
ci.ymltriggers only onmaster/main-targetedPRs, so the full Actions matrix does not run here. Lightweight cross-repo checks (DCO, link,
GitGuardian, contribution gate) are green, and the full matrix was verified locally with the exact
configured gates: TUI lib 11,394/0, contract 23/23, boundary 8/8 + live, migration 54/54 + live
scan, strict workspace Clippy
-D warnings0,cargo fmt --check. The matrix will run on thisbranch when the v0.9.12 integration branch reaches
main.No-Issue: FEAT-020 is tracked in umbrella #5316, which must remain open for the remaining decomposition FEATs.
Paulo Aboim Pinto