Commit graph

25 commits

Author SHA1 Message Date
11aa25c9f4 feat(heph-tui,hephd): surface sync health (last-sync age, conflicts, auth failure)
All checks were successful
Build / validate (pull_request) Successful in 6m11s
A spoke could be silently failing to sync (expired token → 401, or hub
unreachable) with the only signal buried in the daemon log. Now:

- hephd tracks SyncHealth (last attempt/success time, last error, auth-failure
  flag) from the background sync loop and sync.now, classifying a 401 as an auth
  failure. sync.status returns it plus the pending merge-conflict count.
- heph-tui shows a live status-line indicator (spoke only): '⟳ <age>' since the
  last good sync, red '⚠ auth' when re-login is needed, '⚠ offline' when the hub
  is unreachable, and '⚠ N conflicts' when conflicts are pending. The event loop
  polls on a 2s tick so the age advances and failures appear while idle.
- docs: recommended Authentik access/refresh token validity to stop frequent
  re-logins (with the iOS PWA localStorage-eviction caveat).

Closes the 'Add hub connection status to heph-tui' and 'Spoke sync health:
surface unhealthy state instead of silent 401 spam' backlog items.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 10:19:11 -07:00
a0be0f1085 doc(heph-pwa): in-app Authentik login replaces manual token paste
Document the PKCE 'Login with Authentik' flow, the hub /config zero-config
discovery, and the redirect-URI prerequisite on the Authentik heph provider.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 07:09:42 -07:00
936c2635ef doc(heph-pwa): production runbook — host the app from the hub (indri) with OIDC
All checks were successful
Build / validate (pull_request) Successful in 6m18s
Add host-heph-pwa.md: a deployment how-to for serving the PWA from the canonical
hub in the hub/spoke OIDC setup (post-release) — fetch the shell at the hub's
tag, add --web-root, terminate TLS (tailscale serve / reverse proxy), and the
token-paste caveat with the device-code-login follow-up. Cross-linked from
heph-pwa and the how-to index.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:17:25 -07:00
b24a148add doc(heph-pwa): how-to card, index entry, changelog fragment
Document serving the app from the hub (--web-root), connecting (hub URL +
optional token), quick-add syntax, voice, triage, and the deliberate
design choices (PWA over native iOS; online-only; token paste vs device flow)
with their known limitations to revisit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:59:38 -07:00
443763489b C2(hephd-self-update): finalize — single self-update how-to + changelog
All checks were successful
Build / validate (pull_request) Successful in 6m10s
Collapse the eight Mikado scaffolding cards (+ goal card) into one
user-facing how-to, docs/how-to/self-update.md: what self-update is and
how to enable it. The per-card breakdown was build-time scaffolding, not
documentation. Keeps the changelog fragment; updates the how-to index.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:00:37 -07:00
240c8a9f68 C2(hephd-self-update): close service-env-forge-access
Public repo => anonymous HTTPS clone, no credentials (the SSH/canonical
premise was wrong: that was the access-restricted cargo registry, not git
clone). Install URL points at the canonical public host (verified end to
end); the service template bakes cargo onto PATH. Card rewritten to
reflect what actually happened.
2026-06-04 14:47:05 -07:00
59822d7257 C2(hephd-self-update): impl service-env-forge-access (public HTTPS, cargo on PATH)
The repo is public, so self-update needs no credentials: cargo install
--git is a plain anonymous clone (NOT the access-restricted Forgejo cargo
registry, which is what required forge.ops.eblu.me). Point INSTALL_GIT_URL
and the releases poll at the canonical public host over HTTPS — verified
end-to-end (cargo install --git https://forge.eblu.me/... --tag v1.0.3
builds a working hephd with zero auth).

