synctax 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,21 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ---
9
9
 
10
+ ## [2.0.1] — 2026-04-05
11
+
12
+ ### Fixed
13
+
14
+ - **TUI data loader**: Invalid `source` in config now correctly falls back to the default adapter instead of remaining set to the invalid value, preventing downstream TUI failures
15
+ - **TUI data loader**: Theme fallback now uses `"rebel"` to match the schema default in `src/types.ts` (was `"synctax"`, causing inconsistent defaults)
16
+ - **TUI entrypoint**: `NODE_ENV` is now restored in the `finally` block after `waitUntilExit()`, ensuring it is always restored even if `render()` throws, and that it doesn't affect code running during the TUI lifetime
17
+ - **Atomic writes**: Temp file now uses a unique name (`pid-timestamp-random` suffix) instead of a deterministic `.synctax-tmp` suffix, preventing stale file collisions from crashed writes under concurrent access
18
+ - **Lock errors**: Error messages now interpolate the actual computed `lockPath` instead of hardcoding `~/.synctax/sync.lock`, which was misleading when `SYNCTAX_HOME` is set (e.g., in tests)
19
+ - **ESLint config**: `.tsx` files (Ink/React TUI components) are now covered by the ESLint config alongside `.ts` files
20
+ - **Module entry**: `index.ts` no longer emits an unconditional `console.log` side effect on import; replaced with `export {}`
21
+ - **`synctax add`**: Scope flag resolution for `agent` and `skill` now mirrors MCP: `--global` → `"global"`, `--local` → `"local"`, neither → `"global"` (was: `agent`/`skill` ignored `--local` and defaulted to `"local"`, inconsistent with MCP)
22
+
23
+ ---
24
+
10
25
  ## [2.0.0] — 2026-04-05
11
26
 
12
27
  ### Initial Release
package/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
 
8
8
  <p align="center">
9
9
  <a href="https://github.com/Kaos599/Synctax/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Kaos599/Synctax/actions/workflows/ci.yml/badge.svg" /></a>
10
- <img alt="version" src="https://img.shields.io/github/package-json/v/Kaos599/Synctax?color=brightgreen" />
10
+ <a href="https://www.npmjs.com/package/synctax"><img alt="npm" src="https://img.shields.io/npm/v/synctax?color=brightgreen" /></a>
11
11
  <img alt="license" src="https://img.shields.io/github/license/Kaos599/Synctax?color=blue" />
12
- <img alt="runtime" src="https://img.shields.io/badge/runtime-bun-orange" />
12
+ <img alt="runtime" src="https://img.shields.io/badge/node-%E2%89%A518-brightgreen" />
13
13
  <img alt="clients" src="https://img.shields.io/badge/clients-9%20supported-lightgrey" />
14
14
  </p>
15
15
 
@@ -29,21 +29,24 @@ Synctax eliminates this. One master config at `~/.synctax/config.json`. One comm
29
29
 
30
30
  ## Install
31
31
 
