diff --git a/.STATUS b/.STATUS index bdd4d0e92..7c399570b 100644 --- a/.STATUS +++ b/.STATUS @@ -9,7 +9,23 @@ ## Priority: 2 ## Progress: 100 -## Current Session (2026-06-04) — post-release docs polish + Node 20 CI fix +## Current Session (2026-06-05) — obs dispatcher shadowing: plan → review → merge [dev] + +**Session activity:** +- **Phase 1 — removed dead `obs` dispatcher** (`222c43b2`): it shadowed the real `/opt/homebrew/bin/obs` (obsidian-cli-ops) but needed a `python/obs_cli.py` flow-cli never ships, so a function-beats-binary lookup made the broken dispatcher win in every shell. Deleted `lib/dispatchers/obs.zsh`, `zsh/functions/obs.zsh` (symlink), `man/man1/obs.1`, `tests/test-obs-dispatcher.zsh`; scrubbed obs from inventories (`flow.plugin.zsh`, help-compliance/browser, `commands/{flow,alias,doctor,tutorial}.zsh`) + dangling SEE ALSO obs(1) refs. **15 → 14 dispatchers.** Verified: `type obs` → binary, not function. +- **Phase 2 — B3 binary-precedence guard** (`f28b7007`): `flow.plugin.zsh` wraps each `lib/dispatchers/*.zsh` source in `_flow_load_dispatcher` — diffs `${(k)functions}` and `unfunction`s any new command resolving to a PATH binary, unless in `FLOW_INTENTIONAL_SHADOWS=(r mcp cc)` or `FLOW_FORCE_DISPATCHER_=1`. Keys on real defined names (skips `_*` helpers, no filename convention — chosen over spec B1 which broke on `em`/`email-dispatcher`). New guard test `test-dispatcher-binary-precedence.zsh` (16/16); net test files unchanged (211). Reviewed: scope is dispatcher files only, so `at` (shadows `/usr/bin/at`, defined in `atlas-bridge.zsh`) is correctly untouched. +- **Docs** (`67b0071d`): 15 → 14 dispatcher sweep across ~30 active files + repaired mkdocs nav (tutorial 41 deleted); `mkdocs build --strict` ✅. Historical CHANGELOG/RELEASES/specs/.archive left frozen per convention. +- **Note:** a second concurrent session shared this worktree and authored the Phase 1/Phase 2 commits in parallel (stopped mid-session by user); this session verified all three commits and added the docs commit. + +**Dev-session arc (this session):** +- **Planned** the fix: `/brainstorm` → caught that spec's Option B keyed the guard on *filename* (only correct for `obs`; `em`↔`email-dispatcher` + helper files break it) → corrected spec to B3; man-page ownership handoff to obsidian-cli-ops; worktree + ORCHESTRATE plan. +- **Reviewed PR #460** → applied review fixes on the feature branch: guard perf (batch `${(k)functions}` snapshot once + fork-free `${commands}` → ~10ms startup cost eliminated), doc scrub (3 stray obs refs), documented `FLOW_INTENTIONAL_SHADOWS`/`FLOW_FORCE_DISPATCHER_*` env vars, **added empty-array footgun regression test → 16→18 checks**. +- **Merged** PR #460 (`fc00837f`) + PR #459 (`d611e370`, clears the pre-existing `dogfood-scholar-config-sync` fail) → worktrees removed, remote branches deleted, dev synced. Suite now fully green (1 expected `e2e-em-dispatcher` timeout only). +- **`/craft:site:update`:** drift scan clean (obs sweep already landed), `mkdocs --strict` clean, bumped one `.TH` example 7.8.0→7.8.1 (`be5bbd06`). +- **Memory:** updated merge-policy (Claude may merge feature+release PRs when asked; two-tier guardrail behavior), obs guard (merged state + perf + `${+arr}`/define-once gotchas), 2 ZSH gotchas, 2 workflow notes. +- Companion: obsidian-cli-ops `obs.1` man page already merged (PR #25 + tap #110). + +## Previous Session (2026-06-04) — post-release docs polish + Node 20 CI fix **Session activity:** - Audited `docs/index.md` admonition boxes against v7.8.1 — all accurate (links/assets resolve, counts match `.STATUS`); bumped "What's New" header v7.8 → v7.8.1 (944f1617) @@ -20,6 +36,7 @@ - **Fixed at root** (148e257a): replaced caching step in `test.yml` with preinstall-aware `command -v zsh ||` install guard — drops a third-party action, no Node-24 opt-in flag needed; verified green on dev (`Ensure zsh is installed` ✅, no warning) - **PR #457** (dev→main CI fix) → CI CLEAN → merged main → main CI green (sha 37779584), `Ensure zsh is installed` success → dev re-synced (0 ahead) - Cross-repo cache-action audit (grep all dev-tools siblings): craft `actions/cache@v4` already current (no change); **scribe `actions/cache@v3` → @v4** bumped + pushed to scribe dev (a8aff56) — v3 backend sunsetting. Left `peaceiris/actions-gh-pages@v3` (v3 is its current major). No deprecated cache actions remain workspace-wide. +- **Debugged `ccy` "garbled prompt at startup"** (systematic): bisected through fzf → zsh-state → Ghostty → **Bun's startup kitty-PROBE** (Claude 2.1.x is a Bun binary). **NOT a flow-cli/fzf/ccy bug** — plain `claude` garbles too; terminal read flags=0 before launch. Fix = `export BUN_DISABLE_KITTY_PROBE=1` (personal `.zshrc`, verified clean). Two zsh precmd-reset attempts failed (wrong layer) and were removed. Created→dropped `feature/csi-u-diagnostic` worktree (premise obsolete once fix = 1 env var). Memory `ccy-garble-kitty-protocol.md` records cause + bisect. **Future: don't re-blame fzf/ccy for Claude startup garble.** ## Previous Session (2026-06-03) — tok auto-sync spec + craft drive spec @@ -317,7 +334,7 @@ | Worktree | Branch | Status | |----------|--------|--------| -| Main repo | `dev` | v7.8.1 — man-page set merged (#454); releasing | +| Main repo | `dev` | obs removed + B3 binary-precedence guard merged (#460, fc00837f); 14 dispatchers | --- @@ -353,6 +370,6 @@ **Last Updated:** 2026-06-02 **Status:** v7.8.1 SHIPPED | 59/59 tests passing (1 expected interactive/tmux timeout) | 15 dispatchers + at bridge | 211 test files | 12000+ test functions | 0 lint errors | 0 broken links -## wins: Fixed the regression bug (2026-06-03), --category fix squashed the bug (2026-06-03), fixed the bug (2026-06-03), Fixed the regression bug (2026-05-15), --category fix squashed the bug (2026-05-15) +## wins: Fixed the regression bug (2026-06-05), --category fix squashed the bug (2026-06-05), fixed the bug (2026-06-05), Fixed the regression bug (2026-06-03), --category fix squashed the bug (2026-06-03) ## streak: 1 -## last_active: 2026-06-03 23:12 +## last_active: 2026-06-05 00:32 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0188abe62..5999ec7c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [7.9.0] — 2026-06-05 — obs dispatcher removed + binary-precedence guard + +### Removed + +- **`obs` dispatcher** — flow-cli's `obs` shadowed the real Homebrew `obs` binary + (obsidian-cli-ops) but required a `python/obs_cli.py` flow-cli never shipped, so a + function-beats-binary lookup made the broken dispatcher win in every interactive + shell. Deleted the dispatcher, its `man/man1/obs.1`, and its test, and scrubbed + `obs` from all inventories. **15 → 14 dispatchers** (+ the `at` bridge). The + canonical `obs` man page now lives in obsidian-cli-ops. + +### Added + +- **Binary-precedence guard** (`_flow_load_dispatcher` in `flow.plugin.zsh`) — after + sourcing the dispatcher files, drops (`unfunction`) any newly-defined command that + shadows an external `$PATH` binary, so a broken dispatcher can never again mask a + working tool. Keys on the real defined function name (skips `_`-prefixed helpers; + no filename convention). Escape hatches: `FLOW_INTENTIONAL_SHADOWS` (default + `r mcp cc` — commands that legitimately shadow R / mcp / the C compiler) and + `FLOW_FORCE_DISPATCHER_=1`; set `FLOW_DEBUG` to see skip logs. New regression + test `tests/test-dispatcher-binary-precedence.zsh` (18 checks). + +### Fixed + +- **Dogfood scholar-config check** — match the condensed CLAUDE.md format in the + scholar-config assertion (#459). +- **CI Node 20 deprecation** — dropped the deprecated `cache-apt-pkgs-action` (which + pulled in the Node 20 `actions/cache/restore`); replaced with a preinstall-aware + `zsh` install guard (#457). + +### Changed + +- Dependency bumps: prettier 3.8.3, `actions/checkout` v6, lint-staged 17, + `actions/create-github-app-token` v3; dropped unused eslint + eslint-config-prettier. + ## [7.8.1] — 2026-06-04 — full man-page set + version-sync guard ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 41a12b61d..1fc56c21d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,7 +7,7 @@ This file provides guidance to Claude Code when working with code in this reposi **flow-cli** - Pure ZSH plugin for ADHD-optimized workflow management. Zero dependencies. Standalone (works without Oh-My-Zsh or any plugin manager). - **Architecture:** Pure ZSH plugin (no Node.js runtime required) -- **Current Version:** v7.8.1 +- **Current Version:** v7.9.0 - **Install:** Homebrew (recommended), or any plugin manager - **Source:** `source /opt/homebrew/opt/flow-cli/flow.plugin.zsh` (via Homebrew) - **Optional:** Atlas integration for enhanced state management @@ -17,7 +17,7 @@ This file provides guidance to Claude Code when working with code in this reposi ### What It Does - Instant workflow commands: `work`, `dash`, `finish`, `hop` -- 15 smart dispatchers: `g`, `mcp`, `obs`, `qu`, `r`, `cc`, `tm`, `wt`, `dots`, `sec`, `tok`, `teach`, `prompt`, `v`, `em` +- 14 smart dispatchers: `g`, `mcp`, `qu`, `r`, `cc`, `tm`, `wt`, `dots`, `sec`, `tok`, `teach`, `prompt`, `v`, `em` - ADHD-friendly design (sub-10ms response, smart defaults) - Session tracking, project switching, quick capture - Teaching workflow with Scholar integration @@ -87,12 +87,11 @@ yay --week # Weekly summary + graph flow goal set 3 # Set daily win target ``` -### Active Dispatchers (15) +### Active Dispatchers (14) ```bash g # Git workflows mcp # MCP server management -obs # Obsidian notes qu # Quarto publishing r # R package dev cc [cmd] # Claude Code launcher @@ -128,7 +127,7 @@ flow-cli/ │ ├── git-helpers.zsh # Git integration + smart commits │ ├── keychain-helpers.zsh # macOS Keychain secrets │ ├── tui.zsh # Terminal UI components -│ └── dispatchers/ # 15 smart command dispatchers +│ └── dispatchers/ # 14 smart command dispatchers ├── commands/ # 31 command files (work, dash, doctor, teach-*, etc.) ├── setup/ # Installation & setup ├── completions/ # ZSH completions @@ -147,7 +146,7 @@ flow-cli/ | ------------------------------------------- | ----------------------------------------- | | `flow.plugin.zsh` | Plugin entry point (source to load) | | `lib/core.zsh` | Core utilities (logging, colors, helpers) | -| `lib/dispatchers/*.zsh` | 15 smart dispatchers | +| `lib/dispatchers/*.zsh` | 14 smart dispatchers | | `commands/*.zsh` | Core commands (work, dash, finish, etc.) | | `docs/reference/MASTER-DISPATCHER-GUIDE.md` | Complete dispatcher docs | | `docs/reference/MASTER-API-REFERENCE.md` | API function reference | @@ -203,14 +202,20 @@ export FLOW_PROJECTS_ROOT="$HOME/projects" # Project root export FLOW_ATLAS_ENABLED="auto" # Atlas (auto|yes|no) export FLOW_QUIET=1 # Suppress welcome export FLOW_DEBUG=1 # Debug mode + +# Binary-precedence guard (drops a dispatcher that shadows a PATH binary) +export FLOW_INTENTIONAL_SHADOWS=(r mcp cc) # Commands kept even when a same-named binary exists +export FLOW_FORCE_DISPATCHER_OBS=1 # Force-keep one dispatcher (FLOW_FORCE_DISPATCHER_) ``` +> **Guard caveat:** `FLOW_INTENTIONAL_SHADOWS` defaults to `(r mcp cc)` only when unset. Setting it to an empty array (`=()`) is treated as an explicit override, so `cc` (vs `/usr/bin/cc`) etc. would then be dropped — append (`+=(...)`) rather than reassign if you only want to add entries. + --- ## Current Status -**Version:** v7.8.1 | **Tests:** 12000+ (59/59 suite, 1 interactive timeout) | **Docs:** https://Data-Wise.github.io/flow-cli/ +**Version:** v7.9.0 | **Tests:** 12000+ (59/59 suite, 1 interactive timeout) | **Docs:** https://Data-Wise.github.io/flow-cli/ --- -**Last Updated:** 2026-06-04 (v7.8.1) +**Last Updated:** 2026-06-04 (v7.9.0) diff --git a/README.md b/README.md index aaf3849fc..9465e1744 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Each dispatcher has built-in help: `cc help`, `dots help`, `r help`, `em help`, **✨ v7.4.2:** Atlas bridge (`at`) — project intelligence, context parking, quick capture **✨ v7.4.0:** 38 email commands — read, reply, forward, AI compose, organize, manage **✨ v7.1.0:** Dispatcher split — `dot` → `dots` (dotfiles) + `sec` (secrets) + `tok` (tokens) -**✨ 15 dispatchers + Atlas bridge** with unified grammar, built-in help, and fzf integration +**✨ 14 dispatchers + Atlas bridge** with unified grammar, built-in help, and fzf integration --- diff --git a/commands/alias.zsh b/commands/alias.zsh index 18c437180..b6164aeea 100644 --- a/commands/alias.zsh +++ b/commands/alias.zsh @@ -141,8 +141,8 @@ _flow_alias_show_all() { echo " ${FLOW_COLORS[muted]}cat → bat (syntax highlighting)${FLOW_COLORS[reset]}" echo "" - echo "${FLOW_COLORS[success]}🎯 Dispatchers${FLOW_COLORS[reset]} (8 smart functions)" - echo " ${FLOW_COLORS[muted]}g, cc, wt, mcp, r, qu, obs, tm${FLOW_COLORS[reset]}" + echo "${FLOW_COLORS[success]}🎯 Dispatchers${FLOW_COLORS[reset]} (7 smart functions)" + echo " ${FLOW_COLORS[muted]}g, cc, wt, mcp, r, qu, tm${FLOW_COLORS[reset]}" echo " ${FLOW_COLORS[cmd]}flow alias dispatchers${FLOW_COLORS[reset]} for full list" echo "" diff --git a/commands/doctor.zsh b/commands/doctor.zsh index 4fe0da647..1e02beeb9 100644 --- a/commands/doctor.zsh +++ b/commands/doctor.zsh @@ -1007,7 +1007,7 @@ _doctor_update_docs() { # Dispatchers echo "## Dispatchers" echo "" - local -a dispatchers=(g r qu mcp obs) + local -a dispatchers=(g r qu mcp) for cmd in "${dispatchers[@]}"; do echo "### \`$cmd\`" echo "" diff --git a/commands/flow.zsh b/commands/flow.zsh index 912d1061c..daa668e0d 100644 --- a/commands/flow.zsh +++ b/commands/flow.zsh @@ -171,9 +171,6 @@ flow() { mcp) mcp "$@" ;; - obs|obsidian) - obs "$@" - ;; cc|claude) cc "$@" ;; @@ -386,7 +383,7 @@ ${_C_DIM}SHORTCUTS: Most commands work directly too:${_C_NC} work foo = flow work foo js = flow start -${_C_DIM}See also:${_C_NC} man flow, r help, g help, qu help, mcp help, obs help +${_C_DIM}See also:${_C_NC} man flow, r help, g help, qu help, mcp help ${_C_BOLD}Version:${_C_NC} flow-cli v\${FLOW_VERSION:-3.2.0} " diff --git a/commands/tutorial.zsh b/commands/tutorial.zsh index 51a7754e4..eb765bd9d 100644 --- a/commands/tutorial.zsh +++ b/commands/tutorial.zsh @@ -343,7 +343,7 @@ _tutorial_advanced() { echo "" echo " Lessons:" echo " 9. Atlas integration" - echo " 10. Smart dispatchers (g, v, mcp, obs)" + echo " 10. Smart dispatchers (g, v, mcp, cc)" echo " 11. Customization and hooks" echo " 12. Morning routine" echo "" @@ -440,7 +440,7 @@ _tutorial_advanced() { echo " Focus: timer, focus, brk" echo " ADHD: js, next, stuck" echo " Status: status, morning" - echo " Dispatchers: g, v, mcp, obs" + echo " Dispatchers: g, v, mcp, cc" echo "" echo " Get help: help (e.g., 'pick help')" echo " Reset: tutorial reset" diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2df97511d..09a422c06 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,6 +8,41 @@ The format follows [Keep a Changelog](https://keepachangelog.com/), and this pro ## [Unreleased] +## [7.9.0] — 2026-06-05 — obs dispatcher removed + binary-precedence guard + +### Removed + +- **`obs` dispatcher** — flow-cli's `obs` shadowed the real Homebrew `obs` binary + (obsidian-cli-ops) but required a `python/obs_cli.py` flow-cli never shipped, so a + function-beats-binary lookup made the broken dispatcher win in every interactive + shell. Deleted the dispatcher, its `man/man1/obs.1`, and its test, and scrubbed + `obs` from all inventories. **15 → 14 dispatchers** (+ the `at` bridge). The + canonical `obs` man page now lives in obsidian-cli-ops. + +### Added + +- **Binary-precedence guard** (`_flow_load_dispatcher` in `flow.plugin.zsh`) — after + sourcing the dispatcher files, drops (`unfunction`) any newly-defined command that + shadows an external `$PATH` binary, so a broken dispatcher can never again mask a + working tool. Keys on the real defined function name (skips `_`-prefixed helpers; + no filename convention). Escape hatches: `FLOW_INTENTIONAL_SHADOWS` (default + `r mcp cc` — commands that legitimately shadow R / mcp / the C compiler) and + `FLOW_FORCE_DISPATCHER_=1`; set `FLOW_DEBUG` to see skip logs. New regression + test `tests/test-dispatcher-binary-precedence.zsh` (18 checks). + +### Fixed + +- **Dogfood scholar-config check** — match the condensed CLAUDE.md format in the + scholar-config assertion (#459). +- **CI Node 20 deprecation** — dropped the deprecated `cache-apt-pkgs-action` (which + pulled in the Node 20 `actions/cache/restore`); replaced with a preinstall-aware + `zsh` install guard (#457). + +### Changed + +- Dependency bumps: prettier 3.8.3, `actions/checkout` v6, lint-staged 17, + `actions/create-github-app-token` v3; dropped unused eslint + eslint-config-prettier. + ## [7.8.1] — 2026-06-04 — full man-page set + version-sync guard ### Added diff --git a/docs/CONVENTIONS.md b/docs/CONVENTIONS.md index b0136e79f..5cd19eab5 100644 --- a/docs/CONVENTIONS.md +++ b/docs/CONVENTIONS.md @@ -11,7 +11,7 @@ | Frequency | Style | Examples | | ----------------- | ------------- | ---------------------- | | Daily (50+ times) | Single letter | `r`, `g` | -| Frequent (10-50) | Two letters | `qu`, `mcp`, `obs` | +| Frequent (10-50) | Two letters | `qu`, `mcp`, `tm` | | Occasional (<10) | Full word | `work`, `dash`, `pick` | **Note (2025-12-25):** `v` dispatcher was deprecated. Use `flow` command directly. diff --git a/docs/DOC-DASHBOARD.md b/docs/DOC-DASHBOARD.md index 008f24bb7..7c1811838 100644 --- a/docs/DOC-DASHBOARD.md +++ b/docs/DOC-DASHBOARD.md @@ -66,7 +66,7 @@ ## Quick Links - [MASTER-API-REFERENCE.md](reference/MASTER-API-REFERENCE.md) - Complete API documentation -- [MASTER-DISPATCHER-GUIDE.md](reference/MASTER-DISPATCHER-GUIDE.md) - All 15 dispatchers +- [MASTER-DISPATCHER-GUIDE.md](reference/MASTER-DISPATCHER-GUIDE.md) - All 14 dispatchers - [MASTER-ARCHITECTURE.md](reference/MASTER-ARCHITECTURE.md) - System architecture - [QUICK-REFERENCE.md](help/QUICK-REFERENCE.md) - Command quick reference - [TROUBLESHOOTING.md](help/TROUBLESHOOTING.md) - Common issues diff --git a/docs/PHILOSOPHY.md b/docs/PHILOSOPHY.md index 32d9519a7..4ecf414a3 100644 --- a/docs/PHILOSOPHY.md +++ b/docs/PHILOSOPHY.md @@ -21,13 +21,13 @@ r test # R package: run tests g push # Git: push to remote qu preview # Quarto: preview document mcp status # MCP: server status -obs daily # Obsidian: daily note +wt create feat/x # Worktree: create branch worktree ``` **Rules:** - Single letter for high-frequency domains: `r`, `g` -- Two letters for medium-frequency: `qu`, `mcp`, `obs` +- Two letters for medium-frequency: `qu`, `mcp`, `tm` - Full words for low-frequency: `work`, `dash`, `pick` **Note (2025-12-25):** `v`/`vibe` dispatcher was deprecated. Use `flow` command directly for workflow operations. @@ -187,7 +187,6 @@ TIER 1: Daily Drivers (muscle memory) TIER 2: Frequent (weekly) ├── mcp MCP server management -├── obs Obsidian notes ├── work Start session ├── dash Dashboard └── pick FZF picker diff --git a/docs/architecture/SCHOLAR-ENHANCEMENT-ARCHITECTURE.md b/docs/architecture/SCHOLAR-ENHANCEMENT-ARCHITECTURE.md index f3bd92cb1..292aedf5a 100644 --- a/docs/architecture/SCHOLAR-ENHANCEMENT-ARCHITECTURE.md +++ b/docs/architecture/SCHOLAR-ENHANCEMENT-ARCHITECTURE.md @@ -1,7 +1,7 @@ # Scholar Enhancement Architecture **Feature:** Teaching Content Generation System -**Version:** v7.8.1 +**Version:** v7.9.0 **Date:** 2026-01-17 --- @@ -747,4 +747,4 @@ teach slides -w 8 --style computational **Last Updated:** 2026-02-27 **Status:** Production Ready -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/architecture/TEACHING-DATES-ARCHITECTURE.md b/docs/architecture/TEACHING-DATES-ARCHITECTURE.md index 989550c20..9c91cedb6 100644 --- a/docs/architecture/TEACHING-DATES-ARCHITECTURE.md +++ b/docs/architecture/TEACHING-DATES-ARCHITECTURE.md @@ -1,6 +1,6 @@ # Teaching Dates Architecture -**Version:** v7.8.1 +**Version:** v7.9.0 **Status:** Complete **Last Updated:** 2026-02-27 @@ -966,5 +966,5 @@ teach dates import-calendar university-calendar.ics --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 **Status:** Complete diff --git a/docs/commands/alias.md b/docs/commands/alias.md index 487a4cec2..2782c200b 100644 --- a/docs/commands/alias.md +++ b/docs/commands/alias.md @@ -40,9 +40,8 @@ flow alias help # Show all commands | `mcp` | 1 | MCP server shortcuts | | `quarto` | 2 | Quarto publishing shortcuts | | `r` | 4 | R package development shortcuts | -| `obs` | 1 | Obsidian shortcuts | -**Total:** 29 custom aliases +**Total:** 28 custom aliases --- diff --git a/docs/commands/at.md b/docs/commands/at.md index 69114effd..3dde4dcb3 100644 --- a/docs/commands/at.md +++ b/docs/commands/at.md @@ -247,7 +247,7 @@ The `at` bridge integrates with flow-cli's core commands: | `catch ` | Calls `_flow_catch` which uses `atlas catch` | | `crumb ` | Calls `_flow_crumb` which uses `atlas crumb` | | `flow doctor` | Shows Atlas version, backend, project count, MCP status | -| Help browser | Lists `at` with all 15 dispatchers, shows preview via `at help` | +| Help browser | Lists `at` with all 14 dispatchers, shows preview via `at help` | --- diff --git a/docs/commands/config.md b/docs/commands/config.md index 63d15a425..48cd55e27 100644 --- a/docs/commands/config.md +++ b/docs/commands/config.md @@ -42,7 +42,7 @@ Configuration is stored in `~/.config/flow/config.zsh` and organized into 6 cate | ------------------ | ------------ | ------------------------------------- | | `projects_root` | `~/projects` | Root directory for projects | | `atlas_enabled` | `auto` | Atlas integration (`auto`/`yes`/`no`) | -| `load_dispatchers` | `yes` | Load g, r, qu, mcp, obs dispatchers | +| `load_dispatchers` | `yes` | Load g, r, qu, mcp dispatchers | | `quiet` | `0` | Suppress startup messages | | `debug` | `0` | Enable debug output | diff --git a/docs/commands/flow.md b/docs/commands/flow.md index ca648d8ac..8d9e24ddb 100644 --- a/docs/commands/flow.md +++ b/docs/commands/flow.md @@ -56,7 +56,7 @@ flow alias # Show all custom aliases (29 total) flow alias # Show category aliases (e.g., flow alias cc) ``` -**Categories:** `git`, `cc` (Claude Code), `pick`, `dash`, `work`, `capture`, `mcp`, `quarto`, `r`, `obs` +**Categories:** `git`, `cc` (Claude Code), `pick`, `dash`, `work`, `capture`, `mcp`, `quarto`, `r` --- @@ -226,7 +226,6 @@ Flow-cli includes domain-specific dispatchers that are separate from the `flow` | `r` | R package dev | `r test`, `r check` | | `qu` | Quarto publishing | `qu preview` | | `mcp` | MCP servers | `mcp status` | -| `obs` | Obsidian notes | `obs daily` | | `cc` | Claude Code | `cc`, `cc pick` | Get help for any dispatcher with ` help`. diff --git a/docs/contributing/CONTRIBUTING.md b/docs/contributing/CONTRIBUTING.md index f4d2bd05b..7f0354481 100644 --- a/docs/contributing/CONTRIBUTING.md +++ b/docs/contributing/CONTRIBUTING.md @@ -52,7 +52,7 @@ flow-cli/ │ ├── atlas-bridge.zsh # Optional Atlas integration │ ├── project-detector.zsh # Project type detection │ ├── tui.zsh # Terminal UI components -│ └── dispatchers/ # 15 smart command dispatchers +│ └── dispatchers/ # 14 smart command dispatchers │ ├── cc-dispatcher.zsh # Claude Code │ ├── g-dispatcher.zsh # Git workflows │ ├── wt-dispatcher.zsh # Worktrees @@ -60,7 +60,6 @@ flow-cli/ │ ├── r-dispatcher.zsh # R packages │ ├── qu-dispatcher.zsh # Quarto │ ├── tm-dispatcher.zsh # Terminal -│ ├── obs.zsh # Obsidian │ ├── dots-dispatcher.zsh # Dotfiles (chezmoi) │ ├── sec-dispatcher.zsh # Secrets (Keychain) │ ├── tok-dispatcher.zsh # Tokens (API keys) diff --git a/docs/diagrams/TEACHING-V3-WORKFLOWS.md b/docs/diagrams/TEACHING-V3-WORKFLOWS.md index 389e8ce91..dee5772bb 100644 --- a/docs/diagrams/TEACHING-V3-WORKFLOWS.md +++ b/docs/diagrams/TEACHING-V3-WORKFLOWS.md @@ -470,7 +470,7 @@ flowchart TD --- **Generated:** 2026-02-09 -**Version:** v7.8.1 (Teaching Workflow v3.0) +**Version:** v7.9.0 (Teaching Workflow v3.0) **Total Diagrams:** 8 These diagrams provide comprehensive visual documentation for all major Teaching Workflow features. diff --git a/docs/getting-started/00-welcome.md b/docs/getting-started/00-welcome.md index 003e91edf..4af144eaf 100644 --- a/docs/getting-started/00-welcome.md +++ b/docs/getting-started/00-welcome.md @@ -176,7 +176,7 @@ → Use `pick` or `hop` - See [Tutorial 2](../tutorials/02-multiple-projects.md) **"What are the dispatchers?"** -→ `cc`, `g`, `mcp`, `obs`, `qu`, `r`, `tm`, `wt` - See [Dispatcher Reference](../reference/MASTER-DISPATCHER-GUIDE.md) +→ `cc`, `g`, `mcp`, `qu`, `r`, `tm`, `wt` - See [Dispatcher Reference](../reference/MASTER-DISPATCHER-GUIDE.md) **"How do I check my setup?"** → Run `flow doctor` - See [Installation](installation.md) @@ -194,7 +194,7 @@ ### Latest Features -- ✅ **8 dispatchers** - `cc`, `g`, `mcp`, `obs`, `qu`, `r`, `tm`, `wt` +- ✅ **14 dispatchers** - `cc`, `g`, `mcp`, `qu`, `r`, `tm`, `wt`, `dots`, `sec`, `tok`, `teach`, `prompt`, `v`, `em` (+ `at` Atlas bridge) - ✅ **150+ tests** - Full ZSH test suite with CI - ✅ **Worktree integration** - `cc wt ` for Claude in worktrees - ✅ **Git feature workflow** - `g feature start/sync/finish` diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index c02ee7e73..6e6f3780a 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -219,7 +219,6 @@ Flow CLI includes 6 domain-specific dispatchers: | `r` | R packages | `r test`, `r check` | | `qu` | Quarto | `qu preview`, `qu render` | | `mcp` | MCP servers | `mcp status`, `mcp logs` | -| `obs` | Obsidian | `obs daily`, `obs search` | | `cc` | Claude Code | `cc`, `cc pick`, `cc yolo` | Get help for any dispatcher: diff --git a/docs/guides/ATLAS-INTEGRATION-GUIDE.md b/docs/guides/ATLAS-INTEGRATION-GUIDE.md index b73acdcb2..6deb692f2 100644 --- a/docs/guides/ATLAS-INTEGRATION-GUIDE.md +++ b/docs/guides/ATLAS-INTEGRATION-GUIDE.md @@ -335,4 +335,4 @@ export FLOW_ATLAS_ENABLED=no --- **Last Updated:** 2026-02-22 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/guides/BACKUP-SYSTEM-GUIDE.md b/docs/guides/BACKUP-SYSTEM-GUIDE.md index 00b361afa..b7e3ae510 100644 --- a/docs/guides/BACKUP-SYSTEM-GUIDE.md +++ b/docs/guides/BACKUP-SYSTEM-GUIDE.md @@ -1,6 +1,6 @@ # Backup System Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-21 --- @@ -959,5 +959,5 @@ See `lib/backup-helpers.zsh` for implementation details. --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-21 diff --git a/docs/guides/CONFIG-MANAGEMENT-WORKFLOW.md b/docs/guides/CONFIG-MANAGEMENT-WORKFLOW.md index a3185981c..79adfb3c5 100644 --- a/docs/guides/CONFIG-MANAGEMENT-WORKFLOW.md +++ b/docs/guides/CONFIG-MANAGEMENT-WORKFLOW.md @@ -730,5 +730,5 @@ flow config profile load adhd --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 **Related:** [flow.md](../commands/flow.md), [plugin guide](./PLUGIN-MANAGEMENT-WORKFLOW.md) diff --git a/docs/guides/COURSE-PLANNING-BEST-PRACTICES.md b/docs/guides/COURSE-PLANNING-BEST-PRACTICES.md index 2ad8cf074..89cbb5682 100644 --- a/docs/guides/COURSE-PLANNING-BEST-PRACTICES.md +++ b/docs/guides/COURSE-PLANNING-BEST-PRACTICES.md @@ -1,6 +1,6 @@ # Course Planning Best Practices: A Research-Based Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-19 **Target Audience:** Instructors using flow-cli for systematic course design **Status:** Phase 1 Complete (Sections 1-2) @@ -2498,7 +2498,7 @@ teach analytics --outcomes # Outcome achievement analysis # Document Metadata -**Version:** v7.8.1 +**Version:** v7.9.0 **Created:** 2026-01-19 **Last Updated:** 2026-01-19 **Authors:** flow-cli development team diff --git a/docs/guides/DEVELOPER-GUIDE.md b/docs/guides/DEVELOPER-GUIDE.md index ee7d30ba3..4bb2eeecd 100644 --- a/docs/guides/DEVELOPER-GUIDE.md +++ b/docs/guides/DEVELOPER-GUIDE.md @@ -1,6 +1,6 @@ # flow-cli Developer Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Audience:** Contributors, Plugin Developers, Advanced Users @@ -961,4 +961,4 @@ test: add regression test for worktree detection --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/guides/DOCTOR-TOKEN-USER-GUIDE.md b/docs/guides/DOCTOR-TOKEN-USER-GUIDE.md index f52055798..23747f9d7 100644 --- a/docs/guides/DOCTOR-TOKEN-USER-GUIDE.md +++ b/docs/guides/DOCTOR-TOKEN-USER-GUIDE.md @@ -1,6 +1,6 @@ # Doctor Token Enhancement - User Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 --- @@ -633,5 +633,5 @@ Found a bug or have a feature request? --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 **Maintainer:** flow-cli team diff --git a/docs/guides/DOT-WORKFLOW.md b/docs/guides/DOT-WORKFLOW.md index 4c91849d6..3c9341dff 100644 --- a/docs/guides/DOT-WORKFLOW.md +++ b/docs/guides/DOT-WORKFLOW.md @@ -507,5 +507,5 @@ Run: sec unlock --- -**Version:** v7.8.1 +**Version:** v7.9.0 **See Also:** [Dispatcher Reference](../reference/MASTER-DISPATCHER-GUIDE.md#dots-dispatcher) | [Tutorial](../tutorials/12-dot-dispatcher.md) diff --git a/docs/guides/EMAIL-DISPATCHER-GUIDE.md b/docs/guides/EMAIL-DISPATCHER-GUIDE.md index 0c231d65e..6c1dfe80a 100644 --- a/docs/guides/EMAIL-DISPATCHER-GUIDE.md +++ b/docs/guides/EMAIL-DISPATCHER-GUIDE.md @@ -2330,7 +2330,7 @@ Now that you understand the `em` dispatcher: - [Email Refcard](../reference/REFCARD-EMAIL-DISPATCHER.md) — All 38 commands at a glance - [Email Cookbook](EMAIL-COOKBOOK.md) — Practical recipes for common workflows - [EM-V2-ARCHITECTURE.md](../internal/EM-V2-ARCHITECTURE.md) — Internal architecture documentation -- [MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md) — All 15 dispatchers +- [MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md) — All 14 dispatchers ### External diff --git a/docs/guides/ENHANCED-HELP-QUICK-START.md b/docs/guides/ENHANCED-HELP-QUICK-START.md index bee74d02b..68afb128b 100644 --- a/docs/guides/ENHANCED-HELP-QUICK-START.md +++ b/docs/guides/ENHANCED-HELP-QUICK-START.md @@ -184,7 +184,7 @@ flow alias git # Git aliases flow alias # Any category ``` -**Categories:** `git`, `cc`, `pick`, `dash`, `work`, `capture`, `mcp`, `quarto`, `r`, `obs` +**Categories:** `git`, `cc`, `pick`, `dash`, `work`, `capture`, `mcp`, `quarto`, `r` --- diff --git a/docs/guides/INTELLIGENT-CONTENT-ANALYSIS.md b/docs/guides/INTELLIGENT-CONTENT-ANALYSIS.md index 9425207ef..eedde926e 100644 --- a/docs/guides/INTELLIGENT-CONTENT-ANALYSIS.md +++ b/docs/guides/INTELLIGENT-CONTENT-ANALYSIS.md @@ -1,6 +1,6 @@ # Intelligent Content Analysis Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-22 --- diff --git a/docs/guides/QUALITY-GATES.md b/docs/guides/QUALITY-GATES.md index 79ad1c10b..3d3723d42 100644 --- a/docs/guides/QUALITY-GATES.md +++ b/docs/guides/QUALITY-GATES.md @@ -9,7 +9,7 @@ tags: > Every validation layer in flow-cli, from keystroke to production. > -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- @@ -239,4 +239,4 @@ Areas where validation could be added in the future: --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/guides/QUARTO-WORKFLOW-PHASE-2-GUIDE.md b/docs/guides/QUARTO-WORKFLOW-PHASE-2-GUIDE.md index af90b8289..bf4e2aef8 100644 --- a/docs/guides/QUARTO-WORKFLOW-PHASE-2-GUIDE.md +++ b/docs/guides/QUARTO-WORKFLOW-PHASE-2-GUIDE.md @@ -6,7 +6,7 @@ tags: # Quarto Workflow Phase 2 Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Status:** Production Ready diff --git a/docs/guides/SCHOLAR-WRAPPERS-GUIDE.md b/docs/guides/SCHOLAR-WRAPPERS-GUIDE.md index 7d6801732..6109eab34 100644 --- a/docs/guides/SCHOLAR-WRAPPERS-GUIDE.md +++ b/docs/guides/SCHOLAR-WRAPPERS-GUIDE.md @@ -2,7 +2,7 @@ > Complete documentation for the 9 AI content generation commands in the teach system. > -> **Version:** v7.8.1 | **Prerequisites:** Scholar plugin, teach-config.yml +> **Version:** v7.9.0 | **Prerequisites:** Scholar plugin, teach-config.yml ## Table of Contents @@ -1311,6 +1311,6 @@ teach lecture "Topic" --week 5 --math --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-02 **Commands Documented:** 9 Scholar wrappers diff --git a/docs/guides/TEACH-DEPLOY-GUIDE.md b/docs/guides/TEACH-DEPLOY-GUIDE.md index 3c3afe880..a5ed19156 100644 --- a/docs/guides/TEACH-DEPLOY-GUIDE.md +++ b/docs/guides/TEACH-DEPLOY-GUIDE.md @@ -8,7 +8,7 @@ tags: > Deploy your course website from local preview to production with confidence. > -> **Version:** v7.8.1 | **Command:** `teach deploy` +> **Version:** v7.9.0 | **Command:** `teach deploy` ![teach deploy v2 Demo](../demos/tutorials/tutorial-teach-deploy.gif) @@ -1237,4 +1237,4 @@ The deployment summary box now includes a direct link to your GitHub Actions pag --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/guides/TEACHING-TROUBLESHOOTING.md b/docs/guides/TEACHING-TROUBLESHOOTING.md index bddf2c438..37bc3cbe5 100644 --- a/docs/guides/TEACHING-TROUBLESHOOTING.md +++ b/docs/guides/TEACHING-TROUBLESHOOTING.md @@ -2,7 +2,7 @@ > Quick fixes for common issues with the teach dispatcher. > -> **Version:** v7.8.1 +> **Version:** v7.9.0 > **Last Updated:** 2026-02-27 --- diff --git a/docs/guides/TEACHING-WORKFLOW-V3-GUIDE.md b/docs/guides/TEACHING-WORKFLOW-V3-GUIDE.md index 278594a22..eecb9875c 100644 --- a/docs/guides/TEACHING-WORKFLOW-V3-GUIDE.md +++ b/docs/guides/TEACHING-WORKFLOW-V3-GUIDE.md @@ -6,7 +6,7 @@ tags: # Teaching Workflow v3.0 Guide -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Target Audience:** Instructors using flow-cli for course management @@ -2128,5 +2128,5 @@ teach init --config template.yml --- -**Version:** v7.8.1 (Teaching Workflow v3.0) +**Version:** v7.9.0 (Teaching Workflow v3.0) **Last Updated:** 2026-02-27 diff --git a/docs/help/QUICK-REFERENCE.md b/docs/help/QUICK-REFERENCE.md index 8a1b8c0b1..08588ae20 100644 --- a/docs/help/QUICK-REFERENCE.md +++ b/docs/help/QUICK-REFERENCE.md @@ -11,7 +11,7 @@ tags: **Purpose:** Single-page command lookup for all flow-cli features **Format:** Copy-paste ready with expected outputs -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-06-04 --- @@ -24,7 +24,6 @@ tags: - [R Dispatcher (r)](#r-dispatcher-r) - R package development - [Quarto (qu)](#quarto-qu) - Publishing workflow - [MCP (mcp)](#mcp-mcp) - MCP server management -- [Obsidian (obs)](#obsidian-obs) - Note management - [Worktree (wt)](#worktree-wt) - Parallel development - [Dotfiles (dots)](#dotfiles-dots) - Dotfile management - [Secrets (sec)](#secrets-sec) - Secret management @@ -448,40 +447,6 @@ mcp help --- -## Obsidian (obs) - -```bash -# List vaults -obs vaults -# Output: main-vault (/Users/dt/Obsidian/main-vault) -# work-vault (/Users/dt/Obsidian/work-vault) - -# Show vault stats -obs stats -# Output: Total notes: 1,234 -# Total links: 5,678 -# Orphan notes: 12 -# Broken links: 3 - -# Search notes -obs search "search term" -# Output: [List of matching notes] - -# Open note -obs open "note name" -# Output: [Opens in Obsidian] - -# Create note -obs new "note title" -# Output: ✅ Created: note title.md - -# Show help -obs help -# Output: [Obsidian dispatcher help] -``` - ---- - ## Worktree (wt) ```bash @@ -1578,6 +1543,6 @@ mcp help --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-06-04 **Contributors:** See [CHANGELOG.md](../CHANGELOG.md) diff --git a/docs/help/TROUBLESHOOTING.md b/docs/help/TROUBLESHOOTING.md index 81f8573e5..576107b8f 100644 --- a/docs/help/TROUBLESHOOTING.md +++ b/docs/help/TROUBLESHOOTING.md @@ -3,7 +3,7 @@ **Purpose:** Common issues and solutions for flow-cli **Audience:** All users experiencing problems **Format:** Problem → Diagnosis → Solution -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 --- @@ -1048,6 +1048,6 @@ ls -la ~/.cache/flow/ --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Need more help?** https://github.com/Data-Wise/flow-cli/issues diff --git a/docs/help/WORKFLOWS.md b/docs/help/WORKFLOWS.md index 0afb03df6..5dc0974c6 100644 --- a/docs/help/WORKFLOWS.md +++ b/docs/help/WORKFLOWS.md @@ -6,7 +6,7 @@ **Purpose:** Real-world workflow patterns for flow-cli **Audience:** All users (beginners → advanced) **Format:** Step-by-step instructions with examples -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 --- @@ -1071,6 +1071,6 @@ pick # Interactive project picker --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Contributors:** See [CHANGELOG.md](../CHANGELOG.md) diff --git a/docs/index.md b/docs/index.md index f73ad5d32..a628e9d70 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,12 +26,11 @@ tags: ``` **That's it!** No configuration required. -!!! success "🎉 What's New in v7.8.1" - **Token auto-sync:** `tok sync push` / `tok sync repos` fan a token out to GitHub Actions secrets across repos (`gh secret set`) — confirm-once gate, OIDC "use Trusted Publishing" nudge, chezmoi-managed config. Auto-runs after `tok` create/rotate (`--no-sync` to opt out). - **Terminal hygiene fix:** a shared cleanup helper ends the garbled-prompt corruption when launching Claude via `cc wt pick` / `ccy` / `work`. +!!! success "🎉 What's New in v7.9.0" + **`obs` dispatcher removed:** flow-cli's `obs` shadowed (and broke) the real Homebrew `obs` binary — typing `obs` now runs the real tool. **15 → 14 dispatchers.** + **Binary-precedence guard:** the dispatcher loader now drops any command that would shadow an installed `$PATH` binary, unless allowlisted (`FLOW_INTENTIONAL_SHADOWS`, default `r mcp cc`) or forced (`FLOW_FORCE_DISPATCHER_=1`). No dispatcher can silently mask a working tool again. **59 test suites** passing (211 files, 12000+ assertions). - [→ Token Cookbook](guides/TOKEN-COOKBOOK.md){ .md-button } - [→ Tutorial: tok auto-sync](tutorials/47-tok-auto-sync.md){ .md-button } + [→ Dispatcher Guide](reference/MASTER-DISPATCHER-GUIDE.md){ .md-button } [→ Changelog](CHANGELOG.md){ .md-button } --- @@ -239,7 +238,6 @@ Commands that adapt to your project type: | `g` | `g push` / `g commit` | Git with smart safety | | `teach` | `teach init` / `teach deploy` | Teaching workflow | | `mcp` | `mcp status` / `mcp logs` | MCP server management | -| `obs` | `obs vaults` / `obs stats` | Obsidian notes | | `wt` | `wt create` / `wt status` | Worktree management | | `tm` | `tm title` / `tm ghost` | Terminal manager | | `dots` | `dots edit` / `dots sync` | Dotfile management | @@ -292,4 +290,4 @@ catch "idea" # Quick capture --- -**v7.8.1** · Pure ZSH · Zero Dependencies · MIT License +**v7.9.0** · Pure ZSH · Zero Dependencies · MIT License diff --git a/docs/internal/conventions/code/ZSH-COMMANDS-HELP.md b/docs/internal/conventions/code/ZSH-COMMANDS-HELP.md index aabc7c4e6..eb078063f 100644 --- a/docs/internal/conventions/code/ZSH-COMMANDS-HELP.md +++ b/docs/internal/conventions/code/ZSH-COMMANDS-HELP.md @@ -438,7 +438,7 @@ colored/box-drawn `help` output is not copy-pasteable into troff). The `.TH` line's version field must match `FLOW_VERSION`: ```troff -.TH TOK 1 "June 2026" "flow-cli 7.8.0" "User Commands" +.TH TOK 1 "June 2026" "flow-cli 7.9.0" "User Commands" ``` A single guard — `tests/test-manpage-version-sync.zsh`, wired into diff --git a/docs/reference/MASTER-API-REFERENCE.md b/docs/reference/MASTER-API-REFERENCE.md index 0a561ec38..e670996f2 100644 --- a/docs/reference/MASTER-API-REFERENCE.md +++ b/docs/reference/MASTER-API-REFERENCE.md @@ -8,7 +8,7 @@ tags: **Purpose:** Complete API documentation for all flow-cli library functions **Audience:** Developers, contributors, advanced users **Format:** Function signatures, parameters, return values, examples -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-21 --- @@ -53,13 +53,12 @@ lib/ ├── em-cache.zsh # Email: TTL-based caching (8 functions) ├── em-render.zsh # Email: Smart rendering pipeline (7 functions) ├── email-helpers.zsh # Email: Safety gates, AI draft helper (6 functions) -└── dispatchers/ # 15 dispatchers + 4 support modules (630+ functions) +└── dispatchers/ # 14 dispatchers + 4 support modules (630+ functions) ├── g-dispatcher.zsh ├── cc-dispatcher.zsh ├── r-dispatcher.zsh ├── qu-dispatcher.zsh ├── mcp-dispatcher.zsh - ├── obs.zsh ├── wt-dispatcher.zsh ├── dots-dispatcher.zsh # Dotfile management ├── sec-dispatcher.zsh # Secret management @@ -7559,7 +7558,7 @@ URL line is omitted when `$url` is empty or `"null"`. --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-21 **Auto-Generation:** Run `./scripts/generate-api-docs.sh` to update function index **Total Functions:** 880 (428 documented, 452 pending) diff --git a/docs/reference/MASTER-ARCHITECTURE.md b/docs/reference/MASTER-ARCHITECTURE.md index 6b3a3fddb..942d90cc6 100644 --- a/docs/reference/MASTER-ARCHITECTURE.md +++ b/docs/reference/MASTER-ARCHITECTURE.md @@ -3,7 +3,7 @@ **Purpose:** Complete system architecture documentation for flow-cli **Audience:** Contributors, maintainers, advanced users **Format:** Design decisions, diagrams, implementation details -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-21 --- @@ -31,7 +31,7 @@ graph TD User[User] --> CLI[flow.plugin.zsh Entry Point] CLI --> Core[Core Library] - CLI --> Dispatchers[15 Dispatchers] + CLI --> Dispatchers[14 Dispatchers] CLI --> Commands[Core Commands] Core --> Utils[Utilities] @@ -43,7 +43,6 @@ graph TD Dispatchers --> R[r - R] Dispatchers --> QU[qu - Quarto] Dispatchers --> MCP[mcp - MCP] - Dispatchers --> OBS[obs - Obsidian] Dispatchers --> WT[wt - Worktrees] Dispatchers --> DOTS[dots - Dotfiles] Dispatchers --> SEC[sec - Secrets] @@ -89,7 +88,7 @@ flow-cli follows a layered architecture: ┌─────────────────────────────────────────────────────────────┐ │ Layer 3: Commands & Dispatchers │ │ - Core commands (work, dash, pick, doctor) │ -│ - 15 dispatchers + at bridge (g, cc, r, qu, mcp, obs, wt, tm,│ +│ - 14 dispatchers + at bridge (g, cc, r, qu, mcp, wt, tm, │ │ dots, sec, tok, teach, prompt, v, em) │ └─────────────────────────────────────────────────────────────┘ ↓ @@ -1020,7 +1019,7 @@ graph TD --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-21 **Diagrams:** 8 Mermaid diagrams **Total:** 2,500+ lines diff --git a/docs/reference/MASTER-DISPATCHER-GUIDE.md b/docs/reference/MASTER-DISPATCHER-GUIDE.md index e7f13f322..55bbb92ab 100644 --- a/docs/reference/MASTER-DISPATCHER-GUIDE.md +++ b/docs/reference/MASTER-DISPATCHER-GUIDE.md @@ -10,7 +10,7 @@ tags: **Purpose:** Complete reference for all flow-cli dispatchers (15 + at bridge) **Audience:** All users (beginner → intermediate → advanced) **Format:** Progressive disclosure (basics → advanced features) -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-21 --- @@ -34,7 +34,7 @@ teach init # Initialize course ``` -### The 15 Dispatchers +### The 14 Dispatchers | Dispatcher | Domain | Commands | Complexity | | ------------ | -------- | ---------- | ------------ | @@ -43,7 +43,6 @@ teach init # Initialize course | [r](#r-dispatcher) | R packages | 10+ | Intermediate | | [qu](#qu-dispatcher) | Quarto publishing | 8+ | Intermediate | | [mcp](#mcp-dispatcher) | MCP servers | 8 | Intermediate | -| [obs](#obs-dispatcher) | Obsidian notes | 6 | Beginner | | [wt](#wt-dispatcher) | Worktrees | 6 | Advanced | | [dots](#dots-dispatcher) | Dotfile management | 12+ | Intermediate | | [sec](#sec-dispatcher) | Secret management | 10+ | Intermediate → Advanced | @@ -70,7 +69,6 @@ Start with the **Basics** section of each dispatcher: 1. [tm](#tm-dispatcher) - Terminal (easiest) 2. [cc](#cc-dispatcher) - Claude Code 3. [g](#g-dispatcher) basics - Git -4. [obs](#obs-dispatcher) - Obsidian (if you use it) ### For Intermediate Users @@ -974,93 +972,6 @@ Tests server connectivity and health. --- -## obs Dispatcher - -**Domain:** Obsidian note management -**Complexity:** Beginner -**Most Used:** Yes (if using Obsidian) - -### Basics (Beginner) - -**What it does:** Integrates with Obsidian vaults. - -#### Essential Commands - -**List vaults:** - -```bash -obs vaults - -``` - -Output: - -```text - -main-vault (/Users/dt/Obsidian/main-vault) -work-vault (/Users/dt/Obsidian/work-vault) - -``` - -**Show vault stats:** - -```bash -obs stats - -``` - -Output: - -```text - -Total notes: 1,234 -Total links: 5,678 -Orphan notes: 12 -Broken links: 3 - -``` - -**Search notes:** - -```bash -obs search "machine learning" - -``` - -**Open note:** - -```bash -obs open "My Note" - -``` - -Opens note in Obsidian. - -**Create note:** - -```bash -obs new "New Note Title" - -``` - ---- - -### Reference - -
-Complete obs Dispatcher Command List - -- `obs vaults` - List vaults -- `obs stats` - Show vault statistics -- `obs search ` - Search notes -- `obs open ` - Open note in Obsidian -- `obs new ` - Create new note -- `obs help` - Show help - -</details> - ---- - ## wt Dispatcher **Domain:** Git worktree management @@ -3148,7 +3059,6 @@ v off | r | Intermediate | ⭐⭐⭐⭐ | R package dev | | qu | Intermediate | ⭐⭐⭐⭐ | Quarto publishing | | mcp | Intermediate | ⭐⭐⭐ | MCP server management | -| obs | Beginner | ⭐⭐⭐ | Obsidian notes | | wt | Advanced | ⭐⭐⭐⭐ | Parallel development | | dots | Intermediate | ⭐⭐⭐⭐ | Dotfile management | | sec | Intermediate → Advanced | ⭐⭐⭐⭐⭐ | Secret management | @@ -3483,6 +3393,6 @@ at stats --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-22 -**Total:** 15 dispatchers + at bridge fully documented +**Total:** 14 dispatchers + at bridge fully documented diff --git a/docs/reference/REFCARD-ANALYSIS.md b/docs/reference/REFCARD-ANALYSIS.md index 55f7fec52..1775b4bb5 100644 --- a/docs/reference/REFCARD-ANALYSIS.md +++ b/docs/reference/REFCARD-ANALYSIS.md @@ -189,5 +189,5 @@ teach analyze --slide-breaks lectures/week-02-probability.qmd --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-02 diff --git a/docs/reference/REFCARD-DATES.md b/docs/reference/REFCARD-DATES.md index b53f68a38..310b7b397 100644 --- a/docs/reference/REFCARD-DATES.md +++ b/docs/reference/REFCARD-DATES.md @@ -271,5 +271,5 @@ teach dates status --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-02 diff --git a/docs/reference/REFCARD-DOCTOR.md b/docs/reference/REFCARD-DOCTOR.md index 27914c8fb..a26e15011 100644 --- a/docs/reference/REFCARD-DOCTOR.md +++ b/docs/reference/REFCARD-DOCTOR.md @@ -320,5 +320,5 @@ teach doctor --verbose --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-21 diff --git a/docs/reference/REFCARD-DOTFILE-DISPATCHER.md b/docs/reference/REFCARD-DOTFILE-DISPATCHER.md index af83315fd..b9e1934fe 100644 --- a/docs/reference/REFCARD-DOTFILE-DISPATCHER.md +++ b/docs/reference/REFCARD-DOTFILE-DISPATCHER.md @@ -2,7 +2,7 @@ > All `dots` subcommands at a glance. > -> **Version:** v7.8.1 (v3.0.0 dispatcher) | **Dispatcher:** `lib/dispatchers/dots-dispatcher.zsh` +> **Version:** v7.9.0 (v3.0.0 dispatcher) | **Dispatcher:** `lib/dispatchers/dots-dispatcher.zsh` > > **Backend:** [chezmoi](https://www.chezmoi.io/) for dotfile sync. @@ -99,5 +99,5 @@ dots apply --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 diff --git a/docs/reference/REFCARD-EMAIL-DISPATCHER.md b/docs/reference/REFCARD-EMAIL-DISPATCHER.md index 6e500fced..d332197f7 100644 --- a/docs/reference/REFCARD-EMAIL-DISPATCHER.md +++ b/docs/reference/REFCARD-EMAIL-DISPATCHER.md @@ -793,7 +793,6 @@ For Gmail/OAuth2: `email-oauth2-proxy` recommended (see `em doctor`) ### Other Dispatchers - **`g`** — Git (workflows) -- **`obs`** — Obsidian (quick notes about emails) - **`tm`** — Terminal manager (email session windows) ### External Tools @@ -919,7 +918,7 @@ em ai claude # Use a known backend ### References -- [MASTER-DISPATCHER-GUIDE.md](MASTER-DISPATCHER-GUIDE.md) — All 15 dispatchers +- [MASTER-DISPATCHER-GUIDE.md](MASTER-DISPATCHER-GUIDE.md) — All 14 dispatchers - [MASTER-API-REFERENCE.md](MASTER-API-REFERENCE.md) — Function signatures - [MASTER-ARCHITECTURE.md](MASTER-ARCHITECTURE.md) — System design diff --git a/docs/reference/REFCARD-GIT-DISPATCHER.md b/docs/reference/REFCARD-GIT-DISPATCHER.md index 5b93ea821..dde04f431 100644 --- a/docs/reference/REFCARD-GIT-DISPATCHER.md +++ b/docs/reference/REFCARD-GIT-DISPATCHER.md @@ -2,7 +2,7 @@ > All `g` subcommands at a glance — the most-used flow-cli dispatcher. > -> **Version:** v7.8.1 | **Dispatcher:** `lib/dispatchers/g-dispatcher.zsh` +> **Version:** v7.9.0 | **Dispatcher:** `lib/dispatchers/g-dispatcher.zsh` > > Unknown commands pass through to `git` (e.g., `g remote -v` → `git remote -v`). @@ -129,5 +129,5 @@ g pop # Restore stashed changes --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 diff --git a/docs/reference/REFCARD-SCHOLAR-FLAGS.md b/docs/reference/REFCARD-SCHOLAR-FLAGS.md index 6b4c3a21d..5e34c426a 100644 --- a/docs/reference/REFCARD-SCHOLAR-FLAGS.md +++ b/docs/reference/REFCARD-SCHOLAR-FLAGS.md @@ -2,7 +2,7 @@ > All flags available for `teach` Scholar wrapper commands (lecture, slides, exam, quiz, assignment, syllabus, rubric, feedback, demo). > -> **Version:** v7.8.1 | **Source:** `lib/dispatchers/teach-dispatcher.zsh` +> **Version:** v7.9.0 | **Source:** `lib/dispatchers/teach-dispatcher.zsh` ## Selection Flags (Universal) @@ -746,6 +746,6 @@ teach lecture "ANOVA" --week 8 --dry-run --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-02 **Status:** Complete Scholar flag documentation diff --git a/docs/reference/REFCARD-SCHOLAR-WRAPPERS.md b/docs/reference/REFCARD-SCHOLAR-WRAPPERS.md index 17a651173..336d5a70f 100644 --- a/docs/reference/REFCARD-SCHOLAR-WRAPPERS.md +++ b/docs/reference/REFCARD-SCHOLAR-WRAPPERS.md @@ -8,7 +8,7 @@ tags: # Quick Reference: Scholar Wrapper Commands **Purpose:** Reference card for Scholar-powered `teach` subcommands -**Version:** v7.8.1+ +**Version:** v7.9.0+ **Last Updated:** 2026-02-27 --- diff --git a/docs/reference/REFCARD-SECRET-DISPATCHER.md b/docs/reference/REFCARD-SECRET-DISPATCHER.md index 1bb4854ed..0b2d8f31a 100644 --- a/docs/reference/REFCARD-SECRET-DISPATCHER.md +++ b/docs/reference/REFCARD-SECRET-DISPATCHER.md @@ -2,7 +2,7 @@ > All `sec` subcommands at a glance. > -> **Version:** v7.8.1 (v3.0.0 dispatcher) | **Dispatcher:** `lib/dispatchers/sec-dispatcher.zsh` +> **Version:** v7.9.0 (v3.0.0 dispatcher) | **Dispatcher:** `lib/dispatchers/sec-dispatcher.zsh` > > **Backends:** macOS Keychain (primary), Bitwarden (optional secondary). @@ -105,5 +105,5 @@ sec dashboard # Overview of all secrets --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 diff --git a/docs/reference/REFCARD-TEACH-DISPATCHER.md b/docs/reference/REFCARD-TEACH-DISPATCHER.md index 977879009..d2dc107f9 100644 --- a/docs/reference/REFCARD-TEACH-DISPATCHER.md +++ b/docs/reference/REFCARD-TEACH-DISPATCHER.md @@ -2,7 +2,7 @@ > All 34 `teach` subcommands at a glance. For detailed guides, see linked documentation. > -> **Version:** v7.8.1 | **Dispatcher:** `lib/dispatchers/teach-dispatcher.zsh` +> **Version:** v7.9.0 | **Dispatcher:** `lib/dispatchers/teach-dispatcher.zsh` ## Command Taxonomy @@ -477,7 +477,7 @@ teach status --performance # Review metrics ### API Documentation - [MASTER-API-REFERENCE.md](MASTER-API-REFERENCE.md) — Function signatures -- [MASTER-DISPATCHER-GUIDE.md](MASTER-DISPATCHER-GUIDE.md) — All 15 dispatchers +- [MASTER-DISPATCHER-GUIDE.md](MASTER-DISPATCHER-GUIDE.md) — All 14 dispatchers ### Architecture @@ -485,6 +485,6 @@ teach status --performance # Review metrics --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Commands:** 34 total (12 Scholar wrappers + 5 course mgmt + 6 content mgmt + 9 infrastructure + 1 discovery + config subcommands) diff --git a/docs/reference/REFCARD-TEACH-PLAN.md b/docs/reference/REFCARD-TEACH-PLAN.md index ea7dc4a32..3e003e571 100644 --- a/docs/reference/REFCARD-TEACH-PLAN.md +++ b/docs/reference/REFCARD-TEACH-PLAN.md @@ -157,5 +157,5 @@ teach slides --week N # Step 5: Generate content --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-29 diff --git a/docs/reference/REFCARD-WORKTREE-DISPATCHER.md b/docs/reference/REFCARD-WORKTREE-DISPATCHER.md index 1aeb98423..3c8b05d6a 100644 --- a/docs/reference/REFCARD-WORKTREE-DISPATCHER.md +++ b/docs/reference/REFCARD-WORKTREE-DISPATCHER.md @@ -2,7 +2,7 @@ > All `wt` subcommands at a glance. > -> **Version:** v7.8.1 | **Dispatcher:** `lib/dispatchers/wt-dispatcher.zsh` +> **Version:** v7.9.0 | **Dispatcher:** `lib/dispatchers/wt-dispatcher.zsh` ## Commands @@ -105,5 +105,5 @@ cd ~/projects/my-project # Back to feature A (untouched) --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 diff --git a/docs/reference/TEACH-CONFIG-SCHEMA.md b/docs/reference/TEACH-CONFIG-SCHEMA.md index 29f14ce30..883482c4b 100644 --- a/docs/reference/TEACH-CONFIG-SCHEMA.md +++ b/docs/reference/TEACH-CONFIG-SCHEMA.md @@ -2,7 +2,7 @@ > Complete field reference for teaching project configuration. > -> **Version:** v7.8.1 | **Location:** `.flow/teach-config.yml` +> **Version:** v7.9.0 | **Location:** `.flow/teach-config.yml` ## Overview @@ -669,4 +669,4 @@ _teach_config_summary ".flow/teach-config.yml" --- **Last Updated:** 2026-02-02 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/reference/index.md b/docs/reference/index.md index fb1ca8475..0d28c8432 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -57,7 +57,7 @@ tags: | Page | Description | | ---- | ----------- | | [Master API Reference](MASTER-API-REFERENCE.md) | Function signatures and usage for all libraries | -| [Master Dispatcher Guide](MASTER-DISPATCHER-GUIDE.md) | All 15 dispatchers documented | +| [Master Dispatcher Guide](MASTER-DISPATCHER-GUIDE.md) | All 14 dispatchers documented | | [Master Architecture](MASTER-ARCHITECTURE.md) | System architecture with Mermaid diagrams | | [Documentation Dashboard](../DOC-DASHBOARD.md) | Documentation coverage metrics | diff --git a/docs/specs/BRAINSTORM-obs-dispatcher-shadowing-2026-06-04.md b/docs/specs/BRAINSTORM-obs-dispatcher-shadowing-2026-06-04.md new file mode 100644 index 000000000..1e89036c4 --- /dev/null +++ b/docs/specs/BRAINSTORM-obs-dispatcher-shadowing-2026-06-04.md @@ -0,0 +1,101 @@ +# 🧠 BRAINSTORM: obs dispatcher shadowing fix + +**Date:** 2026-06-04 · **Depth:** default · **Focus:** architecture / shell-integration +**Pairs with:** `SPEC-obs-dispatcher-shadowing-2026-06-04.md` +**Converged approach:** **B + A** (general binary-precedence guard **and** delete the dead obs dispatcher) + +--- + +## TL;DR + +The spec's *direction* is right (delete `obs` dispatcher + add a general guard), but its **Option B code sketch is broken** and would not actually generalize. The guard derives the command name from the **filename**, but every real dispatcher file is named `X-dispatcher.zsh` while the command it defines is `X`. `obs.zsh` is the lone bare-named file — so the sketch works *only for obs by accident* and protects nothing else. + +Fixing that naming/identity gap is the real design decision hiding inside this spec. + +--- + +## 🚨 Critical Finding — Option B's sketch is a happy accident + +The spec sketch: + +```zsh +local name="${${disp_file:t}:r}" # filename without dir/ext +command -v "$name" ... # is there a binary with that name? +``` + +Evaluated against the actual files: + +| File on disk | `name` derived | Command actually defined | `command -v $name` | Guard behavior | +|---|---|---|---|---| +| `obs.zsh` | `obs` | `obs()` | `/opt/homebrew/bin/obs` ✅ | **Skips — correct** | +| `g-dispatcher.zsh` | `g-dispatcher` | `g()` | (nothing) | Sources — but for the wrong reason | +| `mcp-dispatcher.zsh` | `mcp-dispatcher` | `mcp()` | (nothing) | Sources | +| `r-dispatcher.zsh` | `r-dispatcher` | `r()` | (nothing) | Sources | + +**Consequence:** the guard never tests the *real* command names (`g`, `mcp`, `r`, …). It only ever tests `obs` because `obs.zsh` is uniquely bare-named. If someone later adds `node-dispatcher.zsh` defining `node()`, the guard checks `command -v node-dispatcher` (nothing) → sources it → **re-shadows the real `node` binary.** The "general hazard" the spec set out to kill is still wide open. + +So Option B as written = Option A with extra steps. + +--- + +## The real fork: how does the guard learn a file's command name? + +To make B *genuinely* general, the loader must map a dispatcher file → the command(s) it defines. Four ways: + +| Way | Mechanism | Pros | Cons | +|---|---|---|---| +| **B1. Strip `-dispatcher` suffix** | `name="${${disp_file:t}:r}"; name="${name%-dispatcher}"` | Tiny diff; matches the existing convention | Relies on naming discipline; `obs.zsh` (no suffix) is the exception — but it's being deleted, so post-delete every file follows the convention | +| **B2. Explicit registry** | A `typeset -A FLOW_DISPATCHER_CMDS=( g-dispatcher g mcp-dispatcher mcp … )` | Unambiguous; supports multi-command files | Manual upkeep; another thing to forget when adding a dispatcher | +| **B3. Post-source self-check** | Source the file, then for each function it defined, if a same-named **external binary** also exists, `unfunction` it (unless forced) | Uses the *actual* command names — zero naming assumptions | Heavier; must diff `${(k)functions}` before/after; ordering vs. `disable r` | +| **B4. Per-dispatcher opt-in header** | Each file declares `# flow-command: g` and loader greps it | Self-documenting, co-located | Parsing comments at load time; perf | + +**Recommendation: B1** (strip the suffix). After Option A deletes `obs.zsh`, **every remaining file follows `X-dispatcher.zsh`**, so suffix-stripping yields the true command name for all of them — making the guard genuinely general with a one-line change. Keep `FLOW_FORCE_DISPATCHER_<NAME>=1` as the escape hatch. Add a **convention test** (filename must be `<cmd>-dispatcher.zsh`) so B1 stays valid as dispatchers are added. + +--- + +## Edge cases pressure-test + +| Case | Risk | Handling | +|---|---|---| +| **`r` is a builtin** (`disable r` at line 72) | Guard might mis-handle builtins | Guard checks **external binaries only** (`command -v` of a *file*, not a builtin). `r` has no `/path` binary → not skipped. ✅ Already noted in spec. | +| **Symlink `zsh/functions/obs.zsh`** → obsidian-cli-ops source | Dangling/legacy after delete | Loader never sources `zsh/functions/`. Still: **delete the symlink** as part of A so it doesn't mislead. | +| **`obs.1` man page** | Drift vs. man-page-sync guard | Man-page spec lists `obs` as a flow dispatcher. Remove `obs.1` + the inventory row, or the sync guard fails CI. Coordinate the two specs in one PR. | +| **Test env has no `obs` binary** | `type obs` assertion flips | Test must **mock an `obs` on PATH** (stub in a temp dir prepended to `$PATH`) before asserting the guard skips it. Otherwise the guard correctly sources nothing-to-skip and the assert is vacuous. | +| **User already has `unfunction obs` in zshrc** | Now redundant/confusing | Acceptance criterion already says no workaround needed; note in release notes so the user can remove it. | +| **`FLOW_DEBUG` log on skip** | Noise | Gate behind `$FLOW_DEBUG` (spec already does). | +| **Forced re-enable** (`FLOW_FORCE_DISPATCHER_OBS=1`) but obs deleted | Dead env var | Harmless; document only if obs is kept. With A, the var simply has no file to act on. | + +--- + +## Quick Wins (< 30 min each) + +1. ⚡ **Delete `lib/dispatchers/obs.zsh`** — dead code that can't run (wants a `python/obs_cli.py` flow-cli never ships). +2. ⚡ **Delete the `zsh/functions/obs.zsh` symlink** — unsourced, points into a sibling repo, pure confusion. +3. ⚡ **Drop `obs` from the loader comment** at `flow.plugin.zsh:24` (`# Load v, g, mcp, obs dispatchers`). + +## Medium Effort (1–2 hours) + +4. □ **Implement guard B1** — suffix-strip + external-binary check + `FLOW_FORCE_DISPATCHER_<NAME>` escape hatch, with `$FLOW_DEBUG` skip log. +5. □ **Convention guard test** — assert every `lib/dispatchers/*.zsh` is named `<cmd>-dispatcher.zsh` (keeps B1 honest). +6. □ **Shadow regression test** — stub an `obs` binary on `$PATH`, source the plugin, assert `type obs` is a *file*, not a function; assert the guard sources `g`/`mcp`/`r` normally. +7. □ **Man-page + inventory sync** — remove `obs.1` and the `obs` row; satisfy `test-manpage-version-sync.zsh` in the same PR. + +## Long-term (future) + +8. □ Consider a tiny **dispatcher manifest** (B2) only if multi-command dispatchers or non-conventional names ever appear. Not needed today. + +--- + +## Recommended Path + +→ **Single feature worktree, one PR, in this order:** (A) delete obs dispatcher + symlink + man page/inventory → (B1) add the suffix-stripping guard → tests (convention + shadow regression) → coordinate the man-page-sync spec so CI stays green. + +The decisive correction vs. the current spec: **replace the Option B sketch with B1 (suffix-strip)** so the guard keys on the true command name. Without that, the "general guard" protects exactly one command (`obs`) and reopens the hazard for the next collision. + +--- + +## Open Questions + +1. Keep the `FLOW_FORCE_DISPATCHER_<NAME>` escape hatch even though obs is deleted? (Recommend **yes** — it's the only override for the *general* guard.) +2. Should the convention test be a hard CI gate or advisory? (Recommend **hard** — it's the invariant B1 depends on.) +3. Any other installed binaries that collide with a *future* planned dispatcher name? (Audit `command -v` for the dispatcher roadmap before shipping.) diff --git a/docs/specs/SPEC-obs-dispatcher-shadowing-2026-06-04.md b/docs/specs/SPEC-obs-dispatcher-shadowing-2026-06-04.md new file mode 100644 index 000000000..32ad0607f --- /dev/null +++ b/docs/specs/SPEC-obs-dispatcher-shadowing-2026-06-04.md @@ -0,0 +1,134 @@ +# SPEC: Stop the `obs` Dispatcher from Shadowing the Real `obs` Binary + +**Status:** ✅ Merged — PR #460 squash-merged to `dev` (fc00837f, 2026-06-05). Shipped Phase 1 (delete obs dispatcher) + Phase 2 (B3 binary-precedence guard). +**Created:** 2026-06-04 +**Type:** dispatcher / shell-integration fix +**Trigger:** On 2026-06-04, interactive `obs` failed with `[ERROR] Python CLI not found at: …/flow-cli/.../zsh/functions/python/obs_cli.py`. flow-cli loads an `obs` **dispatcher** that duplicates the obsidian-cli-ops wrapper but (a) looks for a `python/obs_cli.py` flow-cli never bundles and (b) uses `OBS_PYTHON=$(command -v python3)` → a dep-less `python@3.14`. It **shadows** the working Homebrew `obs` binary (`/opt/homebrew/bin/obs`). + +--- + +## Overview + +obsidian-cli-ops installs a complete, canonical `obs` on `PATH` (Homebrew binary → `libexec/python/obs_cli.py` under a known interpreter). flow-cli **also** defines `obs` via `lib/dispatchers/obs.zsh` (mirrored in `zsh/functions/obs.zsh`), sourced unconditionally by the dispatcher loop in `flow.plugin.zsh`: + +```zsh +if [[ "$FLOW_LOAD_DISPATCHERS" == "yes" ]]; then + for disp_file in "$FLOW_PLUGIN_DIR/lib/dispatchers/"*.zsh(N); do + source "$disp_file" + done +fi +``` + +Because a shell **function** beats a binary in lookup, the broken flow-cli `obs` wins in every interactive shell. The dispatcher cannot work as written — it needs a Python CLI flow-cli doesn't ship — so it provides nothing the Homebrew binary doesn't, while actively breaking it. + +This is a **general hazard**: any dispatcher whose name collides with an installed external binary will shadow it. + +--- + +## Primary User Story + +**As a** flow-cli user who also installs obsidian-cli-ops, +**I want** typing `obs` to run the real, working `obs` binary, +**so that** flow-cli doesn't break a tool it doesn't own. + +### Acceptance Criteria + +- [ ] In an interactive shell with obsidian-cli-ops installed, `obs` resolves to the **binary** (`type obs` → `/opt/homebrew/bin/obs`), not a flow-cli function. +- [ ] flow-cli no longer defines a broken `obs` that errors `Python CLI not found`. +- [ ] Other dispatchers (`v`, `g`, `mcp`, `r`, `qu`, …) are unaffected. +- [ ] No `unfunction obs` workaround required in the user's `~/.config/zsh/.zshrc`. +- [ ] flow-cli's `man/man1/obs.1` is **removed** and `obs` dropped from the flow dispatcher inventory (coordinate with `SPEC-manpage-refresh-2026-06-04.md`, which currently lists `obs` among flow dispatchers and ships `obs.1`). +- [ ] A replacement `obs.1` is **authored in obsidian-cli-ops** (the owner of the binary), covering its v3.2.1 surface — see "Man-Page Ownership" below. + +--- + +## Approaches + +| Option | How | Trade-off | +|--------|-----|-----------| +| **A. Drop the obs dispatcher** | Delete `lib/dispatchers/obs.zsh` + `zsh/functions/obs.zsh`; remove `obs` from the "Load v, g, mcp, obs" comment/inventory; drop `obs.1`. | Simplest; obsidian-cli-ops is canonical. Loses any flow-specific obs sugar (there is none working today). | +| **B. Binary-precedence guard (recommended, general)** | In the dispatcher loop, skip sourcing a dispatcher when its command name already resolves to an external binary on `PATH`, unless `FLOW_FORCE_DISPATCHER_<name>=1`. | Fixes `obs` **and** prevents any future dispatcher↔binary collision. Slightly more loader logic. | +| **C. Thin delegator** | Replace the obs dispatcher body with `command obs "$@"` (or exec the Homebrew binary). | Keeps an `obs` function but it just forwards. Pointless indirection vs. A/B. | + +**Recommendation:** **B** (a general binary-precedence guard in the loader) and **A** (remove the now-redundant obs dispatcher). B protects the ecosystem long-term; A removes dead, harmful code. + +### ⚠️ Filename ≠ command name (corrects the naive sketch) + +A guard keyed on the **filename** is only correct for `obs`, by accident. The dispatcher files are named `X-dispatcher.zsh` but each defines command `X`: + +| File on disk | `${${disp_file:t}:r}` | Command actually defined | `command -v` of derived name | +|---|---|---|---| +| `obs.zsh` | `obs` | `obs()` | `/opt/homebrew/bin/obs` ✅ | +| `g-dispatcher.zsh` | `g-dispatcher` | `g()` | (nothing) ❌ | +| `mcp-dispatcher.zsh` | `mcp-dispatcher` | `mcp()` | (nothing) ❌ | +| `r-dispatcher.zsh` | `r-dispatcher` | `r()` | (nothing) ❌ | + +`obs.zsh` is the **only** bare-named dispatcher file, so a filename-keyed guard tests `obs` and nothing else. Add `node-dispatcher.zsh` (defining `node()`) later and the guard checks `command -v node-dispatcher` → nothing → sources it → **re-shadows the real `node` binary.** That is the exact "general hazard" this spec exists to kill, left open. So the naive guard ≈ Option A with extra steps. + +**Fix:** derive the true command name by **stripping the `-dispatcher` suffix**. After Option A deletes the lone exception (`obs.zsh`), **every** remaining file follows `<cmd>-dispatcher.zsh`, so suffix-stripping recovers the real command name for all of them — making the guard genuinely general with a one-line change. Guard this invariant with a convention test (see Implementation Notes). + +### Sketch (Option B — corrected, suffix-strip) + +```zsh +for disp_file in "$FLOW_PLUGIN_DIR/lib/dispatchers/"*.zsh(N); do + local name="${${disp_file:t}:r}" # g-dispatcher + name="${name%-dispatcher}" # → g (obs.zsh is deleted by Option A) + local force="FLOW_FORCE_DISPATCHER_${name:u}" + if [[ -z "${(P)force}" ]] && command -v "$name" >/dev/null 2>&1 \ + && [[ "$(command -v "$name")" != *"flow"* ]]; then + [[ -n "$FLOW_DEBUG" ]] && _flow_log_info "Skipping dispatcher '$name' (external binary present)" + continue + fi + source "$disp_file" +done +``` + +> The `disable r` at `flow.plugin.zsh:72` is unaffected — `r` is a zsh **builtin**, not an external binary, so `command -v r` (after `disable`) does not resolve to a `/path` file and the guard never skips it. + +--- + +## Man-Page Ownership (handoff to obsidian-cli-ops) + +flow-cli is *dropping* `obs.1` because it doesn't own the command. The man page should not vanish — it should move to **obsidian-cli-ops**, which owns `/opt/homebrew/bin/obs` and currently ships **zero** man pages. This is a cross-repo handoff: flow-cli removes, obsidian-cli-ops adds. Track the "add" half in obsidian-cli-ops (its own branch workflow); this spec only records the contract so the man page isn't lost. + +### Command surface to document (obsidian-cli-ops v3.2.1) + +Authored from the **dispatch table in `src/obs.zsh`**, not from `obs help` — see the undocumented-command note below. + +| Group | Commands | +|---|---| +| Primary | `obs` (list vaults / last-vault stats), `obs stats [vault]`, `obs discover <path>` | +| Graph analysis | `obs analyze <vault>`, `obs health <vault>` | +| AI | `obs ai status`, `obs ai setup`, `obs ai test`, `obs ai similar <note>`, `obs ai analyze <note>`, `obs ai duplicates <vault>`, `obs ai suggest-links <note>`, `obs ai gaps <vault>`, `obs ai summarize <vault>`, `obs ai refactor <vault>` | +| AI — **undocumented in `obs help --all`** | `obs ai merge-suggest`, `obs ai tag-suggest`, `obs ai quality` | +| Utilities | `obs help [--all]`, `obs version` | + +### ⚠️ Finding: three AI subcommands ship without help + +`obs ai merge-suggest`, `obs ai tag-suggest`, and `obs ai quality` are handled in the `obs.zsh` `case` block (≈ lines 464–513) but are **absent from `obs_help()`** (lines 163–174). A man page built from `obs help` would inherit this gap. The obsidian-cli-ops man-page task should: (a) cover all dispatch-table commands, and (b) backfill these three into `obs help --all` so help and man page agree. *(Out of scope for flow-cli — flagged here for the receiving repo.)* + +### Suggested shape (in obsidian-cli-ops) + +- `obs.1` — top-level, with `ai` as a documented subcommand surface, **or** +- `obs.1` + `obs-ai.1` (SEE ALSO cross-links) if the AI surface warrants its own page (10–13 subcommands suggests it might). +- Mirror flow-cli's troff conventions (model `flow-cli/man/man1/g.1`); add an anti-drift `.TH`-version guard like flow-cli's `test-manpage-version-sync.zsh` so the page tracks the package version. + +## Out of Scope / Related + +- The **root cause** that `obs` itself broke (missing Python deps in its interpreter) is an obsidian-cli-ops packaging issue: `obsidian-cli-ops/docs/specs/SPEC-dependency-bootstrapping-2026-06-04.md`. It was patched manually on 2026-06-04 (deps installed into `python@3.12`). +- The dashboard `ops`/`obs-project-sync` tool referenced by `MediationVerse_Dashboard.md` is a **different, archived** tool — not this dispatcher and not in scope. + +## Implementation Notes + +- **Guard keys on the suffix-stripped command name**, not the raw filename — see "Filename ≠ command name" above. The naive filename-keyed sketch only protects `obs`. +- **Convention test (required for B1 to stay valid):** assert every `lib/dispatchers/*.zsh` is named `<cmd>-dispatcher.zsh`. This is the invariant suffix-stripping depends on; make it a hard CI gate so a future bare-named dispatcher can't silently reopen the shadowing hazard. +- Verify `r`'s existing `disable r` handling still works under the new guard (it's a builtin, not a binary — guard only checks external binaries). +- **Shadow regression test:** stub an `obs` executable into a temp dir prepended to `$PATH`, source the plugin, then assert `type obs` is a **file** (not a function) and that `g`/`mcp`/`r` still load normally. Without the stub the assertion is vacuous — the guard has nothing to skip in a bare CI environment that lacks the Homebrew `obs`. +- **Delete the `zsh/functions/obs.zsh` symlink too** (it points into the obsidian-cli-ops source and is *not* sourced by the loader, which globs only `lib/dispatchers/*.zsh`) — leaving it is pure confusion. +- Man-page + inventory cleanup ships in the **same PR** as the deletion: remove `obs.1`, drop `obs` from the loader comment (`flow.plugin.zsh:24`) and any dispatcher inventory/help, or `test-manpage-version-sync.zsh` fails CI (coordinate with `SPEC-manpage-refresh-2026-06-04.md`). + +## History + +- **2026-06-04** — Created after flow-cli's `obs` dispatcher shadowed and broke the Homebrew `obs` binary; stopgap was `unfunction obs` in user zshrc (blocked/avoided). This spec proposes removing the redundant dispatcher + a general binary-precedence guard. +- **2026-06-04** — Brainstorm pass (`BRAINSTORM-obs-dispatcher-shadowing-2026-06-04.md`) found the Option B sketch keyed the guard on the **filename**, which equals the command name only for `obs.zsh` (every other file is `X-dispatcher.zsh` defining `X`). Replaced with the **suffix-strip (B1)** variant so the guard is genuinely general post-Option-A; added the convention test, stub-binary regression test, and symlink-deletion notes. +- **2026-06-04** — Added Man-Page Ownership handoff: flow-cli removes `obs.1`, obsidian-cli-ops authors a replacement. Audited obsidian-cli-ops **v3.2.1** command surface and found `obs ai merge-suggest`, `obs ai tag-suggest`, `obs ai quality` ship in the dispatch table but are missing from `obs help --all`. diff --git a/docs/teaching/index.md b/docs/teaching/index.md index f8b90a4bd..66cdfd00a 100644 --- a/docs/teaching/index.md +++ b/docs/teaching/index.md @@ -232,4 +232,4 @@ teach plan help --- **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/tutorials/14-teach-dispatcher.md b/docs/tutorials/14-teach-dispatcher.md index efcf1373c..8deda03d2 100644 --- a/docs/tutorials/14-teach-dispatcher.md +++ b/docs/tutorials/14-teach-dispatcher.md @@ -10,7 +10,7 @@ tags: > **What you'll learn:** Manage course websites with fast deployment, config validation, and AI-assisted content creation > > **Time:** ~20 minutes | **Level:** Beginner -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- diff --git a/docs/tutorials/20-teaching-dates-automation.md b/docs/tutorials/20-teaching-dates-automation.md index adbacd3c4..326bbca51 100644 --- a/docs/tutorials/20-teaching-dates-automation.md +++ b/docs/tutorials/20-teaching-dates-automation.md @@ -657,4 +657,4 @@ yq eval .flow/teach-config.yml **Questions or issues?** Open an issue on [GitHub](https://github.com/Data-Wise/flow-cli/issues) **Last Updated:** 2026-02-27 -**Version:** v7.8.1 +**Version:** v7.9.0 diff --git a/docs/tutorials/21-teach-analyze.md b/docs/tutorials/21-teach-analyze.md index 98f86e5ee..c72064d95 100644 --- a/docs/tutorials/21-teach-analyze.md +++ b/docs/tutorials/21-teach-analyze.md @@ -9,7 +9,7 @@ tags: > **What you'll learn:** Validate lecture prerequisites, detect concept gaps, and generate optimized slides using `teach analyze` > > **Time:** ~15 minutes | **Level:** Beginner → Intermediate -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- diff --git a/docs/tutorials/24-template-management.md b/docs/tutorials/24-template-management.md index f46fb225c..9bd8aad3e 100644 --- a/docs/tutorials/24-template-management.md +++ b/docs/tutorials/24-template-management.md @@ -9,7 +9,7 @@ tags: > **What you'll learn:** Create and manage teaching content templates with `teach templates` > > **Time:** ~15 minutes | **Level:** Beginner → Intermediate -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- @@ -433,5 +433,5 @@ teach templates sync --force --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-28 diff --git a/docs/tutorials/25-lesson-plan-migration.md b/docs/tutorials/25-lesson-plan-migration.md index 7676aba8a..f3ccf66cf 100644 --- a/docs/tutorials/25-lesson-plan-migration.md +++ b/docs/tutorials/25-lesson-plan-migration.md @@ -3,7 +3,7 @@ > **What you'll learn:** Extract lesson plans with `teach migrate-config` and manage them with `teach plan` > > **Time:** ~15 minutes | **Level:** Beginner -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- @@ -417,5 +417,5 @@ teach lecture --week 5 --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-28 diff --git a/docs/tutorials/26-latex-macros.md b/docs/tutorials/26-latex-macros.md index ece3dcfad..330386f78 100644 --- a/docs/tutorials/26-latex-macros.md +++ b/docs/tutorials/26-latex-macros.md @@ -3,7 +3,7 @@ > **What you'll learn:** Configure LaTeX macros for consistent AI-generated notation with `teach macros` > > **Time:** ~15 minutes | **Level:** Beginner → Intermediate -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- diff --git a/docs/tutorials/27-lesson-plan-management.md b/docs/tutorials/27-lesson-plan-management.md index ff0955bb4..3751196c9 100644 --- a/docs/tutorials/27-lesson-plan-management.md +++ b/docs/tutorials/27-lesson-plan-management.md @@ -3,7 +3,7 @@ > **What you'll learn:** Create, manage, and use lesson plans with `teach plan` to drive AI content generation > > **Time:** ~15 minutes | **Level:** Beginner -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- @@ -339,5 +339,5 @@ teach slides --week 5 # Generate slides --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-01-29 diff --git a/docs/tutorials/29-first-exam-walkthrough.md b/docs/tutorials/29-first-exam-walkthrough.md index f51bd3d5e..93d74149f 100644 --- a/docs/tutorials/29-first-exam-walkthrough.md +++ b/docs/tutorials/29-first-exam-walkthrough.md @@ -3,7 +3,7 @@ > **What you'll learn:** Generate exams and quizzes using Scholar AI wrappers with flow-cli > > **Time:** ~20 minutes | **Level:** Beginner → Intermediate -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- @@ -846,6 +846,6 @@ teach exam "Topic" --week 5 --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-27 **Tutorial Series:** Part 29 of Teaching Workflow Tutorials diff --git a/docs/tutorials/30-new-instructor-complete-workflow.md b/docs/tutorials/30-new-instructor-complete-workflow.md index 160e2123e..e643906b3 100644 --- a/docs/tutorials/30-new-instructor-complete-workflow.md +++ b/docs/tutorials/30-new-instructor-complete-workflow.md @@ -3,7 +3,7 @@ > **What you'll learn:** Go from an empty directory to a deployed course website with AI-powered content > > **Time:** ~30 minutes | **Level:** Beginner -> **Version:** v7.8.1 +> **Version:** v7.9.0 --- diff --git a/docs/tutorials/32-teach-doctor.md b/docs/tutorials/32-teach-doctor.md index 5f6bd137d..ffc1186f4 100644 --- a/docs/tutorials/32-teach-doctor.md +++ b/docs/tutorials/32-teach-doctor.md @@ -390,5 +390,5 @@ Only runs when `scholar.latex_macros.enabled: true` in teach-config.yml: --- -**Version:** v7.8.1 +**Version:** v7.9.0 **Last Updated:** 2026-02-08 diff --git a/docs/tutorials/35-em-cli-email.md b/docs/tutorials/35-em-cli-email.md index fa4ad8608..d21b1aacb 100644 --- a/docs/tutorials/35-em-cli-email.md +++ b/docs/tutorials/35-em-cli-email.md @@ -277,4 +277,4 @@ After installing, configure an account in `~/.config/himalaya/config.toml` and r - **[Tutorial 46: em v2.0 Features](46-em-v2-features.md)** — Calendar integration, IMAP watch, folder management, safety gate - **[Tutorial 33: Email in Neovim](33-himalaya-email.md)** — Read, reply, and process email without leaving your editor - **[Email Cookbook](../guides/EMAIL-COOKBOOK.md)** — Practical recipes for common workflows -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers diff --git a/docs/tutorials/37-mcp-dispatcher.md b/docs/tutorials/37-mcp-dispatcher.md index 2cc4988c3..bbdfd61b6 100644 --- a/docs/tutorials/37-mcp-dispatcher.md +++ b/docs/tutorials/37-mcp-dispatcher.md @@ -190,5 +190,5 @@ A server can be configured for one environment but not the other. ## Next Steps -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers - **[Model Context Protocol](https://modelcontextprotocol.io/)** — Official MCP documentation diff --git a/docs/tutorials/38-r-dispatcher.md b/docs/tutorials/38-r-dispatcher.md index b4c87f0af..0e1d3e08c 100644 --- a/docs/tutorials/38-r-dispatcher.md +++ b/docs/tutorials/38-r-dispatcher.md @@ -194,6 +194,6 @@ install.packages(c("devtools", "usethis", "covr", "spelling", "pkgdown")) ## Next Steps -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers - **[R Packages book](https://r-pkgs.org/)** — The definitive R package development reference - **[devtools documentation](https://devtools.r-lib.org/)** — Full API reference diff --git a/docs/tutorials/39-qu-dispatcher.md b/docs/tutorials/39-qu-dispatcher.md index 2dae594ea..be2db3214 100644 --- a/docs/tutorials/39-qu-dispatcher.md +++ b/docs/tutorials/39-qu-dispatcher.md @@ -190,4 +190,4 @@ pkill -f "quarto preview" # Kill by name - **[Quarto Documentation](https://quarto.org/docs/guide/)** — Full Quarto reference - **[Tutorial 14: teach Dispatcher](14-teach-dispatcher.md)** — Uses Quarto for course sites with deploy/rollback -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers diff --git a/docs/tutorials/40-v-dispatcher.md b/docs/tutorials/40-v-dispatcher.md index 049db61f1..95ef4ff80 100644 --- a/docs/tutorials/40-v-dispatcher.md +++ b/docs/tutorials/40-v-dispatcher.md @@ -159,5 +159,5 @@ Yes. The dispatcher auto-detects your project type and runs the appropriate test ## Next Steps -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers - **[Tutorial 43: ADHD Daily Routine](43-adhd-daily-routine.md)** — Morning briefing, just start, focus timers diff --git a/docs/tutorials/41-obs-dispatcher.md b/docs/tutorials/41-obs-dispatcher.md deleted file mode 100644 index ff27e1415..000000000 --- a/docs/tutorials/41-obs-dispatcher.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -tags: - - tutorial - - dispatchers - - obsidian - - knowledge-base - - ai ---- - -# Tutorial: Obsidian Vault Management with obs - -Discover, analyze, and search your Obsidian vaults with AI-powered graph analysis — all from the command line. - -**Time:** 15 minutes | **Level:** Intermediate | **Requires:** flow-cli, python3, jq - -## What You'll Learn - -1. Listing and discovering Obsidian vaults -2. Viewing vault statistics and graph metrics -3. Configuring AI providers for vault analysis -4. Using AI-powered search for similar and duplicate notes -5. Analyzing individual notes with AI - ---- - -## Step 1: List Your Vaults - -See all registered Obsidian vaults: - -```zsh -obs -``` - -Or explicitly: - -```zsh -obs vaults -``` - -Each vault shows its path and note count. Vault data is stored in `~/.config/obs/obsidian_vaults.db`. - ---- - -## Step 2: Discover Vaults - -Scan a directory to find all Obsidian vaults (identified by `.obsidian/` folders): - -```zsh -obs discover ~/Documents -``` - -For iCloud-synced vaults: - -```zsh -obs discover ~/Library/Mobile\ Documents/iCloud~md~obsidian/Documents -``` - -Discovered vaults are automatically registered and appear in `obs vaults`. - ---- - -## Step 3: Vault Statistics - -Get detailed stats about any vault: - -```zsh -obs stats my-vault -``` - -Shows: note count, link count, tag count, orphan notes, and average links per note. - ---- - -## Step 4: Graph Analysis - -Analyze vault structure and connectivity: - -```zsh -obs analyze my-vault -``` - -Shows: network connectivity score, identified clusters, hub notes (most connected), density metrics, and linking recommendations. - ---- - -## Step 5: AI Setup - -Configure AI providers for advanced vault analysis: - -```zsh -obs ai setup # Interactive setup wizard -obs ai status # Show current AI configuration -obs ai test # Verify all providers work -``` - ---- - -## Step 6: AI-Powered Search - -Find notes by meaning, not just keywords: - -```zsh -obs ai similar "My Note Title" # Find semantically similar notes -obs ai duplicates # Find potential duplicate content -obs ai analyze "Note Title" # AI analysis of a specific note -``` - -`obs ai analyze` returns key concepts, related topics, suggested links, and knowledge graph gaps. - ---- - -## Step 7: Verbose Mode - -Add `--verbose` to any command for detailed output: - -```zsh -obs --verbose stats my-vault -``` - -Shows API calls, file scanning details, and performance timings. - ---- - -## FAQ - -### Where is vault data stored? - -Vault registry is at `~/.config/obs/obsidian_vaults.db`. The last-used vault is tracked in `~/.config/obs/last_vault`. - -### Does obs work with iCloud-synced vaults? - -Yes. Use `obs discover` with the iCloud Obsidian path. They work like any other vault. - -### What AI providers are supported? - -OpenAI, Anthropic (Claude), local models via Ollama, and OpenAI-compatible APIs. Run `obs ai setup` to see options. - -### Does analyzing a vault change my files? - -No. All analysis is read-only. No notes are modified. - ---- - -## Next Steps - -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers -- **[Obsidian Documentation](https://help.obsidian.md/)** — Official Obsidian reference diff --git a/docs/tutorials/42-g-dispatcher.md b/docs/tutorials/42-g-dispatcher.md index 8700e08b3..1e285b714 100644 --- a/docs/tutorials/42-g-dispatcher.md +++ b/docs/tutorials/42-g-dispatcher.md @@ -228,4 +228,4 @@ No. Token validation only triggers for GitHub remotes (URLs containing `github.c - **[Tutorial 8: Git Feature Workflow](08-git-feature-workflow.md)** — Branch conventions and PR workflow - **[Tutorial 9: Worktrees](09-worktrees.md)** — Parallel branch development -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers diff --git a/docs/tutorials/43-adhd-daily-routine.md b/docs/tutorials/43-adhd-daily-routine.md index 65853ee4b..94d327594 100644 --- a/docs/tutorials/43-adhd-daily-routine.md +++ b/docs/tutorials/43-adhd-daily-routine.md @@ -186,4 +186,4 @@ Yes. `timer 50` for a 50-minute focus, `timer break 10` for a 10-minute break. U - **[Tutorial 6: Dopamine Features](06-dopamine-features.md)** — Log wins, build streaks with `win` and `yay` - **[Tutorial 44: Quick Capture](44-quick-capture.md)** — Capture fleeting ideas with `catch` - **[Tutorial 1: First Session](01-first-session.md)** — Start here if you haven't used flow-cli yet -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers diff --git a/docs/tutorials/44-quick-capture.md b/docs/tutorials/44-quick-capture.md index 5810eb3f4..faa5f0654 100644 --- a/docs/tutorials/44-quick-capture.md +++ b/docs/tutorials/44-quick-capture.md @@ -146,4 +146,4 @@ One per context switch or every ~30 minutes of deep work. Don't over-document - **[Tutorial 6: Dopamine Features](06-dopamine-features.md)** — Log accomplishments with `win` and `yay` - **[Tutorial 43: ADHD Daily Routine](43-adhd-daily-routine.md)** — Morning briefing, just start, focus timers -- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 15 dispatchers +- **[MASTER-DISPATCHER-GUIDE](../reference/MASTER-DISPATCHER-GUIDE.md)** — Complete reference for all 14 dispatchers diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md index 2a2ded594..21d70cb0f 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.md @@ -37,7 +37,6 @@ flowchart TD T38["<a href='38-r-dispatcher/'>Tutorial 38</a><br/>R Packages<br/>⏱ 15 min"] T39["<a href='39-qu-dispatcher/'>Tutorial 39</a><br/>Quarto<br/>⏱ 15 min"] T40["<a href='40-v-dispatcher/'>Tutorial 40</a><br/>Workflow (v)<br/>⏱ 15 min"] - T41["<a href='41-obs-dispatcher/'>Tutorial 41</a><br/>Obsidian<br/>⏱ 15 min"] T42["<a href='42-g-dispatcher/'>Tutorial 42</a><br/>Git Shortcuts<br/>⏱ 20 min"] end @@ -100,7 +99,7 @@ flowchart TD classDef intermediate fill:#fff3cd,stroke:#ffc107,color:#856404 classDef optional fill:#e2e3e5,stroke:#6c757d,color:#383d41 - class T1,T2,T3,T6,T10,T11,T12,T13,T35,T37,T38,T39,T40,T41,T42,T43,T44 beginner + class T1,T2,T3,T6,T10,T11,T12,T13,T35,T37,T38,T39,T40,T42,T43,T44 beginner class T8,T9,T14,T21,T22,T23,T24,T25,T26,T36 intermediate class T4,T5,T7 optional ``` @@ -184,7 +183,6 @@ flowchart TD | 38 | [R Dispatcher](38-r-dispatcher.md) | 15 min | 🟡 Intermediate | R package development workflow | | 39 | [Quarto Dispatcher](39-qu-dispatcher.md) | 15 min | 🟢 Beginner | Quarto render, preview, publish | | 40 | [Workflow (v/vibe)](40-v-dispatcher.md) | 15 min | 🟢 Beginner | Testing, sessions, dashboards, health | -| 41 | [Obsidian Vaults](41-obs-dispatcher.md) | 15 min | 🟢 Beginner | Vault discovery, stats, AI search | | 42 | [Git Shortcuts (g)](42-g-dispatcher.md) | 20 min | 🟢 Beginner | Git shortcuts with token validation | | 43 | [ADHD Daily Routine](43-adhd-daily-routine.md) | 20 min | 🟢 Beginner | Morning briefing, just start, timers | | 44 | [Quick Capture](44-quick-capture.md) | 10 min | 🟢 Beginner | catch, inbox, crumb, trail | diff --git a/docs/tutorials/scholar-enhancement/index.md b/docs/tutorials/scholar-enhancement/index.md index a85c814e7..fe2cfe23a 100644 --- a/docs/tutorials/scholar-enhancement/index.md +++ b/docs/tutorials/scholar-enhancement/index.md @@ -1,6 +1,6 @@ # Scholar Enhancement Tutorials -**Version:** v7.8.1 +**Version:** v7.9.0 **Total Duration:** ~65 minutes **Skill Levels:** 3 (Beginner → Advanced) diff --git a/flow.plugin.zsh b/flow.plugin.zsh index 2d968d683..0c8cd9896 100644 --- a/flow.plugin.zsh +++ b/flow.plugin.zsh @@ -21,7 +21,7 @@ FLOW_PLUGIN_DIR=${0:A:h} # Feature flags : ${FLOW_ATLAS_ENABLED:=auto} # auto|yes|no -: ${FLOW_LOAD_DISPATCHERS:=yes} # Load v, g, mcp, obs dispatchers +: ${FLOW_LOAD_DISPATCHERS:=yes} # Load v, g, mcp dispatchers # ============================================================================ # CORE LIBRARY @@ -71,9 +71,51 @@ if [[ "$FLOW_LOAD_DISPATCHERS" == "yes" ]]; then # Disable ZSH builtin 'r' (history repeat) to allow R dispatcher disable r - for disp_file in "$FLOW_PLUGIN_DIR/lib/dispatchers/"*.zsh(N); do - source "$disp_file" - done + # Commands flow-cli deliberately provides even when a PATH binary of the + # same name exists (e.g. `cc` launches Claude Code, not the C compiler; + # `r` is the R-package dispatcher, not Homebrew's R launcher). Pre-set + # FLOW_INTENTIONAL_SHADOWS before sourcing the plugin to customize. + if (( ! ${+FLOW_INTENTIONAL_SHADOWS} )); then + typeset -ga FLOW_INTENTIONAL_SHADOWS=(r mcp cc) + fi + + # Binary-precedence guard (B3): after sourcing the dispatcher files, drop any + # newly-defined command function that would shadow an external PATH binary + # — unless it's an intentional shadow (above) or forced via + # FLOW_FORCE_DISPATCHER_<NAME>=1. Stops a broken dispatcher (historically + # `obs`, which needed a Python CLI flow-cli never shipped) from masking a + # working binary. Keys on the functions actually defined, so it needs no + # filename convention and skips `_`-prefixed helpers automatically. + # + # Perf: snapshots the function table once around the whole batch (not per + # file) and reads the fork-free ${commands} hash instead of $(whence -p), + # keeping the guard's startup cost down on flow-cli's <10ms budget. + _flow_load_dispatcher() { + local -a _before _after _new + _before=( ${(k)functions} ) + + local file + for file in "$@"; do + source "$file" + done + + _after=( ${(k)functions} ) + _new=( ${_after:|_before} ) + + local fn force + for fn in $_new; do + [[ "$fn" == _* ]] && continue # internal helper + (( ${FLOW_INTENTIONAL_SHADOWS[(Ie)$fn]} )) && continue # deliberate shadow + force="FLOW_FORCE_DISPATCHER_${fn:u}" + [[ -n "${(P)force}" ]] && continue # explicit override + [[ -n "${commands[$fn]}" ]] || continue # no PATH binary + [[ -n "$FLOW_DEBUG" ]] && \ + print -ru2 -- "flow: dispatcher '$fn' shadows ${commands[$fn]} — skipped (set $force=1 or add to FLOW_INTENTIONAL_SHADOWS to keep)" + unfunction "$fn" + done + } + + _flow_load_dispatcher "$FLOW_PLUGIN_DIR/lib/dispatchers/"*.zsh(N) fi # ============================================================================ @@ -142,7 +184,7 @@ _flow_plugin_init # Export loaded marker export FLOW_PLUGIN_LOADED=1 -export FLOW_VERSION="7.8.1" +export FLOW_VERSION="7.9.0" # Register exit hook for plugin cleanup add-zsh-hook zshexit _flow_plugin_cleanup diff --git a/lib/dispatchers/obs.zsh b/lib/dispatchers/obs.zsh deleted file mode 100755 index 3f2db4e4b..000000000 --- a/lib/dispatchers/obs.zsh +++ /dev/null @@ -1,400 +0,0 @@ -#!/bin/zsh -# -# Obsidian CLI Ops (obs) -# ====================== -# CLI tool for managing Obsidian vaults with AI-powered graph analysis. -# -# Version: 3.0.0-dev (Proposal A - Pure Obsidian Manager) -# Author: Data-Wise -# Project: obsidian-cli-ops -# -# DEPENDENCIES: -# - python3 (with requirements.txt) -# - jq (for vault operations) -# -# CONFIGURATION: -# - Database: ~/.config/obs/obsidian_vaults.db -# - Last vault: ~/.config/obs/last_vault -# - iCloud default: ~/Library/Mobile Documents/iCloud~md~obsidian/Documents - -# --- Configuration --- -LAST_VAULT_FILE="$HOME/.config/obs/last_vault" -ICLOUD_OBSIDIAN="$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents" - -_ensure_config_dir() { - mkdir -p "$HOME/.config/obs" -} - -_save_last_vault() { - local vault_id=$1 - _ensure_config_dir - echo "$vault_id" > "$LAST_VAULT_FILE" - _log_verbose "Saved last vault: $vault_id" -} - -_get_last_vault() { - if [[ -f "$LAST_VAULT_FILE" ]]; then - cat "$LAST_VAULT_FILE" - fi -} - -# Defaults -VERBOSE=false -VERSION="3.0.0-dev" - -# --- Helper Functions --- - -_log() { - local type=$1 - local msg=$2 - - # Check if colors should be disabled - if [[ -n "$NO_COLOR" ]] || [[ ! -t 1 ]]; then - # No color output - case $type in - "INFO") echo "[INFO] $msg" ;; - "SUCCESS") echo "[OK] $msg" ;; - "WARN") echo "[WARN] $msg" ;; - "ERROR") echo "[ERROR] $msg" ;; - esac - else - # Colored output - case $type in - "INFO") echo "\033[0;34m[INFO]\033[0m $msg" ;; - "SUCCESS") echo "\033[0;32m[OK]\033[0m $msg" ;; - "WARN") echo "\033[0;33m[WARN]\033[0m $msg" ;; - "ERROR") echo "\033[0;31m[ERROR]\033[0m $msg" ;; - esac - fi -} - -_log_verbose() { - if [[ "$VERBOSE" == "true" ]]; then - if [[ -n "$NO_COLOR" ]] || [[ ! -t 1 ]]; then - echo "[VERBOSE] $1" - else - echo "\033[0;90m[VERBOSE]\033[0m $1" - fi - fi -} - -# --- Subcommands --- - -_obs_help() { - # Color fallbacks (in case core.zsh not loaded) - if [[ -z "$_C_BOLD" ]]; then - _C_BOLD='\033[1m' - _C_DIM='\033[2m' - _C_NC='\033[0m' - _C_GREEN='\033[32m' - _C_YELLOW='\033[33m' - _C_BLUE='\033[34m' - _C_MAGENTA='\033[35m' - _C_CYAN='\033[36m' - fi - - echo -e " -${_C_BOLD}╭─────────────────────────────────────────────╮${_C_NC} -${_C_BOLD}│ obs - Obsidian Vault Manager │${_C_NC} -${_C_BOLD}╰─────────────────────────────────────────────╯${_C_NC} - -${_C_GREEN}🔥 MOST COMMON${_C_NC} ${_C_DIM}(80% of daily use)${_C_NC}: - ${_C_CYAN}obs${_C_NC} List vaults - ${_C_CYAN}obs stats <vault>${_C_NC} Show vault statistics - ${_C_CYAN}obs discover <path>${_C_NC} Find vaults in directory - -${_C_YELLOW}💡 QUICK EXAMPLES${_C_NC}: - ${_C_DIM}\$${_C_NC} obs ${_C_DIM}# List all vaults${_C_NC} - ${_C_DIM}\$${_C_NC} obs stats research ${_C_DIM}# Stats for vault${_C_NC} - ${_C_DIM}\$${_C_NC} obs discover ~/Documents ${_C_DIM}# Find new vaults${_C_NC} - ${_C_DIM}\$${_C_NC} obs analyze research ${_C_DIM}# Graph analysis${_C_NC} - -${_C_BLUE}📋 VAULT COMMANDS${_C_NC}: - ${_C_CYAN}obs vaults${_C_NC} List all registered vaults - ${_C_CYAN}obs stats [vault]${_C_NC} Show vault statistics - ${_C_CYAN}obs discover <path>${_C_NC} Find vaults in directory - ${_C_CYAN}obs analyze <vault>${_C_NC} Analyze vault graph metrics - -${_C_BLUE}📋 AI FEATURES${_C_NC}: - ${_C_CYAN}obs ai status${_C_NC} Show AI provider status - ${_C_CYAN}obs ai setup${_C_NC} Interactive AI setup wizard - ${_C_CYAN}obs ai test${_C_NC} Test all AI providers - ${_C_CYAN}obs ai similar <n>${_C_NC} Find similar notes - ${_C_CYAN}obs ai analyze <n>${_C_NC} Analyze note with AI - ${_C_CYAN}obs ai duplicates${_C_NC} Find duplicate notes - -${_C_MAGENTA}💡 TIP${_C_NC}: Use ${_C_CYAN}obs stats <vault_id>${_C_NC} for detailed vault info - ${_C_DIM}Get vault IDs with: obs vaults${_C_NC} - -${_C_DIM}📚 See also:${_C_NC} - ${_C_CYAN}dot${_C_NC} - Dotfile management - ${_C_CYAN}mcp${_C_NC} - MCP server management -" -} - -# Legacy alias for backward compatibility -obs_help() { _obs_help "$@"; } - -obs_version() { - echo "obs (Obsidian CLI Ops) version $VERSION" - echo "" - echo "A command-line tool for managing Obsidian vaults" - echo "with AI-powered knowledge graph analysis." - echo "" - echo "Repository: https://github.com/Data-Wise/obsidian-cli-ops" - echo "Documentation: https://data-wise.github.io/obsidian-cli-ops/" -} - -# --- Legacy v1.x Commands Removed --- -# The following v1.x commands were removed in Phase 7.1 Part 3 (CLI consolidation): -# - obs_check() → dependency checking (low value) -# - obs_audit() → vault structure audit (OBS_ROOT required) -# - obs_sync() → configuration sync (OBS_ROOT required) -# - obs_install() → plugin installation (OBS_ROOT required) -# - obs_search() → plugin search (low usage) -# - obs_list() → vault listing (replaced by 'obs vaults') - -# --- Knowledge Graph Commands (v2.0) --- - -_get_python_cli() { - # Get path to Python CLI - # When obs.zsh is in src/, Python CLI is in src/python/ - local script_path="${(%):-%x}" # Path to current script - local script_dir="$(cd "$(dirname "$script_path")" && pwd)" - local python_cli="$script_dir/python/obs_cli.py" - - if [[ ! -f "$python_cli" ]]; then - _log "ERROR" "Python CLI not found at: $python_cli" >&2 - _log "ERROR" "Script dir: $script_dir" >&2 - return 1 - fi - - echo "$python_cli" -} - -obs_discover() { - local python_cli=$(_get_python_cli) || return 1 - local vault_path=${1:-.} # Default to current directory - - _log_verbose "Running vault discovery in: $vault_path" - - # Build command - local cmd=("$python_cli" "discover" "$vault_path") - - # Add verbose flag if enabled - if [[ "$VERBOSE" == "true" ]]; then - cmd+=(--verbose) - fi - - # Add --scan flag if requested - if [[ "$2" == "--scan" ]]; then - cmd+=(--scan) - fi - - /opt/homebrew/bin/python3 "${cmd[@]}" -} - -obs_analyze() { - local python_cli=$(_get_python_cli) || return 1 - local vault_id=$1 - - if [[ -z "$vault_id" ]]; then - _log "ERROR" "Vault ID required" - echo "Usage: obs analyze <vault_id>" - echo "" - echo "Get vault IDs with: obs vaults" - return 1 - fi - - _log_verbose "Analyzing vault: $vault_id" - - # Build command - local cmd=("$python_cli" "analyze" "$vault_id") - - # Add verbose flag if enabled - if [[ "$VERBOSE" == "true" ]]; then - cmd+=(--verbose) - fi - - /opt/homebrew/bin/python3 "${cmd[@]}" -} - -obs_vaults() { - local python_cli=$(_get_python_cli) || return 1 - - _log_verbose "Listing vaults in database" - - /opt/homebrew/bin/python3 "$python_cli" vaults -} - -obs_stats() { - local python_cli=$(_get_python_cli) || return 1 - local vault_id=$1 - - _log_verbose "Showing statistics" - - if [[ -n "$vault_id" ]]; then - /opt/homebrew/bin/python3 "$python_cli" stats --vault "$vault_id" - else - /opt/homebrew/bin/python3 "$python_cli" stats - fi -} - -# --- AI Commands (v2.0) --- - -obs_ai() { - local python_cli=$(_get_python_cli) || return 1 - local subcmd=$1 - shift - - case "$subcmd" in - status) - _log_verbose "Showing AI provider status" - /opt/homebrew/bin/python3 "$python_cli" "ai" "status" - ;; - - setup) - _log_verbose "Running AI setup wizard" - /opt/homebrew/bin/python3 "$python_cli" "ai" "setup" - ;; - - test) - _log_verbose "Testing AI providers" - local cmd=("$python_cli" "ai" "test") - - # Add --provider flag if specified - if [[ "$1" == "--provider" ]]; then - cmd+=(--provider "$2") - fi - - /opt/homebrew/bin/python3 "${cmd[@]}" - ;; - - similar) - local note_id=$1 - if [[ -z "$note_id" ]]; then - _log "ERROR" "Note ID required" - echo "Usage: obs ai similar <note_id>" - return 1 - fi - _log_verbose "Finding similar notes" - /opt/homebrew/bin/python3 "$python_cli" "ai" "similar" "$note_id" - ;; - - analyze) - local note_id=$1 - if [[ -z "$note_id" ]]; then - _log "ERROR" "Note ID required" - echo "Usage: obs ai analyze <note_id>" - return 1 - fi - _log_verbose "Analyzing note with AI" - /opt/homebrew/bin/python3 "$python_cli" "ai" "analyze" "$note_id" - ;; - - duplicates) - local vault_id=$1 - if [[ -z "$vault_id" ]]; then - _log "ERROR" "Vault ID required" - echo "Usage: obs ai duplicates <vault_id>" - return 1 - fi - _log_verbose "Finding duplicate notes" - /opt/homebrew/bin/python3 "$python_cli" "ai" "duplicates" "$vault_id" - ;; - - *) - _log "ERROR" "Unknown ai subcommand: $subcmd" - echo "Usage: obs ai <subcommand>" - echo "" - echo "Subcommands:" - echo " status - Show AI provider status" - echo " setup - Interactive AI setup wizard" - echo " test - Test all AI providers" - echo " test --provider X - Test specific provider" - echo " similar <note_id> - Find similar notes" - echo " analyze <note_id> - Analyze note with AI" - echo " duplicates <vault> - Find duplicate notes" - return 1 - ;; - esac -} - -# --- Option D Commands Removed --- -# The following commands were removed in Phase 7.1 Part 3 (CLI consolidation): -# - obs_switch() → replaced by 'obs' (default command shows vault list) -# - obs_open() → replaced by 'obs stats <vault_id>' -# - obs_manage() → functionality split into 'obs discover' and 'obs stats' -# - obs_graph() → replaced by 'obs analyze <vault_id>' - -# --- Dispatch --- -obs() { - # Handle help flags early (before global flag parser eats them) - if [[ "$1" == "help" || "$1" == "--help" || "$1" == "-h" ]]; then - _obs_help - return 0 - fi - - # Parse global flags first - while [[ "$1" == --* ]]; do - case "$1" in - --verbose|-v) - VERBOSE=true - _log_verbose "Verbose mode enabled" - shift - ;; - *) - shift - ;; - esac - done - - local cmd=$1 - if [[ -n "$cmd" ]]; then - shift - fi - - # Default behavior (no command): Show vault list - if [[ -z "$cmd" ]]; then - obs_vaults - return $? - fi - - # Route to command handlers - case "$cmd" in - "help"|"--help"|"-h") - _obs_help - ;; - "version") - obs_version - ;; - "discover") - obs_discover "$@" - ;; - "analyze") - obs_analyze "$@" - ;; - "vaults") - obs_vaults "$@" - ;; - "stats") - obs_stats "$@" - ;; - "ai") - obs_ai "$@" - ;; - *) - _log "ERROR" "Unknown command: $cmd" - echo "" - _obs_help - return 1 - ;; - esac -} - -# --- Execution Guard --- -# Execute the main function if the script is run directly. -# Check zsh_eval_context for Zsh and BASH_SOURCE for Bash. -if [[ "${zsh_eval_context[-1]}" == "toplevel" || "${BASH_SOURCE[0]}" == "${0}" ]]; then - obs "$@" -fi diff --git a/lib/help-browser.zsh b/lib/help-browser.zsh index 23d26c24a..154d80490 100644 --- a/lib/help-browser.zsh +++ b/lib/help-browser.zsh @@ -23,7 +23,7 @@ # _flow_show_help_preview "work" # Shows work command help # # Notes: -# - Dispatchers (g, cc, wt, mcp, r, qu, obs, tm, dots, sec, tok, teach, prompt, v, em, at) use: cmd help +# - Dispatchers (g, cc, wt, mcp, r, qu, tm, dots, sec, tok, teach, prompt, v, em, at) use: cmd help # - Regular commands try: cmd --help, then cmd help # - Returns helpful message if command not found/loaded # - Designed for use in fzf --preview parameter @@ -33,7 +33,7 @@ _flow_show_help_preview() { # Command is available in current shell (plugin loaded) if type "${cmd}" >/dev/null 2>&1; then - if [[ "$cmd" =~ ^(g|cc|wt|mcp|r|qu|obs|tm|dots|sec|tok|teach|prompt|v|em|at)$ ]]; then + if [[ "$cmd" =~ ^(g|cc|wt|mcp|r|qu|tm|dots|sec|tok|teach|prompt|v|em|at)$ ]]; then # Dispatcher - call with help $cmd help 2>/dev/null || echo "Help not available for $cmd" else @@ -182,7 +182,7 @@ _flow_help_browser() { echo "" # Show full help - if [[ "$cmd" =~ ^(g|cc|wt|mcp|r|qu|obs|tm|dots|sec|tok|teach|prompt|v|em|at)$ ]]; then + if [[ "$cmd" =~ ^(g|cc|wt|mcp|r|qu|tm|dots|sec|tok|teach|prompt|v|em|at)$ ]]; then $cmd help else $cmd --help 2>/dev/null || $cmd help 2>/dev/null || { diff --git a/lib/help-compliance.zsh b/lib/help-compliance.zsh index fc035f299..f63241dca 100644 --- a/lib/help-compliance.zsh +++ b/lib/help-compliance.zsh @@ -17,8 +17,8 @@ # 8. Color codes (_C_ or \033[) # 9. Help function naming (_<cmd>_help) -# All 15 dispatchers to check -typeset -ga _FLOW_HELP_DISPATCHERS=(g r mcp qu wt v cc tm teach dots sec tok obs prompt em) +# All 14 dispatchers to check +typeset -ga _FLOW_HELP_DISPATCHERS=(g r mcp qu wt v cc tm teach dots sec tok prompt em) # Map dispatcher names to their help function names typeset -gA _FLOW_HELP_FUNCTIONS=( @@ -34,7 +34,6 @@ typeset -gA _FLOW_HELP_FUNCTIONS=( [dots]="_dots_help" [sec]="_sec_help" [tok]="_tok_help" - [obs]="_obs_help" [prompt]="_prompt_help" [em]="_em_help" ) @@ -160,7 +159,7 @@ _flow_help_compliance_check() { fi } -# Check all 15 dispatchers. +# Check all 14 dispatchers. # Returns: 0 if all pass, 1 if any fail _flow_help_compliance_check_all() { local verbose="${1:-false}" diff --git a/man/man1/at.1 b/man/man1/at.1 index 3de55d163..aba92204e 100644 --- a/man/man1/at.1 +++ b/man/man1/at.1 @@ -1,6 +1,6 @@ .\" Man page for at dispatcher (Atlas bridge) .\" Generated: June 2026 -.TH AT 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH AT 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME at \- Atlas project intelligence bridge (optional integration) .SH SYNOPSIS diff --git a/man/man1/cc.1 b/man/man1/cc.1 index 0ba2d6425..c215fed99 100644 --- a/man/man1/cc.1 +++ b/man/man1/cc.1 @@ -1,6 +1,6 @@ .\" Man page for cc dispatcher (Claude Code launcher) .\" Generated: June 2026 -.TH CC 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH CC 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME cc \- Claude Code launcher and dispatcher .SH SYNOPSIS diff --git a/man/man1/dots.1 b/man/man1/dots.1 index 610c3f6e5..3e5ed2c39 100644 --- a/man/man1/dots.1 +++ b/man/man1/dots.1 @@ -1,6 +1,6 @@ .\" Man page for dots dispatcher (Dotfile Management) .\" Generated: June 2026 -.TH DOTS 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH DOTS 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME dots \- Dotfile management dispatcher (chezmoi wrapper) .SH SYNOPSIS diff --git a/man/man1/em.1 b/man/man1/em.1 index 80edec863..c8308a6a0 100644 --- a/man/man1/em.1 +++ b/man/man1/em.1 @@ -1,6 +1,6 @@ .\" Man page for em dispatcher (Email / himalaya) .\" Generated: June 2026 -.TH EM 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH EM 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME em \- Email dispatcher (himalaya wrapper) .SH SYNOPSIS diff --git a/man/man1/flow.1 b/man/man1/flow.1 index bd08961ae..7e1ff9f0b 100644 --- a/man/man1/flow.1 +++ b/man/man1/flow.1 @@ -1,6 +1,6 @@ .\" Man page for flow command .\" Updated: June 2026 -.TH FLOW 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH FLOW 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME flow \- ADHD-friendly workflow CLI for developers .SH SYNOPSIS @@ -236,7 +236,7 @@ dash = flow dash .fi .RE .SH SMART DISPATCHERS -In addition to flow commands, these 15 dispatchers plus the at bridge are available: +In addition to flow commands, these 14 dispatchers plus the at bridge are available: .TP .B g \fIcmd\fR Git workflows: status, push, commit, branch, feature workflow, promote, release. @@ -244,9 +244,6 @@ Git workflows: status, push, commit, branch, feature workflow, promote, release. .B mcp \fIcmd\fR MCP server management: list, cd, test, edit, pick, status, readme. .TP -.B obs \fIcmd\fR -Obsidian vault management: stats, discover, vaults, analyze, ai subcommands. -.TP .B qu \fIcmd\fR Quarto publishing: render, preview, check, clean, publish, format-specific renders, project creation. .TP @@ -295,7 +292,6 @@ Use \fIdispatcher\fR\fB help\fR for details (e.g., .BR r (1), .BR qu (1), .BR mcp (1), -.BR obs (1), .BR cc (1), .BR tm (1), .BR wt (1), diff --git a/man/man1/g.1 b/man/man1/g.1 index c52e92607..34d7e8fe7 100644 --- a/man/man1/g.1 +++ b/man/man1/g.1 @@ -1,6 +1,6 @@ .\" Man page for g dispatcher (Git workflows) .\" Updated: June 2026 -.TH G 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH G 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME g \- Git commands dispatcher .SH SYNOPSIS @@ -198,7 +198,6 @@ g cob feature/new-thing .BR r (1), .BR qu (1), .BR mcp (1), -.BR obs (1), .BR wt (1), .BR git (1) .SH AUTHOR diff --git a/man/man1/mcp.1 b/man/man1/mcp.1 index 240e4c28b..2079ad676 100644 --- a/man/man1/mcp.1 +++ b/man/man1/mcp.1 @@ -1,6 +1,6 @@ .\" Man page for mcp dispatcher (MCP server management) .\" Updated: June 2026 -.TH MCP 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH MCP 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME mcp \- MCP server management dispatcher .SH SYNOPSIS @@ -112,7 +112,6 @@ Shortcut for 'mcp pick' (interactive picker). .BR flow (1), .BR g (1), .BR r (1), -.BR qu (1), -.BR obs (1) +.BR qu (1) .SH AUTHOR DT diff --git a/man/man1/obs.1 b/man/man1/obs.1 deleted file mode 100644 index 816cb0fc7..000000000 --- a/man/man1/obs.1 +++ /dev/null @@ -1,125 +0,0 @@ -.\" Man page for obs dispatcher (Obsidian CLI) -.\" Updated: June 2026 -.TH OBS 1 "June 2026" "flow-cli 7.8.1" "User Commands" -.SH NAME -obs \- Obsidian CLI operations dispatcher -.SH SYNOPSIS -.B obs -[\fB--verbose\fR] [\fIcommand\fR] [\fIarguments\fR] -.SH DESCRIPTION -.B obs -is a CLI tool for managing Obsidian vaults with AI-powered graph analysis. -It provides commands for vault discovery, statistics, and AI-assisted -note analysis. -.PP -When called without arguments, it lists all registered vaults. -.SH OPTIONS -.TP -.B --verbose\fR, \fB-v -Enable verbose output. -.SH COMMANDS -.SS Primary Commands -.TP -.B (none) -List all registered vaults. -.TP -.B stats \fR[\fIvault\fR] -Show vault statistics. If vault specified, shows details for that vault. -.TP -.B discover \fIpath\fR -Find vaults in directory. Use --scan to deep scan. -.TP -.B vaults -List all vaults in database. -.SS Graph Analysis -.TP -.B analyze \fIvault_id\fR -Analyze vault graph metrics (links, orphans, clusters). -.SS AI Features -.TP -.B ai status -Show AI provider status. -.TP -.B ai setup -Interactive AI setup wizard. -.TP -.B ai test \fR[\fB--provider \fIname\fR] -Test AI providers. Optionally specify provider. -.TP -.B ai similar \fInote_id\fR -Find notes similar to specified note. -.TP -.B ai analyze \fInote_id\fR -Analyze note content with AI. -.TP -.B ai duplicates \fIvault_id\fR -Find duplicate notes in vault. -.SS Utilities -.TP -.B help \fR[\fB--all\fR] -Show help. Use --all for extended help. -.TP -.B version -Show version information. -.SH CONFIGURATION -.TP -.B Database -~/.config/obs/obsidian_vaults.db -.TP -.B Last vault -~/.config/obs/last_vault -.TP -.B iCloud default -~/Library/Mobile Documents/iCloud~md~obsidian/Documents -.SH DEPENDENCIES -.TP -.B Required -python3, jq -.TP -.B Python packages -See requirements.txt in obsidian-cli-ops project. -.SH EXAMPLES -List all vaults: -.RS -.nf -obs -.fi -.RE -.PP -Show vault statistics: -.RS -.nf -obs stats my-notes -.fi -.RE -.PP -Discover vaults in iCloud: -.RS -.nf -obs discover ~/Library/Mobile\\ Documents/iCloud~md~obsidian/Documents -.fi -.RE -.PP -Analyze vault graph: -.RS -.nf -obs analyze my-notes -.fi -.RE -.PP -Find similar notes: -.RS -.nf -obs ai similar "2024-01-15-meeting-notes" -.fi -.RE -.SH SEE ALSO -.BR flow (1), -.BR g (1), -.BR r (1), -.BR qu (1), -.BR mcp (1) -.SH WEBSITE -https://data-wise.github.io/obsidian-cli-ops/ -.SH AUTHOR -DT diff --git a/man/man1/prompt.1 b/man/man1/prompt.1 index 78755756a..f306a0da1 100644 --- a/man/man1/prompt.1 +++ b/man/man1/prompt.1 @@ -1,6 +1,6 @@ .\" Man page for prompt dispatcher (Prompt Engine Switcher) .\" Generated: June 2026 -.TH PROMPT 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH PROMPT 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME prompt \- Prompt engine switcher .SH SYNOPSIS diff --git a/man/man1/qu.1 b/man/man1/qu.1 index 9c20ac9d9..72fc757f4 100644 --- a/man/man1/qu.1 +++ b/man/man1/qu.1 @@ -1,6 +1,6 @@ .\" Man page for qu dispatcher (Quarto publishing) .\" Updated: June 2026 -.TH QU 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH QU 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME qu \- Quarto publishing dispatcher .SH SYNOPSIS @@ -114,7 +114,6 @@ qu commit "Update chapter 2" .BR g (1), .BR r (1), .BR mcp (1), -.BR obs (1), .BR quarto (1) .SH AUTHOR DT diff --git a/man/man1/r.1 b/man/man1/r.1 index 1b379cb1b..b4e21ce56 100644 --- a/man/man1/r.1 +++ b/man/man1/r.1 @@ -1,6 +1,6 @@ .\" Man page for r dispatcher (R package development) .\" Updated: June 2026 -.TH R 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH R 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME r \- R package development dispatcher .SH SYNOPSIS @@ -139,7 +139,6 @@ r cran .BR g (1), .BR qu (1), .BR mcp (1), -.BR obs (1), .BR R (1) .SH AUTHOR DT diff --git a/man/man1/sec.1 b/man/man1/sec.1 index d5c58a89f..7da52330d 100644 --- a/man/man1/sec.1 +++ b/man/man1/sec.1 @@ -1,6 +1,6 @@ .\" Man page for sec dispatcher (Secret Management) .\" Generated: June 2026 -.TH SEC 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH SEC 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME sec \- Secret management dispatcher (Keychain and Bitwarden) .SH SYNOPSIS diff --git a/man/man1/teach.1 b/man/man1/teach.1 index ce44576d6..01d94e0a6 100644 --- a/man/man1/teach.1 +++ b/man/man1/teach.1 @@ -1,6 +1,6 @@ .\" Man page for teach dispatcher (Teaching Workflow) .\" Generated: June 2026 -.TH TEACH 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH TEACH 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME teach \- Teaching workflow dispatcher (Scholar integration) .SH SYNOPSIS diff --git a/man/man1/tm.1 b/man/man1/tm.1 index 3915e1409..49efcc372 100644 --- a/man/man1/tm.1 +++ b/man/man1/tm.1 @@ -1,6 +1,6 @@ .\" Man page for tm dispatcher (Terminal Manager) .\" Generated: June 2026 -.TH TM 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH TM 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME tm \- Terminal manager dispatcher .SH SYNOPSIS diff --git a/man/man1/tok.1 b/man/man1/tok.1 index 5ad133c27..c98e5d276 100644 --- a/man/man1/tok.1 +++ b/man/man1/tok.1 @@ -1,6 +1,6 @@ .\" Man page for tok dispatcher (Token Management) .\" Generated: June 2026 -.TH TOK 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH TOK 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME tok \- Token lifecycle management dispatcher .SH SYNOPSIS diff --git a/man/man1/v.1 b/man/man1/v.1 index 1fc9c7616..76087022d 100644 --- a/man/man1/v.1 +++ b/man/man1/v.1 @@ -1,6 +1,6 @@ .\" Man page for v dispatcher (Vibe / Workflow Automation) .\" Generated: June 2026 -.TH V 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH V 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME v \- Workflow automation dispatcher (vibe coding mode) .SH SYNOPSIS diff --git a/man/man1/wt.1 b/man/man1/wt.1 index 8d262b7d8..4762a6b8a 100644 --- a/man/man1/wt.1 +++ b/man/man1/wt.1 @@ -1,6 +1,6 @@ .\" Man page for wt dispatcher (Git Worktree Management) .\" Generated: June 2026 -.TH WT 1 "June 2026" "flow-cli 7.8.1" "User Commands" +.TH WT 1 "June 2026" "flow-cli 7.9.0" "User Commands" .SH NAME wt \- Git worktree management dispatcher .SH SYNOPSIS diff --git a/mkdocs.yml b/mkdocs.yml index 7bd543f8e..85aa9deb4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -143,7 +143,6 @@ nav: - 38. R Packages: tutorials/38-r-dispatcher.md - 39. Quarto Publishing: tutorials/39-qu-dispatcher.md - 40. Workflow (v/vibe): tutorials/40-v-dispatcher.md - - 41. Obsidian Vaults: tutorials/41-obs-dispatcher.md - 42. Git Shortcuts (g): tutorials/42-g-dispatcher.md - ADHD & Productivity: - 43. ADHD Daily Routine: tutorials/43-adhd-daily-routine.md diff --git a/package.json b/package.json index d5960226a..5e5ec61e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flow-cli", - "version": "7.8.1", + "version": "7.9.0", "description": "ADHD-optimized ZSH workflow plugin", "private": true, "scripts": { diff --git a/tests/automated-plugin-dogfood.zsh b/tests/automated-plugin-dogfood.zsh index eb7068798..2f9290753 100644 --- a/tests/automated-plugin-dogfood.zsh +++ b/tests/automated-plugin-dogfood.zsh @@ -2,7 +2,7 @@ # automated-plugin-dogfood.zsh - Full plugin load dogfooding test # # Sources flow.plugin.zsh and verifies everything loaded correctly: -# - All 15 dispatchers are defined +# - All 14 dispatchers are defined # - Core commands exist # - Help functions work for each dispatcher # - No load errors @@ -96,12 +96,12 @@ run_test "No stderr during plugin load" ' echo "" # ============================================================================ -# SECTION 2: All 15 dispatchers defined +# SECTION 2: All 14 dispatchers defined # ============================================================================ echo "${CYAN}--- Section 2: Dispatcher Functions ---${RESET}" -dispatchers=(g mcp obs qu r cc tm wt dots sec tok teach prompt v em) +dispatchers=(g mcp qu r cc tm wt dots sec tok teach prompt v em) for disp in "${dispatchers[@]}"; do run_test "Dispatcher '$disp' is a function" " @@ -142,7 +142,6 @@ typeset -A help_fns help_fns=( g _g_help mcp _mcp_help - obs _obs_help qu _qu_help r _r_help cc _cc_help diff --git a/tests/cli/automated-tests.sh b/tests/cli/automated-tests.sh index 9eca05815..2463d73d9 100755 --- a/tests/cli/automated-tests.sh +++ b/tests/cli/automated-tests.sh @@ -291,7 +291,7 @@ fi log_section "Dispatchers" # Test: Dispatcher files exist -for dispatcher in g mcp obs qu r cc; do +for dispatcher in g mcp qu r cc; do # All dispatchers in lib/dispatchers/ if [[ -f "$FLOW_CLI_DIR/lib/dispatchers/${dispatcher}-dispatcher.zsh" ]] || \ [[ -f "$FLOW_CLI_DIR/lib/dispatchers/${dispatcher}.zsh" ]]; then @@ -302,7 +302,7 @@ for dispatcher in g mcp obs qu r cc; do done # Test: Dispatcher functions defined -for dispatcher in g mcp obs qu r cc; do +for dispatcher in g mcp qu r cc; do if zsh -c "source '$FLOW_CLI_DIR/flow.plugin.zsh' && typeset -f $dispatcher >/dev/null" 2>/dev/null; then log_pass "$dispatcher() function is defined" else diff --git a/tests/dogfood-atlas-bridge.zsh b/tests/dogfood-atlas-bridge.zsh index e5d31d025..5fffbca4b 100644 --- a/tests/dogfood-atlas-bridge.zsh +++ b/tests/dogfood-atlas-bridge.zsh @@ -171,12 +171,12 @@ run_test "help-browser commands list includes at entry" " grep -q '\"at:' \"\$PROJECT_ROOT/lib/help-browser.zsh\" || return 1 " -run_test "help-browser regex includes all 15 dispatchers + at" ' +run_test "help-browser regex includes all 14 dispatchers + at" ' local regex_line regex_line=$(grep "^\^(" "$PROJECT_ROOT/lib/help-browser.zsh" 2>/dev/null | head -1) [[ -z "$regex_line" ]] && regex_line=$(grep "g|cc|wt" "$PROJECT_ROOT/lib/help-browser.zsh" 2>/dev/null | head -1) - for d in g cc wt mcp r qu obs tm dots sec tok teach prompt v em at; do + for d in g cc wt mcp r qu tm dots sec tok teach prompt v em at; do [[ "$regex_line" == *"$d"* ]] || { echo "Missing $d in regex"; return 1; } done ' @@ -247,9 +247,9 @@ run_test "Plugin loads without stderr when Atlas disabled" ' [[ -z "$errs" ]] || { echo "Stderr: $errs"; return 1; } ' -run_test "at() coexists with all 15 dispatchers" ' +run_test "at() coexists with all 14 dispatchers" ' local all_ok=true - for d in g mcp obs qu r cc tm wt dots sec tok teach prompt v em; do + for d in g mcp qu r cc tm wt dots sec tok teach prompt v em; do typeset -f "$d" >/dev/null 2>&1 || { echo "Missing: $d"; all_ok=false; } done typeset -f at >/dev/null 2>&1 || { echo "Missing: at"; all_ok=false; } diff --git a/tests/dogfood-scholar-config-sync.zsh b/tests/dogfood-scholar-config-sync.zsh index 7c1ac0832..d6198530e 100644 --- a/tests/dogfood-scholar-config-sync.zsh +++ b/tests/dogfood-scholar-config-sync.zsh @@ -198,10 +198,15 @@ echo "${CYAN}── Documentation ──${RESET}" # DOCUMENTATION CHECKS # ============================================================================ +# Accept either the per-command form (`teach solution`) or the condensed +# subcommand-list form (`..., solution, sync, validate-r, ...`). CLAUDE.md was +# optimized to the condensed list in a03916ba ("move teach/dispatcher detail to +# pointers"); the subcommands are still documented, just not as two-word literals. +# Boundaries ([(,] before, [,)] after) avoid matching the `--sync` deploy flag. run_test "CLAUDE.md lists new subcommands" ' - grep -q "teach solution" "$PROJECT_ROOT/CLAUDE.md" && - grep -q "teach sync" "$PROJECT_ROOT/CLAUDE.md" && - grep -q "teach validate-r" "$PROJECT_ROOT/CLAUDE.md" + grep -Eq "teach solution|[(,] ?solution[,)]" "$PROJECT_ROOT/CLAUDE.md" && + grep -Eq "teach sync|[(,] ?sync[,)]" "$PROJECT_ROOT/CLAUDE.md" && + grep -Eq "teach validate-r|[(,] ?validate-r[,)]" "$PROJECT_ROOT/CLAUDE.md" ' run_test "QUICK-REFERENCE includes config commands" ' diff --git a/tests/run-all.sh b/tests/run-all.sh index 7d09f1046..4ce503140 100755 --- a/tests/run-all.sh +++ b/tests/run-all.sh @@ -61,7 +61,7 @@ run_test ./tests/test-wt-dispatcher.zsh run_test ./tests/test-r-dispatcher.zsh run_test ./tests/test-qu-dispatcher.zsh run_test ./tests/test-mcp-dispatcher.zsh -run_test ./tests/test-obs-dispatcher.zsh +run_test ./tests/test-dispatcher-binary-precedence.zsh run_test ./tests/test-dot-chezmoi-safety.zsh run_test ./tests/test-em-dispatcher.zsh run_test ./tests/test-em-prompt-flag.zsh diff --git a/tests/test-dispatcher-binary-precedence.zsh b/tests/test-dispatcher-binary-precedence.zsh new file mode 100644 index 000000000..9ec8d7c76 --- /dev/null +++ b/tests/test-dispatcher-binary-precedence.zsh @@ -0,0 +1,168 @@ +#!/usr/bin/env zsh +# test-dispatcher-binary-precedence.zsh +# ────────────────────────────────────────────────────────────────────────────── +# Regression guard for the B3 binary-precedence guard in flow.plugin.zsh. +# +# Invariant: when a dispatcher defines a command function whose name also +# exists as an external binary on $PATH, the loader DROPS the function so the +# binary wins — UNLESS the command is an intentional shadow (listed in +# FLOW_INTENTIONAL_SHADOWS, e.g. cc/r/mcp) or force-kept via +# FLOW_FORCE_DISPATCHER_<NAME>=1. `_`-prefixed helpers are never touched. +# +# This is the general fix behind the `obs` shadowing bug: flow-cli's broken +# obs() dispatcher used to mask the real Homebrew obs binary. obs is now +# deleted (Phase 1); this guard stops any FUTURE dispatcher from re-shadowing +# a working binary by accident. +# +# Usage: zsh tests/test-dispatcher-binary-precedence.zsh +# ────────────────────────────────────────────────────────────────────────────── + +SCRIPT_DIR="${0:A:h}" +PROJECT_ROOT="${SCRIPT_DIR:h}" + +source "$SCRIPT_DIR/test-framework.zsh" + +# ── Fixtures ───────────────────────────────────────────────────────────────── +TMPROOT=$(mktemp -d) +TMPBIN="$TMPROOT/bin" +mkdir -p "$TMPBIN" + +# A stub external binary the test dispatchers will try to shadow. +print -r -- '#!/bin/sh' > "$TMPBIN/flowfaketool" +print -r -- 'echo stub-binary' >> "$TMPBIN/flowfaketool" +chmod +x "$TMPBIN/flowfaketool" + +# Throwaway dispatcher files (one public fn each, plus a helper case). +print -r -- 'flowfaketool() { echo from-dispatcher; }' > "$TMPROOT/collide.zsh" +print -r -- 'flownobinaryxyz() { echo ok; }' > "$TMPROOT/nobin.zsh" +{ + print -r -- 'flowfaketool() { echo cmd; }' + print -r -- '_flowfaketool_helper() { echo helper; }' +} > "$TMPROOT/both.zsh" + +cleanup() { rm -rf "$TMPROOT"; } + +# ── Load the plugin (defines _flow_load_dispatcher + FLOW_INTENTIONAL_SHADOWS, +# and loads the real dispatchers for the "don't break the user" checks). ──── +export FLOW_QUIET=1 +source "$PROJECT_ROOT/flow.plugin.zsh" 2>/dev/null + +if ! typeset -f _flow_load_dispatcher >/dev/null 2>&1; then + echo "${RED}ERROR: _flow_load_dispatcher not defined after sourcing plugin${RESET}" + cleanup + exit 1 +fi + +# Run the guard on a file in an isolated subshell with the stub on $PATH, then +# print how the named function resolves (whence -w => "<name>: command|function"). +# $3 is extra setup eval'd inside the subshell (allowlist/force tweaks). +_run_guard() { + local file="$1" fn="$2" extra="$3" + ( + PATH="$TMPBIN:$PATH" + rehash + eval "$extra" + _flow_load_dispatcher "$file" + whence -w "$fn" + ) +} + +# ── Tests ──────────────────────────────────────────────────────────────────── + +test_case "shadowing dispatcher is dropped (binary wins)" +out=$(_run_guard "$TMPROOT/collide.zsh" flowfaketool "") +assert_contains "$out" "flowfaketool: command" "expected fn dropped -> resolves to binary" +test_case_end + +test_case "FLOW_INTENTIONAL_SHADOWS keeps a deliberate shadow" +out=$(_run_guard "$TMPROOT/collide.zsh" flowfaketool "FLOW_INTENTIONAL_SHADOWS+=(flowfaketool)") +assert_contains "$out" "flowfaketool: function" "expected allowlisted fn kept" +test_case_end + +test_case "FLOW_FORCE_DISPATCHER_<NAME>=1 keeps the function" +out=$(_run_guard "$TMPROOT/collide.zsh" flowfaketool "export FLOW_FORCE_DISPATCHER_FLOWFAKETOOL=1") +assert_contains "$out" "flowfaketool: function" "expected forced fn kept" +test_case_end + +test_case "non-colliding dispatcher loads normally" +out=$(_run_guard "$TMPROOT/nobin.zsh" flownobinaryxyz "") +assert_contains "$out" "flownobinaryxyz: function" "expected non-colliding fn kept" +test_case_end + +# A file that defines BOTH a colliding command and a helper: command dropped, +# helper preserved (the guard ignores `_`-prefixed names). +out=$( + PATH="$TMPBIN:$PATH"; rehash + _flow_load_dispatcher "$TMPROOT/both.zsh" + print -r -- "CMD=$(whence -w flowfaketool) HELP=$(whence -w _flowfaketool_helper)" +) +test_case "colliding command in a multi-fn file is dropped" +assert_contains "$out" "CMD=flowfaketool: command" "command should be dropped" +test_case_end +test_case "internal _helper in the same file is preserved" +assert_contains "$out" "HELP=_flowfaketool_helper: function" "helper should survive" +test_case_end + +# Don't break the user: intentional shadows survive a real plugin load even +# though r/mcp/cc all have PATH binaries on dev machines. +for d in r mcp cc; do + test_case "intentional shadow '$d' survives plugin load" + assert_function_exists "$d" + test_case_end +done + +# Non-colliding real dispatchers still load. +for d in g qu em teach tok dots; do + test_case "dispatcher '$d' loads" + assert_function_exists "$d" + test_case_end +done + +# Regression: the obs dispatcher is gone, so obs must NOT be a function. +test_case "obs is not a function (shadowing bug fixed)" +if typeset -f obs >/dev/null 2>&1; then + test_fail "obs() is still defined — it should resolve to the binary/PATH" +else + test_pass +fi + +# Footgun caveat (documented in CLAUDE.md): FLOW_INTENTIONAL_SHADOWS=() is +# "set but empty" (zsh ${+arr} is 1 for an empty array), so the (r mcp cc) +# default is NOT applied and a normally protected shadow like `cc` (vs +# /usr/bin/cc) gets dropped. This must run in a genuinely fresh shell: the +# guard only acts on functions NEW to the current source pass, so re-sourcing +# in this already-loaded test shell would be a no-op. Hence `zsh -f`. +# Needs a real `cc` binary to observe; skipped otherwise. +test_case "empty FLOW_INTENTIONAL_SHADOWS overrides the default (cc dropped)" +if [[ -z "${commands[cc]}" ]]; then + test_skip "no cc binary on PATH" +else + out=$(FLOW_TEST_ROOT="$PROJECT_ROOT" zsh -fc ' + export FLOW_QUIET=1 + typeset -ga FLOW_INTENTIONAL_SHADOWS=() + source "$FLOW_TEST_ROOT/flow.plugin.zsh" 2>/dev/null + whence -w cc + ') + assert_contains "$out" "cc: command" "cc should be dropped when the allowlist is explicitly emptied" + test_case_end +fi + +# Counterpart: with the var UNSET, the default (r mcp cc) IS applied and cc +# survives — proving the gate, not just the guard. +test_case "unset FLOW_INTENTIONAL_SHADOWS applies the (r mcp cc) default (cc kept)" +if [[ -z "${commands[cc]}" ]]; then + test_skip "no cc binary on PATH" +else + out=$(FLOW_TEST_ROOT="$PROJECT_ROOT" zsh -fc ' + export FLOW_QUIET=1 + unset FLOW_INTENTIONAL_SHADOWS + source "$FLOW_TEST_ROOT/flow.plugin.zsh" 2>/dev/null + whence -w cc + ') + assert_contains "$out" "cc: function" "cc should be kept when the allowlist defaults apply" + test_case_end +fi + +cleanup +print_summary +exit $? diff --git a/tests/test-help-browser-preview.zsh b/tests/test-help-browser-preview.zsh index f487ca2e8..39690b646 100755 --- a/tests/test-help-browser-preview.zsh +++ b/tests/test-help-browser-preview.zsh @@ -52,8 +52,8 @@ test_preview_dispatcher() { } test_preview_all_dispatchers() { - echo -n "Test: Preview works for all dispatchers (g,cc,wt,mcp,r,qu,obs,tm)... " - local dispatchers=(g cc wt mcp r qu obs tm) + echo -n "Test: Preview works for all dispatchers (g,cc,wt,mcp,r,qu,tm)... " + local dispatchers=(g cc wt mcp r qu tm) local failed_dispatchers=() for dispatcher in "${dispatchers[@]}"; do diff --git a/tests/test-help-compliance-dogfood.zsh b/tests/test-help-compliance-dogfood.zsh index fcd6fc3ed..c55b48dfb 100755 --- a/tests/test-help-compliance-dogfood.zsh +++ b/tests/test-help-compliance-dogfood.zsh @@ -160,8 +160,8 @@ _test_individual_rules() { echo "" } -# Test all 15 dispatchers individually -for d in g r mcp qu wt v cc tm teach dots sec tok obs prompt em; do +# Test all 14 dispatchers individually +for d in g r mcp qu wt v cc tm teach dots sec tok prompt em; do _test_individual_rules "$d" done @@ -188,26 +188,12 @@ _test_help_invocation() { } # Test all three invocation forms for each dispatcher -# Note: obs is excluded because obs() may be overridden by external -# obsidian-cli-ops (symlinked via zsh/functions/obs.zsh). We test _obs_help -# directly via the compliance library instead. for cmd in g r mcp qu wt v cc tm prompt; do for form in help --help -h; do _test_help_invocation "$cmd" "$form" done done -# Test obs via _obs_help directly (external override-safe) -for form in help --help -h; do - local _obs_out - _obs_out="$(_obs_help 2>&1)" - if [[ "$_obs_out" == *"╭─"* ]]; then - assert_pass "obs $form → produces help output (via _obs_help)" - else - assert_fail "obs $form → produces help output (via _obs_help)" "no box header found" - fi -done - # teach, dots, sec, tok use the same forms but test explicitly for form in help --help -h; do _test_help_invocation "teach" "$form" @@ -260,7 +246,7 @@ _test_content_quality() { if [[ -n "$see_also_block" ]]; then # At least one cross-reference to another command local has_ref=false - for ref_cmd in g r mcp qu wt v cc tm teach dots sec tok obs prompt work dash pick flow; do + for ref_cmd in g r mcp qu wt v cc tm teach dots sec tok prompt work dash pick flow; do if echo "$see_also_block" | grep -q "$ref_cmd"; then has_ref=true break @@ -285,7 +271,7 @@ _test_content_quality() { echo "" } -for d in g r mcp qu wt v cc tm teach dots sec tok obs prompt; do +for d in g r mcp qu wt v cc tm teach dots sec tok prompt; do _test_content_quality "$d" done @@ -320,7 +306,7 @@ _test_color_fallback() { } # Only test the 7 dispatchers we fixed (they all define their own fallbacks) -for d in obs prompt dots sec tok cc tm teach v; do +for d in prompt dots sec tok cc tm teach v; do _test_color_fallback "$d" done echo "" @@ -349,7 +335,6 @@ _test_box_format() { local src_file case "$dispatcher" in g) src_file="$FLOW_DIR/lib/dispatchers/g-dispatcher.zsh" ;; - obs) src_file="$FLOW_DIR/lib/dispatchers/obs.zsh" ;; teach) src_file="$FLOW_DIR/lib/dispatchers/teach-dispatcher.zsh" ;; prompt) src_file="$FLOW_DIR/lib/dispatchers/prompt-dispatcher.zsh" ;; *) src_file="$FLOW_DIR/lib/dispatchers/${dispatcher}-dispatcher.zsh" ;; @@ -367,7 +352,7 @@ _test_box_format() { fi } -for d in g r mcp qu wt v cc tm teach dots sec tok obs prompt; do +for d in g r mcp qu wt v cc tm teach dots sec tok prompt; do _test_box_format "$d" done echo "" @@ -382,7 +367,7 @@ echo "" _test_function_naming() { # Standard pattern: _<cmd>_help - for d in g r mcp qu wt v cc tm dots sec tok obs prompt; do + for d in g r mcp qu wt v cc tm dots sec tok prompt; do local expected="_${d}_help" if typeset -f "$expected" > /dev/null 2>&1; then assert_pass "$d: function $expected() exists" @@ -397,13 +382,6 @@ _test_function_naming() { else assert_fail "teach: function _teach_dispatcher_help() exists (special case)" fi - - # obs: verify old obs_help still works as alias for backward compat - if typeset -f "obs_help" > /dev/null 2>&1; then - assert_pass "obs: legacy obs_help() alias exists" - else - assert_fail "obs: legacy obs_help() alias exists" - fi } _test_function_naming @@ -428,12 +406,12 @@ _test_doctor_integration() { assert_contains "$output" "Help Function Compliance Check" \ "doctor --help-check shows compliance header" - # Output should report all 15 dispatchers - assert_contains "$output" "All 15 dispatchers compliant" \ - "doctor --help-check reports all 15 compliant" + # Output should report all 14 dispatchers + assert_contains "$output" "All 14 dispatchers compliant" \ + "doctor --help-check reports all 14 compliant" # Each dispatcher should appear in output - for d in g r mcp qu wt v cc tm teach dots sec tok obs prompt em; do + for d in g r mcp qu wt v cc tm teach dots sec tok prompt em; do assert_grep "$output" "✅ $d:" "doctor output includes $d result" done } @@ -450,12 +428,12 @@ echo -e "${BLUE}── Section 8: Compliance Library API ──${NC}" echo "" _test_compliance_api() { - # Dispatcher list has exactly 15 entries + # Dispatcher list has exactly 14 entries local count=${#_FLOW_HELP_DISPATCHERS[@]} - if [[ $count -eq 15 ]]; then - assert_pass "dispatcher list has exactly 15 entries" + if [[ $count -eq 14 ]]; then + assert_pass "dispatcher list has exactly 14 entries" else - assert_fail "dispatcher list has exactly 15 entries" "found $count" + assert_fail "dispatcher list has exactly 14 entries" "found $count" fi # Function map has entry for every dispatcher @@ -532,7 +510,7 @@ echo "" _test_consistency() { # All dispatchers should have the same section order: # box → MOST COMMON → QUICK EXAMPLES → 📋 sections → TIP → See also - for d in g r mcp qu wt v cc tm teach dots sec tok obs prompt; do + for d in g r mcp qu wt v cc tm teach dots sec tok prompt; do local help_fn="${_FLOW_HELP_FUNCTIONS[$d]}" local output output="$($help_fn 2>&1)" @@ -597,7 +575,7 @@ _test_edge_cases() { assert_exit_code "$empty_rc" "1" "empty dispatcher name returns exit 1" # Help output contains no raw FLOW_COLORS references (all converted) - for d in obs prompt dots sec tok cc tm teach; do + for d in prompt dots sec tok cc tm teach; do local help_fn="${_FLOW_HELP_FUNCTIONS[$d]}" local output output="$($help_fn 2>&1)" @@ -605,7 +583,7 @@ _test_edge_cases() { done # Help output contains no literal \033[ (should be rendered as actual ESC) - for d in obs prompt dots sec tok cc tm teach; do + for d in prompt dots sec tok cc tm teach; do local help_fn="${_FLOW_HELP_FUNCTIONS[$d]}" local output output="$($help_fn 2>&1)" diff --git a/tests/test-help-compliance.zsh b/tests/test-help-compliance.zsh index d57fb5f06..e2de74b10 100755 --- a/tests/test-help-compliance.zsh +++ b/tests/test-help-compliance.zsh @@ -3,11 +3,11 @@ # HELP COMPLIANCE TEST SUITE # ══════════════════════════════════════════════════════════════════════════════ # -# Validates all 15 dispatcher help functions against CONVENTIONS.md:173-199 +# Validates all 14 dispatcher help functions against CONVENTIONS.md:173-199 # Uses lib/help-compliance.zsh shared validation library. # # Usage: ./tests/test-help-compliance.zsh -# Expected: All 15 dispatchers pass all 9 compliance rules +# Expected: All 14 dispatchers pass all 9 compliance rules # # ══════════════════════════════════════════════════════════════════════════════ @@ -40,7 +40,7 @@ source "$FLOW_DIR/lib/help-compliance.zsh" 2>/dev/null || { } echo "══════════════════════════════════════════════════════════════" -echo " Help Compliance Test Suite (9 rules × 15 dispatchers)" +echo " Help Compliance Test Suite (9 rules × 14 dispatchers)" echo "══════════════════════════════════════════════════════════════" echo "" diff --git a/tests/test-manpage-version-sync.zsh b/tests/test-manpage-version-sync.zsh index 040c8c522..9003f3fbc 100644 --- a/tests/test-manpage-version-sync.zsh +++ b/tests/test-manpage-version-sync.zsh @@ -71,7 +71,7 @@ _flow_version() { # ── dispatcher-command extraction (for the coverage / missing-page guard) ──── # A "dispatcher" is a public top-level command function (e.g. `tok() { ... }`) # defined in a dispatcher source file. We derive the set from the functions the -# shell actually exposes — NOT from filenames (irregular: obs.zsh, +# shell actually exposes — NOT from filenames (irregular: # email-dispatcher.zsh -> em, at lives in atlas-bridge.zsh) and NOT from a # `_<cmd>_help` convention (teach has none). Pure aliases whose entire body is a # lone `<cmd> "$@"` delegation (e.g. vibe -> v) are excluded. diff --git a/tests/test-obs-dispatcher.zsh b/tests/test-obs-dispatcher.zsh deleted file mode 100755 index 1b3af1ae9..000000000 --- a/tests/test-obs-dispatcher.zsh +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env zsh -# ══════════════════════════════════════════════════════════════════════════════ -# TEST SUITE: OBS Dispatcher -# ══════════════════════════════════════════════════════════════════════════════ -# -# Purpose: Validate obs dispatcher functionality -# Coverage: Function existence, help output, version, unknown commands -# -# Test Categories: -# 1. Function Existence (4 tests) -# 2. Help Output (2 tests) -# 3. Help Content (4 tests) -# 4. Version (1 test) -# 5. Unknown Command (1 test) -# -# Created: 2026-02-16 -# ══════════════════════════════════════════════════════════════════════════════ - -# Source shared test framework -SCRIPT_DIR="${0:A:h}" -PROJECT_ROOT="${SCRIPT_DIR:h}" -source "$SCRIPT_DIR/test-framework.zsh" || { echo "ERROR: Cannot source test-framework.zsh"; exit 1 } - -# ══════════════════════════════════════════════════════════════════════════════ -# SETUP / CLEANUP -# ══════════════════════════════════════════════════════════════════════════════ - -setup() { - if [[ -z "$PROJECT_ROOT" || ! -f "$PROJECT_ROOT/lib/dispatchers/obs.zsh" ]]; then - if [[ -f "$PWD/lib/dispatchers/obs.zsh" ]]; then - PROJECT_ROOT="$PWD" - elif [[ -f "$PWD/../lib/dispatchers/obs.zsh" ]]; then - PROJECT_ROOT="$PWD/.." - fi - fi - - if [[ -z "$PROJECT_ROOT" || ! -f "$PROJECT_ROOT/lib/dispatchers/obs.zsh" ]]; then - echo "ERROR: Cannot find project root — run from project directory" - exit 1 - fi - - # Source core (for color helpers) and the dispatcher - source "$PROJECT_ROOT/lib/core.zsh" 2>/dev/null - source "$PROJECT_ROOT/lib/dispatchers/obs.zsh" 2>/dev/null -} - -cleanup() { - reset_mocks -} -trap cleanup EXIT - -setup - -# ══════════════════════════════════════════════════════════════════════════════ -# 1. FUNCTION EXISTENCE TESTS -# ══════════════════════════════════════════════════════════════════════════════ - -test_suite_start "OBS Dispatcher Tests" - -echo "${YELLOW}Function Existence${RESET}" -echo "────────────────────────────────────────" - -test_case "obs function is defined" -assert_function_exists "obs" && test_pass - -test_case "obs_help function is defined" -assert_function_exists "obs_help" && test_pass - -test_case "obs_version function is defined" -assert_function_exists "obs_version" && test_pass - -test_case "obs_vaults function is defined" -assert_function_exists "obs_vaults" && test_pass - -echo "" - -# ══════════════════════════════════════════════════════════════════════════════ -# 2. HELP TESTS -# ══════════════════════════════════════════════════════════════════════════════ - -echo "${YELLOW}Help Tests${RESET}" -echo "────────────────────────────────────────" - -test_case "obs help shows usage" -local output_help=$(obs help 2>&1) -assert_not_contains "$output_help" "command not found" -assert_contains "$output_help" "Obsidian Vault Manager" && test_pass - -test_case "obs help --all shows full help" -local output_help_all=$(obs help --all 2>&1) -assert_not_contains "$output_help_all" "command not found" -assert_contains "$output_help_all" "VAULT COMMANDS" && test_pass - -echo "" - -# ══════════════════════════════════════════════════════════════════════════════ -# 3. HELP CONTENT TESTS -# ══════════════════════════════════════════════════════════════════════════════ - -echo "${YELLOW}Help Content${RESET}" -echo "────────────────────────────────────────" - -test_case "help shows stats command" -assert_contains "$output_help_all" "stats" && test_pass - -test_case "help shows discover command" -assert_contains "$output_help_all" "discover" && test_pass - -test_case "help shows analyze command" -assert_contains "$output_help_all" "analyze" && test_pass - -test_case "help shows AI features section" -assert_contains "$output_help_all" "AI FEATURES" && test_pass - -echo "" - -# ══════════════════════════════════════════════════════════════════════════════ -# 4. VERSION TESTS -# ══════════════════════════════════════════════════════════════════════════════ - -echo "${YELLOW}Version${RESET}" -echo "────────────────────────────────────────" - -test_case "obs version shows version" -local output_version=$(obs version 2>&1) -assert_not_contains "$output_version" "command not found" -assert_contains "$output_version" "version" && test_pass - -echo "" - -# ══════════════════════════════════════════════════════════════════════════════ -# 5. UNKNOWN COMMAND TESTS -# ══════════════════════════════════════════════════════════════════════════════ - -echo "${YELLOW}Unknown Command${RESET}" -echo "────────────────────────────────────────" - -test_case "obs unknown-cmd shows error" -local output_unknown=$(obs unknown-xyz-command 2>&1) -assert_not_contains "$output_unknown" "command not found" -assert_contains "$output_unknown" "Unknown command" && test_pass - -echo "" - -# ══════════════════════════════════════════════════════════════════════════════ -# SUMMARY -# ══════════════════════════════════════════════════════════════════════════════ - -cleanup -test_suite_end -exit $? diff --git a/zsh/.zshrc.alias-backup b/zsh/.zshrc.alias-backup deleted file mode 100644 index f586d5eaa..000000000 --- a/zsh/.zshrc.alias-backup +++ /dev/null @@ -1,1070 +0,0 @@ -# ============================================ -# ANTIDOTE PLUGIN MANAGER -# ============================================ - -# Enable Powerlevel10k instant prompt (should stay at top) -if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then - source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" -fi - -# Disable OMZ auto-title (we use iterm2-context-switcher instead) -DISABLE_AUTO_TITLE="true" - -# Initialize antidote (installed via homebrew) -source $(brew --prefix)/opt/antidote/share/antidote/antidote.zsh - -# Fix for OMZ async prompt regression -# See: https://github.com/ohmyzsh/ohmyzsh/issues/12328 -zstyle ':omz:alpha:lib:git' async-prompt no - -# Load plugins from .zsh_plugins.txt -# Note: use-omz + ohmyzsh/ohmyzsh path:lib handles compinit automatically -antidote load $ZDOTDIR/.zsh_plugins.txt - -# ============================================ -# POWERLEVEL10K CUSTOMIZATION -# ============================================ - -# Load p10k config if it exists -[[ ! -f $ZDOTDIR/.p10k.zsh ]] || source $ZDOTDIR/.p10k.zsh - -# Add indicator when in R package directory -function prompt_r_package() { - if [[ -f "DESCRIPTION" ]] && grep -q "^Package:" DESCRIPTION 2>/dev/null; then - local pkg_name=$(grep "^Package:" DESCRIPTION | cut -d' ' -f2) - p10k segment -f yellow -i '📦' -t "$pkg_name" - fi -} - -# ============================================ -# ENVIRONMENT VARIABLES -# ============================================ - -# R Package Development -export R_PACKAGES_DIR="$HOME/R-packages" -export QUARTO_DIR="$HOME/quarto-projects" - -# R Console -export R_PROFILE_USER="$HOME/.Rprofile" -export RADIAN_THEME="native" - -# ============================================ -# HISTORY CONFIGURATION -# ============================================ - -HISTFILE=~/.zsh_history -HISTSIZE=50000 -SAVEHIST=50000 - -setopt EXTENDED_HISTORY # Record timestamp -setopt HIST_EXPIRE_DUPS_FIRST # Expire duplicates first -setopt HIST_IGNORE_DUPS # Don't record duplicates -setopt HIST_IGNORE_SPACE # Ignore commands starting with space -setopt HIST_VERIFY # Show before executing history -setopt SHARE_HISTORY # Share history across terminals - -# Enhanced history search (arrow keys) -bindkey "^[[A" history-beginning-search-backward -bindkey "^[[B" history-beginning-search-forward - -# ============================================ -# ZSH OPTIONS -# ============================================ - -# Directory navigation -setopt AUTO_CD # Just type directory name to cd -setopt AUTO_PUSHD # Push directories onto stack -setopt PUSHD_IGNORE_DUPS # Don't push duplicates -setopt PUSHD_SILENT # Don't print directory stack - -# Completion -setopt COMPLETE_IN_WORD # Complete from both ends -setopt ALWAYS_TO_END # Move cursor to end after completion - -# ============================================ -# COMPLETIONS -# ============================================ -# Note: compinit is initialized earlier before loading antidote plugins - -# Case-insensitive completion -zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' - -# Completion colors -zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" - -# Partial completion -zstyle ':completion:*' list-suffixes -zstyle ':completion:*' expand prefix suffix - -# Menu selection -zstyle ':completion:*' menu select - -# Cache completions -zstyle ':completion:*' use-cache on -zstyle ':completion:*' cache-path ~/.zsh/cache - -# ============================================ -# DIRECTORY NAVIGATION -# ============================================ - -# Bookmark system (use cd ~bookmark) -hash -d rpkg="$R_PACKAGES_DIR" -hash -d quarto="$QUARTO_DIR" - -# Directory aliases - REMOVED 2025-12-19: Use 'pick' or 'pp' instead -# alias cdrpkg='cd $R_PACKAGES_DIR' -# alias cdq='cd $QUARTO_DIR' - -# Directory stack shortcut - REMOVED 2025-12-19: Use 'dirs' directly -# alias d='dirs -v | head -10' - -# Quick directory creation and navigation -function mkcd() { - mkdir -p "$1" && cd "$1" -} - -# ============================================ -# MODERN CLI TOOLS -# ============================================ - -# Better ls (check if eza is installed) -if command -v eza >/dev/null; then - alias ls='eza --icons --git' - alias ll='eza -lah --icons --git' - alias la='eza -A --icons --git' - alias l='eza -F --icons --git' - alias tree='eza --tree --icons --git' -else - alias ll='ls -lah' - alias la='ls -A' - alias l='ls -CF' -fi - -# Better cat (you already use bat) -alias cat='bat' -# Note: peek is now a function in smart-dispatchers.zsh for smart file viewing - -# Better find/grep - REMOVED 2025-12-19: Use fd and rg directly -# alias find='fd' -# alias grep='rg' - -# Modern alternatives (if installed) -command -v dust >/dev/null && alias du='dust' -command -v duf >/dev/null && alias df='duf' -command -v btop >/dev/null && alias top='btop' - -# Zoxide (modern replacement for 'z' - faster, Rust-based) -if command -v zoxide >/dev/null; then - eval "$(zoxide init zsh)" - # Optional: Keep 'z' as alias for zoxide (backward compatible) - # Note: zoxide provides 'z', 'zi' (interactive), and 'za' (add) commands -fi - -# Atuin (supercharged shell history - context-aware, searchable, synced) -# Installed: 2025-12-16 -if command -v atuin >/dev/null; then - eval "$(atuin init zsh)" - # Keybindings: - # - Ctrl+R: Interactive fuzzy search - # - Up arrow: Still works for history search - # Features: Search by directory, time, success/failure, sync across machines -fi - -# Direnv (automatic per-project environment setup) -# Installed: 2025-12-16 -if command -v direnv >/dev/null; then - eval "$(direnv hook zsh)" - # Usage: Create .envrc in project root with environment variables - # Example: export R_LIBS_USER=~/R/project-libs - # Auto-loads when you cd into directory (after 'direnv allow') -fi - -# ============================================ -# GIT ENHANCEMENTS -# ============================================ -# Note: Use `g` dispatcher instead (g log, g status, g undo, etc.) -# Old aliases removed 2025-12-17 - -# R package specific - REMOVED 2025-12-19: Use rpkgcommit directly -# alias gpkgcommit='rpkgcommit' - -# ============================================ -# 📦 R PACKAGE DEVELOPMENT -# ============================================ -# CONSOLIDATED 2025-12-26: Use 'r' dispatcher from flow-cli -# Run 'r help' to see all available commands: -# r test, r doc, r check, r build, r cov, r cran, r patch, etc. - -# R Console - radian as default -command -v radian >/dev/null && alias R='radian' - -# ============================================ -# 📝 QUARTO SHORTCUTS -# ============================================ -# Note: qu dispatcher is now active in flow-cli (qu preview, qu render, qu check, qu clean) -# Old aliases removed 2025-12-17 - -# ============================================ -# 🤖 CLAUDE CODE -# ============================================ -# CONSOLIDATED 2025-12-26: Use 'cc' dispatcher from flow-cli -# Run 'cc help' to see all available commands: -# cc, cc yolo, cc plan, cc ask, cc file, cc diff, cc resume, etc. - -# Backward compatibility alias for YOLO mode -alias ccy='cc yolo' - -# ============================================ -# R PACKAGE DEVELOPMENT - FUNCTIONS -# ============================================ - -# File creation functions -function rnewfun() { - if [ -z "$1" ]; then - echo "Usage: rnewfun <function_name>" - return 1 - fi - Rscript -e "usethis::use_r('$1')" -} - -function rnewtest() { - if [ -z "$1" ]; then - echo "Usage: rnewtest <function_name>" - return 1 - fi - Rscript -e "usethis::use_test('$1')" -} - -function rnewvig() { - if [ -z "$1" ]; then - echo "Usage: rnewvig <vignette_name>" - return 1 - fi - Rscript -e "usethis::use_vignette('$1')" -} - -function rnewdata() { - if [ -z "$1" ]; then - echo "Usage: rnewdata <data_name>" - return 1 - fi - Rscript -e "usethis::use_data_raw('$1')" -} - -# Test-specific functions -function rtest1() { - if [ -z "$1" ]; then - echo "Usage: rtest1 <test_pattern>" - return 1 - fi - Rscript -e "devtools::test(filter = '$1')" -} - -function rtestfile() { - if [ -z "$1" ]; then - echo "Usage: rtestfile <path_to_test_file>" - return 1 - fi - Rscript -e "testthat::test_file('$1')" -} - -function rdepsexplain() { - if [ -z "$1" ]; then - echo "Usage: rdepsexplain <package_name>" - return 1 - fi - Rscript -e "pak::pkg_deps_explain('$1')" -} - -# Create new R package with best practices -function rnewpkg() { - if [ -z "$1" ]; then - echo "Usage: rnewpkg <packagename>" - return 1 - fi - - local pkgname="$1" - - echo "📦 Creating R package: $pkgname" - echo "" - - # Create in R-packages directory - mkdir -p "$R_PACKAGES_DIR" - cd "$R_PACKAGES_DIR" - - # Create package - Rscript -e "usethis::create_package('$pkgname', open = FALSE)" - cd "$pkgname" - - # Set up infrastructure - echo "🔧 Setting up infrastructure..." - Rscript -e "usethis::use_git()" - Rscript -e "usethis::use_mit_license()" - Rscript -e "usethis::use_roxygen_md()" - Rscript -e "usethis::use_testthat()" - Rscript -e "usethis::use_package_doc()" - Rscript -e "usethis::use_pipe()" - - # Create basic README - Rscript -e "usethis::use_readme_rmd()" - Rscript -e "usethis::use_news_md()" - - echo "" - echo "✅ Package created!" - rpkgtree - echo "" - echo "Next: Edit DESCRIPTION, then start coding!" -} - -# Full development cycle -function rpkgcycle() { - echo "🔄 Full package development cycle..." - echo "" - echo "📝 Step 1/3: Documentation..." - rdoc || { echo "❌ Failed"; return 1; } - echo "✅ Documentation complete" - echo "" - echo "🧪 Step 2/3: Tests..." - rtest || { echo "❌ Failed"; return 1; } - echo "✅ Tests passed" - echo "" - echo "✅ Step 3/3: R CMD check..." - rcheck || { echo "❌ Failed"; return 1; } - echo "" - echo "🎉 All checks passed!" -} - -# Commit with checks -function rpkgcommit() { - if [ -z "$1" ]; then - echo "Usage: rpkgcommit 'commit message'" - return 1 - fi - - echo "🔍 Running pre-commit checks..." - - echo " 📝 Documenting..." - rdoc || { echo "❌ Failed"; return 1; } - - echo " 🧪 Testing..." - rtest || { echo "❌ Failed"; return 1; } - - # Style code if styler available - if Rscript -e "requireNamespace('styler', quietly = TRUE)" 2>/dev/null; then - echo " 💅 Styling..." - Rscript -e "styler::style_pkg(quiet = TRUE)" - fi - - echo " 📦 Committing..." - git add . - git commit -m "$1" - - echo "" - echo "✅ Committed! Push with: git push" -} - -# Package info -function rpkginfo() { - local pkgname=$(basename "$PWD") - - echo "📦 Package: $pkgname" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "" - - # Version - if [ -f "DESCRIPTION" ]; then - echo "📌 Version:" - Rscript -e "cat(' ', as.character(desc::desc_get_version()), '\n')" 2>/dev/null || echo " (unable to read)" - echo "" - fi - - # Functions - echo "🔧 R Scripts: $(ls -1 R/*.R 2>/dev/null | wc -l | xargs)" - echo "🧪 Tests: $(ls -1 tests/testthat/test-*.R 2>/dev/null | wc -l | xargs)" - echo "📖 Rd files: $(ls -1 man/*.Rd 2>/dev/null | wc -l | xargs)" - echo "" - - # Git - echo "🔀 Git:" - git branch --show-current 2>/dev/null | xargs echo " Branch:" || echo " Not a git repo" - echo "" - - # Structure - rpkgtree -} - -# Interactive file creator -function rpkgnew() { - local type="${1:-function}" - - case $type in - function|fun|f) - read "name?Function name: " - rnewfun "$name" - rnewtest "$name" - echo "✅ Created R/$name.R and tests/testthat/test-$name.R" - ;; - test|t) - read "name?Test name: " - rnewtest "$name" - ;; - vignette|vig|v) - read "name?Vignette name: " - rnewvig "$name" - ;; - data|d) - read "name?Data name: " - rnewdata "$name" - ;; - *) - echo "Usage: rpkgnew [function|test|vignette|data]" - ;; - esac -} - -# Search R package code -function rpkgfind() { - if [ -z "$1" ]; then - echo "Usage: rpkgfind <pattern>" - return 1 - fi - - echo "🔍 Searching for: $1" - echo "" - echo "In R/:" - rg "$1" R/ --heading --line-number 2>/dev/null || echo " (no matches)" - echo "" - echo "In tests/:" - rg "$1" tests/ --heading --line-number 2>/dev/null || echo " (no matches)" -} - -# Auto-activate renv notification -function auto_renv() { - if [[ -f "renv.lock" ]] && [[ "$RENV_ACTIVE" != "TRUE" ]]; then - echo "📦 renv detected - activate with: Rscript -e 'renv::activate()'" - fi -} - -# Run on directory change -chpwd_functions+=(auto_renv) - -# ============================================ -# QUARTO FUNCTIONS -# ============================================ - -# Create new Quarto project -function qnew() { - if [ -z "$1" ]; then - echo "Usage: qnew <projectname>" - return 1 - fi - - mkdir -p "$QUARTO_DIR" - cd "$QUARTO_DIR" - quarto create project default "$1" - cd "$1" - echo "✅ Quarto project created: $1" -} - -# Start Quarto preview in background -function qprev() { - local file="${1:-index.qmd}" - echo "👁️ Starting Quarto preview for $file..." - quarto preview "$file" > /dev/null 2>&1 & - echo "Preview running (PID: $!)" -} - -# Quick Quarto workflow -function qwork() { - local file="${1:-index.qmd}" - - # Open in editor - code "$file" 2>/dev/null || open "$file" - - # Start preview - qprev "$file" - - echo "" - echo "✅ Workflow ready!" - echo " 📝 Editor opened" - echo " 👁️ Preview running" - echo " 💬 Run 'ccc' for Claude" -} - -# ============================================ -# GENERAL R FUNCTIONS -# ============================================ - -# Create new R project -function rnew() { - if [ -z "$1" ]; then - echo "Usage: rnew <projectname>" - return 1 - fi - - mkdir -p "$1" - cd "$1" - git init - - # Create structure - mkdir -p R data output scripts docs - touch README.md .gitignore - - # .gitignore - cat > .gitignore << 'EOF' -.Rproj.user -.Rhistory -.RData -.Ruserdata -*.Rproj -.DS_Store -output/* -EOF - - # README - echo "# $1" > README.md - echo "" >> README.md - echo "Created: $(date +%Y-%m-%d)" >> README.md - - echo "✅ R project created: $1" - tree -L 1 2>/dev/null || ls -la -} - -# ============================================ -# FZF INTEGRATION (if installed) -# ============================================ - -if [ -f ~/.fzf.zsh ]; then - source ~/.fzf.zsh - - # Use fd for fzf - export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git' - export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" - - # R package file finder - rfzf() { - local file - file=$(fd --type f . R tests man | fzf --preview 'bat --color=always {}') - [[ -n "$file" ]] && ${EDITOR:-vim} "$file" - } -fi - -# ============================================ -# SECURE TOKEN MANAGEMENT -# ============================================ - -# Load GitHub token from macOS Keychain (if stored) -if command -v security >/dev/null 2>&1; then - # Disabled to allow gh CLI to use its own valid keyring auth - # export GITHUB_TOKEN=$(security find-generic-password -a "$USER" -s github_token -w 2>/dev/null) - - # Load token specifically for Gemini extensions (uses the 'github_token' keychain item) - export GITHUB_MCP_PAT=$(security find-generic-password -a "$USER" -s github_token -w 2>/dev/null) - - export DC_API_KEY="1lwAVbNQrOq3m71Ff3BPqxQBQRPuWBdZ9o7b89VAadANreAE" -fi - -# To store token securely (run once): -# security add-generic-password -a "$USER" -s github_token -w "your_token_here" - -# ============================================ -# SSH AGENT CONFIGURATION -# ============================================ -# Start ssh-agent if not running -if [ -z "$SSH_AUTH_SOCK" ]; then - eval "$(ssh-agent -s)" > /dev/null - ssh-add --apple-use-keychain ~/.ssh/id_ed25519 2>/dev/null -fi - -# ============================================ -# LAZY LOADING (Performance optimization) -# ============================================ - -# Lazy load pyenv if installed -if command -v pyenv 1>/dev/null 2>&1; then - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init --path)" -fi - -# ============================================ -# CUSTOM FUNCTIONS -# ============================================ - -# Source custom functions -# MOVED TO .zshenv 2025-12-23 - Loaded universally for Claude Code support -# if [[ -f ~/.config/zsh/functions/genpass.zsh ]]; then -# source ~/.config/zsh/functions/genpass.zsh -# fi - -# Option B+ Multi-Editor Quadrant System (2025-12-13) -# MOVED TO .zshenv 2025-12-23 - Loaded universally for Claude Code support -# if [[ -f ~/.config/zsh/functions/work.zsh ]]; then -# source ~/.config/zsh/functions/work.zsh -# fi - -# MOVED TO .zshenv 2025-12-23 -# if [[ -f ~/.config/zsh/functions/claude-workflows.zsh ]]; then -# source ~/.config/zsh/functions/claude-workflows.zsh -# fi - -# MOVED TO .zshenv 2025-12-23 -# if [[ -f ~/.config/zsh/functions/adhd-helpers.zsh ]]; then -# source ~/.config/zsh/functions/adhd-helpers.zsh -# fi - -# MOVED TO .zshenv 2025-12-23 -# if [[ -f ~/.config/zsh/functions/dash.zsh ]]; then -# source ~/.config/zsh/functions/dash.zsh -# fi - -# MOVED TO .zshenv 2025-12-23 -# if [[ -f ~/.config/zsh/functions/status.zsh ]]; then -# source ~/.config/zsh/functions/status.zsh -# fi - -# MOVED TO .zshenv 2025-12-23 -# if [[ -f ~/.config/zsh/functions/obsidian-bridge.zsh ]]; then -# source ~/.config/zsh/functions/obsidian-bridge.zsh -# fi - -if [[ -f ~/.config/zsh/functions/fzf-helpers.zsh ]]; then - source ~/.config/zsh/functions/fzf-helpers.zsh -fi - -# Claude Response Viewer with Glow (2025-12-16) -if [[ -f ~/.config/zsh/functions/claude-response-viewer.zsh ]]; then - source ~/.config/zsh/functions/claude-response-viewer.zsh -fi - -# Background Agent Management (2025-12-16) -if [[ -f ~/.config/zsh/functions/bg-agents.zsh ]]; then - source ~/.config/zsh/functions/bg-agents.zsh -fi - -# Scribe CLI - Terminal-based note access (2025-12-27, Sprint 20) -if [[ -f ~/.config/zsh/functions/scribe.zsh ]]; then - source ~/.config/zsh/functions/scribe.zsh -fi - -# MCP Server Management Dispatcher (2025-12-19) -# MOVED TO .zshenv 2025-12-23 -# if [[ -f ~/.config/zsh/functions/mcp-dispatcher.zsh ]]; then -# source ~/.config/zsh/functions/mcp-dispatcher.zsh -# fi - -# ============================================ -# LOCAL CUSTOMIZATIONS -# ============================================ - -# Source local config if it exists (for machine-specific settings) -[[ -f ~/.zshrc.local ]] && source ~/.zshrc.local - -# ============================================ -# ZSH-CLAUDE WORKFLOW -# ============================================ - -# Add zsh-claude-workflow commands to PATH -export PATH="$HOME/projects/dev-tools/zsh-claude-workflow/commands:$PATH" - -# Aliases for quick access - REMOVED 2025-12-19: Use full commands instead -# alias ptype='proj-type' -# alias pinfo='proj-info' -# alias cctx='claude-ctx' -# alias cinit='claude-init' -# alias cshow='claude-show' -# alias pclaude='proj-claude' - -# ============================================ -# 📊 PROJECT STATUS (Local Operations) -# ============================================ -# Note: dashupdate() function defined at line 962 -# REMOVED 2025-12-19: Use full commands instead - -# alias pstat='~/projects/dev-tools/apple-notes-sync/scanner.sh' -# alias pstatshow='pstat && jq -C . /tmp/project-status.json | less -R' -# alias pstatview='pstat && cat /tmp/project-status.json | jq -r ".projects[] | \"\(.priority) \(.name) [\(.progress)%] - \(.next)\""' -# alias pstatlist='command find ~/projects/r-packages/active -name ".STATUS" -exec echo {} \;' -# alias pstatcount='pstat && jq -r "\"Total: \(.projects|length) | Blocked: \([.projects[]|select(.status==\"blocked\")]|length) | Active: \([.projects[]|select(.status==\"active\")]|length)\"" /tmp/project-status.json' - -# ============================================ -# 📝 NOTES SYNC (Apple Notes Operations) -# ============================================ -# REMOVED 2025-12-19: Use full commands instead - -# alias nsync='pstat && ~/projects/dev-tools/apple-notes-sync/dashboard-applescript.sh' -# alias nsyncview='osascript -e "tell application \"Notes\" to return body of (first note of account \"iCloud\" whose name is \"📊 Project Dashboard\")" | sed "s/<[^>]*>//g" | sed "s/ / /g"' -# alias nsyncclip='~/projects/dev-tools/apple-notes-sync/dashboard-clipboard.sh' -# alias nsyncexport='~/projects/dev-tools/apple-notes-sync/dashboard-export.sh' - -# ============================================ -# ⚡ ULTRA-SHORT ALIASES (Power Users) -# ============================================ - -# Project Status (ps conflicts with Unix command, use carefully) - REMOVED 2025-12-19 -# alias psv='pstatview' -# alias psl='pstatlist' -# alias psc='pstatcount' -# alias pss='pstatshow' - -# Notes Sync - REMOVED 2025-12-19: Use full commands instead -# alias ns='nsync' -# alias nsv='nsyncview' -# alias nsc='nsyncclip' -# alias nse='nsyncexport' - -# ============================================ -# 🔄 DEPRECATED (Backward Compatibility) -# ============================================ -# Use new aliases: pstat*, nsync* instead -# Note: dashupdate() function exists at line 998 (no alias needed) - -# REPLACED 2025-12-19: dashsync is now a function in adhd-helpers.zsh -# REMOVED 2025-12-19: alias dashclip, alias dashexport (deprecated) - -# ============================================ -# 🔧 TYPO TOLERANCE (ADHD-Friendly Recovery) -# ============================================ -# Common typos auto-correct to correct command - -# Claude typos - REMOVED 2025-12-19: Type correctly -# alias claue='claude' -# alias cluade='claude' -# alias clade='claude' -# alias calue='claude' -# alias claudee='claude' - -# R package typos - REMOVED 2025-12-19: Type correctly -# alias rlaod='rload' -# alias rlod='rload' -# alias rtets='rtest' -# alias rtset='rtest' -# alias rdco='rdoc' -# alias rchekc='rcheck' -# alias rchck='rcheck' -# alias rcylce='rcycle' - -# Git typos - REMOVED 2025-12-19: Git plugin now provides all git aliases -# alias gti='g' -# alias tgi='g' -# alias gis='g' -# alias gitstatus='g status' - -# Common command typos - REMOVED 2025-12-19: Type correctly -# alias clera='clear' -# alias claer='clear' -# alias sl='ls' -# alias pdw='pwd' - -# Quarto typos - REMOVED 2025-12-19: Type correctly -# alias qurto='quarto' -# alias qaurt='quarto' - -# ============================================ -# 💎 GEMINI CLI ALIASES (v0.22.2) - Updated 2025-12-25 -# ============================================ -# Note: 'gm' conflicts with GraphicsMagick, using 'gem' prefix instead -# Note: -p flag deprecated, use positional prompts: gemini "query" - -# Main shortcut -alias gem='gemini' - -# Web search functions (updated to remove deprecated -p flag) -gemw() { - if [ -z "$*" ]; then - echo "Usage: gemw <search query>" - echo "Example: gemw latest AI news" - return 1 - fi - gemini "Search the web for: $*" -} - -gemws() { - if [ -z "$*" ]; then - echo "Usage: gemws <search query>" - echo "Example: gemws Python best practices 2025" - return 1 - fi - gemini "Find and summarize information about: $*" -} - -# Quick interactive with common options -alias gemi='gemini -i' # Interactive mode -alias gemy='gemini -y' # YOLO mode (auto-approve) -alias gems='gemini -s' # Sandbox mode -alias gemr='gemini -r latest' # Resume latest session - -# Model selection shortcuts -alias gemf='gemini -m gemini-2.5-flash' # Fast model -alias gemp='gemini -m gemini-2.5-pro' # Pro model - -# Output formats -alias gemj='gemini -o json' # JSON output -alias gemsj='gemini -o stream-json' # Streaming JSON - -# Common workflows -gemc() { - # Code review current changes - gemini "Review my git changes and suggest improvements" -} - -geme() { - # Explain current codebase - gemini "Explain the architecture of this codebase" -} - -gemd() { - # Debug help - gemini "Help me debug this issue: $*" -} - -# ============================================ -# 🔷 OPENCODE ALIAS - Added 2025-12-25 -# ============================================ -alias oc='opencode' - -# Emacs (Homebrew) -export PATH="/opt/homebrew/opt/emacs/bin:$PATH" - -# Use emacs directly as editor (simplest approach) -export EDITOR="nvim" -export VISUAL="emacs" - -# Optional: start emacs daemon on login via brew services (uncomment to enable) -# brew services start emacs >/dev/null 2>&1 || true -export PATH="/opt/homebrew/bin:$PATH" - -# ============================================ -# CUSTOM WORKFLOW FUNCTIONS -# ============================================ -# Source custom workflow functions -if [[ -f ~/.config/zsh/functions.zsh ]]; then - source ~/.config/zsh/functions.zsh -fi - -# ============================================ -# 🔍 ALIAS DISCOVERY HELPER (ADHD-Optimized) -# ============================================ - -# Main discovery function - shows categorized aliases -aliases() { - local category="${1:-all}" - - case "$category" in - all|"") - echo "╔════════════════════════════════════════════════════════════╗" - echo "║ 📋 ZSH ALIAS QUICK REFERENCE ║" - echo "╚════════════════════════════════════════════════════════════╝" - echo "" - echo "🤖 CLAUDE CODE (31 aliases)" - alias | grep "^cc" | head -5 - echo " ... (run 'aliases claude' for all)" - echo "" - echo "📦 R PACKAGE DEV (27 aliases)" - alias | grep "^r" | grep -v "^run-help" | head -5 - echo " ... (run 'aliases r' for all)" - echo "" - echo "⚡ ULTRA-SHORT (5 aliases)" - echo " ld → rload | ts → rtest | dc → rdoc | ck → rcheck | bd → rbuild" - echo "" - echo "💎 GEMINI CLI (13 aliases - v0.22.2)" - alias | grep "^gem" | head -5 - echo " ... (run 'aliases gemini' for all)" - echo "" - echo "📝 QUARTO (4 aliases)" - alias | grep "^q[a-z]" - echo "" - echo "🔀 GIT (6 aliases)" - alias | grep "^g" | grep -v "^gem" - echo "" - echo "📂 FILE VIEWING (9 aliases)" - alias | grep "^peek\|^cat=\|^find=\|^grep=" - echo "" - echo "Run: aliases <category> for details (claude, r, gemini, quarto, git, files)" - ;; - - claude|cc) - echo "🤖 CLAUDE CODE ALIASES (31 total)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - alias | grep "^cc" - ;; - - r|rpkg|rpackage) - echo "📦 R PACKAGE DEVELOPMENT ALIASES (27 total)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - alias | grep "^r" | grep -v "^run-help" - ;; - - gemini|gem) - echo "💎 GEMINI CLI ALIASES (v0.22.2)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "Main: gem, gemi, gemy, gems, gemr" - echo "Models: gemf (flash), gemp (pro)" - echo "Output: gemj (json), gemsj (stream-json)" - echo "Web: gemw, gemws" - echo "Workflows: gemc (code review), geme (explain), gemd (debug)" - echo "" - echo "Full list:" - alias | grep "^gem" | sort - ;; - - quarto|q) - echo "📝 QUARTO ALIASES (4 total)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - alias | grep "^q[a-z]" - ;; - - git|g) - echo "🔀 GIT ALIASES (6 total)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - alias | grep "^g" | grep -v "^gem" - ;; - - files|file|peek) - echo "📂 FILE VIEWING ALIASES (9 total)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - alias | grep "^peek\|^cat=\|^find=\|^grep=" - ;; - - short|ultra|fast) - echo "⚡ ULTRA-SHORT ALIASES (5 total)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "ld → rload (Load R package)" - echo "ts → rtest (Test R package)" - echo "dc → rdoc (Document R package)" - echo "ck → rcheck (Check R package)" - echo "bd → rbuild (Build R package)" - ;; - - *) - echo "❌ Unknown category: $category" - echo "Available: all, claude, r, gemini, quarto, git, files, short" - return 1 - ;; - esac -} - -# Category-specific shortcuts - REMOVED 2025-12-19: Use 'aliases <category>' directly -# alias aliases-claude='aliases claude' -# alias aliases-r='aliases r' -# alias aliases-gemini='aliases gemini' -# alias aliases-quarto='aliases quarto' -# alias aliases-git='aliases git' -# alias aliases-files='aliases files' -# alias aliases-short='aliases short' - - - -# ════════════════════════════════════════════════════════════════════ -# DASHBOARD UPDATE FUNCTION -# ════════════════════════════════════════════════════════════════════ -# Part of apple-notes-sync project -# Added: 2025-12-13 - -# Dashboard update function - scans .STATUS files and prepares for Claude -# DEPRECATED: Use 'pstat' instead -dashupdate() { - echo "⚠️ DEPRECATED: Use 'pstat' instead of 'dashupdate'" - echo "" - - local projects_dir="${1:-$HOME/projects/r-packages/active}" - local output_file="/tmp/project-status.json" - local scanner="$HOME/projects/dev-tools/apple-notes-sync/scanner.sh" - - echo "📊 Scanning project status..." - echo "" - - # Run scanner - if [[ -x "$scanner" ]]; then - "$scanner" "$projects_dir" "$output_file" - else - echo "❌ Scanner not found: $scanner" - return 1 - fi - - # Show summary - echo "" - echo "📋 Status JSON ready at: $output_file" - echo "" - echo "┌─────────────────────────────────────────────────┐" - echo "│ Next: Open Claude Desktop and say: │" - echo "│ │" - echo "│ [Dashboard] Update from project-status.json │" - echo "│ │" - echo "└─────────────────────────────────────────────────┘" - echo "" - - # Copy path to clipboard - echo "$output_file" | pbcopy - echo "📎 Path copied to clipboard" -} - -# Alias for quick access -# REPLACED 2025-12-19: alias dash='dashupdate' → Now a function in dash.zsh -# REMOVED 2025-12-19: alias dashopen='dashupdate && open -a "Claude"' -# REMOVED: alias do='dashopen' -# Reason: 'do' is a ZSH reserved word (for loops: for x do ... done) -# Aliasing it breaks parsing of any subsequent 'for' loops, causing: -# "parse error near `unset'" in Positron's shell integration script -# Use 'dashopen' or 'dash' directly instead - -# ─── iTerm2 Smart Context Switching ─────────────────────────────────────────── -[[ -f ~/projects/dev-tools/iterm2-context-switcher/zsh/iterm2-integration.zsh ]] && \ - source ~/projects/dev-tools/iterm2-context-switcher/zsh/iterm2-integration.zsh -export PATH="/opt/homebrew/opt/imagemagick@6/bin:$PATH" - -# Smart Function Dispatchers (ADHD-Optimized) -# NOTE 2025-12-25: Dispatchers in flow-cli plugin (loaded via flow.plugin.zsh) -# -# Active dispatchers in ~/projects/dev-tools/flow-cli/lib/dispatchers/: -# g - Git workflows -# mcp - MCP server management -# obs - Obsidian integration -# qu - Quarto publishing (restored 2025-12-25) -# r - R package development (restored 2025-12-25) -# -# Removed: v, vibe (deprecated - use 'flow' command instead) -# -# Not restored (personal shortcuts in .zshrc work better): -# cc/gem - Use ccy, gem* aliases below instead -# note - Use obs dispatcher -# timer - Use flow timer command - -# Terminal Management System (tmux + project launcher) - Added 2025-12-21 -[[ -f ~/.local/share/terminal-aliases.sh ]] && \ - source ~/.local/share/terminal-aliases.sh - -# ============================================ -# FLOW CLI PLUGIN - Added 2025-12-23 -# ============================================ -# Modern ZSH plugin architecture with single source location -# Replaces old ~/.config/zsh/functions/ and .zshenv loading -[[ -f ~/.zsh/plugins/flow-cli/flow.plugin.zsh ]] && \ - source ~/.zsh/plugins/flow-cli/flow.plugin.zsh - -# obs CLI completion -fpath=(~/.zsh/completions $fpath) - -## Shell Command Integration -test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh" - -# Nexus Desktop - Quick Launcher -alias nexus='cd ~/projects/dev-tools/nexus/nexus-desktop && npm start' - - -# ============================================ -# CLAUDE SKILLS MANAGEMENT - Added 2025-01-02 -# ============================================ -[[ -f ~/.config/zsh/functions/skill-helpers.zsh ]] && \ - source ~/.config/zsh/functions/skill-helpers.zsh - - -# ============================================ -# Ghostty config shortcuts - Added 2026-01-15 -# ============================================ -# Ghostty config shortcuts -export GHOSTTY_CONFIG="$HOME/.config/ghostty/config" -alias gconf='$EDITOR $GHOSTTY_CONFIG' - -# Quick open -alias gconfv='subl ~/.config/ghostty/config' diff --git a/zsh/functions/obs.zsh b/zsh/functions/obs.zsh deleted file mode 120000 index cdeeaca9a..000000000 --- a/zsh/functions/obs.zsh +++ /dev/null @@ -1 +0,0 @@ -/Users/dt/projects/dev-tools/obsidian-cli-ops/src/obs.zsh \ No newline at end of file