Add Pi activity tracking plugin - #3594
Conversation
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
worktrunk-bot
left a comment
There was a problem hiding this comment.
Reviewing as a draft — flagging anything that looks worth a quick fix. Mark ready for a full review.
Nice work — the pi.rs handler and the dev/pi-plugin.ts hook closely mirror the existing opencode plugin, which is the right pattern to follow. A few things I'd tighten before this goes green:
1. The parent wt config plugins help + snapshot are out of sync. Adding the Pi variant to ConfigPluginsCommand changes the wt config plugins --help command list, but tests/snapshots/…__help_config_plugins.snap still enumerates only claude/codex/opencode — so test_help_config_plugins (and test_docs_are_in_sync) will fail in CI. The snapshots regenerate via the pre-merge hook (cargo run -- hook pre-merge --yes, or cargo insta test --accept -- --test integration "test_help").
That regen won't fix the authored prose, though: the Plugins command's after_long_help in src/cli/config.rs (the ## Supported tools list and ## Examples, near the Install and manage Worktrunk plugins for AI coding tools. block) still omits Pi. That one's a hand edit — add:
- **pi** — Pi / oh-my-pi plugin (activity tracking)
to the Supported tools list, and $ wt config plugins pi install to the Examples block.
2. PI_CODING_AGENT_DIR precedence when a profile is active. In pi_agent_dir(), PI_CODING_AGENT_DIR is honored only when active_profile().is_none() — an active $OMP_PROFILE/$PI_PROFILE silently overrides an explicit $PI_CODING_AGENT_DIR. I can't verify Pi's own resolution order from CI, but "explicit dir override loses to profile" reads backwards from the usual "most-explicit wins" expectation. Worth confirming against Pi's actual behavior (and a one-line comment in the code recording why, since it's non-obvious).
3. Hook doesn't tolerate wt failing. The opencode hook guards every call with || true so a wt failure (not in a managed repo, wt not on PATH) never propagates into the host. The Pi hook does a bare await pi.exec("wt", …). If pi.exec rejects on a non-zero exit, an agent_start in a non-worktrunk directory would surface an error into the Pi session. Does pi.exec reject on non-zero exit, or is it fire-and-forget? If it rejects, wrap the body in a try/catch (or the Pi equivalent of || true).
4. Test coverage is lighter than opencode's. The opencode suite covers the already-installed, prompt-declined, and uninstall-not-installed branches; the Pi tests cover only the install/uninstall happy paths (and only OMP_PROFILE, not PI_PROFILE or PI_CONFIG_DIR). Those extra branches are exactly what codecov/patch tends to flag — worth mirroring the opencode tests before marking ready.
Minor: handle_pi_uninstall uses std::fs::remove_file — identical to the accepted opencode uninstall (removes only the tool's own hook at a fixed path), so low-risk, but flagging it since it's on worktrunk's data-safety radar. @max-sixty for eventual eyes on the deletion path.
|
Thanks for the draft review. The parent help/snapshots, Pi directory precedence, |
…thout a plugin (#3848) ## Problem #3847 asks for a documented "generic agent" integration: worktrunk ships plugins for Claude Code, Codex, OpenCode, and Gemini, so users of any other agent CLI have no documented way to get the 🤖/💬 activity markers in `wt list`. The mechanism is already agent-agnostic — the plugins just call `wt config state marker` on their host's session events — but the docs only present manual markers as a personal-workflow convenience, so users reverse-engineer the integration from that section. #3571 (pi / oh-my-pi) is the same gap from a different host. ## Solution A new **Agent CLIs without a plugin** subsection under Activity tracking in [`docs/content/claude-code.md`](https://github.com/max-sixty/worktrunk/blob/main/docs/content/claude-code.md), stating the three-call contract (set 🤖 on session start, set 💬 on turn end, clear on session end) plus the three things that actually bite: - the command resolves the branch from its working directory, so the hook must run inside the worktree (`--branch` where the host pins cwd elsewhere); - `marker set` exits non-zero outside a repository, and hosts differ on what a non-zero hook does — guard it; - pair every set with a clear, and expect a stale marker if the process is killed first. Docs-only. The skill and plugin-skill mirrors are regenerated by the sync test. ## Testing `cargo test --test integration test_docs_are_in_sync` passes (it regenerated both mirrors, committed here). Each claim in the section was verified against a scratch repo with a linked worktree rather than taken from the existing prose: <details><summary>Verification</summary> ``` $ wt config state marker set "🤖" # from /tmp/mrepo.feature-x ✓ Set marker for feature-x to 🤖 $ git config --get worktrunk.state.feature-x.marker {"marker":"🤖","set_at":1787044121} ``` - Works from a subdirectory of the worktree (branch still resolves to `feature-x`). - Outside a repository: `✗ git rev-parse --git-common-dir failed (exit 128)`, exit code 1 — the basis for the "guard it" bullet. - `marker clear` with no marker set exits 0 (`○ No marker set for main`), so a session-end hook is safe to run unconditionally. - `wt list` renders the marker in the Status column as documented. </details> ## Scope Deliberately host-agnostic. The reporter's second ask — a native `wt config plugins copilot` target — is a maintainer call and isn't attempted here: GitHub Copilot CLI does expose the needed events (`sessionStart` / `agentStop` / `sessionEnd`, user-level hooks under `~/.copilot/hooks/`, per the [hooks reference](https://docs.github.com/en/copilot/reference/hooks-reference)), but nothing in CI can drive a Copilot session to verify a generated hook file end to end. A concrete Copilot config is posted on the issue for the reporter to confirm; if it works, adding it here as a worked example is a natural follow-up. #3594 (native `pi` target) is the adjacent in-flight work and doesn't overlap with this. --- Refs #3847 — automated triage --------- Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
|
Addressed the draft-review items on current
Focused validation:
The Unix help snapshot test module is intentionally disabled on Windows, so I updated the reviewed snapshot directly; the refreshed Linux CI run will verify its rendered form. The PR remains draft while that CI completes. |
worktrunk-bot
left a comment
There was a problem hiding this comment.
Reviewing as a draft — flagging anything that looks worth a quick fix. Mark ready for a full review.
My previous item 2 sent you the wrong way — sorry. I asked you to confirm the PI_CODING_AGENT_DIR-vs-profile precedence against Pi's actual behavior, and the new commit resolved it by dropping the guard. Pi's own docs say the opposite: PI_CODING_AGENT_DIR is a "Full agent-directory override for the default profile only; named profiles ignore it" (environment-variables.md), restated in config-usage.md as "Named profiles ignore PI_CODING_AGENT_DIR." So the original .filter(|_| active_profile().is_none()) was correct and removing it is a regression: with OMP_PROFILE=research and PI_CODING_AGENT_DIR both set, Pi loads hooks from ~/.omp/profiles/research/agent/hooks/pre/, but the installer now writes to $PI_CODING_AGENT_DIR/hooks/pre/worktrunk.ts and reports success — the hook never loads and no markers ever appear. Inline suggestions restore the guard (with the comment recording why), flip test_pi_agent_dir_override_takes_precedence_over_profile to pin the upstream behavior, and correct the --help text.
Everything else in the resolution order checks out against those docs: active_profile()'s "OMP_PROFILE wins even when explicitly empty, and default/empty/whitespace means the default profile" matches config-usage.md exactly, PI_CONFIG_DIR as a dirname under $HOME matches, and <agent-dir>/hooks/pre/* is the right user-level hook root.
codecov/patch is red at 95.4% on src/commands/config/pi.rs — the four missed lines are the two prompt-declined return Ok(()) branches (install and uninstall). That's the one branch from my earlier item 4 that isn't covered yet; test_opencode_install_prompt_declined is the pattern to mirror — no --yes, piped stdin declines the prompt.
The user-facing plugin docs don't mention Pi. docs/src/content/docs/claude-code.md ("Agent Integration") is the primary hand-edited page listing every plugin — Pi needs a column in the capability table, an ### Pi block under Installation naming ~/.omp/agent/hooks/pre/worktrunk.ts and the env vars, and a mention in the frontmatter description and intro paragraph. skills/worktrunk/reference/claude-code.md derives from it, so don't edit that copy. This isn't caught by CI (check-docs passes — the generated regions are unaffected), but CLAUDE.md treats behavior changes as requiring doc updates.
Two smaller things I'd fold in rather than leave: wt config show renders a section per agent tool (render_opencode_status and friends, keyed off a which::which probe), and Pi has none — an installed-but-outdated Pi hook is invisible there, and the "Plugin not installed. To install, run …" hint is how the feature gets discovered. And confirm_or_yes is now byte-identical in opencode.rs and pi.rs; worth lifting into the parent config module while there are only two copies.
Test hermeticity note
set_temp_home_env pins OPENCODE_CONFIG_DIR and CLAUDE_CONFIG_DIR so those tests can't be steered by the developer's own environment, and isolate_subprocess_env scrubs GIT_*/WORKTRUNK_*. Nothing scrubs OMP_PROFILE, PI_PROFILE, PI_CONFIG_DIR, or PI_CODING_AGENT_DIR, so test_pi_install_is_idempotent, test_pi_uninstall_removes_hook, and test_pi_install_creates_profile_aware_hook all assert against .omp/agent/... paths that an ambient OMP_PROFILE in the runner's shell would move. test_pi_install_honors_pi_profile_and_config_dir already env_removes one of them, which is the tell. Adding those four to the env_remove list in set_temp_home_env (src/testing/mod.rs, beside the CLAUDE_CONFIG_DIR line) fixes all of them at once — the tests that want a value set it afterwards, and the later cmd.env wins.
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
|
Coverage follow-up:
The hosted patch-coverage check is rerunning on |
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
|
Coverage is green on The profile-guard restoration in Four items from my last review are still open, listed here so the finish line is visible rather than as new asks:
Where the hermeticity fix goes
|
worktrunk-bot
left a comment
There was a problem hiding this comment.
Full (non-draft) pass on 1d7e7ba4d. The code itself reads well — pi_agent_dir() matches Pi's documented resolution in both directions, the hook is failure-isolated via try/catch, the marker vocabulary (agent_start/agent_end/session_shutdown → 🤖/💬/clear) lines up with the Claude and OpenCode hooks, and codecov/patch is green. Two things keep this from an approval.
Holding for @max-sixty — deletion surface. handle_pi_uninstall calls std::fs::remove_file (src/commands/config/pi.rs, the Failed to remove plugin @ {target_display} line). This repo's review policy lists std::fs::remove_file as a hold trigger — .claude/skills/running-tend/references/review-pr.md, "Data-Loss Surface: Hold for Human Review" — so a new plugin surface that deletes a file isn't mine to sign off, even though it is the same shape as the already-accepted handle_opencode_uninstall (fixed path, the tool's own hook, behind a prompt). @max-sixty for the call.
Four gaps from the draft rounds are still open on this head. I'd normally not restate, but you've marked it ready, so here's the finish line. Item 2 is wider than I scoped it before; the rest are unchanged.
-
User-facing docs.
docs/src/content/docs/claude-code.mdis the hand-edited "Agent Integration" page enumerating every plugin, and Pi appears nowhere in it — no column in the capability table, no### Piblock under Installation, and the frontmatterdescriptionstill reads "Claude Code, Codex, OpenCode, and Gemini CLI".CLAUDE.mdtreats behavior changes as requiring doc updates, and nothing in CI catches this one: the generated regions are unaffected, socheck-docsandtest_docs_are_in_syncboth pass.skills/worktrunk/reference/claude-code.mdderives from that page — don't edit the copy. -
The duplication is the whole module, not just
confirm_or_yes. Comparingsrc/commands/config/pi.rsagainstsrc/commands/config/opencode.rs:confirm_or_yesis byte-identical, andhandle_pi_install/handle_pi_uninstalldiffer from their OpenCode counterparts only in the tool name inside the prompt string and the path resolver they call — the already-installed short-circuit, theUpdate/Installselection, the preview closure,create_dir_all+write_atomically, the success + hint lines, and the not-installed early return are all reproduced verbatim. That's ~80 lines with two owners. The drift has already started:wt config plugins pi uninstallprintsPlugin removed @ <path>where the OpenCode command printsPlugin removed from <path>for the identical operation (visible in the two*_uninstall_*snapshots). A shared helper parameterized by (display name, plugin source, resolved target) collapses both into their*_dir()functions and stops the next divergence. -
wt config showhas no Pi section.show.rsrenders a block per agent tool —render_claude_code_status,render_codex_status,render_opencode_status,render_gemini_status, each behind awhich::whichprobe — and there's norender_pi_status.opencode.rsexportsis_plugin_installed()andplugin_file_exists()for exactly that three-way status;pi.rsexports neither. Concretely: a user who installs the Pi hook today and upgradeswtnext month has a staleworktrunk.tsthatwt config showsays nothing about, and thePlugin outdated. To update, run …/Plugin not installed. To install, run …hints — which are how the feature gets discovered at all — never fire for Pi. -
Test hermeticity. Nothing scrubs
OMP_PROFILE,PI_PROFILE,PI_CONFIG_DIR, orPI_CODING_AGENT_DIR. On a machine where the developer exportsOMP_PROFILE=work,test_pi_install_is_idempotent,test_pi_install_prompt_declined,test_pi_uninstall_removes_hook,test_pi_uninstall_prompt_declined, andtest_pi_install_honors_agent_dir_overrideall resolve to~/.omp/profiles/work/agent/...and fail their.omp/agent/...assertions.test_pi_install_honors_pi_profile_and_config_diralreadyenv_removesOMP_PROFILE, which is the tell. CI runners don't set these, so this is a local-developer failure, not a red build.
Where the hermeticity fix goes
set_temp_home_env in src/testing/mod.rs pins OPENCODE_CONFIG_DIR and CLAUDE_CONFIG_DIR (the cmd.env("CLAUDE_CONFIG_DIR", home.join(".claude")) line) for exactly this reason. Adding the four Pi vars to an env_remove beside it covers all five tests in one edit — the tests that want a value set it afterwards via cmd.env, which wins over the removal.
Happy to push a commit for 1 and 4 if you'd like — both are mechanical and I've already worked out the content. Say the word and I'll do it; 2 and 3 are yours since they involve design choices about where the shared helper lives and what the Pi availability probe should be (Pi's binary name isn't obvious to me from CI).
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
|
Addressed the four non-draft follow-ups on the current head: documented Pi in the agent-integration capability table and install section; extracted the shared OpenCode/Pi file-plugin install/uninstall flow; added Pi current/outdated/missing status to wt config show using the pi executable probe; and scrubbed OMP_PROFILE, PI_PROFILE, PI_CONFIG_DIR, and PI_CODING_AGENT_DIR in the shared test-home setup. Validation: Pi integration 10/10, OpenCode regression 12/12, Pi config-show states 3/3, cargo clippy --tests -- -D warnings, Astro check with 0 diagnostics, and docs tests 9/9. The remove_file policy hold remains intentionally unresolved for @max-sixty's human review; I did not try to override that repository-policy gate. |
|
All four follow-ups landed as described — I checked each on
1. 2. 3. Worth running Where each failure came from
|
worktrunk-bot
left a comment
There was a problem hiding this comment.
All four follow-ups from the last pass landed — the shared install_file_plugin/uninstall_file_plugin helper, the Pi section in wt config show, the hand-edited claude-code.md page, and the four env vars scrubbed in set_temp_home_env. The uninstall wording drift is gone too, now that both tools print through the same helper.
Three things are red on 083bcba17, and I reproduced each one locally on the merged tree.
1. code-coverage is failing the test run, not the coverage bar. check_stderr_macros_come_from_styling rejects the seven new eprintln! sites in src/commands/config/mod.rs, because the guard only counts use worktrunk::styling::… statements at column 0 and the helper's imports are function-local. The guard's own doc comment on styling_imports calls this shape out — "a future function-local one fails this scan and gets hoisted". Inline suggestions hoist all four use lines to the module top; they're one edit, so apply all three together. Verified locally: cargo clippy --all-targets -- -D warnings clean, cargo fmt --check clean, and the guard test passes.
2. check-docs is failing on a hardcoded copy of the capability table's header. docs/tests/built-site.test.mjs asserts the /claude-code/ table by exact header list, and the new Pi column moves it — /claude-code/ is missing table Capability | Claude Code | Codex | OpenCode | Gemini CLI. Find the findTable('/claude-code/', …) call in the short wide tables become labeled records without capturing dense tables test and add the column:
findTable('/claude-code/', ['Capability', 'Claude Code', 'Codex', 'OpenCode', 'Pi', 'Gemini CLI']).attributes,With that one line, npm run test:site goes 13/13 here. It's outside the diff so I can't suggest it inline — happy to push it if you'd rather not round-trip.
3. test_docs_are_in_sync will fail the test (linux|macos|windows) legs. claude-code.md is primary, so its three derived copies need regenerating and none are in the diff:
Files out of sync (updated):
[skill files] skills/worktrunk/reference/claude-code.md
[plugin skills mirror] plugins/worktrunk/skills/worktrunk/reference/claude-code.md
[llms.txt] docs/public/llms.txt
cargo test --test integration test_docs_are_in_sync writes them, then fails; a second run passes. Those legs were still in flight when I looked, so this is a local reproduction rather than a CI report.
And one that CI can't catch: the availability probe names a binary that doesn't exist. is_pi_available() calls which::which("pi"), but oh-my-pi ships omp, not pi — packages/coding-agent/package.json declares "bin": { "omp": "src/cli.ts" }, and https://omp.sh/install writes the release asset to ${INSTALL_DIR}/omp. So on a real install the PI heading never renders, and the Plugin not installed. To install, run … / Plugin outdated… hints — which are the whole reason for adding the section — never fire. test_config_show_pi_plugin_status stays green because it sets WORKTRUNK_TEST_PI_INSTALLED=1 and never exercises the which path. Upstream badlogic/pi-mono does ship a pi binary, but everything else here targets the fork: ~/.omp, $OMP_PROFILE, and the @oh-my-pi/pi-coding-agent type import. Inline suggestion switches the probe.
The rest of the resolution checks out against upstream. ~/.omp/agent/hooks/pre/ is the right user hook root (config-usage.md: user root ~/.omp/agent/..., hooks at hooks/pre/*), agent_start / agent_end / session_shutdown are all real events in docs/hooks.md, and pi.exec(command, args, { cwd }) matches HookAPI.exec — it returns { code } rather than throwing on non-zero, so the try/catch is covering spawn failures, which is the case that matters.
How I verified the four findings
code-coverage: job log —FAIL … check_stderr_macros_come_from_styling, listingsrc/commands/config/mod.rs:{54,68,82,86,105,113,121}, then2027/4731 tests were not run due to test failure. Hoisting the imports locally turns it green.check-docs: ran thedocs-buildaction's steps by hand (npm ci,npm run check,npm test,npm run build,npm run test:site) — onlytest:sitefails, attests/built-site.test.mjs:442.- doc sync:
cargo test --test integration test_docs_are_in_syncon the merged tree, output quoted above. - binary name:
gh api repos/can1357/oh-my-pi/contents/packages/coding-agent/package.jsonandcurl -fsSL https://omp.sh/install.packages/{metaharness,stats,mnemopi}declaremetaharness,omp-stats, andmnemopi; no package in the repo declares apibin.
Still holding rather than approving, for the std::fs::remove_file reason in my last pass — that's unchanged, just moved into uninstall_file_plugin. @max-sixty for that call. Patch coverage is unverified on this head, since the code-coverage job died before uploading.
| if let Ok(val) = std::env::var("WORKTRUNK_TEST_PI_INSTALLED") { | ||
| return val == "1"; | ||
| } | ||
| which::which("pi").is_ok() |
There was a problem hiding this comment.
oh-my-pi installs its CLI as omp — "bin": { "omp": "src/cli.ts" } in packages/coding-agent/package.json, and the install script writes ${INSTALL_DIR}/omp. With pi here the whole PI block is unreachable on a real install.
| which::which("pi").is_ok() | |
| which::which("omp").is_ok() |
While you're here: is_opencode_available and render_opencode_status both carry a doc line (/// Check if OpenCode CLI is available, /// Render OPENCODE section (plugin status). plus the Caller must check … note), and the two Pi functions have none. Worth matching, and the same goes for install_file_plugin / uninstall_file_plugin next to the documented run_plugin_cli.
Signed-off-by: Aditya Datta <crazyme07071996@gmail.com>
|
Fixed the three deterministic failures in |
worktrunk-bot
left a comment
There was a problem hiding this comment.
The three doc/import findings from the last pass all landed, and I re-ran each locally on the merged tree: check_stderr_macros_come_from_styling passes, test_docs_are_in_sync passes with a clean tree afterwards, and the built-site.test.mjs header now matches claude-code.md's actual | Capability | Claude Code | Codex | OpenCode | Pi | Gemini CLI |. check-docs, code-coverage, test (linux) and lint are green; macOS/Windows still in flight.
codecov/patch is red, and two of the four missed lines are a real regression the refactor introduced. Patch is 139/143 = 97.2% against an auto target of 98.13% (the base's project coverage), so it fails by 4 lines. Only two of them are yours to fix, and fixing them alone clears the gate (141/143 = 98.6%).
The two that matter are src/commands/config/mod.rs:67 and :110 — the || eprintln!("{}", preview_msg), argument in each helper. On main this was a named binding on its own line (let preview = || eprintln!("{}", preview_msg); in opencode.rs), and codecov scored that line a hit: the statement that creates the closure runs on every install, even though the body only runs when the user types ? at the prompt. Inlining the closure as a call argument collapses the line to the closure body's region, which no test reaches — so the refactor turned two covered lines into two misses. Restoring the binding restores the hits without adding a test. Inline suggestions do that; I applied both locally and cargo fmt --check and cargo clippy --bin wt -- -D warnings stay clean.
The other two, src/commands/config/show.rs:385 and :393, aren't fixable and I don't think you should chase them. They're the )?; lines closing the writeln! calls in render_pi_status's "Plugin outdated" and "Plugin not installed" arms — the error-propagation region of a writeln! into a String, which cannot fail. All three arms are exercised (test_config_show_pi_plugin_status's three rstest cases hit the function 3 times), and the byte-identical lines in render_opencode_status are codecov misses on main today. They only count here because the function is new.
Still holding rather than approving, unchanged from the last pass: uninstall_file_plugin calls std::fs::remove_file, which this repo's review reference lists as a hold-for-human trigger. @max-sixty for that call. The is_pi_available() thread on show.rs is also still open — no new argument from me, it just hasn't been picked up.
How I got the coverage numbers
Codecov's API was intermittently rate-limited, so I cross-checked two ways and they agree exactly.
cobertura.xmlfrom thecode-coverageartifact on this head (run 33241342622), intersected withgit diff -U0 bb421ec...3fd3044: misses atmod.rs:{67,110}andshow.rs:{385,393}, everything else inpi.rs,main.rs,opencode.rs,testing/mod.rsat 100%.GET /api/v2/github/max-sixty/repos/worktrunk/compare/?pullid=3594→totals.patch = {lines: 143, hits: 139, misses: 4, coverage: 97.2},totals.base.coverage = 98.13; per-filemod.rs96.55%,show.rs92.0%,pi.rs100%.- The
main-side comparison:file_report/src/commands/config/opencode.rs?sha=bb421ecreports the file at 100% with lines 87–88 (thepreview_msg/let preview = …pair) as hits, whilefile_report/src/commands/config/show.rs?sha=bb421ecreports lines 346 and 354 — the)?;closers inrender_opencode_status— as misses.
| let preview_msg = info_message(cformat!("Would write to <bold>{target_display}</>")); | ||
| let confirmed = yes | ||
| || prompt_yes_no_preview( | ||
| &cformat!("{action} {name} plugin @ <bold>{target_display}</>?"), | ||
| || eprintln!("{}", preview_msg), | ||
| )? == PromptResponse::Accepted; |
There was a problem hiding this comment.
| let preview_msg = info_message(cformat!("Would write to <bold>{target_display}</>")); | |
| let confirmed = yes | |
| || prompt_yes_no_preview( | |
| &cformat!("{action} {name} plugin @ <bold>{target_display}</>?"), | |
| || eprintln!("{}", preview_msg), | |
| )? == PromptResponse::Accepted; | |
| let preview_msg = info_message(cformat!("Would write to <bold>{target_display}</>")); | |
| let preview = || eprintln!("{}", preview_msg); | |
| let confirmed = yes | |
| || prompt_yes_no_preview( | |
| &cformat!("{action} {name} plugin @ <bold>{target_display}</>?"), | |
| preview, | |
| )? == PromptResponse::Accepted; |
Binding the closure first puts a statement on the line that runs on every install, which is what opencode.rs did on main and why codecov counted it. As an inline argument the line maps only to the closure body, which nothing reaches.
| let preview_msg = info_message(cformat!("Would remove <bold>{target_display}</>")); | ||
| let confirmed = yes | ||
| || prompt_yes_no_preview( | ||
| &cformat!("Remove {name} plugin @ <bold>{target_display}</>?"), | ||
| || eprintln!("{}", preview_msg), | ||
| )? == PromptResponse::Accepted; |
There was a problem hiding this comment.
| let preview_msg = info_message(cformat!("Would remove <bold>{target_display}</>")); | |
| let confirmed = yes | |
| || prompt_yes_no_preview( | |
| &cformat!("Remove {name} plugin @ <bold>{target_display}</>?"), | |
| || eprintln!("{}", preview_msg), | |
| )? == PromptResponse::Accepted; | |
| let preview_msg = info_message(cformat!("Would remove <bold>{target_display}</>")); | |
| let preview = || eprintln!("{}", preview_msg); | |
| let confirmed = yes | |
| || prompt_yes_no_preview( | |
| &cformat!("Remove {name} plugin @ <bold>{target_display}</>?"), | |
| preview, | |
| )? == PromptResponse::Accepted; |
Same for the uninstall helper — this is the second of the two patch misses.
Summary
wt config plugins pi install|uninstallValidation
cargo fmt --check— passedcargo test --test integration test_pi_ -- --nocapture— 3 passedINSTA_UPDATEcargo clippy --bin wt -- -D warnings— passedCloses #3571