Make the headless service able to run the apply path: 'heph daemon
start --self-update' (default off) generates a launchd/systemd service
that passes --self-update and bakes a PATH (incl ~/.cargo/bin) + HOME so
the minimal service env can find cargo. restart preserves the setting.
Default (no flag) services are byte-identical to before. Template + URL
behavior covered by unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 14:46:34 -07:00
c237be6604 C2(hephd-self-update): close self-restart-after-update
Restarter + ProcessRestarter wired: install then exit(0) so the service
manager respawns the new binary; restart only on a successful install.
Unit-tested via injection.
2026-06-04 13:54:50 -07:00
e7cb86efdf C2(hephd-self-update): close cargo-install-from-tag
Installer trait + CargoInstaller + apply_update landed and unit-tested
via injection. Real cargo execution is gated on the deployment env
(service-env-forge-access).
2026-06-04 13:52:45 -07:00
fd76aa0b3a C2(hephd-self-update): close verify-hub-dropout-resilience
All checks were successful
Build / validate (pull_request) Successful in 5m24s
Spoke survival across hub downtime is now covered by a test; added a
client timeout so a black-hole hub can't stall the loop.
2026-06-04 13:47:53 -07:00
2a7a3ec270 C2(hephd-self-update): close service-respawn-on-clean-exit
systemd unit now Restart=always; both managers respawn after a clean exit.
2026-06-04 13:44:56 -07:00
544c8bba0e C2(hephd-self-update): impl systemd Restart=always for clean-exit respawn
Self-restart works by exiting cleanly and letting the service manager
respawn the new binary. launchd already does this (KeepAlive=true), but
the systemd user unit was Restart=on-failure, which ignores a clean
exit (code 0). Switch to Restart=always + RestartSec=1, update the unit
test, and note in run-the-daemon that existing Linux installs must
`heph daemon restart` once to regenerate the unit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:44:36 -07:00
758854478b C2(hephd-self-update): close self-update-poll-loop
All checks were successful
Build / validate (pull_request) Successful in 3m56s
Notify-only poller landed: ticks on the interval, logs when a newer
release is available. The daemon now self-reports update availability.
2026-06-04 13:42:48 -07:00
35569b0649 C2(hephd-self-update): close self-update-opt-in-flag
--self-update flag + config plumbing landed; opt-in observable via the
startup log line.
2026-06-04 13:40:47 -07:00
4a0094f955 C2(hephd-self-update): close release-poll-version-check
Version-compare + forge release parsing landed and unit-tested.
2026-06-04 13:37:14 -07:00
e6524fddbb C2(hephd-self-update): plan add goal + prerequisite cards for hephd self-update
All checks were successful
Build / validate (pull_request) Successful in 5m23s
Kick off the C2 Mikado chain for an opt-in (default-off) hephd
self-update mode (forge-poll -> cargo install from tag -> self-restart).
Goal card plus eight prerequisite cards, indexed from how-to.md:

  release-poll-version-check, self-update-opt-in-flag (leaves)
    -> self-update-poll-loop                 (notify-only core)
  service-env-forge-access (leaf, the cargo/forge blocker)
    + self-update-poll-loop -> cargo-install-from-tag
  service-respawn-on-clean-exit (leaf, systemd Restart=always)
    + cargo-install-from-tag -> self-restart-after-update
  verify-hub-dropout-resilience (leaf, lock in the base-case guarantee)

Grounded in research of hephd's sync loop, daemon lifecycle, the
launchd/systemd service templates, and the forge releases API.
Captured from Hephaestus task 01KTA2NSNRYT902HC3VRW00S1J.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:20:46 -07:00
521e5d62df docs: install-heph defaults to the v1.0.0 release tag (v1 is out)
All checks were successful
Build / validate (pull_request) Successful in 5m5s
Replace the pre-release 'install from feature/v1-prototype' instructions with
`--tag v1.0.0` as the default, and document `--branch main` as the track-
unreleased-work alternative.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 09:47:23 -07:00
c266f7ee4a docs: release bumps Cargo.toml/lock on a tag-only commit; --version reports X.Y.Z (sha)
Documents the desired end state before the code change (C1 docs-first):
- release.yaml bumps the workspace version into a commit only the tag points
  at, keeping main at 0.0.0
- heph/hephd --version will report the release version plus the build SHA

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 09:37:14 -07:00
a0b04eefda feat: multi-tenancy seam (resolve_owner) + hub-setup how-to (v1 prep)
All checks were successful
Build / validate (pull_request) Successful in 10m34s
The cheap "seam" that keeps the single-owner hub from calcifying, ahead of
the gilbert -> indri bring-up:

- Replace the single-tenant gate `Store::authorize_owner_sub(sub) -> bool`
  with `resolve_owner(sub) -> Option<owner_id>`. The hub auth middleware now
  resolves the token's identity to the owner it may act as (Some -> allow,
  None -> 403). Behavior is identical for the single-owner hub (claim-on-first;
  strangers still 403), but the contract no longer assumes one global owner, so
  serving N owners later is additive, not a rewrite. The per-request owner is
  marked at the exact line where downstream scoping wires through.
