Todoist uses "every 5th" for monthly-on-the-5th; map it to
FREQ=MONTHLY;BYMONTHDAY=N (1..=31). Surfaced by the Todoist import.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make heph a real task driver and the complete daemon-API surface (the
three-surface model's capture/scripting role). Structured fields are flags.
- datespec: human date parsing (today/tomorrow/+3d/fri/ISO, injectable today
for deterministic tests) + compact display; recurrence presets + the common
Todoist-style natural-language forms ("every 3 days", "every fri", "every
April 15") + raw RRULE passthrough. Table-driven unit tests.
- main: new commands covering every RPC — list, done/drop/skip, attention,
edit (reschedule via task.set_schedule), promote, show, log (append/tail),
health, node update/rm, resolve, links/backlinks, link add,
project add [--parent], sync [--status], conflicts [resolve]. task/next/list
show human dates; projects referenced by name (resolved, errors if absent).
- tests/cli.rs: real-socket process tests for the new verbs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Close the auth loop: clients obtain a bearer token and present it to the
hub (tech-spec §13).
- oauth module: DeviceFlow (RFC 8628 — discover, start, poll handling
authorization_pending/slow_down, refresh) + StoredToken + TokenStore
(OS keyring via `keyring`, in-memory for tests) + current_bearer (loads
and refreshes-on-expiry).
- heph auth login/logout: runs the device flow, prints the verification
URL + user code, caches the token in the keyring.
- sync_once gains a bearer arg; the daemon (Daemon::spawn_sync_loop +
sync.now) obtains it via current_bearer; RemoteStore attaches it to /rpc.
--oidc-issuer/--oidc-client-id configure the spoke/client.
- Fix a latent panic: reqwest::blocking spins its own runtime and panics
inside the daemon's spawn_blocking pool. All blocking auth/proxy HTTP
(OidcVerifier JWKS, DeviceFlow, RemoteStore) now uses runtime-free `ureq`;
async reqwest remains only for sync_once. (Caught by the new e2e test.)
- Tests (offline): device flow + refresh + token store vs a mock OAuth
server; a full spoke->authenticated-hub loop (valid token accepted,
missing token rejected) signed by a runtime-generated RSA key.
112 tests green; clippy -D warnings + fmt + prek clean. Slice 10 (auth)
complete; next is heph.nvim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Slice query-surface, part 2 (tech-spec §6). Migration v2 adds an FTS5
external-content table over nodes(title, body), kept in sync by
insert/update/delete triggers (with a backfill for existing rows).
- Store::search(query): owner-scoped, tombstones excluded, best-match
first (FTS5 MATCH + rank). Exposed over RPC; `heph search` and
`heph journal` CLI commands added.
3 search integration tests (title/body match, edits reflected via trigger,
tombstone exclusion, all insert paths indexed). 79 tests green. This
completes the local feature surface; the remaining slices are the
distributed/auth/nvim layer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>