Skip to content

Releases: hungv47/syncthis

v0.15.1

09 Jun 03:40
b452a94

Choose a tag to compare

Fixed

  • First-run welcome banner now shows the noun-first grammar. The 0.15.0 refactor moved the canonical surface to noun-first verbs but left welcome.tsx's hardcoded command list on the pre-0.15 spelling (add plugin, bare mcp/skills, <from> <to>, rm <server>, plugin list). The banner now lists plugins add, mcp sync, skills update, mcp <from> <to>, mcp rm, and plugins list, matching syncthis help.

v0.15.0

09 Jun 03:29
cdf4a75

Choose a tag to compare

Includes everything in 0.14.1 (cross-agent plugin/skill identity hardening), which was never published on its own.

Added

  • Noun-first CLI grammar. Three nouns — plugins, skills, mcp — each with scoped verbs (plugins list|mirror|add|rm, skills update|add|from-plugins|rm, mcp sync|doctor|from|rm, plus directional mcp <from> <to>), alongside the flagship sync. This is now the canonical, advertised surface (syncthis help, syncthis <noun> help). The change is additive and non-breaking: every pre-0.15 command still works as an unadvertised alias routing to the same handler (run, bare mcp, doctor, mirror, from, <from> <to>, add/rm <skill|plugin|mcp>, plugin list/plugin rm). Bare-noun behavior preserves legacy side effects (mcp → union sync, skills → update) while help advertises the explicit verbs; bare plugins prints group help. A collision guard in cmdMcp keeps a future agent id from being shadowed by a verb name. Routing + alias equivalence is pinned by tests/cli-routing.test.ts.
  • Reproducible terminal demos. VHS tapes (docs/demos/tapes/) render the GIFs embedded in the README from a sandboxed fixture-$HOME harness (docs/demos/seed-fixtures.ts, docs/demos/build.sh): pure-file MCP flows are recorded live (showing real mutations + the .syncthis.bak backup), shell-out plugin/skills flows as dry-run/preview, so no external CLIs are needed and the output is deterministic.

Changed

  • Inline TUI walk-through guidance. The interactive picker now renders breadcrumb headers and inline affordances via the existing note()/tui-style helpers (no new mode, no new runtime deps), so each flow shows where you are in source → items → destinations → preview → confirm.

v0.14.0

05 Jun 02:53

Choose a tag to compare

Changed

  • Interactive multiselect picker restyled to match the native prompts. The grouped/flat checkbox picker (plugins, skills, agents, MCP servers) hand-rolled its render with ASCII pipes, a stray backtick footer, and no color, so long lists looked broken next to the clack select() menus. It now renders with the same treatment as those menus — gray bars, a end-cap, a colored / state glyph, / checkboxes, and a cyan-highlighted active row — via a new dependency-free src/tui-style.ts that re-derives clack's Unicode/ASCII fallback and NO_COLOR/non-TTY-aware color (zero added runtime deps). Marketplace group rows now carry a glyph + bold label over dimmed, indented children, the window height adapts to the terminal, and the row-eating ... truncation is replaced by dim ↑ N more / ↓ N more counters.

Added

  • Type-to-filter in the multiselect picker. On lists longer than one page (e.g. the 200+ plugin catalog), just start typing to incrementally filter — matches collapse to the typed substring with a synthetic select all (N matches) row, backspace narrows back, and clearing the filter restores the full grouped structure. Selections persist across filter changes. The previous hidden a-selects-all shortcut is retired (the key is now free for typing); the visible select all row remains the discoverable bulk-select mechanism.

v0.13.1

03 Jun 02:41

Choose a tag to compare

