diff --git a/docs/reference/heph-nvim.md b/docs/reference/heph-nvim.md index 0a5854e..3295457 100644 --- a/docs/reference/heph-nvim.md +++ b/docs/reference/heph-nvim.md @@ -57,9 +57,11 @@ the per-task log, and context-item **promotion** arrive in slices 11b/11c. The headless e2e suite drives the plugin in `nvim --headless` against a real `hephd` over a temp socket, asserting both buffer contents and resulting DB state (via an isolated RPC session). It uses a **self-contained busted-style -runner** (`tests/e2e/runner.lua`) — no external plugins, no network — so CI is -deterministic. `make test` builds the daemon and runs it; a deliberately -failing spec exits non-zero (no false-green). +runner** (`tests/e2e/runner.lua`) — no external plugins, no network — so it is +deterministic. `mise run test-nvim` builds the daemon and runs the suite against +system-installed Neovim; a deliberately failing spec exits non-zero (no +false-green). In CI the same suite runs inside a Dagger container that provides +Neovim + the Rust toolchain (slice 11c). ## Related diff --git a/docs/reference/tech-spec.md b/docs/reference/tech-spec.md index aa9e5ea..a5dc5f6 100644 --- a/docs/reference/tech-spec.md +++ b/docs/reference/tech-spec.md @@ -345,14 +345,14 @@ See [[design]] §5–§7 for the constraints later phases impose on present choi - ✅ **Auth — client side (§13, slice 10b):** OAuth2 **device-code flow** (`hephd::oauth::DeviceFlow`: discover → start → poll handling `authorization_pending`/`slow_down`, + refresh). `TokenStore` (OS keyring via `keyring`, in-memory for tests); `current_bearer` refreshes on expiry. `heph auth login` runs the flow + caches the token; spokes (`sync_once`) and `client` mode (`RemoteStore`) attach the bearer, refreshing as needed (`--oidc-issuer`/`--oidc-client-id`). **All auth/proxy HTTP uses `ureq`** (runtime-free blocking) — `reqwest::blocking` panics inside the daemon's `spawn_blocking`; async `reqwest` remains only for `sync_once`. Tested offline against a mock OAuth server (device flow, refresh, store) + a full spoke⇄authed-hub loop. - ✅ **CLI (§1):** `heph` next/task/doc/get/export/search/journal/**auth login·logout**. - ✅ **CI (§9):** `.forgejo/scripts/build` runs fmt/clippy/test (self-bootstrapping rustup). -- ✅ **`heph.nvim` slice 11a (§8) — the primary surface begins:** the Lua plugin (`heph.nvim/`) as a thin client of the `hephd` unix socket. **RPC client** over a `vim.uv` pipe (blocking `call` via `vim.wait`; id-demuxed; partial-line buffered; `luanil` so JSON `null`→`nil`; isolated `Session`s for tests). **Buffer-backed nodes** — `heph://node/` buffers (`buftype=acwrite`), `BufReadCmd`→`node.get` / `BufWriteCmd`→`node.update` (whole-buffer body, CRDT-diffed; exact round-trip). **`[[wiki-link]]` follow** on `` via a new **`node.resolve {title}`** RPC (exact alias-then-title match, the same mapping that materializes `wiki` links — never fuzzy `search`; unresolved links allowed). **Daily journal** (`:Heph today`/`journal `, idempotent). `:Heph` command surface + completion. **Headless e2e (§9):** drives the plugin in `nvim --headless` against a real daemon over a temp socket via a **self-contained busted-style runner** (`tests/e2e/runner.lua` — no external plugins/network, deterministic CI exit codes); specs cover journal round-trip, follow-link (+ unresolved no-op), and link-two-docs/backlink. `make -C heph.nvim test` builds the daemon and runs it. +- ✅ **`heph.nvim` slice 11a (§8) — the primary surface begins:** the Lua plugin (`heph.nvim/`) as a thin client of the `hephd` unix socket. **RPC client** over a `vim.uv` pipe (blocking `call` via `vim.wait`; id-demuxed; partial-line buffered; `luanil` so JSON `null`→`nil`; isolated `Session`s for tests). **Buffer-backed nodes** — `heph://node/` buffers (`buftype=acwrite`), `BufReadCmd`→`node.get` / `BufWriteCmd`→`node.update` (whole-buffer body, CRDT-diffed; exact round-trip). **`[[wiki-link]]` follow** on `` via a new **`node.resolve {title}`** RPC (exact alias-then-title match, the same mapping that materializes `wiki` links — never fuzzy `search`; unresolved links allowed). **Daily journal** (`:Heph today`/`journal `, idempotent). `:Heph` command surface + completion. **Headless e2e (§9):** drives the plugin in `nvim --headless` against a real daemon over a temp socket via a **self-contained busted-style runner** (`tests/e2e/runner.lua` — no external plugins/network, deterministic exit codes); specs cover journal round-trip, follow-link (+ unresolved no-op), and link-two-docs/backlink. `mise run test-nvim` builds the daemon and runs the suite (dev: system nvim/rustc; CI: a Dagger container provides them — slice 11c). **Not yet done (resume order)** > The Rust backend is feature-complete; `heph.nvim` is being built in checkpointed sub-slices (11a done). The rest are non-blocking polish + an end-of-v1 sweep (§11). 1. ⏳ **`heph.nvim` slice 11b (§8) — task views:** enrich `list` to titled rows; Tactical `next` + Organizational `list` views; task capture, set-attention, mark done/dropped; per-task log quick-append; `vim.ui.select` pickers (Telescope auto-upgrade when present). e2e: capture→next→context→checklist→done, and the recurring fresh-checklist workflow. -2. ⏳ **`heph.nvim` slice 11c (§8) — promotion + CI runner:** add **`task.promote`** (mint a committed task from a `- [ ]` context-item line, rewrite it into a `[[link]]`; `item_ref` = 1-based code-fence-aware context-item index) + the in-buffer promote flow + its e2e; extend `.forgejo/scripts/build` to build `hephd` and run the nvim e2e suite (runner needs `neovim`; the self-contained busted runner needs **no** plenary). +2. ⏳ **`heph.nvim` slice 11c (§8) — promotion + CI runner:** add **`task.promote`** (mint a committed task from a `- [ ]` context-item line, rewrite it into a `[[link]]`; `item_ref` = 1-based code-fence-aware context-item index) + the in-buffer promote flow + its e2e; **CI via Dagger** — a `test` function in `.dagger/` (mirroring `build_docs`) bakes a pinned `neovim` + Rust toolchain into a container and runs the e2e suite (the self-contained busted runner needs **no** plenary). Dev stays native: `mise run test-nvim` against system nvim/rustc; Dagger is the CI-only provisioner. The Forgejo workflow shrinks to `dagger call test`. 3. ⏳ **`heph.nvim` slice 11d (§6/§8) — DEFERRED, post-parity:** daemon **server-push** notification framing (no-`id` lines on the socket; the client read-loop already demuxes them) + the **dirty-buffer reconcile** (the §8 "known-hard" case) + the "update-arrives-while-open" e2e (§9). 4. ⏳ **Adoption refinement + multi-tenant (§13) — non-blocking:** local→authed **adoption** currently rewrites `owner_id` (`adopt_owner`) but not yet the owner-embedded deterministic ids (journal/tag) + their links; and the hub is single-tenant (one owner per store) — owner-per-token storage is a future extension. 5. ⏳ **Dependency-refresh pass (§11) — before declaring v1 done:** sweep all external deps to latest stable (e.g. `keyring` 3→4, which restructured to `keyring_core`), re-run the full suite. diff --git a/heph.nvim/Makefile b/heph.nvim/Makefile deleted file mode 100644 index 0243c55..0000000 --- a/heph.nvim/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# heph.nvim — headless e2e suite (tech-spec §9). -# -# `make test` builds the daemon, then drives the plugin in headless Neovim -# against a real hephd over a temp socket, via a self-contained busted-style -# runner (no external plugins, no network — see tests/e2e/runner.lua). - -HEPHD_BIN ?= $(CURDIR)/../target/debug/hephd -export HEPHD_BIN - -.PHONY: test build-hephd - -build-hephd: - cargo build -p hephd --manifest-path $(CURDIR)/../Cargo.toml - -test: build-hephd - nvim --headless -u NONE -c "luafile tests/e2e/run.lua" diff --git a/heph.nvim/README.md b/heph.nvim/README.md index 173e67c..9fc630f 100644 --- a/heph.nvim/README.md +++ b/heph.nvim/README.md @@ -47,9 +47,10 @@ require("heph").setup({ The e2e suite drives the plugin in headless Neovim against a real daemon: ```bash -make test # builds hephd, runs the headless e2e suite +mise run test-nvim # builds hephd, runs the headless e2e suite ``` The suite uses a small self-contained busted-style runner (`tests/e2e/runner.lua`) — no external plugins and no network, so it is -deterministic in CI. It needs only Neovim (≥ 0.10) and a built `hephd`. +deterministic. Dev runs use system-installed Neovim (≥ 0.10) + rustc; CI runs +the same suite inside a Dagger container that provides them (slice 11c). diff --git a/mise-tasks/test-nvim b/mise-tasks/test-nvim new file mode 100755 index 0000000..f0a1047 --- /dev/null +++ b/mise-tasks/test-nvim @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +#MISE description="Run the heph.nvim headless e2e suite (builds hephd, drives nvim --headless)" + +# Dev path: uses system-installed nvim + rustc. CI runs the same suite inside a +# Dagger container that provides them (tech-spec §9, slice 11c). The runner is +# self-contained (tests/e2e/runner.lua) — no external nvim plugins, no network. + +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +if ! command -v nvim >/dev/null 2>&1; then + echo "error: nvim not found on PATH (install Neovim >= 0.10)" >&2 + exit 1 +fi + +echo "== building hephd (debug) ==" +cargo build -p hephd + +export HEPHD_BIN="$ROOT/target/debug/hephd" + +echo "== heph.nvim headless e2e ==" +cd "$ROOT/heph.nvim" +nvim --headless -u NONE -c "luafile tests/e2e/run.lua"