Check-ins with non-propagating tags:
|
2026-05-16
| ||
| 18:01 | chore: bump submodule pins (leaf/v0.0.12,bridge/v0.0.4) leaf check-in: 5070f96573 user: 41898282+github-actions[bot]@users.noreply.github.com tags: trunk, v0.0.20 | |
| 17:55 |
feat(hub): expose embedded NATS WebSocket endpoint (#177)
Adds Config.EnableWebSocket (opt-in; default off for security since no TLS/WSS is wired up here) plus Config.NATSWebSocketPort (0 = auto-pick, mirroring the sibling NATSClientPort / NATSLeafPort convention). When enabled, the embedded nats-server binds a WebSocket listener on 127.0.0.1:NNNN with NoTLS=true. Surfaces the resolved listener URL via the new Hub.NATSWebSocketURL() getter, which returns "ws://127.0.0.1:NNNN" when WebSocket is enabled and "" otherwise — same shape as NATSURL() / LeafURL(). Tests cover the disabled-by-default contract, the auto-pick URL shape, and an end-to-end round trip: a nats.go client dials the ws:// URL, subscribes to a subject, and receives a payload published by a TCP client on the same embedded server. Fixes #176 Co-authored-by: Dan Mestas <[email protected]> check-in: ae52558ba4 user: [email protected] tags: trunk, leaf/v0.0.12, bridge/v0.0.4 | |
|
2026-05-13
| ||
| 21:03 |
fix: exclude modernc driver registration from wasm builds (#169)
The init()-based modernc registration added in #166 (v0.0.18) blocked wasm builds because modernc references syscalls unavailable under js/wasm. Adds a //go:build !js && !wasm constraint to hub/driver.go so the registration is skipped on wasm targets — wasm consumers register their own driver (libfossil's ncruces driver supports wasm via its ncruces_js.go file). Native builds are unchanged: hub still auto-registers modernc. Wasm builds: hub package now compiles successfully under GOOS=js GOARCH=wasm; consumer brings its own driver. Verified: GOOS=js GOARCH=wasm go vet ./hub/... # clean GOOS=js GOARCH=wasm go build ./hub/... # success go test ./hub/... -timeout 120s # 38/38 pass on native Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> check-in: 0fa13d595b user: [email protected] tags: trunk, v0.0.19 | |
| 20:27 |
refactor(hub): register modernc SQL driver internally (#166)
The hub package promised consumers wouldn't need to import libfossil directly, but they still had to blank-import libfossil's SQL driver to satisfy the underlying db layer's registration requirement. Move the blank import into hub itself (hub/driver.go) so the package fulfills its own dependency. Consumers like sesh can now reduce their main.go to a plain `import "github.com/danmestas/EdgeSync/hub"` (or whatever wrapper they use) without taking a direct dep on libfossil's internal SQL machinery. modernc is registered as the production default. If a consumer ever needs ncruces (WASM/WASI), an escape hatch can be added then. Tests in hub/ drop their now-redundant blank imports. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> check-in: 754914fd82 user: [email protected] tags: trunk, v0.0.18 | |
|
2026-05-12
| ||
| 21:09 |
feat(cli): expose hub --project-code and --seed-from-upstream flags (#159)
The hub.Config.ProjectCode and hub.Config.SeedFromUpstream fields landed in #157 but were unreachable from the `edgesync hub serve` CLI. Wires them through and fixes a latent auth bug in seedFromUpstream that prevented it from cloning against the standard nobody-caps=gio deployment. Changes: * cli/hub_serve.go — adds --project-code (40-char lowercase hex, format pre-validated for a friendlier error than libfossil's) and --seed-from-upstream (http(s) URL of upstream hub xfer endpoint). * hub/clone.go — drop bootstrapUser from the clone CloneOpts. Passing a local-creation user as the upstream-auth identity caused libfossil's clone to send a login card for a user the upstream had never heard of ("authentication failed"). Anonymous clone falls through to the upstream's "nobody" caps, matching the typical NobodyCaps:"gio" deploy. * hub/cross_leaf_test.go — adds TestCrossLeaf_SeedFromUpstream_PropagatesCommit covering the seed-then-sync path end-to-end (clone over HTTP, leaf-link, observe A→B commit propagation via NATS). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> check-in: e8190a881f user: [email protected] tags: trunk, v0.0.17 | |
|
2026-05-06
| ||
| 21:17 | chore: bump submodule pins (leaf/v0.0.11) check-in: 8871efad56 user: 41898282+github-actions[bot]@users.noreply.github.com tags: trunk, v0.0.16 | |
| 21:15 |
feat(leaf/agent): CommitOpts.Tags — symmetric to hub.CommitOpts.Tags (#150)
Adds Tags []TagSpec to agent.CommitOpts (mirroring hub.CommitOpts from v0.0.15) and plumbs it straight through to libfossil.CommitOpts.Tags. Synthetic agent slots (bones ADR 0050) commit through the leaf path, so the hub-only change in #148 didn't reach them. With this, callers can land commits on agent/<id> branches via the propagating fossil branch tag pair. Closes #149. check-in: aa902c6e06 user: [email protected] tags: trunk, leaf/v0.0.11 | |
| 20:40 |
feat(hub): CommitOpts.Tags — attach tags at commit time (incl. branch=) (#148)
Plumbs libfossil's `Tags []TagSpec` primitive through `hub.CommitOpts` so callers can land a checkin on a non-current branch (or attach any other tag) without going around the EdgeSync API to libfossil. Fossil branches are propagating tags: `branch=<name>` + `sym-<name>=*` together place a checkin on a branch. Exposing `Tags` rather than a git-flavored `Branch string` keeps the API fossil-native and is strictly more expressive — any tag (closed, release, custom) can be attached at commit time, not just branch creators. Empty `Tags` preserves the existing trunk-default behavior; current callsites compile and run unchanged. Closes #147 check-in: 7536beb856 user: [email protected] tags: trunk, v0.0.15 | |
|
2026-05-05
| ||
| 15:42 |
fix(hub): periodic WAL checkpoint so vanilla fossil can read hub.fossil (#144)
Hub.fossil opens in WAL journal mode, so without checkpointing the on-disk file stays as a 4 KiB stub plus a multi-hundred-KiB *-wal sidecar — vanilla fossil tooling (fossil ui / fossil info / fossil timeline) refuses it because its validity probe stats the main file before consulting the WAL. Wire a goroutine in NewHub that runs PRAGMA wal_checkpoint(PASSIVE) every Config.CheckpointInterval (default 10s) so vanilla fossil can always read hub.fossil while the hub is running. PASSIVE never blocks readers or writers. Hub.Stop drains the goroutine before closing the libfossil handle; libfossil v0.6.0's own (*Repo).Close runs a TRUNCATE checkpoint, so the post-Stop on-disk file is self-contained. Closes #143. Bumps libfossil v0.5.0 → v0.6.0 (danmestas/libfossil#28). check-in: 72cfc528b2 user: [email protected] tags: trunk, v0.0.14 | |
| 00:41 | chore: bump submodule pins (bridge/v0.0.3) check-in: 5a798c1a36 user: 41898282+github-actions[bot]@users.noreply.github.com tags: trunk, v0.0.13 | |
|
2026-05-04
| ||
| 23:42 |
chore: bump actions/checkout v4→v6 + actions/setup-go v5→v6 (#142)
Quiets the Node.js 20 deprecation annotation that surfaced on the auto-release.yml dry-run. v6 of both actions ships on Node.js 24, ahead of the June 2026 forced-upgrade. No behavior change expected — same API surface. check-in: 0707c5f3d4 user: [email protected] tags: trunk, bridge/v0.0.3 | |
| 22:15 |
chore: bump leaf v0.0.9 → v0.0.10 (#139)
Bumps the root module's leaf pin from `v0.0.9` to `v0.0.10`. `leaf/v0.0.10` is already tagged and pushed. `leaf/v0.0.10` ships: - **feat(leaf/agent)** Config.CloneFromHubURL + agent.CloneRepo helper (#137 gap A, PR #138). Lets downstream consumers bootstrap a leaf repo against an existing hub without importing libfossil directly. After this merges, the next root tag (`v0.0.12`) cuts the full release including the matching hub additions (#137 gaps B + C, also PR #138) — that's enough for bones to drop libfossil from go.mod entirely. check-in: ddb923acb9 user: [email protected] tags: trunk, v0.0.12 | |
| 22:05 |
feat: close three gaps blocking bones go.mod libfossil drop (#137) (#138)
* feat(leaf/agent): clone-if-absent via Config.CloneFromHubURL (#137 gap A) Adds agent.Config.CloneFromHubURL — when set and Config.RepoPath does not yet exist on disk, agent.New clones the leaf repo from the hub HTTP URL before opening it. Matching project-codes between leaf and hub are required for downstream NATS sync subjects to align, so callers that need to bootstrap a leaf against an existing hub no longer have to import libfossil directly for the pre-agent clone step. Also exposes agent.CloneRepo(ctx, repoPath, hubURL) as a standalone helper for callers that need a clone independent of agent construction. Existing behavior is preserved: when CloneFromHubURL is empty, agent.New errors on missing RepoPath as before (covered by TestAgentNew_RejectsMissingRepoWithoutCloneURL). Closes part of #137 (gap A — bones internal/coord/leaf.go). * feat(hub): subscribe to fossil-sync NATS subject in NewHub (#137 gap B) NewHub now connects a local NATS client to its embedded server and subscribes to "fossil.<project-code>.sync" so peer leaf agents can push xfer requests to the hub over NATS — alongside the existing HTTP path. Previously, achieving this required running a leaf-agent in serve mode on top of the hub (Pull=false, Push=false, Autosync=AutosyncOff, ServeNATSEnabled=true), which transitively pulled libfossil into the consumer's import graph. The subscriber is enabled by default. Read-only HTTP-only mirrors that shouldn't accept NATS pushes can opt out via Config.DisableFossilSyncOverNATS. Note on naming: the issue brief proposed Config.ServeFossilSyncOverNATS defaulting to true. Go bool zero-value semantics make default-true awkward without pointers, so the inverted-name shape (DisableX, defaults false = enabled) was used instead. Closes part of #137 (gap B — bones internal/coord/hub.go). * feat(hub): FileToCommit.Perm + CommitOpts.Time pass-through (#137 gap C) Adds two additive fields to the public hub commit surface so consumers no longer need libfossil-direct access to preserve executable bits or seed reproducible commit timestamps: - hub.FileToCommit.Perm — "x" marks the file executable on the resulting manifest's F-card. Empty preserves prior behavior. Other libfossil perm markers pass through verbatim. - hub.CommitOpts.Time — explicit commit timestamp; zero defaults to time.Now().UTC() at commit time, matching the prior behavior. Tests cover round-tripping the executable bit via libfossil.Repo.ListFiles, honoring an explicit time via Timeline, and falling back to "now" on the zero value. Closes part of #137 (gap C — bones internal/hub/hub.go seed path). * ci: include #137 sim tests in the serve-tests allowlist Adds TestAgentNew_ and TestHubNATSFossilSync_ to the sim serve-tests regex in both Makefile and test.yml so the new clone-if-absent and hub-NATS-subscriber tests actually run in CI alongside TestHubLeafE2E. check-in: ad1d55f5b9 user: [email protected] tags: trunk, leaf/v0.0.10 | |
| 21:08 |
chore: bump leaf v0.0.8 → v0.0.9 (#136)
Pulls in the Agent.Commit ParentID/MergeParents fix (#125, PR #133). Without it, agent.Commit produces orphan checkins that fragment the timeline. Required so downstream consumers can pin to a root release exposing the fix. check-in: 2945dc8dce user: [email protected] tags: trunk, v0.0.11 | |
| 20:59 |
feat(hub): SetUserCaps + Config.NobodyCaps for unauth-clone hubs (#135)
Adds Repo.SetUserCaps(login, caps) and a Hub delegate, wrapping libfossil's Repo.SetCaps. Lets consumers grant or change caps on existing users without leaving the hub package — primarily for the common bones case where the libfossil-pre-populated 'nobody' user needs 'gio' to allow unauthenticated clone/pull/push. Also adds Config.NobodyCaps so the typical setup is one declarative field instead of a manual SetUserCaps call after every NewHub. NobodyCaps is applied at bootstrap by calling SetUserCaps("nobody", v) internally — no method-body duplication. Empty NobodyCaps leaves nobody at whatever libfossil set it to (idempotent re-open path preserves prior caps, doesn't overwrite). Tests: - TestRepo_SetUserCaps_RoundTrip — set + read back - TestRepo_SetUserCaps_RejectsEmptyLogin - TestNewHub_NobodyCaps_AppliedAtBootstrap — Config field works - TestNewHub_NobodyCaps_Idempotent — re-running with same caps OK - TestNewHub_NobodyCaps_EmptyDoesNotOverwrite — empty doesn't reset Closes #130 check-in: 93ab4aa0e9 user: [email protected] tags: trunk, leaf/v0.0.9 | |
| 19:24 |
chore: bump leaf v0.0.7 → v0.0.8 (#123)
Pulls in the SetMaxOpenConns(1) deadlock fix (#120/PR #122) and the libfossil v0.5.0 baseline (PR #121). This is the version downstream consumers should pin to instead of v0.0.7 (which deterministically deadlocks under concurrent clones). check-in: ca812c4f85 user: [email protected] tags: trunk, v0.0.10 | |
| 19:17 |
fix(leaf,hub): drop SetMaxOpenConns(1) to unblock concurrent clones (#122)
The applySQLiteTuning helper added in #108 (and propagated to hub/ in #109) capped the libfossil DB connection pool at 1 connection. The intent was to make libfossil's per-connection PRAGMAs stick, but libfossil's clone path has internal goroutines that all need a DB connection — capping the pool deadlocks every concurrent clone, with one goroutine holding the conn while another waits for it. Bones reported (issue #120) that bumping leaf v0.0.6 → v0.0.7 deterministically deadlocks examples/hub-leaf-e2e/'s 3-leaf concurrent clone test. Reproduced here in hub/clone_concurrency_test.go: 3 parallel libfossil.Clone calls against a shared hub. Without the fix the test hangs until its 25s timeout. With the fix it completes in ~80ms. Keeping the busy_timeout=30000 PRAGMA — that's the correct primitive for concurrent-write safety; SQLite retries SQLITE_BUSY internally up to the timeout. The pool cap was always overkill. If we later need PRAGMA stickiness across pooled connections, route it through the modernc driver's per-connection init hook instead of a pool cap. Closes #120 check-in: b251b87613 user: [email protected] tags: trunk, leaf/v0.0.8 | |
| 18:58 |
chore: bump leaf v0.0.3 → v0.0.7 (#119)
Pulls in the libfossil-hidden Agent code-artifact API (Commit, Sync, SyncTo, Read, Files, Diff, Tip, ExtractTo, Config, plus internal SQLite tuning) and the libfossil-hidden notify Service methods (ListThreads, ReadThread, MessageCount, AddDevice/ListDevices/RemoveDevice, CreatePairingToken/ValidateToken). Carries through the v0.0.5/v0.0.6 fixes for sync-error classification and the notify Subscriber race. Required so downstream consumers (bones) can pin to a root EdgeSync release that exposes the new agent surface. Supersedes the in-flight chore/bump-leaf-v0.0.6 branch. check-in: 49b9471550 user: [email protected] tags: trunk, v0.0.9 | |
| 18:42 |
feat(notify): libfossil-hidden Service methods (#111)
Adds methods on *Service that wrap the existing libfossil-typed free functions, so consumers can use notify's chat-over-NATS-with-fossil- durability behavior without seeing *libfossil.Repo in any signature: - ListThreads(ctx, project) — wraps free ListThreads - ReadThread(ctx, project, threadShort) — wraps free ReadThread - MessageCount(ctx, project, threadShort) — len(ReadThread) - ListDevices / AddDevice / RemoveDevice (Device type) - CreatePairingToken / ValidateToken (PendingToken type) The free *libfossil.Repo-typed functions are unchanged; advanced consumers and existing callers continue to work. Service.Repo() stays as an escape hatch with an updated doc comment recommending the new methods. Note: ListThreads / ReadThread / MessageCount take an explicit project parameter (the brief listed them without one). The notify repo holds threads for multiple projects and the underlying free functions need project; carrying a default project on Service would be a reasonable follow-up but is out of scope here. Closes #104 check-in: 02c7e2b781 user: [email protected] tags: trunk, leaf/v0.0.7 | |
|
2026-05-01
| ||
| 22:47 | fix(leaf/notify): mutex-gate Watch teardown to prevent send-on-closed-channel panic (#101) check-in: 1fe42a59e7 user: [email protected] tags: trunk, leaf/v0.0.6 | |
| 22:20 | fix(leaf): classify ErrNoResponders and ctx.Canceled as benign sync errors (#99) check-in: 8ca34471cd user: [email protected] tags: trunk, leaf/v0.0.5 | |
| 21:57 | fix(leaf): demote per-target sync errors when another target succeeded (#97) check-in: 5bbb70b342 user: [email protected] tags: trunk, leaf/v0.0.4 | |
| 00:01 |
build(release): publish standalone leaf brew formula (#94)
Add a second goreleaser build target for the leaf daemon (built from the EdgeSync/leaf submodule via dir: leaf) and a separate Homebrew formula at danmestas/tap/leaf so downstream tools (notably bones, which spawns leaf via exec) can declare it as a brew dependency instead of requiring users to clone EdgeSync and run make leaf. Existing edgesync formula is now scoped via ids: [edgesync] so it doesn't pick up the new leaf binary. check-in: b601f8a1af user: [email protected] tags: trunk, v0.0.8 | |
|
2026-04-30
| ||
| 10:31 |
Merge pull request #87 from danmestas/chore/bump-libfossil-v0.4.5
chore: bump libfossil v0.4.3 → v0.4.5 check-in: c77ecea4f7 user: [email protected] tags: trunk, v0.0.7 | |
|
2026-04-28
| ||
| 00:02 |
Merge pull request #84 from danmestas/release-tooling
release: GoReleaser config + tag-push workflow + edgesync --version check-in: 30cd2bb5fe user: [email protected] tags: trunk, v0.0.6 | |
|
2026-04-27
| ||
| 17:37 |
Merge pull request #81 from danmestas/fix-root-module-deps
go.mod: pin sub-module deps to real tags so EdgeSync/cli is consumable check-in: 0d8829ccf1 user: [email protected] tags: trunk, v0.0.5 | |
| 16:57 |
Merge pull request #80 from danmestas/extract-cli-package
cli: extract command tree into reusable package check-in: 18a10cd49e user: [email protected] tags: trunk, v0.0.4 | |
|
2026-04-26
| ||
| 15:37 |
Merge pull request #79 from danmestas/bump-libfossil-v0.4.3
deps: bump libfossil v0.1.0 → v0.4.3 across all modules check-in: efeaf4c90f user: [email protected] tags: trunk, v0.0.3, leaf/v0.0.3, bridge/v0.0.2 | |
| 15:20 |
Merge pull request #78 from danmestas/add-docs-site
docs: Hugo+hextra docs site with Cloudflare Workers deploy check-in: d59e2dece9 user: [email protected] tags: trunk, v0.0.2 | |
|
2026-04-24
| ||
| 16:02 |
notify: extract shared natshdr.Carrier to kill duplicate header-carrier
Two copies of natsHeaderCarrier existed (leaf/agent/nats.go and leaf/agent/notify/pubsub.go), both carrying the same latent case-sensitive Get bug that was fixed in Task 6. Extract the type to leaf/agent/internal/natshdr so the next bug can be fixed once. While consolidating, drop the 4-tier fallback in Get in favor of a single EqualFold scan. Header maps are tiny (typically 3 entries) and tiers 1-3 were subsumed by tier 4 anyway. The new implementation is demonstrably correct and easier to read. check-in: b53032d01f user: [email protected] tags: trunk, leaf/v0.0.2 | |
|
2026-04-23
| ||
| 19:23 |
rename module to github.com/danmestas/EdgeSync
Fix the case-sensitive module path to match the actual GitHub repo URL (danmestas/EdgeSync). Remove tracked leaf/leaf binary and ignore .claude/skills/ scratchpad dirs. check-in: eda7960b81 user: [email protected] tags: trunk, v0.0.1, leaf/v0.0.1, bridge/v0.0.1 | |