From 9dbbd50d5eac17b1949a9ad1e288d00825bcc844 Mon Sep 17 00:00:00 2001 From: StuBehan Date: Thu, 30 Apr 2026 08:38:12 +0200 Subject: [PATCH 1/2] chore: prep repo for going public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the standard community files and a CI workflow ahead of an open-source release. Patterns adapted from stackvox. Community files - CONTRIBUTING.md — local setup, make targets, source layout, the rebuild-invalidates-TCC gotcha, commit / branch conventions, PR checklist - CODE_OF_CONDUCT.md — Contributor Covenant 2.1, support@stackone.com for enforcement reports - SECURITY.md — security@stackone.com, in/out-of-scope split (stackvox and other deps redirect upstream), pre-1.0 latest-only support policy - NOTICE — copyright + third-party acknowledgements (stackvox is pulled fresh from PyPI, terminal-notifier inspired the click-routing pattern, stackone-say-hooks seeded the phrase pools) - CHANGELOG.md — keep-a-changelog format with backfilled v0.1.0 / v0.2.0 / v0.3.0 entries reflecting what's already shipped - LICENSE copyright line updated to "StackOne Technologies Ltd. and contributors" GitHub configuration - .github/PULL_REQUEST_TEMPLATE.md - .github/ISSUE_TEMPLATE/{bug_report,feature_request,config}.yml — bug report captures stack-nudge specifics (agent, editor, config excerpts, panel/daemon log paths) - .github/dependabot.yml — github-actions only (no SPM, no tracked Python deps; install.sh pulls stackvox from PyPI at install time) CI - .github/workflows/ci.yml — three jobs: 1. shell — bash -n + shellcheck (severity warning) on every tracked .sh 2. build-macos — runs build.sh for arm64 and x86_64 on macos-15, verifies the resulting Mach-O matches the matrix arch, lints both Info.plists with plutil - Existing auto-tag.yml + release.yml workflows retained as-is Misc - .gitignore expanded — covers stack-nudge-panel.app, common editor artefacts, /tmp/, *.log No release-please / pre-commit / commitizen for now — stack-nudge has no Python toolchain and the existing tag-from-Info.plist flow works. Release tooling can land in a follow-up if it pays back. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/ISSUE_TEMPLATE/bug_report.yml | 103 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 ++ .github/ISSUE_TEMPLATE/feature_request.yml | 32 +++++++ .github/PULL_REQUEST_TEMPLATE.md | 30 ++++++ .github/dependabot.yml | 17 ++++ .github/workflows/ci.yml | 61 ++++++++++++ .gitignore | 18 +++- CHANGELOG.md | 59 ++++++++++++ CODE_OF_CONDUCT.md | 19 ++++ CONTRIBUTING.md | 76 +++++++++++++++ LICENSE | 2 +- NOTICE | 42 +++++++++ SECURITY.md | 35 +++++++ 13 files changed, 499 insertions(+), 3 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 NOTICE create mode 100644 SECURITY.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..03583e5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,103 @@ +name: Bug report +description: Something doesn't work as expected +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report a bug. The more specific your reproduction steps, the faster we can fix it. + + - type: textarea + id: what-happened + attributes: + label: What happened? + description: A clear description of the bug, plus the expected behavior. + placeholder: When Claude Code requests a permission, the banner appears but pressing Enter on the panel row does not approve it. + validations: + required: true + + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: Minimal command sequence a maintainer can follow. + placeholder: | + 1. `./install.sh` + 2. Set `STACKNUDGE_PANEL=true` in `~/.stack-nudge/config` + 3. Run a Claude Code session in a VS Code terminal + 4. Trigger any permission prompt + 5. Press the global hotkey, then Enter on the row + 6. Observe: focus changes but Enter doesn't fire + validations: + required: true + + - type: input + id: version + attributes: + label: stack-nudge version + description: Run `git -C ~/path/to/stack-nudge describe --tags` or paste the latest commit SHA. + placeholder: "v0.3.0 / commit abc1234" + validations: + required: true + + - type: dropdown + id: os + attributes: + label: Operating system + options: + - macOS + - Linux + - Other + validations: + required: true + + - type: input + id: macos-version + attributes: + label: macOS version (if applicable) + placeholder: "macOS 15.2" + + - type: dropdown + id: agent + attributes: + label: Agent + multiple: true + options: + - Claude Code + - Cursor + - Gemini CLI + - Codex + - Other / custom hook + + - type: dropdown + id: editor + attributes: + label: Editor / terminal hosting the agent + multiple: true + options: + - VS Code + - Cursor + - iTerm2 + - Warp + - Ghostty + - Terminal.app + - Other + + - type: textarea + id: config + attributes: + label: Relevant config + description: | + Contents of `~/.stack-nudge/config` (redact anything personal). + Particularly useful: `STACKNUDGE_PANEL`, `STACKNUDGE_BANNER`, `STACKNUDGE_VOICE`, `STACKNUDGE_PANEL_HOTKEY`. + render: shell + + - type: textarea + id: logs + attributes: + label: Relevant logs / output + description: | + - `~/.stack-nudge/panel.log` for panel daemon errors + - `~/.stack-nudge/daemon.log` for stackvox errors + Redact anything sensitive. + render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..8d41708 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Security vulnerability + url: https://github.com/StackOneHQ/stack-nudge/security/policy + about: Do not open public issues for security reports. Follow SECURITY.md instead. + - name: Questions / discussion + url: https://github.com/StackOneHQ/stack-nudge/discussions + about: General questions, usage help, or ideas that aren't yet a concrete feature request. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..b9b92f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,32 @@ +name: Feature request +description: Suggest a new capability or improvement +labels: ["enhancement"] +body: + - type: textarea + id: problem + attributes: + label: What problem are you trying to solve? + description: Describe the use case first, not the solution. + placeholder: | + I run multiple Claude Code sessions in different VS Code windows and want to know which session each nudge came from at a glance. + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: Proposed solution + description: Optional — if you have a shape in mind, sketch it. Keys, config flags, UI changes, etc. + + - type: textarea + id: alternatives + attributes: + label: Alternatives you've considered + description: Optional — other approaches you rejected, and why. + + - type: checkboxes + id: willing-to-contribute + attributes: + label: Contribution + options: + - label: I'd be willing to open a PR for this. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2073a24 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,30 @@ + + +## Summary + + + +## Changes + + + +- +- + +## Testing + + + +## Related issues + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6243e6f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + # No tracked Swift dependencies (no SPM Package.swift) and no tracked + # Python dependencies (stackvox is pulled fresh from PyPI by install.sh). + # The only thing dependabot can usefully bump here is the GitHub Actions + # we pin in workflows. + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - dependencies + - ci + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..23deff0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + shell: + name: shell syntax + shellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: bash -n on tracked shell scripts + run: | + set -e + mapfile -d '' files < <(git ls-files -z '*.sh') + for f in "${files[@]}"; do + echo "→ bash -n $f" + bash -n "$f" + done + + - name: shellcheck + uses: ludeeus/action-shellcheck@master + with: + severity: warning + + build-macos: + name: swift build (${{ matrix.arch }}) + runs-on: macos-15 + strategy: + fail-fast: false + matrix: + arch: [arm64, x86_64] + steps: + - uses: actions/checkout@v4 + + - name: build both .app bundles + run: ./build.sh ${{ matrix.arch }} + + - name: verify executables exist + are correct arch + run: | + set -e + for app in build/stack-nudge.app build/stack-nudge-panel.app; do + bin=$(ls "$app/Contents/MacOS/") + file "$app/Contents/MacOS/$bin" + file "$app/Contents/MacOS/$bin" | grep -q "${{ matrix.arch }}" + done + + - name: verify Info.plists are valid + run: | + plutil -lint notifier/Info.plist + plutil -lint panel/Info.plist diff --git a/.gitignore b/.gitignore index f4b2781..9c76aac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,26 @@ -.DS_Store +# Build output build/ stack-nudge stack-nudge.app +stack-nudge-panel.app + +# macOS +.DS_Store -# Python +# Editors / IDEs +.vscode/ +.idea/ +*.swp +*~ + +# Python (ad-hoc venvs in the repo, the stackvox venv lives in ~/.stack-nudge/) __pycache__/ *.py[cod] *.egg-info/ dist/ .venv/ venv/ + +# Stack-nudge dev artifacts +/tmp/ +*.log diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f58c633 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,59 @@ +# Changelog + +All notable changes to stack-nudge are documented in this file. + +The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Pre-1.0, breaking changes bump the **minor** version. + +## [Unreleased] + +### Added + +- Repo prepared for open-source release: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `NOTICE`, this changelog, GitHub issue / PR templates, dependabot config for actions, and a CI workflow that verifies the Swift build and shell scripts on macOS. + +## [0.3.0] — 2026-04-30 + +### Added + +- **Tabbed keyboard panel** — Events / Sessions / Settings tabs reachable via `Cmd+1` / `Cmd+2` / `Cmd+3` or the in-panel tab strip. +- **Sessions tab** — live list of running `claude` / `gemini` / `codex` agent processes (including node-hosted variants like `gemini-cli`). Polls `ps` + `lsof` every 3 seconds while visible. Supports focus-source-terminal (⏎), inline rename (`n`), and SIGTERM kill (⌫). Closes #3. +- **Settings tab** — keyboard-driven rows for hotkey, banner / voice toggles, sound picks (with audio preview on cycle), voice picker (with conversational-phrase preview on cycle), speed, plus action shortcuts to permissions / open config / quit. +- **Hotkey recorder** — record a new global hotkey from inside Settings; re-registers live and persists to `~/.stack-nudge/config`. Surfaces an inline error when the OS rejects the combo. +- **Per-pane focus in VS Code / Cursor** — before sending the approval keystroke, the panel walks the editor's accessibility tree to focus the terminal pane labelled with the agent's binary name (claude / gemini / codex). Falls back gracefully if no match. +- **Per-language voice phrase pools** — `phrases/{en,fr,hi,it,pt}.sh` provide event-specific (response / notification) phrasing keyed off the configured Kokoro voice's language prefix. Voice messages now sound like *"unified cloud api is ready for you"* or *"unified cloud api requires a decision"* instead of the literal "Done". +- **Config file watcher** — external edits to `~/.stack-nudge/config` flow back into the running panel without a restart. Re-arms on rename/delete so atomic-save editors don't orphan the watcher. +- **Permissions window** with a Reset & prompt action that clears the TCC entry and triggers macOS's standard grant dialog — recovers the rebuild-invalidates-cdhash gotcha that bites every iteration of an ad-hoc-signed dev build. +- **Voice replaces sound** — when `STACKNUDGE_VOICE=true`, the chime is suppressed across all surfaces so the user doesn't get double-cued. +- **`make dev`** watch-loop for inner-loop development; rebuild + reinstall + bounce in ~2s on any `.swift` / `notify.sh` / `phrases/` save. + +### Changed + +- Default hotkey switched from `cmd+shift+n` (collides with "New Incognito Window" in browsers, "New Window" in many editors, "New Folder" in Finder) to `cmd+opt+n`. +- stackvox vendored copy removed; `install.sh` now pulls `stackvox>=0.3.0` from PyPI into the venv. The `find_python` helper in `install.sh` selects a Python ≥ 3.10 from common Homebrew paths when the system `python3` is too old. + +### Fixed + +- Permissions window crash on open (`NSInternalInconsistencyException` from setting both `.canJoinAllSpaces` and `.moveToActiveSpace` on `collectionBehavior`). +- Hotkey recording-mode trap — ↑/↓/Tab now cancel recording so users who entered by mistake aren't stuck. +- Banner suppression when source window is frontmost respects the voice / sound interplay. + +## [0.2.0] — 2026-04-25 + +### Added + +- **Keyboard-native floating panel** — opt-in `STACKNUDGE_PANEL=true` runs a persistent daemon that surfaces nudges in a borderless HUD-blur window summoned by global hotkey. Acts on events with the keyboard (↑/↓ select, ⏎ approve / focus, ⌫ dismiss, esc hide). +- **Menu bar bell icon** with quick toggles for banner / voice, links to the panel and config file, and a Quit action. +- **Per-event PID / session enrichment** — `notify.sh` walks the parent process tree on each hook and emits `agent_pid`, `shell_pid`, `terminal_pid`, `terminal_app`, `term_program`, and `session_id` alongside the existing fields. Used by the panel for session correlation. + +## [0.1.0] — 2026-04-22 + +### Added + +- Initial release. Supports Claude Code, Cursor, Gemini CLI, and Codex via `notify.sh `. +- macOS native banners with click-to-focus that route back to the source editor / terminal window. Supported apps: VS Code, Cursor, iTerm2, Warp, Ghostty, Terminal.app. +- Voice notifications via [stackvox](https://github.com/StackOneHQ/stackvox) — bundled and set up automatically by `./install.sh`. +- `STACKNUDGE_ACTIVATE_IMMEDIATELY=true` for click-free editor focus. + +[Unreleased]: https://github.com/StackOneHQ/stack-nudge/compare/v0.3.0...HEAD +[0.3.0]: https://github.com/StackOneHQ/stack-nudge/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/StackOneHQ/stack-nudge/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/StackOneHQ/stack-nudge/releases/tag/v0.1.0 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d4632ce --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,19 @@ +# Code of Conduct + +This project adopts the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) as its code of conduct. Contributors are expected to follow its standards when participating in this repository — in issues, pull requests, discussions, commit messages, reviews, and any other project space. + +The full text is available at the link above and applies in whole. Please read it before contributing. + +## Scope + +This Code of Conduct applies within all project spaces, and also applies when an individual is officially representing the project or its community in public spaces. + +## Enforcement + +Concerns about conduct can be reported by emailing **support@stackone.com**. All reports will be reviewed and investigated promptly and fairly. Project maintainers are obligated to respect the privacy and safety of the reporter. + +Maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adopted from the Contributor Covenant, version 2.1, available at . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f69d2bb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +# Contributing to stack-nudge + +Thanks for your interest in making stack-nudge better. This doc covers local setup, how to run the app during development, and conventions for commits and PRs. + +## Development setup + +```bash +git clone https://github.com/StackOneHQ/stack-nudge.git +cd stack-nudge +./install.sh # builds + installs the .apps, registers hooks, sets up the voice venv +``` + +`install.sh` is idempotent — re-run it any time after pulling changes to refresh the installed binaries and `notify.sh`. + +System dependencies: + +- **macOS** — Swift 5.9+ via the Xcode Command Line Tools (`xcode-select --install`). PortAudio ships with the system; voice will additionally pull `stackvox` from PyPI into a venv at `~/.stack-nudge/venv`. +- **Linux** — Bash, `paplay` / `aplay` / `notify-send` for sound notifications. The Swift panel app is macOS-only; on Linux only the `notify.sh` flow runs. + +## Inner-loop development + +```bash +make build # builds both .app bundles into build/ +make install # full install (build + copy + register hooks + launchd) +make reload # rebuild + replace installed panel + refresh notify.sh + bounce daemon +make dev # watch sources; auto-reload on .swift / Info.plist / notify.sh / phrase changes +make uninstall # remove apps, hooks, launchd agents, ~/.stack-nudge/ +``` + +`make dev` is the main inner-loop tool. Leave it running in another terminal while you edit Swift files or `notify.sh` — the daemon bounces with the new build in ~2 seconds. + +The Swift sources are compiled directly with `swiftc`. There is no Xcode project, no Swift Package Manager manifest, and no third-party Swift dependencies. The build system is intentionally minimal — see `build.sh`. + +## Source layout + +- `notifier/` — the transient banner-renderer that fires per nudge and exits +- `panel/` — the persistent floating-panel daemon (hotkey, NSPanel, socket listener, menu bar, sessions list, settings, permissions window) +- `shared/` — code shared by both binaries (currently `AppActivator.swift`) +- `phrases/` — per-language voice phrase pools sourced by `notify.sh` at hook time +- `notify.sh` — the shell entry-point CC/Cursor/Gemini hooks invoke; routes events to banner / panel / voice surfaces +- `assets/` — logo / icon source files + +## macOS permissions during development + +The panel daemon needs **Accessibility** and **Automation → System Events** to send the approval keystroke. Each `make reload` re-signs the binary with a new ad-hoc signature, which invalidates prior TCC grants — System Settings still shows the entry as "on" but `AXIsProcessTrusted()` returns false. The Permissions checker (menu bar → Check permissions…) has a **Reset & prompt** button that runs `tccutil reset` and triggers a fresh dialog bound to the current cdhash. Use it whenever approval stops working after a build. + +## Commit and branch style + +- Branch names: `/` (e.g. `feat/voice-phrases`, `fix/permissions-crash`, `chore/oss-readiness`). +- Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/): + - `feat: add X` + - `fix: handle Y` + - `docs: update README` + - `refactor: extract panel components` + - `test: cover hotkey parser` + - `chore: bump dependencies` +- Prefer small, focused commits over large omnibus ones. The exception is genuinely-coupled work that has to land together; in that case, structure the commit body to explain the coupling. + +## Pull request checklist + +- [ ] `make build` succeeds locally and you've manually verified the change with `make reload`. +- [ ] No new compiler warnings in your changed files (existing `NSUserNotification` deprecation warnings in `notifier/` are pre-existing — leave them). +- [ ] README updated if user-visible behavior changed. +- [ ] No credentials, API keys, or PII in the diff. +- [ ] Branch is rebased on the latest `main` if it's been more than a day. + +## Code style notes + +- **Swift**: keep the no-Xcode / no-SPM constraint. New files go under `panel/`, `notifier/`, or `shared/` and are added to the explicit file list in `build.sh`. No third-party Swift dependencies — the value of the build's simplicity outweighs the convenience of pulling libraries. +- **Shell**: `notify.sh` and the `phrases/*.sh` are POSIX-bash. Use `bash -n` to syntax-check before committing. Avoid `bashisms` that aren't strictly necessary. +- **Filesystem paths** should resolve relative to the script (`BASH_SOURCE` for shell, `NSHomeDirectory()` / `~/.stack-nudge/...` for Swift) rather than being hardcoded against `$HOME` or `/Users/...`. +- **Comments** explain the *why* — particularly for AppKit / AX edge cases that aren't obvious from the code. Don't comment what the code already says. + +## Reporting security issues + +Do not file public GitHub issues for security vulnerabilities — see [`SECURITY.md`](./SECURITY.md). diff --git a/LICENSE b/LICENSE index f384de2..bd58e1a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 StackOne contributors +Copyright (c) 2026 StackOne Technologies Ltd. and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..85630c6 --- /dev/null +++ b/NOTICE @@ -0,0 +1,42 @@ +stack-nudge +Copyright 2026 StackOne Technologies Ltd. + +This product includes software developed by StackOne Technologies Ltd. +(https://www.stackone.com/) and is licensed under the MIT License. A copy +of the license is provided in the LICENSE file. + +-------------------------------------------------------------------------------- +Third-party components +-------------------------------------------------------------------------------- + +This product relies on, but does not bundle, the following components. They +are downloaded or installed separately at install / first-run time. Their +original copyright notices and license terms apply. + +stackvox (offline TTS engine) + Copyright (c) StackOne Technologies Ltd. + Licensed under the Apache License, Version 2.0 + https://github.com/StackOneHQ/stackvox + + stack-nudge installs stackvox from PyPI into an isolated venv at + ~/.stack-nudge/venv when ./install.sh runs. stackvox itself bundles + Kokoro-82M model weights downloaded on first use; see its NOTICE for + details. + +terminal-notifier (architectural reference) + Copyright (c) Eloy Durán, Julien Blanchard + Licensed under the MIT License + https://github.com/julienXX/terminal-notifier + + stack-nudge's click-routing pattern (process exits after delivering the + notification, macOS re-launches the app on click and surfaces the + delivered notification via NSApplicationLaunchUserNotificationKey) is + adapted from terminal-notifier. No code is copied verbatim. + +stackone-say-hooks (phrase pool reference) + Copyright (c) StackOne Technologies Ltd. + Licensed under the MIT License + https://github.com/StackOneHQ/stackone-claude-internal-marketplace + + The per-event / per-language voice phrase pools in `phrases/` were + initially adapted from the stackone-say-hooks plugin's phrase files. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a6778d1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,35 @@ +# Security policy + +## Reporting a vulnerability + +Please **do not** open public GitHub issues for security reports. Instead, email **security@stackone.com** with: + +- A description of the issue and the version of stack-nudge affected. +- Steps to reproduce or a proof-of-concept, if available. +- Any known mitigations. + +We aim to acknowledge reports within 3 business days and to provide a remediation timeline within 10 business days of the initial acknowledgement. + +## Scope + +In scope: + +- The `stack-nudge.app` and `stack-nudge-panel.app` macOS binaries (notifier and floating-panel daemon). +- The unix-socket protocol the panel daemon uses to receive nudges from `notify.sh` (`~/.stack-nudge/panel.sock`). +- File-permission handling in `~/.stack-nudge/` and the launchd plists installed by `install.sh`. +- The shell hook entry point `notify.sh` and its handling of agent-supplied JSON (Claude Code passes hook payloads on stdin). +- Supply-chain issues in the immediate stack-nudge repository (e.g. typo-squat risk on installer URLs). + +Out of scope (report upstream instead): + +- Vulnerabilities in `stackvox` (the offline TTS engine) — report to . +- Vulnerabilities in `kokoro-onnx`, `onnxruntime`, or any other dependency of stackvox — report to the respective project. +- macOS Accessibility / Automation TCC bugs — report to Apple. + +## Supported versions + +stack-nudge is pre-1.0. Only the latest published release receives security fixes. Once 1.0 ships, we will maintain the most recent minor release of the current major version. + +## Privacy + +stack-nudge runs entirely locally — see [`PRIVACY.md`](./PRIVACY.md) for the full story. There is no network telemetry, no analytics, no cloud component. Voice synthesis happens locally via stackvox; the only network traffic at install time is `pip install stackvox` from PyPI. From f3d45fe68e754bbe5671a78d075d276778ee5293 Mon Sep 17 00:00:00 2001 From: StuBehan Date: Thu, 30 Apr 2026 09:14:54 +0200 Subject: [PATCH 2/2] chore(ci): silence SC2034 for phrase template arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit shellcheck flags TEMPLATES_RESPONSE / TEMPLATES_NOTIFICATION as unused because they're consumed by notify.sh after sourcing — the consumer is in a different file. Disable directive sits between the file's header comment and the array declaration so future phrase pools inherit it. Co-Authored-By: Claude Opus 4.7 (1M context) --- phrases/en.sh | 1 + phrases/fr.sh | 1 + phrases/hi.sh | 1 + phrases/it.sh | 1 + phrases/pt.sh | 1 + 5 files changed, 5 insertions(+) diff --git a/phrases/en.sh b/phrases/en.sh index 2436d03..4bc12d7 100755 --- a/phrases/en.sh +++ b/phrases/en.sh @@ -1,5 +1,6 @@ #!/bin/bash # English phrase templates. %s is the repo name. +# shellcheck disable=SC2034 # arrays are consumed by notify.sh after sourcing TEMPLATES_RESPONSE=( "%s is ready for you" "%s needs your attention" diff --git a/phrases/fr.sh b/phrases/fr.sh index 7cd3991..09811e7 100755 --- a/phrases/fr.sh +++ b/phrases/fr.sh @@ -1,5 +1,6 @@ #!/bin/bash # French phrase templates. Formal addressing (vous). %s is the repo name. +# shellcheck disable=SC2034 # arrays are consumed by notify.sh after sourcing TEMPLATES_RESPONSE=( "%s est prêt pour vous" "%s requiert votre attention" diff --git a/phrases/hi.sh b/phrases/hi.sh index 57be264..99c1bfe 100755 --- a/phrases/hi.sh +++ b/phrases/hi.sh @@ -1,6 +1,7 @@ #!/bin/bash # Hindi phrase templates (romanized, matches Kokoro's hf_* / hm_* voices). # Formal addressing (aap). %s is the repo name. +# shellcheck disable=SC2034 # arrays are consumed by notify.sh after sourcing TEMPLATES_RESPONSE=( "%s aapke liye taiyaar hai" "%s ko aapke dhyaan ki zaroorat hai" diff --git a/phrases/it.sh b/phrases/it.sh index 9b5db48..8e94c89 100755 --- a/phrases/it.sh +++ b/phrases/it.sh @@ -1,5 +1,6 @@ #!/bin/bash # Italian phrase templates. Formal addressing (Lei). %s is the repo name. +# shellcheck disable=SC2034 # arrays are consumed by notify.sh after sourcing TEMPLATES_RESPONSE=( "%s è pronto per Lei" "%s richiede la Sua attenzione" diff --git a/phrases/pt.sh b/phrases/pt.sh index 77630d1..1f58fc0 100755 --- a/phrases/pt.sh +++ b/phrases/pt.sh @@ -1,5 +1,6 @@ #!/bin/bash # Portuguese (Brazilian) phrase templates. %s is the repo name. +# shellcheck disable=SC2034 # arrays are consumed by notify.sh after sourcing TEMPLATES_RESPONSE=( "%s está pronto para você" "%s requer sua atenção"