Skip to content

feat(control): add the Control Centre companion - #17

Merged
LMLiam merged 20 commits into
mainfrom
feat/issue-5-control-centre-companion
Jul 29, 2026
Merged

feat(control): add the Control Centre companion#17
LMLiam merged 20 commits into
mainfrom
feat/issue-5-control-centre-companion

Conversation

@LMLiam

@LMLiam LMLiam commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add the macOS app and the Control Centre extension.
  • Send exact enable and disable requests from the sandboxed extension to the app.
  • Keep the app in the background for control requests.
  • Install and use the restricted privileged helper.
  • Read the current SleepDisabled value from pmset -g.
  • Add tests and local feasibility evidence.

Reason

An ad-hoc-signed main app cannot run the control intent through linkd. The extension can run the intent, but it cannot run the privileged helper. This change keeps the intent in the extension and sends a validated custom URL to the background app. The app then uses the existing helper and reloads the control from the real system state.

User impact

Users can install one ad-hoc-signed app from the GitHub release. They can add Battery Clamshell Mode to Control Centre. A control action does not show a window, Dock icon, or menu-bar item. The control colour follows the verified pmset state.

Verification

  • swift format lint --recursive --strict Package.swift Sources Tests App
  • swiftlint lint --strict
  • scripts/check.sh
  • 71 package tests
  • 10 Control Centre tests in the Release configuration
  • 17 app tests in the Release configuration
  • Release app build
  • Valid nested ad-hoc signature with no Team ID
  • Cold background disable test
  • Warm background enable test
  • Missing-helper failure test
  • Real Control Centre disable test

Closes #5

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 033fb88a-6f9b-401a-9f2d-0e6c8f79f68d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

Control contract and extension

Layer / File(s) Summary
Typed control actions and power state
App/ClamshellControlProtocol/..., App/ClamshellControl/Model/..., Sources/ClamshellCore/Power/..., App/ClamshellControlTests/..., Tests/ClamshellCoreTests/Power/...
Defines strict enable/disable URLs, reads system-wide SleepDisabled, and applies requested state changes through the shared control model.
WidgetKit relay
App/ClamshellControl/BatteryClamshellControl.swift, App/ClamshellControl/Intent/..., App/ClamshellControlTests/...
Adds the Battery Clamshell Control widget and a background intent that opens the typed action URL without activating the app.

Privileged installation and CLI exposure

Layer / File(s) Summary
Managed companion command installation
Sources/ClamshellCore/Privilege/...
Adds optional creation and removal of /usr/local/bin/clamshellctl, validates managed destinations, detects conflicts, and exposes installation status.
CLI flags and installation tests
Sources/ClamshellCLI/Commands/..., Tests/ClamshellCLITests/..., Tests/ClamshellCoreTests/Privilege/...
Adds --expose-command and --remove-command, with coverage for symlink creation, conflicts, managed removal, and preserved foreign links.

Setup diagnostics and authorisation

Layer / File(s) Summary
Setup services and model
App/ClamshellApp/Setup/Diagnostics/..., App/ClamshellApp/Setup/Privilege/..., App/ClamshellApp/Setup/SetupModel.swift, App/ClamshellApp/Setup/SetupComposition.swift
Adds companion payload diagnostics, installation-state mapping, administrator requests, AppleScript authorisation, and observable setup operations.
Setup interface
App/ClamshellApp/Setup/SetupView.swift, App/ClamshellApp/Setup/SetupWindowController.swift, App/ClamshellAppTests/...
Adds the setup window, state presentation, command exposure toggle, refresh/removal actions, and model and authorisation tests.

App URL relay and lifecycle

Layer / File(s) Summary
Application entry and URL handling
App/ClamshellApp/ClamshellApp.swift, App/ClamshellApp/Control/..., App/ClamshellApp/Info.plist, App/ClamshellAppTests/...
Adds the SwiftUI app entry point, Apple Event URL handling, control execution, deferred Control Centre reloads, launch gating, and background-style app metadata.

Project wiring and feasibility evidence

Layer / File(s) Summary
Xcode targets and package product
project.yml, Package.swift
Defines the macOS app, WidgetKit extension, static frameworks, test bundles, dependencies, signing settings, and the ClamshellCore library product.
Design, implementation plan, and feasibility record
docs/control-centre-action-relay-*.md, docs/control-feasibility-test.md
Documents the URL relay architecture, implementation tasks, security constraints, build commands, automated results, and manual verification checklist.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The extra design and implementation-plan markdown files appear to be outside the issue-owned scope and add unrelated documentation. Move those documents to a separate PR or remove them unless they are required by the issue acceptance criteria.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The PR description covers the main outcome, reason, user impact, and verification, though it omits several template sections.
Linked Issues check ✅ Passed The app, extension, pmset state, helper reuse, setup/removal, tests, and feasibility evidence all align with #5.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-5-control-centre-companion

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LMLiam LMLiam added this to the v1.0.0 milestone Jul 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 63cbc002-c693-4b6f-a348-8a443ccc4b17

📥 Commits

Reviewing files that changed from the base of the PR and between 1703d12 and 8032520.