- New how-to docs/how-to/set-up-sync-hub.md: stand up the hub and connect an
  existing device as an offline-capable spoke, the data-safe way (Path A: the
  hub adopts the device's identity rather than rewriting the device).

The decision (cheap seam now, defer full multi-tenancy + adoption rewrite) is
recorded in the Adoption + multi-tenant task's context doc. Two enabler gaps
the how-to surfaced (heph daemon hub/spoke service flags; Path-A seeding tool)
are filed as Hephaestus tasks.

Green: 228 tests, clippy -D warnings + fmt + prek clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 07:08:39 -07:00
d36ed18590 infra: extract heph.nvim into its own forge repo
Some checks failed
Build / validate (pull_request) Failing after 1m12s
The Neovim plugin now lives at eblume/hephaestus.nvim (plugin at the repo
root). Remove heph.nvim/ from the monorepo and the build/test wiring that
referenced it:

- Dagger: drop the test_nvim function + the pinned-Neovim NVIM_VERSION
- build.yaml: drop the `dagger call test-nvim` step
- drop the mise run test-nvim task and .stylua.toml + the stylua prek hook
  (no Lua remains in the monorepo)
- install-heph.md: install via a plain lazy.nvim spec pointing at the
  plugin repo over SSH (no more local-dir checkout hack)
- README / AGENTS / heph-nvim.md: note the surface lives in its own repo

The CLI/TUI -> nvim integration is unchanged (they shell out to `nvim`
expecting the heph plugin installed). The v1-prototype tech-spec §14 build
record and prior changelog fragments are left as frozen history.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 22:42:39 -07:00
6514296b87 docs: reframe tech-spec as historical; heph self-hosts its roadmap
v1 reached Todoist feature-parity, so remaining/future work is now tracked
in heph itself — tasks in the Hephaestus project (heph view ondeck) — not in
a doc. Renamed docs/reference/tech-spec.md -> v1-prototype-tech-spec.md and
rewrote all 27 [[tech-spec]] wiki-links + README/changelog path refs (docs
checks green). Retitled + bannered the spec as a historical v1 build record
and froze its §14 tracker. AGENTS.md gains a "Planning future work" section
(capture via `heph task --project Hephaestus`, triage in heph-tui On Deck);
README status reflects parity + the three daily-driver surfaces. The design
doc remains the living rationale.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 20:19:35 -07:00
1315b9ce18 docs: daemon lifecycle becomes an explicit service (connect-only surfaces)
Some checks failed
Build / validate (pull_request) Has been cancelled
A surface-owned, auto-spawned daemon can't be shared once the CLI is also a
first-class client — so drop auto-spawn and manage the daemon as an OS service.

- design §4: daemon lifecycle = explicit OS service; surfaces connect-only
- heph-nvim.md: rewrite the daemon-lifecycle section (connect-only) + history
- new how-to/run-the-daemon.md (heph daemon start/stop/restart/status); indexed
- install-heph.md: post-install is `heph daemon start`; plugin no longer spawns
- tech-spec §14: mark the managed-daemon entry superseded
- changelog fragment

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 21:07:11 -07:00
0b32ed4397 feat(tooling): mise run import-todoist — seed a heph store from Todoist
All checks were successful
Build / validate (pull_request) Successful in 7m1s
Turn the one-off Todoist importer into a documented, repeatable mise task.
Self-contained (spawns its own hephd), dry-run by default into a throwaway
store, `-- --commit` writes into the real store after backing it up. Auth via
TODOIST_TOKEN or TODOIST_OP_REF (op://). Mapping per design §6.2.1:
project hierarchy (+ Inbox→unfiled), priority→attention by meaning, due→do-date,
NL recurrence, descriptions + sub-tasks→canonical-context doc.

- mise-tasks/import-todoist
- docs/how-to/import-todoist.md (+ how-to index, reference mise-tasks table)
- changelog fragment

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 20:15:05 -07:00
652d2e89e6 heph: dev/installed isolation — mise run dev task + install how-to
Some checks failed
Build / validate (pull_request) Failing after 10m32s
- mise-tasks/dev runs the working-tree hephd on isolated .dev/ paths (gitignored)
  so in-repo development never touches the installed daemon's data; point a dev
  nvim at it via HEPH_SOCKET/HEPH_DB.
- docs/how-to/install-heph.md: install heph/hephd from the forge (build from
  source), the lazy.nvim `dir` setup for the subdir plugin, and dev isolation.
- gitignore .dev/ and the transient .claude scheduled-task state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:39:59 -07:00
28c1f7886a Initial commit 2026-05-31 06:13:36 -07:00