diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 55b6496..ef7f9ee 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,6 +9,11 @@ "name": "switchboard", "source": "./plugin", "description": "One Switchboard connector and eight shared operator skills for Claude Code and Codex: tasks, notch, whiteboard, PIP, and wrapps." + }, + { + "name": "switchboard-notch", + "source": "./packages/notch-mod", + "description": "Claude's questions drop from your Mac's notch as a native card. A Claude Code mod (v2.1.287+, macOS 13+)." } ] } diff --git a/packages/notch-mod/.claude-plugin/plugin.json b/packages/notch-mod/.claude-plugin/plugin.json new file mode 100644 index 0000000..1af9aef --- /dev/null +++ b/packages/notch-mod/.claude-plugin/plugin.json @@ -0,0 +1,18 @@ +{ + "name": "switchboard-notch", + "version": "0.1.0", + "description": "Claude's questions drop from your Mac's notch as a native card. Pick with 1-4, type your own answer, or press esc to answer in Claude Code as usual.", + "author": { + "name": "sameeeeeeep", + "url": "https://github.com/sameeeeeeep/switchboard" + }, + "displayName": "Switchboard Notch", + "homepage": "https://thelastprompt.ai/switchboard", + "license": "MIT", + "keywords": [ + "notch", + "macos", + "mod", + "AskUserQuestion" + ] +} diff --git a/packages/notch-mod/.gitignore b/packages/notch-mod/.gitignore new file mode 100644 index 0000000..85df01a --- /dev/null +++ b/packages/notch-mod/.gitignore @@ -0,0 +1,3 @@ +.claude-plugin/types/ +tsconfig.json +dist/ diff --git a/packages/notch-mod/README.md b/packages/notch-mod/README.md new file mode 100644 index 0000000..eeb7a26 --- /dev/null +++ b/packages/notch-mod/README.md @@ -0,0 +1,65 @@ +# Switchboard Notch + +When Claude asks you something, the question drops from your Mac's notch as a native card, so you +can answer without switching back to the terminal. + +- **1–4** picks an option, **↵** confirms the highlighted one (Claude's recommendation starts highlighted) +- **Type** in the box to answer in your own words +- **esc** dismisses the card and the question appears in Claude Code as usual, so it is never lost + +Needs macOS 13+ and Claude Code **v2.1.287** or later (`claude --version`). It is a Claude Code +[mod](https://code.claude.com/docs/en/plugins/mods/overview): it hooks Claude's `AskUserQuestion` +tool and nothing else. + +## Try it for one session + +Nothing is installed and nothing is written to your settings: + +```sh +claude --plugin-url https://github.com/sameeeeeeep/switchboard/releases/download/notch-v0.1.0/switchboard-notch.zip +``` + +Ask Claude something that makes it ask you back, or run `/notch test`. + +## Keep it + +In Claude Code (v2.1.275+ adds the marketplace and installs in one step): + +```text +/plugin install switchboard-notch --marketplace sameeeeeeep/switchboard +``` + +Updates: `claude plugin update switchboard-notch@switchboard`. + +## Settings + +| Command | Effect | +| --- | --- | +| `/notch cursor` | Open cards beside the pointer instead of at the notch | +| `/notch notch` | Back to the notch | +| `/notch off` / `/notch on` | Use Claude Code's own dialog / the card | +| `/notch test` | Show a test card | + +Multi-select, free-text and number questions always use Claude Code's own form. + +## Where it works + +Cards appear when Claude Code runs on your Mac: the `claude` CLI in any terminal, and the Desktop +app's Code tab once it ships Claude Code v2.1.287. In other places, such as cloud sessions, the mod +steps aside and Claude Code asks as usual. + +## What it does on your machine + +The mod's only action is to run `helper/sb-card`, a small native program that draws one card and +prints your answer. It needs no permissions, makes no network requests, and exits as soon as you +answer. The binary is signed with Developer ID (STAYOFT VENTURES PRIVATE LIMITED, 55354KFTHU) and +notarized by Apple. Its source is [`helper/sb-card.swift`](helper/sb-card.swift). To see what the mod +hooks before you load it, run `claude plugin validate` on this directory. + +## Develop + +```sh +claude --plugin-dir "$PWD" # load this checkout; edits hot-reload +claude plugin test # unit tests (no session needed) +./build.sh # rebuild, sign and notarize helper/sb-card +``` diff --git a/packages/notch-mod/build.sh b/packages/notch-mod/build.sh new file mode 100755 index 0000000..03c9b25 --- /dev/null +++ b/packages/notch-mod/build.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# Build helper/sb-card as a universal binary, sign it with Developer ID, notarize it, and package +# dist/switchboard-notch.zip for `claude --plugin-url`. +# Set SKIP_NOTARIZE=1 for a local build. +set -eu +cd "$(dirname "$0")" + +IDENTITY="Developer ID Application: STAYOFT VENTURES PRIVATE LIMITED (55354KFTHU)" +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +for arch in arm64 x86_64; do + swiftc -O -target "$arch-apple-macos13" -o "$TMP/sb-card-$arch" helper/sb-card.swift \ + -framework AppKit -framework SwiftUI +done +lipo -create -output helper/sb-card "$TMP/sb-card-arm64" "$TMP/sb-card-x86_64" +codesign --force --options runtime --timestamp --identifier ai.thelastprompt.sb-card \ + --sign "$IDENTITY" helper/sb-card + +if [ "${SKIP_NOTARIZE:-0}" != 1 ]; then + ditto -c -k helper/sb-card "$TMP/sb-card.zip" + xcrun notarytool submit "$TMP/sb-card.zip" --keychain-profile relay-notary --wait +fi + +mkdir -p dist +rm -f dist/switchboard-notch.zip +zip -qr dist/switchboard-notch.zip .claude-plugin/plugin.json hooks helper/sb-card README.md +echo "built dist/switchboard-notch.zip" diff --git a/packages/notch-mod/helper/sb-card b/packages/notch-mod/helper/sb-card new file mode 100755 index 0000000..9863361 Binary files /dev/null and b/packages/notch-mod/helper/sb-card differ diff --git a/packages/notch-mod/helper/sb-card.swift b/packages/notch-mod/helper/sb-card.swift new file mode 100644 index 0000000..a1888e1 --- /dev/null +++ b/packages/notch-mod/helper/sb-card.swift @@ -0,0 +1,230 @@ +// sb-card — one-shot native card for the Switchboard notch mod. +// +// Shows ONE question as a Dynamic-Island-style card dropped from the notch (or beside the cursor), +// waits for the answer, prints it as JSON on stdout, and exits. No daemon, no Switchboard.app, +// no TCC permissions: it only draws its own window and reads the public mouse position. +// +// sb-card '' +// json: { title?, question, options:[{label, detail?, recommended?}], at?: "notch"|"cursor", +// source?, timeout?: seconds } +// stdout: {"answer":"