Commit Graph
11 Commits
Author SHA1 Message Date
vhaudiquet 00adf092ff fix(forge,claw): forge keys separate the issue from the pull
The watch key encoded source, repo, and number but not the thread
kind, and on GitLab an issue and a merge request share one number
space: iid 7 twice produced one key, one snapshot, and comments on
the merge request landing in the issue (or a 404 fallback that
misrouted the other way). The key carries the kind now —
{source}:{kind}:{owner}/{name}#{number}, with GitLab spelling the
pull variant mr — comment and snapshot route outright by kind, and a
kind-less payload parses to the unparsable key instead of guessing
issue. The claw's callers thread the kind from the payload and strip
the segment where the bare repo is wanted; pre-kind stored keys parse
as None rather than misroute. Four route-pinning wiremock tests cover
the GitLab split, and the GitHub/Gitea clients take the kind without
using it (their issues and PRs share the same REST space).
2026-11-05 19:03:52 +01:00
vhaudiquet e92739aa1b chore: collapse the ifs the 1.98 clippy flags
The pinned toolchain's clippy grew opinions the older lint let stand:
nested if/if-let pairs it wants as let-chains, and a modulo test it
wants as is_multiple_of. Machine-applied collapses, fmt-settled, no
behavior change — the gauntlet runs clean again.
2026-10-27 01:12:46 -05:00
vhaudiquet e4f4a3a10b chore: enforce missing_docs from the workspace manifest
One [workspace.lints.rust] table replaces the deny attribute
scattered across every lib.rs, and each crate opts in through
[lints]. The lint now also reaches the integration-test crates,
whose roots gain their one-line docs.
2026-10-25 07:02:48 +02:00
vhaudiquet 15d3478429 fix(calendar): the source constructor reports CalendarError 2026-10-25 07:02:48 +02:00
vhaudiquet 90212d1e0f refactor(claw): the forge kind is the integration's — config.rs carries no forge code
The last forge content in config.rs was vocabulary, not data:
`ForgeKind` (name/parse/token_env/default_base) and the pure
`resolve_token` helper. By the same rule that moved `Watch` to the
watch table and left `CalendarWatch` in the calendar integration,
the kind belongs to the crate that speaks the forges.

- `rhema-forge-integration` gains `kind::ForgeKind` and
  `resolve_token`, with the parse and token-fallback tests moved
  alongside — the claw's config tests were testing the integration's
  type through a re-export.
- The claw's surfaces import the type from the integration directly;
  the crate root re-exports it, so `rhema_claw::ForgeKind` keeps
  resolving for everything downstream.

config.rs is now config: credentials, the surface, paths, cadence,
and nothing that knows what a forge or a calendar is.
2026-10-24 16:48:18 +02:00
vhaudiquet 7f6c13f608 chore: apply cargo fmt 2026-10-24 02:02:39 +02:00
vhaudiquet 818079d1f4 refactor(claw): the calendar table is the one truth — live, not config
Same move as the watches, and the config's last piece of integration
state goes with it:

- `rhema-calendar-integration` owns the calendar table now
  (`store.rs`): SQLite in the shared dispatch database, the pattern
  the claw's watch table established. `CalendarWatch` gains the
  `validate` the config's boot check used to run — per-kind URL and
  credential rules, plus the lead-under-horizon check — so an invalid
  calendar is loud at the one door every writer shares.
- `CalendarSource::from_store` reads the table fresh on every detect
  pass (the forge source's pattern): a calendar added over the route
  is live next tick, a removed one stops polling, no restart in the
  story. The static constructor stays for tests.
- `POST/DELETE/GET /v1/calendars` on the daemon: the POST body is the
  integration's `CalendarWatch` shape, validated at the table; DELETE
  takes `?name=`; the api listing names the door.
- `ClawConfig.calendars` is gone. A config still carrying it is
  refused at parse time, like the retired `watches:` seed. The
  config-side validation and its tests moved with the type.

The config file now carries only what boot needs: credentials, the
surface, paths, the poll cadence. Everything the daemon reconfigures
at runtime lives in its tables, behind its HTTP doors.
2026-10-24 01:52:09 +02:00
vhaudiquet b70a56c325 refactor(calendar): move the reminder source beside the feeds
CalendarWatch, the client resolution, and the slot policy were all
feed domain living in the claw's config and source tree; only the
extension adapter was the claw's. The reminder source now ships in
the integration as the default answer to "what does a start time
mean": one slot per lead time, calendar:<name> keys, fed to the
consumer's dispatcher. The crate doc drops its no-policy claim to
match, and the claw's resident prefixes take the calendar prefix
from the integration so the spelling cannot drift.
2026-10-20 05:53:43 +02:00
vhaudiquet fc0cbbcb6b refactor(forge): classify account notifications beside the vocabulary
The triage mapped the forges' notification reasons onto the claw's
verdicts, but it co-evolves with the vocabulary, not with the claw:
a reason that enters it (Gitea's collapsed shape) needs a verdict in
the same change, and its tests pin the mapping against the
vocabulary's own types. It now lives in the integration crate as the
default classification; a consumer may reclassify on top. The claw
imports it like the rest of the forge seam.
2026-10-20 05:49:14 +02:00
vhaudiquet 04549a7df5 fix(claw): dispatch reason-less forge notifications to the thread's agent
Gitea's notifications feed names no per-row reason, so the adapter
collapses every row under one fixed NotificationReason::Other spelling
— and the claw's triage mapped every Other to Surface: the notification
reached the device queue and never a dispatch. A comment on a thread
the account authored could therefore never wake the agent on a
reason-less forge, whatever the watches said.

The adapter now publishes that spelling as gitea::COLLAPSED_REASON —
it is the seam's contract, not a detail — and the triage treats it as
the known shape it is: a notification on a thread of the account's own
dispatches the implementer. A spelling no adapter owns still surfaces;
an unknown shape remains the user's to judge, never the agent's to
guess at.
2026-10-19 19:40:44 +02:00
vhaudiquet 81da26b955 feat(rhema-code): add the colors setting with four palettes
The stored `colors` key names a palette — rhema (the default,
Jadeite), aquamarine, black-and-white, or dracula — and the
Appearance page of /settings cycles it live, like the theme and
icon toggles beside it. Each palette carries a dark and a light
appearance under the existing `theme` key; dracula's light side is
derived, the official palette ships only dark.

The appearance decision moves off token comparison: Theme now
answers is_dark() from the ground/text luminance, so palettes
beyond the original two get the right per-profile fallback tones.
2026-10-17 04:28:31 +08:00