Fixed

  • syncthis update now updates the copy on your PATH — fixing the stale version after update. On a machine with more than one Node prefix (e.g. a Homebrew node on PATH while npm's global prefix points at a version-manager prefix), npm install -g installed the new version into a prefix you never run from, so the banner stayed frozen at the old version every release. update now derives the global prefix from the running binary (import.meta.url) and pins npm to it with --prefix, so the exact copy you execute is the one refreshed. It then re-reads that copy's package.json and reports the real result (updated X → Y / now at Y) instead of a blind "updated to latest" that could mask a stale install. New pure, tested src/self-update.ts (deriveGlobalPrefix) handles the unix lib/node_modules vs Windows node_modules layouts and falls back to npm's default in a dev/source run.

Changed

  • Plugin-install status lines reflect the network-free local-marketplace path. The add plugin apply note now reads "Codex installs from local marketplace clones (offline); Cursor/skills steps use npx (network)", and the mirror provisioning note clarifies that Codex installs from local clones when available, with npx plugins add as the fallback — matching the 0.13.0 mechanism instead of overstating npx/network use.

v0.13.0

03 Jun 02:25

Choose a tag to compare

Changed

  • Network-free, idempotent plugin install via the source's local marketplace clone. Transferring a Claude plugin to Codex (add plugin, mirror, and the interactive plugin sync) now registers the source's on-disk marketplace clone on the target — codex plugin marketplace add <clonePath> (reused when already registered by root or name, never re-added) — then codex plugin add <name>@<marketplace>. No npx plugins fetch, no network round-trip, and no duplicate marketplace rows in ~/.codex/config.toml. npx plugins provisioning remains a guarded fallback only when no local clone exists. New pure resolver src/plugins/marketplace.ts (parseMarketplaceList, readLocalMarketplace, resolveLocalMarketplace); new PluginInstallOpts.sourceClonePath; Claude clone paths resolved from known_marketplaces.json and threaded through add.ts / mirror.ts. A URL-named install id or multi-plugin alias whose manifest name differs from the entry name still falls through to the existing coverage/skills-fallback path, so behavior there is unchanged.

Added

  • Discoverable select-all in the interactive picker. The multi-select now renders a visible select all (N) control row, and — for grouped lists like plugins by marketplace — a per-group <marketplace> (N) select-all row, alongside the existing a shortcut. Plugins default to those installed on the source agent, grouped by marketplace, with a toggle to show all available marketplace clones (installed-and-not). New tested src/picker-logic.ts (buildRows, nextSelectionForRow, groupPluginsByMarketplace) holds the pure selection/grouping logic, decoupled from the terminal.
  • Share installed skills agent → agent. A new interactive skills flow picks a source agent, its installed skills, and destination agents, then adds each skill to the destinations using the skill's own on-disk store path as the npx skills add source — no dir-copy that would corrupt the shared ~/.agents/skills/ symlink store.

v0.12.4

02 Jun 07:44
a47f715

Choose a tag to compare

Fixed

  • Interactive multi-select prompts now use real checkboxes without flooding large lists. Plugin, skill, agent, and MCP pickers use a windowed checkbox prompt with Space to toggle, a to select all, and Enter to confirm. Large installs stay paged instead of rendering hundreds of rows at once, and empty submits warn/retry without crashing.

v0.12.3

02 Jun 07:18
72e002d

Choose a tag to compare

Added

  • syncthis update. Updates the global @hungv47/syncthis install to latest, using npm install -g @hungv47/syncthis@latest by default and Bun's global install when the current executable comes from Bun. Supports --dry-run.
  • syncthis version / --version / -v. Prints the installed package version directly.

Fixed

  • Version reporting now reads installed package metadata at runtime. The welcome banner and version command read the installed package.json instead of bundling a JSON snapshot, preventing stale version output from a generated dist/syncthis.mjs.

v0.12.2

02 Jun 07:00

Choose a tag to compare

Fixed

  • Claude plugin reads no longer depend on truncated CLI JSON. Large Claude plugin installs can make claude plugin list --json exit 0 with exactly 65 536 bytes of malformed JSON. The Claude plugin adapter now prefers Claude's durable ~/.claude/plugins/installed_plugins.json state file, keeping plugin list, add plugin, plugin rm, and mirror working on large installs.

Changed

  • Interactive plugin management now uses one selected sync flow. The TUI no longer presents a separate "Mirror all" option. Manage plugins → Sync plugins asks for source, plugin selection, and destination agents; selecting all covers the old interactive mirror use case. The syncthis mirror CLI command remains as a batch/back-compat shortcut.

v0.12.1

02 Jun 03:17

Choose a tag to compare

Fixed

  • Tolerate Claude plugin list --json truncation. On a machine with many plugins, claude plugin list --json can hit a ~64 KB stdout cap and return malformed JSON, which previously broke every plugin-aware path (plugin list, mirror, plugin rm, add plugin). The Claude plugin adapter now reads ~/.claude/plugins/installed_plugins.json directly when the CLI is missing, exits non-zero, or returns unparseable/unexpected JSON (with a hint when stdout is exactly 65 536 bytes — the telltale of a buffer cap). marketplaceSources() gets the same fallback against ~/.claude/plugins/known_marketplaces.json, so mirror's <name>@<marketplace> resolution and provisioning still work when claude plugin marketplace list --json is unreadable too. Same shape, same data — just read from Claude's own state files instead of round-tripping the CLI. New exported parseClaudeInstalledPlugins for tests.
  • Skill already-synced guard is now per-agent, not global. addSkillsFromPlugins previously skipped a source repo whenever every skill name was globally present in npx skills list -g --json — even if those skills were registered only on some agents and the current sync was targeting agents that didn't have them. After a TUI "Add from repo" that picked a subset of agents, a later syncthis run (cohort) would falsely report "already synced" and leave the missing agents missing. Now a repo is skipped only when every skill it contributes is already registered on every requested agent. force: true (interactive Add-from-repo / Sync-from-plugins) still bypasses the guard. Default run/sync behavior unchanged for the common case where the cohort already has everything.

v0.12.0

02 Jun 03:00

Choose a tag to compare

Added

  • Selective MCP sync — share chosen servers from one agent to others. New core runSelectiveMcpSync (sync.ts): pick a source agent, pick specific MCP server names, pick destination agents, and add just those servers — additive and conflict-safe. A server name already present on a destination with a different config is left untouched and reported (same conflict policy as union sync, sacred element #3); a name missing from the source is reported as notFound. This is not an add mcp — it never installs a new server or overwrites one, it only spreads servers an agent already has, so MCP stays sync + remove only. Exposed interactively via the MCP manager's Sync selected flow (source → servers → destinations → preview → confirm).

Changed

  • Interactive capability management, simplified. Running syncthis with no args now opens a top-level menu of per-capability managers — Manage plugins (sync selected / mirror / list / remove), Manage skills (add from repo / sync from plugins / update / remove), Manage MCPs (sync everything / sync selected / sync all only / remove / doctor), and Check problems — each walking the same source → items → destinations → preview/confirm shape. This replaces 0.11.0's single "Add or remove capabilities" entry. No CLI command behavior changed; the picker is just clearer to navigate.
  • Skill add gained a force mode. addSkillsFromPlugins({ force }) bypasses the global already-present guard so the interactive "Add from repo" / "Sync from plugins" flows can re-add chosen plugin skills to chosen agents on demand, instead of being silently skipped when the skill name is already globally present. The default (non-force) run/sync path is unchanged — it still skips already-synced repos so a repeat run doesn't re-fetch.