📒 Files selected for processing (57)
  • App/ClamshellApp/ClamshellApp.swift
  • App/ClamshellApp/Control/ApplicationLaunchPolicy.swift
  • App/ClamshellApp/Control/ControlActionApplicationDelegate.swift
  • App/ClamshellApp/Control/ControlActionHandler.swift
  • App/ClamshellApp/Info.plist
  • App/ClamshellApp/Setup/Diagnostics/CompanionDiagnosing.swift
  • App/ClamshellApp/Setup/Diagnostics/CompanionDiagnostics.swift
  • App/ClamshellApp/Setup/Diagnostics/CompanionPayloadInspecting.swift
  • App/ClamshellApp/Setup/Diagnostics/FoundationCompanionPayloadInspector.swift
  • App/ClamshellApp/Setup/Diagnostics/InstallationStatusReading.swift
  • App/ClamshellApp/Setup/Privilege/AdministratorAuthorizationError.swift
  • App/ClamshellApp/Setup/Privilege/AdministratorAuthorizing.swift
  • App/ClamshellApp/Setup/Privilege/AdministratorRequest.swift
  • App/ClamshellApp/Setup/Privilege/AppleScriptAdministratorAuthorizer.swift
  • App/ClamshellApp/Setup/SetupComposition.swift
  • App/ClamshellApp/Setup/SetupModel.swift
  • App/ClamshellApp/Setup/SetupState.swift
  • App/ClamshellApp/Setup/SetupView.swift
  • App/ClamshellApp/Setup/SetupWindowController.swift
  • App/ClamshellAppTests/AppleScriptAdministratorAuthorizerTests.swift
  • App/ClamshellAppTests/ApplicationLaunchPolicyTests.swift
  • App/ClamshellAppTests/CompanionDiagnosticsTests.swift
  • App/ClamshellAppTests/ControlActionHandlerTests.swift
  • App/ClamshellAppTests/SetupModelTests.swift
  • App/ClamshellControl/BatteryClamshellControl.swift
  • App/ClamshellControl/ClamshellControlBundle.swift
  • App/ClamshellControl/Info.plist
  • App/ClamshellControl/Intent/ClamshellControlIntents.swift
  • App/ClamshellControl/Intent/SetBatteryClamshellIntent.swift
  • App/ClamshellControl/Intent/WorkspaceControlActionRequester.swift
  • App/ClamshellControl/Model/ControlModel.swift
  • App/ClamshellControlProtocol/ControlActionRequest.swift
  • App/ClamshellControlTests/ControlActionRequestTests.swift
  • App/ClamshellControlTests/ControlModelTests.swift
  • App/ClamshellControlTests/SetBatteryClamshellIntentTests.swift
  • App/ClamshellControlTests/WorkspaceControlActionRequesterTests.swift
  • Package.swift
  • Sources/ClamshellCLI/Commands/SetupCommand.swift
  • Sources/ClamshellCLI/Commands/UninstallCommand.swift
  • Sources/ClamshellCore/Errors/ClamshellError.swift
  • Sources/ClamshellCore/Power/PowerSettingsClient.swift
  • Sources/ClamshellCore/Power/PowerSettingsParser.swift
  • Sources/ClamshellCore/Privilege/Installation/CompanionCommandInstallation.swift
  • Sources/ClamshellCore/Privilege/Installation/FoundationInstallationFileSystem.swift
  • Sources/ClamshellCore/Privilege/Installation/InstallationFileSystem.swift
  • Sources/ClamshellCore/Privilege/Installation/InstallationStatus.swift
  • Sources/ClamshellCore/Privilege/Installation/PrivilegedInstallation.swift
  • Sources/ClamshellCore/Privilege/PrivilegedPaths.swift
  • Tests/ClamshellCLITests/Commands/SetupCommandTests.swift
  • Tests/ClamshellCoreTests/Power/PowerSettingsClientTests.swift
  • Tests/ClamshellCoreTests/Power/PowerSettingsParserTests.swift
  • Tests/ClamshellCoreTests/Privilege/Installation/PrivilegedInstallationCompanionTests.swift
  • Tests/ClamshellCoreTests/Support/InstallationTestSupport.swift
  • docs/control-centre-action-relay-design.md
  • docs/control-centre-action-relay-implementation-plan.md
  • docs/control-feasibility-test.md
  • project.yml

Comment thread App/ClamshellApp/Setup/SetupView.swift
Comment thread App/ClamshellControl/Intent/SetBatteryClamshellIntent.swift Outdated
Comment thread App/ClamshellControlTests/SetBatteryClamshellIntentTests.swift
Comment thread docs/control-centre-action-relay-implementation-plan.md Outdated
Comment thread docs/control-feasibility-test.md
@LMLiam
LMLiam force-pushed the feat/issue-5-control-centre-companion branch from 8032520 to 5575bef Compare July 29, 2026 19:56
@LMLiam

LMLiam commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

Out-of-scope check: the design, implementation plan, and feasibility record remain in this PR. Issue #5 includes an ad-hoc distributed app, a Control Centre extension, and a root helper boundary. These documents record the approved architecture, security constraints, and release gate for that work, so they are part of the issue scope.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 29, 2026
@LMLiam
LMLiam merged commit a561652 into main Jul 29, 2026
8 checks passed
@LMLiam
LMLiam deleted the feat/issue-5-control-centre-companion branch July 29, 2026 20:56
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.

feat(app): add the native Control Centre companion

1 participant