Skip to content

Releases

LinkMarks v2.1.2 — public-surface scrub + sync --dry-run preview

Choose a tag to compare

@louzt louzt released this 17 Aug 13:50
v2.1.2

What's new

  • linkmarks sync --dry-run — preview the yrs-encoded payload that would be sent to the relay, per collection. No network, no commit, no risk. Useful for inspecting wire shape before deploying the relay.
  • linkmarks-bench-crdt workspace member — the benchmark suite that backs the CRDT choice is now a first-class workspace member (was poc/crdt-spike/). Numbers stay the same; the path is honest.
  • deploy/ + docs/relay-deployment.md — operator template for self-hosting the relay (systemd unit + nginx config + healthcheck). The relay itself is not in this release; the deployment surface is.

Cleanup

  • Internal docs (ARCHITECTURE, CONCERNS, ROADMAP, SPEC, decisions/) move out of the public repo. The maintainer-only context lives elsewhere; the public repo carries only consumer-facing docs.
  • All references to internal phase labels (Fase N / ADR NNNN / Day N / poc/) scrubbed from source, tests, templates, systemd unit, and manpage.

Install

```bash
cargo install --git https://github.com/LOUST-PRO/LinkMarks \
--tag v2.1.2 \
--path crates/linkmarks-cli \
--bin linkmarks \
--locked
```

See docs/relay-deployment.md for the relay self-host walkthrough.

v2.1.1 — TUI wiring + packaging + README drift

Choose a tag to compare

@louzt louzt released this 16 Aug 07:47
v2.1.1

v2.1.1 — TUI wiring + packaging + README drift

Fixed

  • TUI: FilterMode::Fuzzy now reachable via Ctrl+F inside the filter (cycles Substring → Tag → Fuzzy). SortMode gains a 4th variant CanonicalUrl and a global s keybinding to cycle the four modes (updated / title / url / created). Status bar surfaces sort: <label> and help overlay lists both bindings.
  • debian/rules: replaced deprecated dh $@ --with cargo with dh $@ --buildsystem cargo. override_dh_auto_test now honors DEB_BUILD_OPTIONS=nocheck.
  • arch/PKGBUILD: install hook switched from a hand-copied /usr/share/libalpm/scripts/ copy to the canonical install=linkmarks.install directive. .SRCINFO regenerated.
  • rpm/linkmarks.spec: License: AGPL-3.0-or-later AND LicenseRef-Commercial → AGPL-3.0-or-later OR LicenseRef-Commercial (dual-license SPDX semantics).
  • README.md: cargo install --git … --bin linkmarks → … --path crates/linkmarks-cli --bin linkmarks --locked (workspace path resolution). [CONTRIBUTING](./.github/PULL_REQUEST_TEMPLATE.md) label mismatch corrected. text language hint added to project-layout fenced block (MD040).

