fix(add-statusbar): derive log path from binary location, fix SKILL.md

- statusbar.swift: derive project root from binary location instead of
  hardcoding ~/Documents/Projects/nanoclaw
- SKILL.md: remove references to non-existent apply-skill.ts, compile
  directly from skill directory using ${CLAUDE_SKILL_DIR}
- SKILL.md: add xattr -cr step for Gatekeeper on macOS Sequoia+
- Remove unused manifest.yaml

Co-Authored-By: tomermesser <tomeaces@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-03-25 23:54:05 +02:00
parent 32dda34af4
commit 349b54ae9e
3 changed files with 31 additions and 40 deletions

View File

@@ -1,11 +1,12 @@
--- ---
name: add-statusbar name: add-statusbar
description: Add a macOS menu bar status indicator for NanoClaw. Shows a icon with a green/red dot indicating whether NanoClaw is running, with Start, Stop, and Restart controls. macOS only. description: Add a macOS menu bar status indicator for NanoClaw. Shows a bolt icon with a green/red dot indicating whether NanoClaw is running, with Start, Stop, and Restart controls. macOS only.
--- ---
# Add macOS Menu Bar Status Indicator # Add macOS Menu Bar Status Indicator
Adds a persistent menu bar icon that shows NanoClaw's running status and lets the user start, stop, or restart the service — similar to how Docker Desktop appears in the menu bar. Adds a persistent menu bar icon that shows NanoClaw's running status and lets the user
start, stop, or restart the service — similar to how Docker Desktop appears in the menu bar.
**macOS only.** Requires Xcode Command Line Tools (`swiftc`). **macOS only.** Requires Xcode Command Line Tools (`swiftc`).
@@ -39,45 +40,38 @@ If not found, tell the user:
launchctl list | grep com.nanoclaw.statusbar launchctl list | grep com.nanoclaw.statusbar
``` ```
If it returns a PID (not `-`), tell the user it's already installed and skip to Phase 4 (Verify). If it returns a PID (not `-`), tell the user it's already installed and skip to Phase 3 (Verify).
## Phase 2: Apply Code Changes ## Phase 2: Compile and Install
### Initialize skills system (if needed)
If `.nanoclaw/` directory doesn't exist yet:
```bash
npx tsx scripts/apply-skill.ts --init
```
### Apply the skill
```bash
npx tsx scripts/apply-skill.ts .claude/skills/add-statusbar
```
This copies `src/statusbar.swift` into the project and records the application in `.nanoclaw/state.yaml`.
## Phase 3: Compile and Install
### Compile the Swift binary ### Compile the Swift binary
The source lives in the skill directory. Compile it into `dist/`:
```bash ```bash
swiftc -O -o dist/statusbar src/statusbar.swift mkdir -p dist
swiftc -O -o dist/statusbar "${CLAUDE_SKILL_DIR}/add/src/statusbar.swift"
``` ```
This produces a small (~55KB) native binary at `dist/statusbar`. This produces a small native binary at `dist/statusbar`.
On macOS Sequoia or later, clear the quarantine attribute so the binary can run:
```bash
xattr -cr dist/statusbar
```
### Create the launchd plist ### Create the launchd plist
Determine the absolute project root: Determine the absolute project root and home directory:
```bash ```bash
pwd pwd
echo $HOME
``` ```
Create `~/Library/LaunchAgents/com.nanoclaw.statusbar.plist`, substituting the actual values for `{PROJECT_ROOT}` and `{HOME}`: Create `~/Library/LaunchAgents/com.nanoclaw.statusbar.plist`, substituting the actual values
for `{PROJECT_ROOT}` and `{HOME}`:
```xml ```xml
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
@@ -113,7 +107,7 @@ Create `~/Library/LaunchAgents/com.nanoclaw.statusbar.plist`, substituting the a
launchctl load ~/Library/LaunchAgents/com.nanoclaw.statusbar.plist launchctl load ~/Library/LaunchAgents/com.nanoclaw.statusbar.plist
``` ```
## Phase 4: Verify ## Phase 3: Verify
```bash ```bash
launchctl list | grep com.nanoclaw.statusbar launchctl list | grep com.nanoclaw.statusbar
@@ -123,7 +117,7 @@ The first column should show a PID (not `-`).
Tell the user: Tell the user:
> The icon should now appear in your macOS menu bar. Click it to see NanoClaw's status and control the service. > The bolt icon should now appear in your macOS menu bar. Click it to see NanoClaw's status and control the service.
> >
> - **Green dot** — NanoClaw is running > - **Green dot** — NanoClaw is running
> - **Red dot** — NanoClaw is stopped > - **Red dot** — NanoClaw is stopped
@@ -136,5 +130,4 @@ Tell the user:
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.statusbar.plist launchctl unload ~/Library/LaunchAgents/com.nanoclaw.statusbar.plist
rm ~/Library/LaunchAgents/com.nanoclaw.statusbar.plist rm ~/Library/LaunchAgents/com.nanoclaw.statusbar.plist
rm dist/statusbar rm dist/statusbar
rm src/statusbar.swift
``` ```

View File

@@ -7,6 +7,14 @@ class StatusBarController: NSObject {
private let plistPath = "\(NSHomeDirectory())/Library/LaunchAgents/com.nanoclaw.plist" private let plistPath = "\(NSHomeDirectory())/Library/LaunchAgents/com.nanoclaw.plist"
/// Derive the NanoClaw project root from the binary location.
/// The binary is compiled to {project}/dist/statusbar, so the parent of
/// the parent directory is the project root.
private static let projectRoot: String = {
let binary = URL(fileURLWithPath: CommandLine.arguments[0]).resolvingSymlinksInPath()
return binary.deletingLastPathComponent().deletingLastPathComponent().path
}()
override init() { override init() {
super.init() super.init()
setupStatusItem() setupStatusItem()
@@ -108,7 +116,7 @@ class StatusBarController: NSObject {
} }
@objc private func viewLogs() { @objc private func viewLogs() {
let logPath = "\(NSHomeDirectory())/Documents/Projects/nanoclaw/logs/nanoclaw.log" let logPath = "\(StatusBarController.projectRoot)/logs/nanoclaw.log"
NSWorkspace.shared.open(URL(fileURLWithPath: logPath)) NSWorkspace.shared.open(URL(fileURLWithPath: logPath))
} }

View File

@@ -1,10 +0,0 @@
skill: statusbar
version: 1.0.0
description: "macOS menu bar status indicator — shows NanoClaw running state with start/stop/restart controls"
core_version: 0.1.0
adds:
- src/statusbar.swift
modifies: []
structured: {}
conflicts: []
depends: []