From 15fd143249beb31ca0e7bbfedba25e03fc37955e Mon Sep 17 00:00:00 2001 From: barkz Date: Tue, 18 Aug 2026 07:10:16 -0500 Subject: [PATCH 1/2] Update docs for the app-bundle rename and refresh test counts --- README.md | 36 +++++++++++++++++++++++++++--------- docs/TESTING.md | 10 +++++++++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c6e6bd4..3d96cf9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A local, terminal-first client for the Glean Client REST API. Inspired by Claude - **One-command install, and a Spotlight-launchable macOS app** — `python3 install.py` builds a single-file zipapp (~84 KB, still zero dependencies) and puts `glean` on your PATH, plus a - registered `Glean.app` so `Cmd+Space` → "Glean" opens the REPL. + registered `Glean Code.app` so `Cmd+Space` → "Glean Code" opens the REPL. [#11](https://github.com/barkz/glean-code-cli/pull/11) · [`e46d517`](https://github.com/barkz/glean-code-cli/commit/e46d517) - **Every REST call audited against Glean's published OpenAPI spec** — the new @@ -22,7 +22,7 @@ A local, terminal-first client for the Glean Client REST API. Inspired by Claude [#10](https://github.com/barkz/glean-code-cli/pull/10) · [`f81902d`](https://github.com/barkz/glean-code-cli/commit/f81902d) - **Repo hygiene fixes** — removed 35 tracked `__pycache__` artifacts, corrected stale docs - (the suite is 721 tests, not 604), and dropped a Spotlight ignore rule that macOS never + (the documented test count was stale by over a hundred), and dropped a Spotlight ignore rule that macOS never honored. [#12](https://github.com/barkz/glean-code-cli/pull/12) · [`17199b5`](https://github.com/barkz/glean-code-cli/commit/17199b5) @@ -76,9 +76,9 @@ python3 install.py ``` This builds a single-file zipapp (~84 KB, still stdlib-only) and installs it as -`glean` in `~/.local/bin`. On macOS it also creates `~/Applications/Glean.app` and -registers it with LaunchServices, so the REPL is launchable from Spotlight — -`Cmd+Space` → "Glean" → Enter opens it in a Terminal window. +`glean` in `~/.local/bin`. On macOS it also creates `~/Applications/Glean Code.app` +and registers it with LaunchServices, so the REPL is launchable from Spotlight — +`Cmd+Space` → "Glean Code" → Enter opens it in a Terminal window. | Flag | Effect | | --- | --- | @@ -87,11 +87,26 @@ registers it with LaunchServices, so the REPL is launchable from Spotlight — | `--dev` | App launches from the working tree, so edits apply with no rebuild | | `--prefix DIR` | Install the `glean` executable somewhere other than `~/.local/bin` | | `--verify` | Report what is currently installed | -| `--uninstall` | Remove everything the installer created (config is left alone) | +| `--uninstall` | Remove the CLI and the app bundle this installer created (config is left alone) | Re-run `python3 install.py` after pulling changes to refresh the snapshot, or install once with `--dev` and skip that step entirely. +**The bundle is called `Glean Code.app`, never `Glean.app`** — the latter is Glean's own +desktop client (`com.glean.desktop`). The installer reads `CFBundleIdentifier` before it +writes anything and refuses a bundle it did not create, and `--uninstall` skips one for the +same reason, so neither can damage an app it doesn't own: + +```text +x ~/Applications/Glean Code.app already exists and belongs to another app + (CFBundleIdentifier: com.glean.desktop). + Refusing to write into it. Move or rename that bundle, or run with --cli-only. +``` + +If you installed before this change you have a `Glean.app` bundle that we do own; the next +`python3 install.py` removes it and replaces it with `Glean Code.app`. That's why the +Spotlight entry changes name — nothing is lost. + ### Or just alias it ```bash @@ -221,7 +236,10 @@ Config lives at `~/.gleancode/config.json`. Change any key with `/config set =1,<2`. mcp 2.0.0 renamed `FastMCP` to `MCPServer` and removed the module this +server imports, so an unpinned install breaks it ([details](docs/MCP.md#mcp-sdk-v2)). The +REPL itself remains Python 3.9+ and stdlib-only. Setup for all three clients, the tool table, and the mock-mode rationale: **[docs/MCP.md](docs/MCP.md)**. @@ -265,13 +283,13 @@ python3 -m unittest discover tests/ ``` On macOS, keep bytecode caches out of the working tree — Spotlight indexes stray `.pyc` -files, and they outrank the `Glean.app` launcher in `Cmd+Space`: +files, and they outrank the `Glean Code.app` launcher in `Cmd+Space`: ```bash export PYTHONPYCACHEPREFIX="$HOME/.cache/python" ``` -721 tests covering the client and every mock response, commands and dispatch, config, UI, auth, completion, help docs, the mock corpus, indexing-walk, scaffold, the installer, and the MCP server. Development notes: [docs/TESTING.md](docs/TESTING.md). +740 tests covering the client and every mock response, commands and dispatch, config, UI, auth, completion, help docs, the mock corpus, indexing-walk, scaffold, the installer, and the MCP server. Development notes: [docs/TESTING.md](docs/TESTING.md). ## Documentation diff --git a/docs/TESTING.md b/docs/TESTING.md index f462831..4d5ec34 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -2,7 +2,7 @@ Notes on the test suite added during development of glean-code-cli. See [Running tests](../README.md#running-tests) for the user-facing instructions on how to run the tests. -All 699 tests pass. Here's what was added across the development passes: +All 740 tests pass. Here's what was added across the development passes: `tests/test_commands_extended.py` (155 new tests) — covers all previously untested commands: @@ -48,6 +48,14 @@ All 699 tests pass. Here's what was added across the development passes: - Cross-endpoint coherence — a `/search` result URL resolves through `/getdocuments` and `/summarize` to the same document, `/chat` citations track the question, `/getdocumentpermissions` owner is the document author, `/people` reads the roster - Custom corpus files — `mock_corpus_path` and `GLEAN_MOCK_CORPUS` overrides (config wins), bare-array form, and `CorpusError` on a missing file, invalid JSON, a document with no title, or an empty document list +`tests/test_install.py` (10 new tests) — covers app-bundle ownership in the installer: + +- `bundle_identifier` / `owns_bundle` — reads `CFBundleIdentifier` out of `Info.plist`; a missing bundle counts as ours (nothing to clobber), a foreign identifier and an unreadable or binary plist do not +- Refusal — `install_macos_app` exits rather than writing into a bundle it did not create, leaving that bundle's `Info.plist` byte-identical and creating no `Contents/Resources` +- Legacy cleanup — an old `Glean.app` is removed on install when we own it, and left alone when it belongs to another app +- Uninstall — removes our own bundle, and never deletes a foreign one (the regression that would have deleted a user's Glean Desktop install) +- The default `APP_DIR` is asserted **not** to be `Glean.app` + `tests/test_mcp.py` (9 new tests) — covers mock mode on the MCP server: - `_build_client` — forces live mode whatever `mode` the config file carries (including `auto`), and switches to mock only when `GLEAN_MOCK` is set; truthy spellings (`1`, `true`, `yes`, `on`) accepted, everything else ignored From 722ceb43ac2e0fd5c97e2ee6b56065c4be8e87ff Mon Sep 17 00:00:00 2001 From: barkz Date: Tue, 18 Aug 2026 07:22:33 -0500 Subject: [PATCH 2/2] Rename the CI workflow to release and publish the zipapp as an artifact --- .github/workflows/{tests.yml => release.yml} | 23 +++++++++++++++++++- README.md | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) rename .github/workflows/{tests.yml => release.yml} (65%) diff --git a/.github/workflows/tests.yml b/.github/workflows/release.yml similarity index 65% rename from .github/workflows/tests.yml rename to .github/workflows/release.yml index dc65ba9..bd30b83 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: tests +name: release on: push: @@ -54,3 +54,24 @@ jobs: if [ -n "$(git status --porcelain)" ]; then echo "::error::working tree dirty after build"; git status --short; exit 1 fi + + # One leg only — actions/upload-artifact@v4 rejects a second upload under + # the same name, and the zipapp is identical across the matrix anyway. + - name: Build the downloadable zipapp + if: matrix.os == 'ubuntu-latest' && matrix.python == '3.13' + env: + PYTHONPYCACHEPREFIX: ${{ runner.temp }}/pycache + run: | + python -c " + import pathlib, install + out = install.build_zipapp(pathlib.Path('$RUNNER_TEMP/glean-code.pyz')) + print(f'built {out} ({out.stat().st_size / 1024:.0f} KB)') + " + + - name: Upload glean-code.pyz + if: matrix.os == 'ubuntu-latest' && matrix.python == '3.13' + uses: actions/upload-artifact@v4 + with: + name: glean-code-pyz + path: ${{ runner.temp }}/glean-code.pyz + if-no-files-found: error diff --git a/README.md b/README.md index 3d96cf9..36f23a6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![Glean](https://img.shields.io/badge/Glean-343CED?style=for-the-badge&logoColor=white) ![Python](https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white) ![Claude](https://img.shields.io/badge/Claude-D97757?style=for-the-badge&logo=claude&logoColor=white) -[![Tests](https://img.shields.io/github/actions/workflow/status/barkz/glean-code-cli/tests.yml?style=for-the-badge&label=tests&logo=githubactions&logoColor=white)](https://github.com/barkz/glean-code-cli/actions/workflows/tests.yml) +[![Release](https://img.shields.io/github/actions/workflow/status/barkz/glean-code-cli/release.yml?style=for-the-badge&label=release&logo=githubactions&logoColor=white)](https://github.com/barkz/glean-code-cli/actions/workflows/release.yml) A local, terminal-first client for the Glean Client REST API. Inspired by Claude Code. Built in Python with zero runtime dependencies.