Added

  • 9 state-wiring integration tests in crates/linkmarks-tui/src/app_test.rs covering every SortMode and FilterMode variant via emulated KeyEvents + downstream app.visible() assertions.
  • 6 sort tests + 4 input-handler tests (s cycles sort, Ctrl+F cycles filter, Ctrl+F outside filter is no-op, Ctrl+F preserves query).
  • 13 new ~/.claude/rules/*.md codified from this review (10 from CodeRabbit + 3 from mid-turn hardening dialogue).

Test surface

  • 302/302 tests green (was 286 in v2.1.0).
  • cargo clippy --workspace --all-targets -- -D warnings clean.
  • cargo build --release clean.
  • Manual sanity checks for packaging (linter gap acknowledged: namcap/lintian/rpmlint not installed; dpkg lock from unattended-upgrade).

v2.1.0 — F2.5 batch

Choose a tag to compare

@louzt louzt released this 15 Aug 21:19
v2.1.0
fc39930

What's new

Minor release — F2.5 batch. Three real concerns under one minor bump because they share the same release-cycle intent:

  1. TUI fuzzy filter + sort modes — fuzzy match via nucleo = "0.5" (case-insensitive CaseMatching::Ignore: users typing HELLO almost always mean hello), plus four sort modes (CanonicalUrl, Title, CreatedDesc, UpdatedDesc). Toggle in the TUI status bar. 18 tests cover empty/whitespace pass-through, exact-title-outscores-partial, case-insensitive, unicode accents, tag scoring, score-DESC ordering, stable tie ordering, and a 1000-bookmark performance smoke (< 2 s).

  2. completions <shell> subcommand — emits fresh bash/zsh/fish/powershell/elvish completion scripts at install time. Always regenerated from the live Cli parser, so a renamed flag never goes stale. Install recipes in README.md. 6 tests cover structural signatures (one per shell + one that confirms every shell surfaces in --help).

  3. Packaging templates — declarative stubs under debian/, rpm/, arch/, homebrew/ for downstream maintainers. Each directory has its own README.md documenting the maintenance contract and the anti-feature conformance check. Upstream does NOT build packages — the templates are starting points that downstream maintainers adapt.

Plus: README refresh (Install / Subcommands / CI / Exit codes / Project layout / Packaging / Environment) sync to v2.1.0, and [2.1.0] CHANGELOG entry.

Why CaseMatching::Ignore (semantics over convention)

nucleo's default is Smart (case-sensitive if the query has any uppercase ASCII). That's the wrong default for bookmark search: a bookmark titled "Rust by Example" would silently fail to match a query of RUST. Documented inline in crates/linkmarks-tui/src/filter.rs:

Ignore (case-insensitive) for bookmark search is the right default: users typing "HELLO" almost always mean "hello". Smart (lowercase-only = lenient, any-uppercase = strict) is a worse UX for this domain — a bookmark titled "Rust by Example" would silently not match a query of "RUST".

Scope boundary (what this release is NOT)

  • No GUI. Dioxus integration is the natural choice for Fase 4, deferred per operator direction in the F2.5 planning turn.
  • No CRDT sync. Spike deferred (yrs vs automerge-rs); Fase 3 remains in docs/ROADMAP.md.
  • No actual built packages. The packaging templates are declarative starting points; downstream maintainers adapt them per distro policy.
  • No packaging-time shell-completion install. Completions are generated on demand by the binary the operator just installed, not baked into a package.

Quality gates

  • cargo fmt --all -- --check ✅
  • cargo build --workspace --all-targets ✅
  • cargo clippy --workspace --all-targets -- -D warnings ✅
  • cargo test --workspace --no-fail-fast ✅ 286 / 286 green.

Compatibility / migration

  • clap_complete = "4" is the only new workspace dep. No MSRV bump (still 1.78).
  • Behaviour change: filter /<query> in the TUI now routes through nucleo::Matcher instead of substring equality. Observable only inside the TUI.
  • Workspace version 2.0.1 → 2.1.0; all 6 crates inherit via [workspace.package] version.

Anti-features (locked, unchanged from v2.0.0)

  • No telemetry, no phoning home, no automatic update notifier.
  • No server-authoritative mode.
  • No AI-without-cost-gate.
  • No Docker-only deploy.
  • No closed-source build.
  • No packaging-time shell-completion install.

gpg-signed tag v2.1.0 cut from fc39930. Full diff: PR #11 (30 files, +1607 / −54).

v2.0.1 — Dependabot rust-security group + compat fixes

Choose a tag to compare

@louzt louzt released this 15 Aug 15:47
v2.0.1

Patch release — Dependabot `rust-security` group + compat fixes

Changed (dependency upgrades)

Package From To
`thiserror` 1.0.69 2.0.20
`ulid` 1.2.1 3.0.0
`rusqlite` 0.31.0 0.40.2
`clap` 4.6.4 4.6.6
`quick-xml` 0.36.2 0.41.0
`lz4_flex` 0.11.6 0.14.0
`dirs` 5.0.1 6.0.0
`toml` 0.8.23 1.1.4+spec-1.1.0
`ratatui` 0.28.1 0.30.2
`crossterm` 0.28.1 0.29.0

Fixed

  • ulid 1.x → 3.x: `Ulid::new()` removed; updated to `Ulid::generate()` in `crates/linkmarks-core/src/model.rs:23`.
  • quick-xml 0.36 → 0.41: `Event::GeneralRef` is now emitted as a separate event for character references (`&`, ` `, `á` …). Added exhaustive-match arm in `crates/bridges/linkmarks-bridge-netscape/src/parser.rs`. Bonus fix: removed spurious ASCII-space separator between text chunks so `AT&T` round-trips correctly.
  • clippy `explicit-auto-deref` under Rust 1.97: `&**text` → `let raw_bytes: &[u8] = text;`.

Validation

  • 250/250 tests green (`cargo test --workspace --no-fail-fast`)
  • `cargo clippy --workspace --all-targets -- -D warnings` clean
  • `cargo build --workspace --all-targets` clean
  • `cargo fmt --all -- --check` clean
  • CI smoke (`fmt + build + test + clippy + release binary + groff manpage`) green on PR #10

Refs: #10

LinkMarks v2.0.0 — Fase 2 batch (TUI + Firefox + SQLite store)

Choose a tag to compare

@louzt louzt released this 15 Aug 09:01
v2.0.0

LinkMarks v2.0.0 — Fase 2 batch

Major version bump (1.0.1 → 2.0.0) because Fase 2 introduces a new
persistence surface (SQLite store) and the new tui subcommand changes
the CLI surface.

What's in this release

F1 — SQLite store (linkmarks-core): rusqlite with WAL mode,
busy_timeout=5000ms, foreign_keys=ON, soft-archive via
archived_at. XDG path resolution, TOML config loader, schema
migration runner.

F2 — Netscape bookmark HTML bridge: full parser + sink with
custom HTML5 named-entity decoder (~40 entities) + numeric
character reference handling. Atomic write via tempfile + persist.

F3 — Firefox bridge (linkmarks-bridge-firefox): read-only
places.sqlite reader (moz_bookmarks / moz_places / moz_tags)
plus raw LZ4 block decompressor for bookmarks-backups/*.jsonlz4
using lz4_flex after stripping the mozLz40\0 prefix.

F4 — Interactive TUI (linkmarks-tui, new crate, ~2159 LOC):
ratatui + crossterm-based terminal browser. Browse collections,
filter by substring / tag, view metadata, open URLs. 71 tests across
4 integration suites.

F5 — Install + docs + CI:

  • scripts/install.sh — bash, set -euo pipefail. Auto-detects host.
    Options: --prefix, --binary-from, --force, --dry-run, --help.
  • docs/man/linkmarks.1 — 358-line roff -man page. Renders cleanly
    with groff -man.
  • .github/workflows/ci-smoke.yml — fmt + build + test + clippy +
    release binary smoke + groff render, all on ubuntu-latest.
  • tests/install_test.sh, tests/manpage_test.sh — bash smoke scripts.

Validation

  • cargo build --workspace --all-targets — clean
  • cargo test --workspace --no-fail-fast — 250/250 green
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • bash tests/install_test.sh — all checks passed
  • bash tests/manpage_test.sh — all checks passed

Anti-features (locked — unchanged from v1.0.0)

  • No telemetry, no phoning home, no automatic update notifier.
  • No server-authoritative mode.
  • No AI-without-cost-gate.
  • No Docker-only deploy.
  • No closed-source build.

Deferred to F2.5 (next batch)

  • Fuzzy filter via nucleo — implementation present in working
    tree on branch chore/snapshot-2026-08-15-fuzz-foreign-wt
    (crates/linkmarks-tui/src/filter.rs).
  • Sort modes — crates/linkmarks-tui/src/sort.rs preserved on the
    same snapshot branch.
  • Shell completions (clap_complete + build script).
  • README Install / Subcommands / CI sections refresh — separate
    docs pass.
  • Packaging: Debian / RPM / Arch / Homebrew — future maintenance
    release once install.sh stabilizes.
  • cargo fmt --check — 56 hunks of pre-existing drift to batch
    with F2.5.

What's next (see ROADMAP.md)

  • Fase 3 — CRDT sync server. Spike first comparing yrs
    (Y-CRCT) vs automerge-rs, decision documented in
    docs/decisions/03-crdt-choice.md. linkmarks-server crate
    (axum HTTP + WebSocket, sqlx). Opt-in only — local mode unchanged.
  • Fase 4 — Dioxus desktop GUI.
  • Fase 5 — Plugin market with stable ABI + signed binaries.

Full CHANGELOG entry: https://github.com/LOUST-PRO/LinkMarks/blob/v2.0.0/CHANGELOG.md

LinkMarks v1.0.1: hardening round 1

Choose a tag to compare

@louzt louzt released this 28 Jul 20:59
v1.0.1

LinkMarks v1.0.1 — hardening round 1

Additive release. No breaking changes vs v1.0.0.

Highlights

  • Tracking-param blocklist: 6 → 21 entries with documented sources
    (fbclid, gclid, gbraid, wbraid, msclkid, dclid, yclid,
    twclid, li_fat_id, igshid, ttclid, ref, ref_src, ref_url,
    source, spm, scm, _hsenc, _hsmi, mkt_tok; utm_* and
    mc_* as prefix match).
  • Per-domain preservation: new canonical_config module with
    ALWAYS_FUNCTIONAL list and CanonicalConfig::is_preserved. Operators
    can override the blocklist per domain via ~/.config/linkmarks/config.toml.
    See config.toml.example for the YouTube / Vimeo / GitHub / Twitter-X /
    Amazon recipes.
  • SQLite hardening: new storage module applies 5 pragmas at every
    open(): journal_mode=WAL, busy_timeout=5000, synchronous=NORMAL,
    foreign_keys=ON, temp_store=MEMORY. Concurrent-reader + single-writer
    pattern with bounded lock contention.

Documentation

3 ADRs in MADR format document the design rationale:

Validation

  • 65/65 tests pass (was 58 in v1.0.0; +4 canonical + +3 storage).
  • cargo clippy --all-targets -- -D warnings → 0 warnings.
  • cargo fmt --check → clean.
  • cargo build --release → OK, binary ≈ 2.5 MB.

Commits (4 ahead of main at v1.0.0)

98d0d19 docs: config.toml.example with per-domain preservation rules
a460b36 docs(decisions): ADR 0002/0003/0004 — canonical, sqlite, crdt tombstones
4757e8c feat(core): SQLite WAL + busy_timeout storage helper
fab59d0 feat(core): expand tracking-param blocklist + per-domain preservation rules

Compatibility

All new APIs are additive. Existing v1.0.0 callers of canonicalize(),
is_tracking(), and the bridge crates continue to work unchanged. The
storage module is opt-in: callers that don't yet use it are unaffected.

Full Changelog

See CHANGELOG.md and the v1.0.0...v1.0.1 comparison.