32
- **Prerequisites:** [Bun](https://bun.sh) v1.0+
32
+ ```bash
33
+ npm install -g synctax
34
+ ```
35
+
36
+ Works with npm, pnpm, yarn, or Bun:
33
37
 
34
38
  ```bash
35
- git clone https://github.com/Kaos599/synctax.git
36
- cd synctax
37
- bun install
38
- bun ./bin/synctax.ts init
39
- bun ./bin/synctax.ts sync
39
+ pnpm add -g synctax
40
+ yarn global add synctax
41
+ bun add -g synctax
40
42
  ```
41
43
 
42
- After `init` completes its optional PATH setup, you can use the short form everywhere:
44
+ **Requires Node.js ≥18.** No other runtime needed Synctax is a self-contained bundle.
45
+
46
+ Then initialize:
43
47
 
44
48
  ```bash
45
49
  synctax init
46
- synctax sync
47
50
  ```
48
51
 
49
52
  ---
@@ -138,10 +141,10 @@ synctax sync --interactive # Select which resources to sync
138
141
  |--------|-----|--------|--------|-------------|
139
142
  | Claude Code | ✅ | ✅ | ✅ | `CLAUDE.md` |
140
143
  | Cursor | ✅ | ✅ | ✅ | `.cursorrules` |
141
- | GitHub Copilot | ✅ | ✅ | ✅ | `.github/copilot-instructions.md` |
142
- | GitHub Copilot CLI | ✅ | ✅ | ✅ | `.github/copilot-instructions.md` |
143
144
  | OpenCode | ✅ | ✅ | ✅ | `AGENTS.md` |
144
145
  | Antigravity | ✅ | ✅ | ✅ | `.antigravityrules` |
146
+ | GitHub Copilot (VS Code) | ✅ | — | — | `.github/copilot-instructions.md` |
147
+ | GitHub Copilot CLI | — | — | ✅ | `.github/copilot-instructions.md` |
145
148
  | Cline | ✅ | — | — | `.clinerules` |
146
149
  | Zed | ✅ | — | — | `.rules` |
147
150
  | Gemini CLI | — | — | — | `.geminirules` |
@@ -238,7 +241,16 @@ synctax profile diff personal
238
241
 
239
242
  ## Development
240
243
 
244
+ **Prerequisites for contributing:** [Bun](https://bun.sh) v1.0+
245
+
241
246
  ```bash
247
+ git clone https://github.com/Kaos599/synctax.git
248
+ cd synctax
249
+ bun install
250
+
251
+ # Run the CLI directly from source
252
+ bun ./bin/synctax.ts <command>
253
+
242
254
  # Run all tests
243
255
  bun run test
244
256
 
@@ -251,8 +263,8 @@ bun run lint
251
263
  # Run a single test file
252
264
  bunx vitest run tests/adapters.test.ts
253
265
 
254
- # Run the CLI directly
255
- bun ./bin/synctax.ts <command>
266
+ # Build the Node.js bundle (what gets published to npm)
267
+ bun run build
256
268
  ```
257
269
 
258
270
  ---
package/dist/synctax.js CHANGED
@@ -16175,7 +16175,8 @@ import path from "path";
16175
16175
  async function atomicWriteFile(targetPath, content, mode) {
16176
16176
  const dir = path.dirname(targetPath);
16177
16177
  await fs.mkdir(dir, { recursive: true }).catch(() => {});
16178
- const tempPath = targetPath + ".synctax-tmp";
16178
+ const tmpSuffix = `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
16179
+ const tempPath = `${targetPath}.synctax-tmp-${tmpSuffix}`;
16179
16180
  await fs.writeFile(tempPath, content, {
16180
16181
  encoding: "utf-8",
16181
16182
  mode: mode ?? 420
@@ -24252,7 +24253,7 @@ var init_adapters = __esm(() => {
24252
24253
 
24253
24254
  // src/version.ts
24254
24255
  function getVersion() {
24255
- return "2.0.0";
24256
+ return "2.0.1";
24256
24257
  }
24257
24258
 
24258
24259
  // node_modules/@inquirer/core/dist/lib/key.js
@@ -26945,7 +26946,7 @@ async function acquireLock(command = "unknown") {
26945
26946
  try {
26946
26947
  await tryWrite();
26947
26948
  } catch {
26948
- throw new Error("Another synctax process is running. If this is incorrect, delete ~/.synctax/sync.lock");
26949
+ throw new Error(`Another synctax process is running. If this is incorrect, delete ${lockPath}`);
26949
26950
  }
26950
26951
  } else {
26951
26952
  let holder = "unknown";
@@ -26954,7 +26955,7 @@ async function acquireLock(command = "unknown") {
26954
26955
  const info2 = JSON.parse(content);
26955
26956
  holder = `PID ${info2.pid} (${info2.command})`;
26956
26957
  } catch {}
26957
- throw new Error(`Another synctax process is running (${holder}). Wait for it to finish or delete ~/.synctax/sync.lock`);
26958
+ throw new Error(`Another synctax process is running (${holder}). Wait for it to finish or delete ${lockPath}`);
26958
26959
  }
26959
26960
  } else {
26960
26961
  throw err;
@@ -29203,7 +29204,7 @@ async function addCommand(domain2, name, options) {
29203
29204
  prompt: options.prompt || "",
29204
29205
  model: options.model,
29205
29206
  tools: options.tools ? options.tools.split(",") : undefined,
29206
- scope: options.global ? "global" : "local"
29207
+ scope: options.global ? "global" : options.local ? "local" : "global"
29207
29208
  };
29208
29209
  } else if (domain2 === "skill") {
29209
29210
  config2.resources.skills[name] = {
@@ -29211,7 +29212,7 @@ async function addCommand(domain2, name, options) {
29211
29212
  description: options.description,
29212
29213
  trigger: options.trigger,
29213
29214
  content: options.content || "",
29214
- scope: options.global ? "global" : "local"
29215
+ scope: options.global ? "global" : options.local ? "local" : "global"
29215
29216
  };
29216
29217
  } else {
29217
29218
  error48(`Unsupported domain for add: ${domain2}`);
@@ -61530,9 +61531,9 @@ async function runInkTui(options) {
61530
61531
  exitOnCtrlC: false,
61531
61532
  patchConsole: false
61532
61533
  });
61533
- process.env.NODE_ENV = prevEnv;
61534
61534
  await instance.waitUntilExit();
61535
61535
  } finally {
61536
+ process.env.NODE_ENV = prevEnv;
61536
61537
  process.stdout.write("\x1B[?25h");
61537
61538
  process.stdout.write("\x1B[?1049l");
61538
61539
  }
@@ -61563,6 +61564,7 @@ async function loadTuiFrameData() {
61563
61564
  let source = normalizedSource || fallbackSource;
61564
61565
  if (normalizedSource && !Object.hasOwn(adapters, normalizedSource)) {
61565
61566
  warnings.push(`Configured source '${normalizedSource}' is not a valid adapter.`);
61567
+ source = fallbackSource;
61566
61568
  }
61567
61569
  const enabledClients = Object.entries(config2.clients).filter(([id, client]) => Object.hasOwn(adapters, id) && client?.enabled).length;
61568
61570
  if (enabledClients === 0) {
@@ -61572,7 +61574,7 @@ async function loadTuiFrameData() {
61572
61574
  version: getVersion(),
61573
61575
  profile: config2.activeProfile || "default",
61574
61576
  source,
61575
- theme: config2.theme || "synctax",
61577
+ theme: config2.theme ?? "rebel",
61576
61578
  health: warnings.length > 0 ? "WARN" : "OK",
61577
61579
  enabledClients,
61578
61580
  totalClients: adapterIds.length,
@@ -61648,7 +61650,7 @@ init_commands();
61648
61650
 
61649
61651
  // src/version.ts
61650
61652
  function getVersion2() {
61651
- return "2.0.0";
61653
+ return "2.0.1";
61652
61654
  }
61653
61655
 
61654
61656
  // bin/synctax.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synctax",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Universal config sync for the agentic developer stack — sync MCP servers, agents, skills, and permissions across 9 AI clients from a single source of truth.",
5
5
  "type": "module",
6
6
  "license": "MIT",