50 descendants and 21 ancestors of 3295f73d5d8e61a3
|
2026-05-05
| ||
| 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 | |
| 23:30 |
chore: add auto-release workflow + scripts/release.sh (#141)
Mechanizes the multi-step release flow that today is hand-driven via: 1. tag leaf submodule, push 2. open chore/bump-leaf PR, merge 3. tag root, push (fires release.yml + bones dispatch) scripts/release.sh detects which submodules have changes since their last <name>/v* tag, computes next versions (patch by default; --bump= minor|major), tags and pushes them, rewrites the matching require pin in root go.mod, commits straight to main as github-actions[bot], then tags the next root v* and pushes — firing release.yml. Local invocation prompts before each push so the operator can intervene. Workflow invocation (auto-release.yml) passes --ci to suppress prompts and uses the bot identity. --dry-run reports the plan without touching anything. Direct-to-main bot commits is the right tradeoff here: the change is deterministic robot work (one-line go.mod edit derived from the just- tagged version) and avoiding a PR round-trip lets a release ship in a single workflow run rather than coordinating across two. If branch protection blocks the github-actions bot, configure RELEASE_PUSH_TOKEN as a fine-grained PAT with contents:write. Side observation: dry-run flags that bridge/ has unreleased changes since bridge/v0.0.2 (libfossil bump + README), so the next auto-release run will tag bridge/v0.0.3 alongside whatever else changes. check-in: 8414300b13 user: [email protected] tags: trunk | |
| 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 | |
| 21:04 |
chore: bump leaf v0.0.8 → v0.0.9
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. leaf check-in: ab5b55e3b0 user: [email protected] tags: trunk, chore/bump-leaf-v0.0.9 | |
| 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 | |
| 20:53 |
feat(hub): SetUserCaps + Config.NobodyCaps for unauth-clone hubs
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 leaf check-in: a8e62ce82d user: [email protected] tags: trunk, feat/130-hub-setusercaps | |
| 20:51 |
feat(hub): add OpenRepo + *hub.Repo type for server-less operations (#134)
Adds hub.OpenRepo(path) (*Repo, error) — a server-less handle for one-off CLI invocations and short-lived helpers (bones #186 needs this for `bones hub user list`, `bones plan finalize`, and slot-user provisioning, all of which currently drop to direct libfossil.Open because hub.NewHub spins up a redundant NATS server every time). The new *hub.Repo type holds the libfossil handle and carries every user / commit / read method that *hub.Hub used to define on itself. *hub.Hub now holds a *hub.Repo internally and one-line-delegates each method, so both code paths share method bodies — no duplication. Adds Hub.Repo() *Repo accessor for sharing the live handle out of a running hub. Documented contract: don't call Close on a *Repo returned by Hub.Repo while the Hub is still serving — Hub.Stop is the right teardown for that case. Repo.Close is idempotent so accidental double- close from teardown ordering is safe. Tests: - TestOpenRepo_RoundTrip — every *Repo method against a path bootstrapped by NewHub. Same observable state. - TestOpenRepo_RejectsEmptyPath, TestOpenRepo_RejectsMissingPath. - TestRepo_Close_IsIdempotent. - TestHub_Repo_AccessorReturnsLiveHandle — operations on the *Repo accessor are observable via the *Hub. Closes #131 check-in: 5f025def67 user: [email protected] tags: trunk | |
| 20:48 |
fix(leaf/agent): chain Commit onto trunk tip by default (ParentID/MergeParents) (#133)
Adds ParentID and MergeParents to agent.CommitOpts. When ParentID is 0, Agent.Commit auto-resolves the current trunk tip and uses that as the parent — matching `fossil ci`'s default behavior. On an empty repo (BranchTip returns sql.ErrNoRows), the resolution falls through to 0 and the commit is a legitimate orphan root (the first commit). Before this fix, agent.Commit always passed ParentID=0 to libfossil, producing P-card-less manifests. Every commit became its own root, fragmenting the timeline and breaking trunk-based development for downstream consumers (notably bones). Tests added: - TestAgent_Commit_ChainsOntoTrunkTipByDefault — two consecutive Commit calls produce a chained pair with linked Parents. - TestAgent_Commit_ExplicitParentIDOverride — caller-supplied ParentID is used verbatim. The hub-leaf e2e test (sim/hub_leaf_test.go) was reading by "trunk" tip on the hub; switched to reading by the explicit RevID returned from Agent.Commit so the test exercises the transport contract (file lands on hub) without coupling to branch-tip resolution semantics on the hub side after sync — which appears to be a separate concern worth its own investigation. Closes #125 check-in: 82e4b0075d user: [email protected] tags: trunk | |
| 20:41 |
fix(leaf/agent): chain Commit onto trunk tip by default (ParentID/MergeParents)
Adds ParentID and MergeParents to agent.CommitOpts. When ParentID is 0, Agent.Commit auto-resolves the current trunk tip and uses that as the parent — matching `fossil ci`'s default behavior. On an empty repo (BranchTip returns sql.ErrNoRows), the resolution falls through to 0 and the commit is a legitimate orphan root (the first commit). Before this fix, agent.Commit always passed ParentID=0 to libfossil, producing P-card-less manifests. Every commit became its own root, fragmenting the timeline and breaking trunk-based development for downstream consumers (notably bones). Tests added: - TestAgent_Commit_ChainsOntoTrunkTipByDefault — two consecutive Commit calls produce a chained pair with linked Parents. - TestAgent_Commit_ExplicitParentIDOverride — caller-supplied ParentID is used verbatim. The hub-leaf e2e test (sim/hub_leaf_test.go) was reading by "trunk" tip on the hub; switched to reading by the explicit RevID returned from Agent.Commit so the test exercises the transport contract (file lands on hub) without coupling to branch-tip resolution semantics on the hub side after sync — which appears to be a separate concern worth its own investigation. Closes #125 leaf check-in: 93966ff081 user: [email protected] tags: trunk, fix/125-commit-parent-id | |
| 20:26 |
ci(bump-upstream): walk every go.mod in the repo (#132)
The auto-generated upstream-bump PR for libfossil v0.5.0 (#121) only updated the root go.mod. leaf/go.mod and bridge/go.mod independently pin libfossil and stayed on v0.4.5 until I extended the PR by hand. Walk every go.mod file in the repo, skip ones that don't depend on the target module (so go get doesn't add it as a new dep), then run go get + go mod tidy in each. Verify-build and the git-add for the commit also iterate the same set. The find-based discovery automatically picks up future modules — when the hub package is promoted to its own go.mod (#118) or any other new module is added, no workflow change is needed. Verified by dry-running the find/grep logic locally against this repo's main: correctly identifies ./, leaf/, bridge/ as libfossil dependants and skips ./docs/site/ (Hugo site, no libfossil). Closes #127 check-in: adb39a9af9 user: [email protected] tags: trunk | |
| 20:21 |
ci(bump-upstream): walk every go.mod in the repo
The auto-generated upstream-bump PR for libfossil v0.5.0 (#121) only updated the root go.mod. leaf/go.mod and bridge/go.mod independently pin libfossil and stayed on v0.4.5 until I extended the PR by hand. Walk every go.mod file in the repo, skip ones that don't depend on the target module (so go get doesn't add it as a new dep), then run go get + go mod tidy in each. Verify-build and the git-add for the commit also iterate the same set. The find-based discovery automatically picks up future modules — when the hub package is promoted to its own go.mod (#118) or any other new module is added, no workflow change is needed. Verified by dry-running the find/grep logic locally against this repo's main: correctly identifies ./, leaf/, bridge/ as libfossil dependants and skips ./docs/site/ (Hugo site, no libfossil). Closes #127 leaf check-in: a6d596273d user: [email protected] tags: trunk, feat/127-bump-walk-all-gomods | |
| 20:20 |
feat(notify): add NewServiceFromPath constructor (#129)
Adds a path-based Service constructor for callers that want notify without managing the *libfossil.Repo lifecycle separately: type ServiceFromPathConfig struct { RepoPath string NATSConn *nats.Conn From string FromName string } func NewServiceFromPath(cfg ServiceFromPathConfig) (*Service, error) If the repo already exists at RepoPath it's opened; otherwise it's created via InitNotifyRepo. Service.Close() now closes the repo when the Service was constructed via NewServiceFromPath; the existing NewService path is unchanged (caller still owns the repo). The new constructor uses the same open-or-create pattern hub.NewHub uses, so re-entry on an existing path Just Works. Closes #115 check-in: 5ceb63c701 user: [email protected] tags: trunk | |
| 20:19 |
docs(architecture): add hub-package.md ADR (#128)
Documents the top-level hub/ package shipped in PR #109 + revised in PR #122 (deadlock fix). Covers public API surface, lifecycle ordering (HTTP listener bound during NewHub for immediate HTTPAddr availability, then NATS server ReadyForConnections), the SQLite tuning decision (busy_timeout yes, MaxOpenConns(1) explicitly no — see #120), the in-root vs. separate- module choice (with #118 as the migration path), and integration with the leaf agent (sim/hub_leaf_test.go::TestHubLeafE2E locks the contract). Cross-referenced from agent-deployment.md and listed at the top of CLAUDE.md alongside the other ADRs. Closes #114 check-in: afa1002be5 user: [email protected] tags: trunk | |
| 19:44 |
test(sim): hub + leaf agent end-to-end integration test (#126)
Adds sim/hub_leaf_test.go: a real *hub.Hub bound to auto-allocated ports, a real *agent.Agent built against a leaf repo cloned from the hub, and a round-trip Commit + SyncTo + Hub.ReadAt that exercises the HTTP-xfer path end-to-end. Without this test, the kind of cross-component regression bones surfaced in #120 (the SetMaxOpenConns deadlock under concurrent clones) only shows up downstream. With it, EdgeSync's own CI catches it. Wired into the existing 'Sim serve tests' step (Makefile + test.yml) alongside TestServeHTTP/TestLeafToLeaf/TestAgentServe so the test runs on every PR. Closes #113 check-in: 995066ac2a user: [email protected] tags: trunk | |
| 19:34 |
test(sim): hub + leaf agent end-to-end integration test
Adds sim/hub_leaf_test.go: a real *hub.Hub bound to auto-allocated ports, a real *agent.Agent built against a leaf repo cloned from the hub, and a round-trip Commit + SyncTo + Hub.ReadAt that exercises the HTTP-xfer path end-to-end. Without this test, the kind of cross-component regression bones surfaced in #120 (the SetMaxOpenConns deadlock under concurrent clones) only shows up downstream. With it, EdgeSync's own CI catches it. Wired into the existing 'Sim serve tests' step (Makefile + test.yml) alongside TestServeHTTP/TestLeafToLeaf/TestAgentServe so the test runs on every PR. Closes #113 leaf check-in: 7275783d59 user: [email protected] tags: trunk, feat/113-hub-leaf-e2e | |
| 19:33 |
refactor(leaf/agent): use libfossil v0.5.0 UUIDFromRID + whole-checkin Diff (#124)
Cleans up two workarounds in code_artifact.go that existed only because libfossil v0.4.x didn't expose them as first-class APIs: - Delete the ridToUUID helper (raw SQL probe of libfossil's blob table). Replaced with r.UUIDFromRID(rid) at both callsites: Agent.Tip and Agent.toSyncResult. - Collapse Agent.Diff from ~25 LOC of file enumeration to a single r.Diff(ridA, ridB, "") call. Uses libfossil v0.5.0's Option-A whole- checkin form. Also fixes wrong-ish rename-detection in the previous hand-rolled implementation. Adds TestAgent_Diff_RenameAcrossRevs to exercise the rename case the old enumeration got wrong. Closes #112 check-in: ab2db30284 user: [email protected] tags: trunk | |
| 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:18 |
chore: bump leaf v0.0.7 → v0.0.8
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). leaf check-in: 89133cefa6 user: [email protected] tags: trunk, chore/bump-leaf-v0.0.8 | |
| 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 | |
| 19:17 |
chore: bump libfossil → v0.5.0 (#121)
* chore: bump libfossil → v0.5.0 * chore: bump libfossil → v0.5.0 in leaf and bridge modules The auto-generated bump-upstream PR only updated the root module's go.mod. The leaf and bridge modules pin libfossil independently and need the bump too — without this, the upcoming #112 cleanup (delete ridToUUID + simplify Agent.Diff using libfossil v0.5.0's UUIDFromRID + whole-checkin Diff) can't land on leaf since leaf's go.mod still resolves to v0.4.5. Worth fixing the bump-upstream workflow separately to walk every go.mod under the repo, but treating that as a follow-up rather than blocking this PR on it. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Dan Mestas <[email protected]> check-in: c52b0b3b44 user: [email protected] tags: trunk | |
| 19:11 |
chore: bump libfossil → v0.5.0 in leaf and bridge modules
The auto-generated bump-upstream PR only updated the root module's go.mod. The leaf and bridge modules pin libfossil independently and need the bump too — without this, the upcoming #112 cleanup (delete ridToUUID + simplify Agent.Diff using libfossil v0.5.0's UUIDFromRID + whole-checkin Diff) can't land on leaf since leaf's go.mod still resolves to v0.4.5. Worth fixing the bump-upstream workflow separately to walk every go.mod under the repo, but treating that as a follow-up rather than blocking this PR on it. leaf check-in: c299ef11e2 user: [email protected] tags: trunk, chore/bump-libfossil-v0.5.0 | |
| 19:04 | chore: bump libfossil → v0.5.0 check-in: 8e8db6b593 user: 41898282+github-actions[bot]@users.noreply.github.com tags: trunk, chore/bump-libfossil-v0.5.0 | |
| 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:53 |
chore: bump leaf v0.0.3 → v0.0.7
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. leaf check-in: 94b10802bf user: [email protected] tags: trunk, chore/bump-leaf-v0.0.7 | |
| 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 | |
| 18:38 |
feat(cli/repo): EdgeSync-owned repo subcommand library (#110)
Adds github.com/danmestas/EdgeSync/cli/repo, a kong-compatible command tree for fossil repo operations (ci, co, timeline, diff, cat, config, merge, …) that consumers can embed without importing libfossil/cli. Cmd and Globals are type aliases of libfossil/cli.RepoCmd and libfossil/cli.Globals. Re-declaring them as wrapper structs would require mirroring ~38 subcommands' worth of kong flags by hand, brittle to libfossil flag changes. Aliases give consumers source-level isolation (no "github.com/danmestas/libfossil/cli" import in their code) while reusing libfossil's tested CLI implementation. cmd/edgesync/cli.go migrates to the new package as the first consumer. The flag surface, subcommand set, and behavior are unchanged from the end-user perspective. Closes #105 check-in: bb432d52a6 user: [email protected] tags: trunk | |
| 18:34 |
feat(hub): new package for hub-fossil management and HTTP serving (#109)
Adds a top-level hub/ package that hosts an EdgeSync hub in-process: fossil hub repo bootstrap, embedded NATS server with JetStream, auto-port allocation, libfossil HTTP server (timeline UI + xfer endpoint), user management, and hub-side commits/reads. All libfossil and nats-server types are wrapped internally — the public surface exposes only stdlib types and types defined here. Public API: - Config + NewHub + ServeHTTP + Stop - NATSURL / LeafUpstream / HTTPAddr accessors - AddUser / GetUser / HasUser / ListUsers / RemoveUser (User type) - Commit / Read / ReadAt (RevID, FileToCommit, CommitOpts types) Auto port allocation: passing 0 for FossilHTTPPort, NATSClientPort, or NATSLeafPort yields three distinct bound ports. The HTTP listener is bound during NewHub so HTTPAddr() is immediately usable, even before ServeHTTP is called. SQLite tuning (SetMaxOpenConns(1) + busy_timeout=30s) applied at hub bootstrap, matching the leaf agent's tuning. Lives inside the EdgeSync root module (not a separate go.mod) so it ships in lockstep with the leaf agent. Can be promoted to its own module later if downstream consumers need to depend on it independently. Closes #102 check-in: 67ea682587 user: [email protected] tags: trunk | |
| 18:29 |
feat(leaf/agent): libfossil-hidden code-artifact API (#108)
Adds Commit, Sync, SyncTo, Read, Files, Diff, Tip, ExtractTo, Config methods on *Agent that take/return only primitives or types defined in this package. No *libfossil.* in any new signature, so consumers can perform the bones-style code-artifact operations without importing libfossil. New types: RevID (opaque commit handle), FileToCommit, CommitOpts, SyncOpts, SyncResult — all libfossil-free. Internal SQLite tuning (SetMaxOpenConns(1) + busy_timeout=30s) is now applied on every agent boot. libfossil PRAGMAs are per-connection so the single-conn cap is what makes them stick — concurrent-write safety that any production agent needs. Repo() and NotifyRepo() stay as escape hatches for sim/test and advanced consumers; doc comments updated to recommend the new methods. Closes #103 check-in: 3309ec60d5 user: [email protected] tags: trunk | |
| 16:50 |
chore(agents): scaffold ## Agent skills section + docs/agents/ (#107)
Adds the per-repo configuration that the engineering skills (triage, to-issues, to-prd, diagnose, tdd, improve-codebase-architecture) assume: - Issue tracker mapping → docs/agents/issue-tracker.md (GitHub via gh CLI) - Triage label vocabulary → docs/agents/triage-labels.md (canonical names; needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix) - Domain doc layout → docs/agents/domain.md (single-context; ADRs live in docs/architecture/, no CONTEXT.md so skills fall back to CLAUDE.md + MEMORY.md) CLAUDE.md gets an ## Agent skills block pointing at the three docs. The four missing triage labels (needs-triage, needs-info, ready-for-agent, ready-for-human) were created on the GitHub repo at the same time. check-in: f894e896c1 user: [email protected] tags: trunk | |
| 16:44 |
fix(leaf/notify): lock s.subs append/clear in Subscriber (#106)
Concurrent Subscribe/SubscribeThread callers raced on the unsynchronized append in subscribeReturn (and the iterate/clear in Unsubscribe), which the race detector flagged in downstream bones tests under -race -short. Subscriber already had s.mu for dedup state — extending it to cover the subs slice is the cleanest fix. Unsubscribe snapshots the slice under the lock and iterates outside it so we never hold s.mu across NATS calls (the dispatch callback path takes s.mu via isDuplicate). Adds a concurrent-Subscribe stress test that fires the race reliably under -race without the fix. Closes #95 check-in: 0577a01d66 user: [email protected] tags: trunk | |
|
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
| ||
| 16:01 |
chore: bump libfossil → v0.4.6-rc3 (#92)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> check-in: f26dbee41f user: [email protected] tags: trunk | |
| 16:00 |
Merge pull request #93 from danmestas/fix/goreleaser-skip-prerelease-brews
fix(release): skip Homebrew formula update on prereleases check-in: 929d7783dc user: [email protected] tags: trunk | |
| 15:55 |
fix(release): skip Homebrew formula update on prereleases
Adds skip_upload: auto to the brews block. With release.prerelease: auto, GoReleaser correctly marks rc/beta/alpha tags as GitHub prereleases — but without skip_upload: auto, the Homebrew formula was still being updated for those prereleases. Effect: brew upgrade edgesync would pull the rc binary as a stable update. skip_upload: auto skips brew formula updates whenever the release is marked as prerelease. Stable releases (vX.Y.Z without suffix) still update the formula. check-in: 233d9d94d5 user: [email protected] tags: trunk | |
| 15:49 | chore: bump libfossil → v0.4.6-rc3 leaf check-in: f60982256b user: 41898282+github-actions[bot]@users.noreply.github.com tags: trunk, chore/bump-libfossil-v0.4.6-rc3 | |
| 14:31 |
Merge pull request #90 from danmestas/feat/upstream-bump-and-dispatch
feat(ci): receive libfossil dispatches, dispatch to bones, group changelog check-in: 4f299fe932 user: [email protected] tags: trunk | |
| 14:23 |
feat(release): add changelog groups (Features/Bug fixes/Other)
Replaces flat commit list with conventional-commit-grouped sections in the auto-generated GitHub release notes. Existing exclude patterns preserved. check-in: e557d54f0d user: [email protected] tags: trunk | |
| 14:22 |
feat(ci): dispatch upstream-bump to bones on tag
After goreleaser publishes a release, fires repository_dispatch to danmestas/bones so it can open a chore-bump PR. Uses DISPATCH_PAT (fine-grained, scoped to bones contents:write). This closes the edgesync→bones link of the cascade. Combined with PR #6 (libfossil's release.yml), pushing a libfossil tag will fire the full chain: libfossil tag → EdgeSync bump PR → merge+tag → bones bump PR. check-in: e831226826 user: [email protected] tags: trunk | |
| 14:21 |
feat(ci): add bump-upstream receiver workflow
Listens for repository_dispatch event_type=upstream-bump from libfossil's release workflow. Validates payload (repo/module_path/version regex), checks for existing open PR (idempotency), retries go get up to 3 times to absorb GOPROXY propagation lag, opens a chore PR via github-actions[bot]. Falls back to workflow_dispatch with the same inputs for manual recovery. EXPECTED_REPO=libfossil; EXPECTED_MODULE=github.com/danmestas/libfossil. Other dispatch sources are silently ignored. Mirrors the production-tested shape from bones #90. check-in: 0e93a687f0 user: [email protected] tags: trunk | |
| 13:22 |
Merge pull request #89 from danmestas/chore/local-dev-hygiene
chore: add local dev hygiene targets and pre-push hook check-in: 5ea1ad56be user: [email protected] tags: trunk | |
| 13:15 |
fix(make): ci-fast also tests leaf and bridge sub-modules
leaf/ and bridge/ are separate Go modules (each has go.mod), so 'go test ./...' from repo root does not descend into them. Without this fix, both pre-commit and pre-push hooks would pass even when leaf or bridge is broken — exactly the class of bug the old pre-commit was trying to catch. Reuse ci-vet (which already runs vet across all three modules) as a dependency, then run -short tests in root, leaf, and bridge sequentially. Sub-module tests run in ~2s each on a dev box; total ci-fast runtime approximately doubles to ~12s (still well under the 60s pre-push budget). check-in: 3f4035e5e2 user: [email protected] tags: trunk | |
| 13:09 |
fix(hooks): replace broken pre-commit with make ci-fast
The previous pre-commit ran 'go test ./leaf/agent/' from repo root, which fails because leaf is a separate Go module. The hook had been masked by a global core.hooksPath override; activating local .githooks/ via 'make setup-hooks' (added in this PR) exposed the breakage. Replace with the same pattern as pre-push: 'make ci-fast' (~6s in this repo). Skip with: git commit --no-verify. check-in: 9197f23350 user: [email protected] tags: trunk | |
| 13:03 |
feat: add release annotation template
Used by 'make release VERSION=...' as the body skeleton for annotated tags. check-in: 8a43ebc3f7 user: [email protected] tags: trunk | |
| 13:03 |
feat: add pre-push hook running make ci-fast
Catches obvious breakage before push. ~60s. Skip with: git push --no-verify check-in: 1c034a7e90 user: [email protected] tags: trunk | |
| 13:01 |
feat(make): add release VERSION=... helper
Validates clean tree, runs make ci, opens $EDITOR with auto-populated tag annotation template, creates annotated tag locally. Push is intentionally manual. check-in: 3295f73d5d user: [email protected] tags: trunk | |
| 13:01 |
feat(make): add ci and ci-fast targets
ci mirrors .github/workflows/ci.yml verbatim: ci-vet — vet root + leaf + bridge ci-leaf-bridge — leaf and bridge short tests (sequential; CI runs parallel) ci-cmd — cmd/edgesync build + test ci-fast runs vet + build + short tests (~60s) for pre-push hook. Note: test.yml's sim/interop tests are slower and need fossil; not mirrored here. Run them on demand for releases. check-in: 13ba906678 user: [email protected] tags: trunk | |
| 10:40 |
Merge pull request #88 from danmestas/docs/changelog-v0.0.7
docs: changelog entry for v0.0.7 + skip CI on docs-only changes check-in: 31f055cc4c user: [email protected] tags: trunk | |
| 10:36 | ci: skip docs-only changes (paths-ignore) check-in: 60ccb8082f user: [email protected] tags: trunk | |
| 10:34 | docs: changelog entry for v0.0.7 check-in: 9831416916 user: [email protected] tags: trunk | |
| 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 | |
| 10:27 |
chore: bump libfossil v0.4.3 → v0.4.5
Pulls in fixes from two libfossil releases: - v0.4.4 (libfossil#14): hub xfer handler no longer panics with "content.MakePublic: rid must be positive" when a client cancels mid-transfer. Affects EdgeSync hubs that serve concurrent clones. - v0.4.5 (libfossil#17, libfossil#18): sync.Clone now converges against a hub being written to during the clone session. Three compounding root causes fixed: server-side rid cap (snapshot via CookieCard), client-side CloneSeqNoCard cursor emission, and cookie roundtrip. Wire-format compatible with older peers. No EdgeSync source changes required — both fixes are libfossil-internal. Closes #86. leaf check-in: 6c16b3e646 user: [email protected] tags: trunk, chore/bump-libfossil-v0.4.5 | |
|
2026-04-28
| ||
| 00:44 |
Merge pull request #85 from danmestas/polish/libfossil-level
polish: CHANGELOG + CONTRIBUTING (libfossil-level hygiene) check-in: c345d7737b user: [email protected] tags: trunk | |
| 00:40 |
polish: add CHANGELOG + CONTRIBUTING (libfossil-level hygiene)
Matches the bones polish template. CHANGELOG covers root-module versions (v0.0.1 initial through v0.0.6 latest) and notes the multi-module tagging scheme (leaf/, bridge/ submodules carry their own tags). CONTRIBUTING covers the make setup bootstrap, test/sim commands, the four-binary build (edgesync + leaf + bridge + iroh-sidecar), wasm targets, and submodule coordination guidance for releases. check-in: d9574335d0 user: [email protected] tags: trunk | |
| 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 | |
| 00:00 |
release: GoReleaser config + tag-push workflow + edgesync --version
Cross-compile edgesync for darwin/linux × amd64/arm64, archive as tarballs, generate checksums, publish a GitHub release, and update the Homebrew formula at danmestas/homebrew-tap on every git tag matching v*. Mirrors the bones release pipeline (PRs danmestas/bones#25, #26). Files: - .goreleaser.yml — build matrix, archive shape, brews stanza pointing at danmestas/homebrew-tap, ldflags for version injection. - .github/workflows/release.yml — runs on tag push, sets up Go 1.26.0, calls goreleaser-action@v6 with `release --clean`. Needs HOMEBREW_PAT_TOKEN secret on this repo (PAT with contents:write on danmestas/homebrew-tap). - cmd/edgesync/main.go — version/commit/date package vars filled by ldflags. `edgesync --version` and `-V` short-circuit before Kong (avoids collision with `repo extract --version` sub-flag). After merge: 1. Add HOMEBREW_PAT_TOKEN secret to this repo. 2. Tag v0.0.6 and push — release workflow takes it from there. 3. Verify: brew install danmestas/tap/edgesync. check-in: 176fae9490 user: [email protected] tags: trunk | |
|
2026-04-27
| ||
| 20:39 |
Merge pull request #83 from danmestas/readme-dx-improvements
README: front-load value prop, add prereqs, badges, deep-dive links check-in: 8cbcae9e10 user: [email protected] tags: trunk | |
| 20:32 |
README: front-load value prop, add prereqs, badges, status, deep-dive links
DX-audit pass for public-repo readiness: 1. New tagline + Why EdgeSync section that explains the use case in terms a non-Fossil-aware reader can evaluate (real-time over messaging, no central server, Fossil-compatible wire). 2. Status section sets pre-1.0 expectations honestly. 3. Prerequisites section before Quick Start: Go 1.26+, NATS server, optional Fossil binary, optional direnv. 4. Quick Start now creates a demo repo, starts NATS, and shows a stock fossil clone hitting the leaf — the cold-start path actually works end-to-end. 5. New "Use as a Go library" section with go get for each module and a pkg.go.dev link. 6. New "Deep Dive" section linking docs/architecture/* by topic (was filesystem-grep-only before). 7. Badges: CI status, Go reference, license, Go report card. 8. License section references the Apache-2.0 file added in PR #82. Project Layout updated: cli/ added, libfossil moved to its own repo note, hugo site path corrected. check-in: f7d05cf9ac user: [email protected] tags: trunk | |
| 20:15 |
Merge pull request #82 from danmestas/pre-public-cleanup
pre-public: LICENSE, IP placeholders, module READMEs, WASM build fix check-in: 83d2a03038 user: [email protected] tags: trunk | |
| 19:51 | pre-public: LICENSE, untrack .mcp.json, placeholder IPs, module READMEs, fix wasm targets check-in: 28f11dc3c4 user: [email protected] tags: trunk | |
| 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 | |
| 17:29 |
go.mod: pin sub-module dependencies to real tags
Replace v0.0.0-00010101 placeholders with leaf v0.0.3 and bridge v0.0.2 in the root and bridge go.mod files. Local replace directives stay so intra-repo development against unreleased changes still works; the real version pins make EdgeSync/cli consumable by external repos via `go get`. Without this, `go get github.com/danmestas/EdgeSync/cli` fails with "unknown revision 000000000000" when the consumer tries to resolve EdgeSync/bridge. check-in: e6c688849f user: [email protected] tags: trunk | |
| 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 | |
| 16:36 |
cli: extract command tree into reusable package
Move sync, bridge, notify, and doctor commands from cmd/edgesync/ into a new top-level cli/ package. The integration struct in cmd/edgesync/cli.go now imports from EdgeSync/cli (aliased as edgecli) and assembles the binary's command surface. This mirrors libfossil/cli's pattern — the cli/ package exports embeddable Kong command structs that downstream consumers (e.g. agent-infra) can integrate alongside libfossil/cli.RepoCmd into their own unified CLI. No behavior change: cmd/edgesync still builds the same binary with the same flags, and the existing notify_test.go end-to-end suite passes unchanged. check-in: 845d1d229e user: [email protected] tags: trunk | |
|
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:29 |
deps: bump libfossil v0.1.0 → v0.4.3 across all modules
Picks up four releases worth of upstream fixes and surface additions: - v0.4.0 → v0.4.3: xfer protocol fix (always emit project-code on push/pull cards, libfossil#12), diff byte-fidelity ("\\ No newline at end of file", libfossil#10), repo.ResolveVersion + ReadFileAt for symbolic version lookups (libfossil#11). - v0.2.0 / v0.3.0: prior 5xx error mapping, transport rewrites, repo admin surface, content cache, observer rework — all consumed transitively without code changes here. `go build ./...` clean. `make test` green across leaf/, bridge/, sim/, notify, telemetry. No code changes needed in EdgeSync — the libfossil public API stayed stable across these releases. This bump is needed by the sibling agent-infra repo, which already pins libfossil v0.4.2 directly for chat/workspace and was relying on the local `replace ../EdgeSync/leaf` directive to mask the version drift. With this bump and a follow-up tag (leaf/v0.0.3), agent-infra can drop the replace and pin clean module versions. check-in: 7db3317617 user: [email protected] tags: trunk | |
| 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 | |