diff --git a/packages/notch-mod/.claude-plugin/plugin.json b/packages/notch-mod/.claude-plugin/plugin.json index 0143e49..25d1e89 100644 --- a/packages/notch-mod/.claude-plugin/plugin.json +++ b/packages/notch-mod/.claude-plugin/plugin.json @@ -1,14 +1,14 @@ { - "name": "switchboard-notch", - "version": "0.1.4", - "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.", + "name": "ask-notch", + "version": "0.3.0", + "description": "Claude's questions drop from your Mac's notch as a card. Click an option, 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", - "repository": "https://github.com/sameeeeeeep/switchboard-notch", + "displayName": "Ask Notch", + "homepage": "https://github.com/sameeeeeeep/ask-notch", + "repository": "https://github.com/sameeeeeeep/ask-notch", "license": "MIT", "keywords": [ "notch", @@ -18,7 +18,7 @@ "AskUserQuestion" ], "icon": "./assets/icon.png", - "documentationUrl": "https://github.com/sameeeeeeep/switchboard-notch#readme", - "supportUrl": "https://github.com/sameeeeeeep/switchboard-notch/issues", - "privacyPolicyUrl": "https://github.com/sameeeeeeep/switchboard-notch#privacy" + "documentationUrl": "https://github.com/sameeeeeeep/ask-notch#readme", + "supportUrl": "https://github.com/sameeeeeeep/ask-notch/issues", + "privacyPolicyUrl": "https://github.com/sameeeeeeep/ask-notch#privacy" } diff --git a/packages/notch-mod/README.md b/packages/notch-mod/README.md index ab68248..01c83fa 100644 --- a/packages/notch-mod/README.md +++ b/packages/notch-mod/README.md @@ -1,7 +1,7 @@ -# Switchboard Notch +# Ask 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. +When Claude asks you something, the question drops from your Mac's notch as a card, so you can +answer without switching back to the terminal. ![A question from Claude shown as a card at the Mac notch, with three numbered options and a text box](assets/card-light.png) @@ -14,14 +14,15 @@ can answer without switching back to the terminal. 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. +tool and nothing else. Nothing is compiled: the card is a JavaScript file that macOS's own +`osascript` runs. ## Try it for one session Nothing is installed and nothing is written to your settings: ```sh -claude --plugin-url https://github.com/sameeeeeeep/switchboard-notch/releases/latest/download/switchboard-notch.zip +claude --plugin-url https://github.com/sameeeeeeep/ask-notch/releases/latest/download/ask-notch.zip ``` Ask Claude something that makes it ask you back, or run `/notch test`. @@ -31,32 +32,46 @@ Ask Claude something that makes it ask you back, or run `/notch test`. In Claude Code (v2.1.275+ adds the marketplace and installs in one step): ```text -/plugin install switchboard-notch --marketplace sameeeeeeep/switchboard-notch +/plugin install ask-notch --marketplace sameeeeeeep/ask-notch ``` -Updates: `claude plugin update switchboard-notch@switchboard-notch`. +Updates: `claude plugin update ask-notch@ask-notch`. ## Settings +Say what you want after `/notch`, in your own words: `/notch put it by my mouse`, `/notch pause for now`, +`/notch bring the cat`, `/notch show me one`. Claude reads it and changes the setting. On its own, `/notch` +shows the current settings. The words below skip Claude and take effect instantly: + | Command | Effect | | --- | --- | | `/notch cursor` | Open cards beside the pointer instead of at the notch | | `/notch notch` | Back to the notch | +| `/notch companion cat` | A small painted cat hops out beside the card and waits with you | +| `/notch companion off` | No companion (the default) | | `/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. +## Choices come to you + +While cards are on, Claude asks with `AskUserQuestion` whenever it would otherwise list options in its reply +("A or B?", "go ahead?"), so those choices arrive as a card at the notch. The plugin adds one short paragraph saying +so to Claude's system prompt while cards are on (none while they're off), and ships the same guidance as a skill, +`ask-at-the-notch`. + ## Examples Any request where Claude stops to ask you a question shows the card. Three to try: 1. **A design choice.** "Add a settings page to this app. Ask me which layout to use before you - build it." The card shows the layouts Claude proposes, with its pick highlighted. Press **1–4** or **↵**. + build it." The card shows the layouts Claude proposes, with its pick highlighted. Click one, or + click the card and press **1–4** or **↵**. 2. **A risky step.** "Clean up the old migration files, but ask me before deleting anything." Claude's question lands at the notch while you work in another app; answer it there and Claude carries on. -3. **Your own answer.** "Help me name this CLI tool and ask me to choose." Ignore the options, type - a name in the card's text box, and press **↵**. Claude receives exactly what you typed. +3. **Your own answer.** "Help me name this CLI tool and ask me to choose." Ignore the options, click + the card's text box, type a name, and press **↵**. Claude receives exactly what you typed. `/notch test` shows a sample card without asking Claude anything. @@ -71,46 +86,64 @@ as usual. ## Troubleshooting - **No card appears.** Run `claude --version` (needs v2.1.287+), then `/plugin` and look for - `switchboard-notch` in the `mods active` line under the tabs. Run `/notch test`. If `/notch` is off, run `/notch on`. + `ask-notch` in the `mods active` line under the tabs. Run `/notch test`. If `/notch` is off, run `/notch on`. - **The card opens on the wrong screen.** Run `/notch cursor` to open it beside the pointer. - **You'd rather answer in the terminal.** Press **esc** on any card, or run `/notch off`. ## What it does on your machine -Everything the mod does is in [`hooks/register.js`](hooks/register.js) (about 90 lines): +The mod is [`hooks/register.js`](hooks/register.js) (about 100 lines) and the card is +[`helper/card.js`](helper/card.js) (about 600 lines). Both are plain JavaScript you can read; the +plugin ships no compiled code. - **Which tool it answers, and when.** It handles only Claude Code's `AskUserQuestion` tool, and only single-choice questions. When you pick or type an answer in the card, the mod returns that answer in place of Claude Code's own question dialog, in the same shape the dialog returns. If you press esc, the card times out (9 minutes), the question is multi-select, text or number, or the card can't start, it hands the question back to Claude Code's dialog unchanged. -- **The one program it starts, and why.** It runs `helper/sb-card` (in this plugin) to draw the card, - with one argument: a JSON object holding the question, its options, and where to show the card. - It starts nothing else and runs no shell. -- **What it reads, and where that goes.** It reads the question Claude is asking (part of your - conversation) and passes it to `helper/sb-card` as that argument. `helper/sb-card` prints your - answer and exits, and the mod gives the answer back to Claude. Nothing is sent anywhere else: the - mod makes no network requests, and neither does `helper/sb-card`. -- **What it stores.** Only your `/notch` setting (on or off, notch or cursor), in Claude Code's - local storage for this plugin. - -`helper/sb-card` is a small native macOS program built from -[`helper/sb-card.swift`](helper/sb-card.swift) (about 230 lines of AppKit and SwiftUI). It needs no -permissions and writes no files. It is signed with Developer ID (STAYOFT VENTURES PRIVATE LIMITED, -55354KFTHU) and notarized by Apple. To list the mod's hooks and calls yourself, run -`claude plugin validate` on this directory. +- **The one program it starts, and why.** It always runs the same fixed command, + `/usr/bin/osascript -l JavaScript helper/card.js`, from this plugin's own folder. `osascript` is + macOS's built-in script runner; the plugin needs it because a Claude Code mod can only draw inside + Claude Code's window, and the card has to appear at the Mac's notch. The question, its options, + where to show the card and, if you turned one on, the companion's folder go to the card on its + **standard input** as one JSON object. It starts nothing else and runs no shell. +- **What the card does.** `helper/card.js` uses macOS's JavaScript bridge to AppKit to draw one + window, reads the pointer position (for `/notch cursor`) and, with a companion, the pictures in + `assets/companion/`. It prints your answer as one line of JSON and exits. It makes no network + requests, writes no files, reads no environment variables and needs no permissions. It refuses + the keyboard until you click it, and appears without activating, so it can't take keystrokes + meant for the app you're using. +- **What it reads, and where it sends it.** It reads the question Claude is asking (part of your + conversation) and sends it to exactly one place: the local `osascript` process above, on its + standard input. The card prints your answer on standard output and exits, and the mod gives the + answer back to Claude. Nothing leaves your Mac: no network requests, no files written, no + credentials or environment variables read. +- **Standing in for a tool.** The mod answers `AskUserQuestion` in place of Claude Code's dialog + only when you answer on the card; every other case calls through to Claude Code's own dialog. +- **Settings in plain words.** `/notch` followed by words it doesn't recognise sends Claude one + prompt that quotes them. Claude then changes the setting through the plugin's own tool, + `mcp__ask-notch__settings` (on/off, notch/cursor, companion, test card). The tool reads and writes + only the settings below. +- **The system prompt note and the skill.** While cards are on, the mod adds one fixed paragraph to + Claude's system prompt (`CHOICES_NOTE` in `hooks/register.js`) asking it to put choices to you + with `AskUserQuestion`. `skills/ask-at-the-notch/SKILL.md` says the same at length. Both are plain + text and run nothing. +- **What it stores.** Only your `/notch` settings (on or off, notch or cursor, companion), in + Claude Code's local storage for this plugin. + +To list the mod's hooks and calls yourself, run `claude plugin validate` on this directory. ## Privacy -Switchboard Notch collects nothing. The question, its options and your answer pass only between -Claude Code and `helper/sb-card` on your Mac. There is no network access, no analytics and no -account. The only thing saved is your `/notch` setting (on or off, notch or cursor), in Claude -Code's local storage for this plugin; uninstalling the plugin removes it. +Ask Notch collects nothing. The question, its options and your answer pass only between Claude Code +and `osascript` running `helper/card.js` on your Mac. There is no network access, no analytics and +no account. The only thing saved is your `/notch` settings (on or off, notch or cursor, companion), +in Claude Code's local storage for this plugin; uninstalling the plugin removes it. ## Support Report problems or ask questions at -[github.com/sameeeeeeep/switchboard-notch/issues](https://github.com/sameeeeeeep/switchboard-notch/issues). +[github.com/sameeeeeeep/ask-notch/issues](https://github.com/sameeeeeeep/ask-notch/issues). For security issues, email [sameeeeeeep@gmail.com](mailto:sameeeeeeep@gmail.com) instead of opening a public issue. ## Develop @@ -119,6 +152,6 @@ The source lives in [`packages/notch-mod`](https://github.com/sameeeeeeep/switch in the Switchboard repo, which also holds the build and release scripts; this repo is a mirror. ```sh -claude --plugin-dir "$PWD" # load a checkout for one session; edits hot-reload +claude --plugin-dir /path/to/ask-notch # load a checkout for one session; edits hot-reload claude plugin test # unit tests (no session needed) ``` diff --git a/packages/notch-mod/assets/card-dark.png b/packages/notch-mod/assets/card-dark.png index 57d24a9..7a53366 100644 Binary files a/packages/notch-mod/assets/card-dark.png and b/packages/notch-mod/assets/card-dark.png differ diff --git a/packages/notch-mod/assets/card-light.png b/packages/notch-mod/assets/card-light.png index 7201942..5c36037 100644 Binary files a/packages/notch-mod/assets/card-light.png and b/packages/notch-mod/assets/card-light.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-01.png b/packages/notch-mod/assets/companion/cat/intro-01.png new file mode 100644 index 0000000..9f5711b Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-01.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-02.png b/packages/notch-mod/assets/companion/cat/intro-02.png new file mode 100644 index 0000000..db21b32 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-02.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-03.png b/packages/notch-mod/assets/companion/cat/intro-03.png new file mode 100644 index 0000000..9682113 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-03.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-04.png b/packages/notch-mod/assets/companion/cat/intro-04.png new file mode 100644 index 0000000..e9a7c2c Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-04.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-05.png b/packages/notch-mod/assets/companion/cat/intro-05.png new file mode 100644 index 0000000..3081164 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-05.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-06.png b/packages/notch-mod/assets/companion/cat/intro-06.png new file mode 100644 index 0000000..f87f1c7 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-06.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-07.png b/packages/notch-mod/assets/companion/cat/intro-07.png new file mode 100644 index 0000000..b0db25f Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-07.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-08.png b/packages/notch-mod/assets/companion/cat/intro-08.png new file mode 100644 index 0000000..87fb7c6 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-08.png differ diff --git a/packages/notch-mod/assets/companion/cat/intro-09.png b/packages/notch-mod/assets/companion/cat/intro-09.png new file mode 100644 index 0000000..740273b Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/intro-09.png differ diff --git a/packages/notch-mod/assets/companion/cat/settle-1.png b/packages/notch-mod/assets/companion/cat/settle-1.png new file mode 100644 index 0000000..b9ab7d7 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/settle-1.png differ diff --git a/packages/notch-mod/assets/companion/cat/settle-2.png b/packages/notch-mod/assets/companion/cat/settle-2.png new file mode 100644 index 0000000..ca7cb97 Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/settle-2.png differ diff --git a/packages/notch-mod/assets/companion/cat/sit.png b/packages/notch-mod/assets/companion/cat/sit.png new file mode 100644 index 0000000..1c85cde Binary files /dev/null and b/packages/notch-mod/assets/companion/cat/sit.png differ diff --git a/packages/notch-mod/assets/companion/clawd/README.md b/packages/notch-mod/assets/companion/clawd/README.md new file mode 100644 index 0000000..7f984f4 --- /dev/null +++ b/packages/notch-mod/assets/companion/clawd/README.md @@ -0,0 +1,24 @@ +# Clawd companion: placeholder (art pending the owner's decision) + +**Status: no art here on purpose.** `/notch companion clawd` is a hidden option (not in the README or +the directory listing). With this folder holding no `sequence.json`, the card shows no companion, so +the option is a safe no-op until a decision is made. + +Why it's empty: Clawd is Anthropic's character. Whether Ask Notch ships a Clawd companion in its +Claude directory submission is the owner's call (trademark and review risk), so no Clawd artwork has +been copied from anywhere into this repo. `build.sh` and `publish.sh` leave this folder out of the +published plugin. + +## To fill the slot (only after the decision) + +Use the same contract as `../cat/` (see `listing/make-companion.py`, which builds it): + +- `sequence.json`: `canvas` `[w, h]` in points; `overlap` (points of the canvas that sit behind the + card's right edge); `intro` `{ delay_ms, frames: [[file, ms], ...] }` played when the card appears; + `idle` (file shown while waiting); `settle` `{ after_s, frames }` played once after `after_s`. +- Frames: transparent PNGs at 2× the canvas size, all the same size, feet on the canvas's ground line, + so the card only swaps pictures. File names: letters, digits, `.`, `-`, `_`, ending in `.png`. +- Keep the folder small (the cat is about 220 KB). + +Then remove the `-x 'assets/companion/clawd/*'` exclusion in `build.sh`, the matching `rm` in +`publish.sh`, and document `/notch companion clawd` in the README and listing. diff --git a/packages/notch-mod/build.sh b/packages/notch-mod/build.sh index 5a48f29..a379c8c 100755 --- a/packages/notch-mod/build.sh +++ b/packages/notch-mod/build.sh @@ -1,28 +1,14 @@ #!/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. +# Package dist/ask-notch.zip for `claude --plugin-url`. Nothing is compiled or signed: the card is +# helper/card.js, run by macOS's own /usr/bin/osascript. 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 - +claude plugin validate "$PWD" >/dev/null mkdir -p dist -rm -f dist/switchboard-notch.zip -zip -qr dist/switchboard-notch.zip .claude-plugin/plugin.json hooks helper/sb-card assets README.md -echo "built dist/switchboard-notch.zip" +rm -f dist/ask-notch.zip +# Leave out macOS/Windows system files (the directory's validator blocks them) and the Clawd companion +# slot, which holds no art until the owner decides (assets/companion/clawd/README.md). +zip -qr dist/ask-notch.zip .claude-plugin/plugin.json hooks helper skills assets README.md \ + -x '*.DS_Store' -x '*Thumbs.db' -x '*desktop.ini' -x '__MACOSX/*' -x 'assets/companion/clawd/*' +echo "built dist/ask-notch.zip ($(du -h dist/ask-notch.zip | cut -f1))" diff --git a/packages/notch-mod/helper/card.js b/packages/notch-mod/helper/card.js new file mode 100644 index 0000000..fac3579 --- /dev/null +++ b/packages/notch-mod/helper/card.js @@ -0,0 +1,603 @@ +// Ask Notch card: one question as a native card at the Mac notch (or beside the pointer). +// +// Plain JavaScript for macOS's built-in script runner (JavaScript for Automation, with its bridge to +// AppKit). Nothing is compiled; this file is the whole program: +// +// /usr/bin/osascript -l JavaScript helper/card.js '' +// json: { title?, question, options:[{label, detail?, recommended?}], at?: "notch"|"cursor", +// source?, timeout?: seconds, appearance?: "light"|"dark", companion?: {name, dir}, +// debug?: true } (tests also use at: "offscreen", a window on no display) +// stdout: {"answer":"