Skip to content

feat(ui): surface helper state and actions - #670

Draft
Alex Shabalin (alex-sparus) wants to merge 1 commit into
alex/fix-helper-reconcilefrom
alex/fix-helper-ui
Draft

feat(ui): surface helper state and actions#670
Alex Shabalin (alex-sparus) wants to merge 1 commit into
alex/fix-helper-reconcilefrom
alex/fix-helper-ui

Conversation

@alex-sparus

@alex-sparus Alex Shabalin (alex-sparus) commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Problem: none of the helper machinery is visible or drivable — no way to grant or disable, no sign that macOS is waiting in Login Items or that an upgrade is waiting out a running activation — and the repair banner evaluates once per launch, so it keeps warning about a helper the convergence loop fixed seconds later.

Solution: orpc endpoints for status, grant, and disable; one permission row produced whole from each reconciliation report, with replace_row letting the convergence loop publish updates without running a second reconciliation; the repair banner follows live helper state instead of the launch snapshot. The UI never re-words or re-classifies a report — rows render the backend sentence verbatim, and the TS test fixtures mirror the backend vocabulary exactly.

Stacked on #669; completes the helper-redesign stack.

Test Plan

  • cargo test green (row/report mapping, permissions state)
  • bunx tsc --noEmit && bun run test:unit (panel + repair suites; fixtures assert the backend sentences verbatim)

Docs

  • No docs update needed

Prior review

Nearly all of this PR matches content from #636: repair.tsx/lib.ts/types.ts/permissions_state.rs/orpc byte-identical, permissions-panel.tsx differs by 2 lines, test fixtures updated to the new backend sentences. Caveat: Scott's #636 approval predates the convergence-loop and banner additions that landed on that branch afterwards, so those parts (mostly in #669's helper_permission.rs) were never formally approved.

@alex-sparus

Alex Shabalin (alex-sparus) commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by jj-ryu.

@darkmatter

darkmatter Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🎨 Storybook preview

Open Storybook preview

Updated for cc4aa49


⚠️ Detected UI changes (5)

These stories' HTML snapshots changed. I've added screenshots + links to the changed stories below. Review them carefully then accept the changes to regenerate baselines and include them in this PR:

Flows/Evolve › Playground

Flows/Evolve › Playground

Flows/Evolve › 1. Begin (idle)

Flows/Evolve › 1. Begin (idle)

Flows/Evolve › 2. Evolving (progress)

Flows/Evolve › 2. Evolving (progress)

Flows/Evolve › Evolving With Error Event

Flows/Evolve › Evolving With Error Event

Flows/Evolve › 3. Review (changes generated)

Flows/Evolve › 3. Review (changes generated)


Accept UI changes

  • Click here to accept these changes

Alternatively, you can run bun run test:update-snapshots locally to re-generate the baselines and then push the changes to this PR.

What does this do?

The screenshots above show UI changes detected by the Storybook
snapshot tests run on this PR. Each image is the rendered output of
a Storybook story from the code in this PR branch; the snapshot
test compared it against the committed baseline in
__snapshots__/ and flagged the difference.

Checking the box tells the darkmatter[bot] to regenerate the
baselines from this PR's current code and commit them directly to
this branch. The new baselines become the source of truth for
future runs — only accept after confirming the visual changes are
intentional.

Comparison baseline: the committed __snapshots__/ files on this
PR branch (carried forward from develop). Accept updates them in
place on this branch.

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

No Linear issue ID found in this PR's title, description, or branch name (expected something like ENG-123). Add one so this work is traceable in Linear, or add #no-linear to the PR description to acknowledge it's intentionally untracked.

⚠️ PR is marked WIP / draft — do not merge until ready for review.
⚠️ ❗ Big PR (1636 lines changed). Consider splitting it into smaller, focused changes.

📋 PR Overview

Lines changed 1636 (+1291 / -345)
Files 3 added, 14 modified, 0 deleted
Draft / WIP yes
Has Test Plan yes
Linear issue no
No Test Plan Needed no
New UI components no
New Storybook stories no
New Rust modules no
New TS source files yes (1)
New tests yes (2)
package.json touched no
Cargo.toml touched no
Infra / CI touched no

🔬 Coverage

Report Lines Statements Functions Branches
apps/native/coverage/coverage-summary.json 36.5% 36.1% 31.5% 30.6%

Generated by 🚫 dangerJS against cc4aa49

// The condition is exactly that: the standing decision is `granted` and the row
// is not. It covers a registration waiting for approval in Login Items, a copy
// of nixmac running from a folder macOS will not register, and a register that
// failed — and it deliberately cannot tell them apart, because the row carries

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to change this, it doesn't seem very user-friendly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, to change what? This is just a missing required permissions banner - just like full-disk access or any other permissions that the app requires and the user might disable at some point

onClick: () => void;
};

/**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these (I suspect AI-generated) comments are overly verbose and potentially fragile (for example, specific classnames in the comments, over-explaining specifics of how the UX works) and should be cut back, seems particularly the case in the frontend code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. Kept only the regression-preventing facts (the design-system button resize/animation gotchas, the live-vs-snapshot rule) and dropped the classname walkthroughs and UX narration.

The buttons in the UI really need some refactoring, I have it noted for fixing later - there are several copies by now with various fixes

try {
const report = await client.darwin.helperDisable();
setNotice({ tone: "info", message: report.detail });
// deprecated(orpc): replace with client/orpc from @/lib/orpc

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably start addressing these in new code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100%, the two new-code sites now use the oRPC client; the remaining marked sites in these files predate this PR

variant: "secondary",
};
}
if (perm.id === "privileged-helper") {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a const for this value elsewhere that should probably be used as long as there's not an enum.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a const

* The one permission nixmac installs itself instead of asking macOS for, and so
* the one row whose state nixmac keeps working on after the probe returns.
*/
export const HELPER_PERMISSION_ID = "privileged-helper";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Back-reference to another comment -- there are several places this could/should be used but isn't, I believe.

import { computeRepairPlan, type RepairInputs } from "./lib";

/** What the backend reports while macOS holds the registration for approval. */
const APPROVE_IN_LOGIN_ITEMS =

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally unless it's otherwise important I'd make a less-tight assertion so that there's options for varying the text without having to duplicate the change int he test code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sentence is now declared once in utils/test-fixtures, kept the exact assertion

RestartSetupConfirmation: () => null,
}));

const APPROVE_IN_LOGIN_ITEMS =

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicative of repair.test.tsx.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Problem: none of the helper machinery is visible or drivable — no way
to grant or disable, no sign that macOS is waiting in Login Items or
that an upgrade is waiting out a running activation — and the repair
banner evaluates once per launch, so it keeps warning about a helper
the convergence loop fixed seconds later.

Solution: orpc endpoints for status, grant, and disable; one
permission row produced whole from each reconciliation report, with
replace_row letting the convergence loop publish updates without
running a second reconciliation; the repair banner follows live helper
state instead of the launch snapshot. The UI never re-words or
re-classifies a report — rows render the backend sentence verbatim,
and the TS test fixtures mirror the backend vocabulary exactly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants