sidecarsync 1.3.0 → 2.0.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sidecarsync",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "description": "A Git-backed sidecar inbox for repo-local development metadata.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,18 +28,22 @@
28
28
  "postinstall": "node scripts/postinstall.js",
29
29
  "prepack": "cp ../../README.md README.md && cp ../../LICENSE LICENSE && bun run build",
30
30
  "prepublishOnly": "bun run check",
31
- "test": "bun run build && vitest run"
31
+ "test": "vitest run",
32
+ "test:integration": "bun run build && SIDECAR_INTEGRATION=1 vitest run"
32
33
  },
33
34
  "engines": {
34
35
  "node": ">=20"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@types/node": "^22.13.10",
39
+ "@types/picomatch": "^4",
38
40
  "typescript": "^5.8.2",
39
41
  "vitest": "^3.0.8"
40
42
  },
41
43
  "dependencies": {
42
44
  "chokidar": "^4.0.3",
45
+ "ignore": "^7.0.8",
46
+ "picomatch": "^4.0.5",
43
47
  "smol-toml": "^1.7.0"
44
48
  }
45
49
  }
@@ -7,6 +7,12 @@ import { fileURLToPath } from "node:url";
7
7
 
8
8
  const LABEL = "com.anteprojector.sidecar";
9
9
  const BIN_NAME = process.platform === "win32" ? "sidecar.cmd" : "sidecar";
10
+ // A repo declares its sidecars as `.sidecar` and any `.sidecar.<peer>` beside
11
+ // it. Mirrors `peerNameOf` in the CLI: a name is lowercase letters, digits,
12
+ // and hyphens, and the suffixes an editor or a backup would leave are not
13
+ // peers. Only presence matters here — the CLI does the reading.
14
+ const PEER_FILE = /^\.sidecar(?:\.([a-z0-9][a-z0-9-]*))?$/;
15
+ const NOT_PEERS = new Set(["default", "swp", "swo", "swx", "bak", "orig", "rej", "tmp", "old", "example", "sample", "lock"]);
10
16
 
11
17
  try {
12
18
  const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
@@ -65,7 +71,7 @@ function recordInstallSource(packageRoot) {
65
71
  // directory that silently never updates — worse than no checkout at all.
66
72
  function setUpLocalInstall(packageRoot) {
67
73
  const projectRoot = findInstallProjectRoot();
68
- if (!projectRoot || !fs.existsSync(path.join(projectRoot, ".sidecar"))) return;
74
+ if (!projectRoot) return;
69
75
 
70
76
  const globalSidecar = findGlobalSidecar(packageRoot);
71
77
  if (!globalSidecar) {
@@ -134,10 +140,21 @@ function findInstallProjectRoot() {
134
140
  return undefined;
135
141
  }
136
142
 
143
+ function declaresPeers(dir) {
144
+ try {
145
+ return fs.readdirSync(dir).some((entry) => {
146
+ const match = PEER_FILE.exec(entry);
147
+ return Boolean(match) && !NOT_PEERS.has(match[1]);
148
+ });
149
+ } catch {
150
+ return false;
151
+ }
152
+ }
153
+
137
154
  function findConfigRoot(start) {
138
155
  let current = path.resolve(start);
139
156
  while (true) {
140
- if (fs.existsSync(path.join(current, ".sidecar"))) return current;
157
+ if (declaresPeers(current)) return current;
141
158
  const parent = path.dirname(current);
142
159
  if (parent === current) return undefined;
143
160
  current = parent;