feat(api): add lockime:// URL scheme automation#25
Conversation
Expose a lockime:// URL scheme so other apps, scripts, Shortcuts, and launchers can drive LockIME — toggle locking, retarget the input source, manage app/URL rules, and read state back. Query and action commands are parsed in the kit (URLCommandParser) and executed against the live AppState by a thin AppKit handler, with x-callback-url success and error callbacks. The API is opt-in and off by default: the user must enable it under Settings ▸ General ▸ Automation, and the flag is stored in its own per-device UserDefaults key, deliberately kept out of LockConfiguration so it never travels through config export/import. Callback URLs are restricted to non-file, non-own schemes to avoid a confused-deputy. On a URL-triggered cold launch, AppKit can deliver application(_:open:) before applicationDidFinishLaunching, so the handler calls the idempotent start() first to ensure the persisted config is loaded before any command can commit() over it. Ship a full URL Scheme API reference in every SupportedLanguage and link it from the README. Signed-off-by: Kevin Cui <bh@bugs.cc>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Summary by CodeRabbit
WalkthroughThis PR adds a Sequence DiagramsequenceDiagram
participant ExternalCaller as External App / Script / Shortcuts
participant macOS as macOS URL dispatch
participant AppDelegate
participant URLCommandHandler
participant URLCommandParser
participant AppState
participant LockEngine
participant NSWorkspace as NSWorkspace (callback)
ExternalCaller->>macOS: open lockime://<command>?params
macOS->>AppDelegate: application(_:open:urls)
AppDelegate->>AppState: start() (ensure config loaded)
AppDelegate->>URLCommandHandler: handle(url)
URLCommandHandler->>AppState: check apiEnabled
alt API disabled
URLCommandHandler->>NSWorkspace: open x-error (api_disabled)
else API enabled
URLCommandHandler->>URLCommandParser: parse(url)
URLCommandParser-->>URLCommandHandler: ParsedURLCommand
URLCommandHandler->>AppState: execute command
AppState->>LockEngine: switchSourceOnce / lock / rule update
LockEngine-->>AppState: result
AppState-->>URLCommandHandler: payload (nil or JSON dict)
URLCommandHandler->>NSWorkspace: open x-success or x-error URL
NSWorkspace->>ExternalCaller: callback URL opened
end
Possibly Related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches✨ Simplify code
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Tests/LockIMEKitTests/LogStoreTests.swift`:
- Around line 65-67: The force-unwrapping of recent.first! and recent.last! on
the timestamp ordering expectation check can crash and hide test failures if the
earlier count expectation fails. Replace the force-unwraps with a `#require`
statement that verifies recent has at least one element before attempting to
access first and last properties in the timestamp ordering comparison. This
ensures graceful test failure with proper error reporting rather than a
force-unwrap crash.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a643d317-4f1d-4d97-8d23-7073353aa271
📒 Files selected for processing (40)
AGENTS.mdREADME.mdSources/LockIME/API/URLCommandHandler.swiftSources/LockIME/AppDelegate.swiftSources/LockIME/AppState.swiftSources/LockIME/Info.plistSources/LockIME/Localizable.xcstringsSources/LockIME/UI/Settings/ActivationLogPane.swiftSources/LockIME/UI/Settings/BackupSettingsPane.swiftSources/LockIME/UI/Settings/GeneralSettingsPane.swiftSources/LockIME/UI/SettingsRootView.swiftSources/LockIME/Updates/LockIMEUserDriver.swiftSources/LockIMEKit/API/URLCommand.swiftSources/LockIMEKit/LockEngine/InputSource.swiftSources/LockIMEKit/LockEngine/LockController.swiftSources/LockIMEKit/LockEngine/LockEngine.swiftSources/LockIMEKit/Logging/LogStore.swiftSources/LockIMEKit/Logging/LogSubsystem.swiftTests/LockIMEKitTests/LockControllerTests.swiftTests/LockIMEKitTests/LogStoreTests.swiftTests/LockIMEKitTests/URLCommandParserTests.swiftdocs/DESIGN.mddocs/README/README.de.mddocs/README/README.es.mddocs/README/README.fr.mddocs/README/README.ja.mddocs/README/README.pt.mddocs/README/README.ru.mddocs/README/README.zh-CN.mddocs/README/README.zh-TW.mddocs/URL-Scheme-API/README.de.mddocs/URL-Scheme-API/README.es.mddocs/URL-Scheme-API/README.fr.mddocs/URL-Scheme-API/README.ja.mddocs/URL-Scheme-API/README.mddocs/URL-Scheme-API/README.pt.mddocs/URL-Scheme-API/README.ru.mddocs/URL-Scheme-API/README.zh-CN.mddocs/URL-Scheme-API/README.zh-TW.mdproject.yml
A failing count assertion would otherwise crash on first!/last!, hiding the real failure signal. Require the elements before the ordering check.
The committed screenshots predated the URL match-type badges and drag-to-reorder priority (#26) and the General "Automation" section (#25), so all three panes were out of date. Regenerate the full set of 12 (General, App Rules, URL Rules x en/zh-CN x light/dark). The URL Rules pane now shows four rules spanning every match type (domain suffix, exact domain, domain keyword, URL regex) to surface the new badges and the reorder caption. Images are now 2024x1600 because SettingsRootView gained a 600pt minimum content height. Signed-off-by: Kevin Cui <bh@bugs.cc>
Expose a lockime:// URL scheme so other apps, scripts, Shortcuts, and launchers can drive LockIME — toggle locking, retarget the input source, manage app/URL rules, and read state back. Query and action commands are parsed in the kit (URLCommandParser) and executed against the live AppState by a thin AppKit handler, with x-callback-url success and error callbacks.
The API is opt-in and off by default: the user must enable it under Settings ▸ General ▸ Automation, and the flag is stored in its own per-device UserDefaults key, deliberately kept out of LockConfiguration so it never travels through config export/import. Callback URLs are restricted to non-file, non-own schemes to avoid a confused-deputy.
On a URL-triggered cold launch, AppKit can deliver application(_:open:) before applicationDidFinishLaunching, so the handler calls the idempotent start() first to ensure the persisted config is loaded before any command can commit() over it.
Ship a full URL Scheme API reference in every SupportedLanguage and link it from the README.