@rigxyz/tapd 0.6.2 → 0.6.4

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.
@@ -27,6 +27,25 @@ function writeBindingConfig(rootDir, config) {
27
27
  mkdirSync(dirname(path), { recursive: true });
28
28
  writeFileSync(path, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
29
29
  }
30
+ var SYNC_PAUSED_PATH = ".rig/sync-paused.json";
31
+ function syncPausedFile(rootDir) {
32
+ return join(rootDir, SYNC_PAUSED_PATH);
33
+ }
34
+ function isSyncPaused(rootDir) {
35
+ const path = syncPausedFile(rootDir);
36
+ if (!existsSync(path)) return false;
37
+ try {
38
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
39
+ return parsed.paused === true;
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+ function writeSyncPaused(rootDir, reason) {
45
+ const path = syncPausedFile(rootDir);
46
+ mkdirSync(dirname(path), { recursive: true });
47
+ writeFileSync(path, JSON.stringify({ paused: true, reason }, null, 2) + "\n");
48
+ }
30
49
  var NotInitializedError = class extends Error {
31
50
  constructor(rootDir) {
32
51
  super(`not initialized \u2014 no binding config at ${rootDir}/${BINDING_CONFIG_PATH}`);
@@ -61,6 +80,12 @@ var RelayError = class extends Error {
61
80
  status;
62
81
  body;
63
82
  };
83
+ function isRecord(v) {
84
+ return typeof v === "object" && v !== null;
85
+ }
86
+ function isBindingDeletedError(err) {
87
+ return err instanceof RelayError && err.status === 410 && isRecord(err.body) && err.body.error === "binding_deleted";
88
+ }
64
89
  async function readJson(res) {
65
90
  const ct = res.headers.get("content-type") ?? "";
66
91
  if (!ct.includes("application/json")) return void 0;
@@ -662,7 +687,7 @@ async function mapPool(items, limit, fn) {
662
687
  function sha256OfBuffer(bytes) {
663
688
  return `sha256:${createHash2("sha256").update(bytes).digest("hex")}`;
664
689
  }
665
- function isRecord(v) {
690
+ function isRecord2(v) {
666
691
  return typeof v === "object" && v !== null;
667
692
  }
668
693
  var UPLOAD_CONCURRENCY = 8;
@@ -704,7 +729,7 @@ async function init(opts) {
704
729
  fetch: opts.fetch
705
730
  });
706
731
  } catch (err) {
707
- if (err instanceof RelayError && isRecord(err.body) && err.body.error === "org_forbidden" && opts.org) {
732
+ if (err instanceof RelayError && isRecord2(err.body) && err.body.error === "org_forbidden" && opts.org) {
708
733
  throw new OrgForbiddenError(opts.org);
709
734
  }
710
735
  throw err;
@@ -1105,7 +1130,7 @@ var ImportTokenScopeError = class extends Error {
1105
1130
  }
1106
1131
  ops;
1107
1132
  };
1108
- function isRecord2(v) {
1133
+ function isRecord3(v) {
1109
1134
  return typeof v === "object" && v !== null;
1110
1135
  }
1111
1136
  function deriveName(canonicalPath) {
@@ -1151,7 +1176,7 @@ async function addImport(opts) {
1151
1176
  fetch: opts.fetch
1152
1177
  });
1153
1178
  } catch (err) {
1154
- if (err instanceof RelayError && isRecord2(err.body) && err.body.reason === "import_requires_read_subscribe") {
1179
+ if (err instanceof RelayError && isRecord3(err.body) && err.body.reason === "import_requires_read_subscribe") {
1155
1180
  throw new ImportTokenScopeError();
1156
1181
  }
1157
1182
  throw err;
@@ -1681,7 +1706,21 @@ async function startSubscription(opts) {
1681
1706
  mode
1682
1707
  });
1683
1708
  } catch (err) {
1684
- console.error("tapd apply error:", err);
1709
+ if (isBindingDeletedError(err)) {
1710
+ const { deletedAt, deletedBy } = err.body;
1711
+ const by = deletedBy?.name ?? deletedBy?.email ?? "someone";
1712
+ console.error(
1713
+ `tapd: binding ${opts.config.bindingId} was deleted by ${by} at ${deletedAt} \u2014 pausing sync and stopping.`
1714
+ );
1715
+ writeSyncPaused(opts.rootDir, "deleted");
1716
+ stopped = true;
1717
+ if (pollTimer) clearTimeout(pollTimer);
1718
+ if (sseApplyTimer) clearTimeout(sseApplyTimer);
1719
+ if (sseSubscriber) await sseSubscriber.stop();
1720
+ opts.onBindingDeleted?.({ deletedAt });
1721
+ } else {
1722
+ console.error("tapd apply error:", err);
1723
+ }
1685
1724
  }
1686
1725
  } while (rerunRequested && !stopped);
1687
1726
  return lastApplyResult;
@@ -1930,6 +1969,7 @@ import { join as join10 } from "path";
1930
1969
  import chokidar from "chokidar";
1931
1970
 
1932
1971
  // src/claude-code.ts
1972
+ import { spawnSync } from "child_process";
1933
1973
  import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync3 } from "fs";
1934
1974
  import { homedir } from "os";
1935
1975
  import { join as join9, relative as relative3, sep as sep3 } from "path";
@@ -1990,6 +2030,10 @@ function toRigRelative(absPath, rootDir) {
1990
2030
  }
1991
2031
  return sep3 === "/" ? rel : rel.replaceAll(sep3, "/");
1992
2032
  }
2033
+ function isWithin2(absPath, base) {
2034
+ const rel = relative3(base, absPath);
2035
+ return rel === "" || !(rel.startsWith("..") || sep3 !== "/" && rel.includes(".." + sep3));
2036
+ }
1993
2037
  var PROMPT_SNIPPET_MAX = 2e3;
1994
2038
  function num(v) {
1995
2039
  return typeof v === "number" && Number.isFinite(v) ? v : 0;
@@ -2025,6 +2069,9 @@ function parseSessions(transcriptPath, rootDir, opts = {}) {
2025
2069
  } catch {
2026
2070
  continue;
2027
2071
  }
2072
+ if (opts.expectedCwd && typeof line.cwd === "string" && line.cwd) {
2073
+ if (!isWithin2(line.cwd, opts.expectedCwd)) return [];
2074
+ }
2028
2075
  const type = line.type;
2029
2076
  if (type === "ai-title" && typeof line.aiTitle === "string") {
2030
2077
  aiTitle = line.aiTitle.trim() || aiTitle;
@@ -2088,8 +2135,29 @@ function parseSessions(transcriptPath, rootDir, opts = {}) {
2088
2135
  }));
2089
2136
  }
2090
2137
  var parseCache = /* @__PURE__ */ new Map();
2091
- function listSessions(rootDir, opts = {}) {
2092
- const dir = join9(opts.projectsRoot ?? defaultClaudeProjectsRoot(), claudeProjectDirName(rootDir));
2138
+ var WORKTREE_TTL_MS = 3e4;
2139
+ var worktreeCache = /* @__PURE__ */ new Map();
2140
+ function gitWorktrees(rootDir) {
2141
+ const now = Date.now();
2142
+ const cached = worktreeCache.get(rootDir);
2143
+ if (cached && now - cached.at < WORKTREE_TTL_MS) return cached.paths;
2144
+ let paths = [];
2145
+ try {
2146
+ const res = spawnSync("git", ["worktree", "list", "--porcelain"], {
2147
+ cwd: rootDir,
2148
+ encoding: "utf8",
2149
+ timeout: 2e3,
2150
+ windowsHide: true
2151
+ });
2152
+ if (res.status === 0 && typeof res.stdout === "string") {
2153
+ paths = res.stdout.split("\n").filter((l) => l.startsWith("worktree ")).map((l) => l.slice("worktree ".length).trim()).filter((p) => p !== "" && p !== rootDir);
2154
+ }
2155
+ } catch {
2156
+ }
2157
+ worktreeCache.set(rootDir, { at: now, paths });
2158
+ return paths;
2159
+ }
2160
+ function sessionsInDir(dir, base) {
2093
2161
  if (!existsSync6(dir)) return [];
2094
2162
  let files;
2095
2163
  try {
@@ -2111,10 +2179,22 @@ function listSessions(rootDir, opts = {}) {
2111
2179
  out.push(...cached.bouts);
2112
2180
  continue;
2113
2181
  }
2114
- const bouts = parseSessions(abs, rootDir);
2182
+ const bouts = parseSessions(abs, base, { expectedCwd: base });
2115
2183
  parseCache.set(abs, { mtimeMs: st.mtimeMs, size: st.size, bouts });
2116
2184
  out.push(...bouts);
2117
2185
  }
2186
+ return out;
2187
+ }
2188
+ function listSessions(rootDir, opts = {}) {
2189
+ const projectsRoot = opts.projectsRoot ?? defaultClaudeProjectsRoot();
2190
+ const out = [];
2191
+ const seen = /* @__PURE__ */ new Set();
2192
+ for (const base of [rootDir, ...gitWorktrees(rootDir)]) {
2193
+ const dir = join9(projectsRoot, claudeProjectDirName(base));
2194
+ if (seen.has(dir)) continue;
2195
+ seen.add(dir);
2196
+ out.push(...sessionsInDir(dir, base));
2197
+ }
2118
2198
  out.sort((a, b) => (a.lastTs ?? "").localeCompare(b.lastTs ?? ""));
2119
2199
  return out;
2120
2200
  }
@@ -2275,7 +2355,13 @@ async function start(opts) {
2275
2355
  fetch: opts.fetch,
2276
2356
  pollSeconds,
2277
2357
  noSse: opts.noSse,
2278
- sseHeartbeatTimeoutMs: opts.sseHeartbeatTimeoutMs
2358
+ sseHeartbeatTimeoutMs: opts.sseHeartbeatTimeoutMs,
2359
+ onBindingDeleted: (info) => {
2360
+ stopped = true;
2361
+ if (scanTimer) clearTimeout(scanTimer);
2362
+ if (watcher) void watcher.close();
2363
+ opts.onBindingDeleted?.({ bindingId: config.bindingId, deletedAt: info.deletedAt });
2364
+ }
2279
2365
  });
2280
2366
  }
2281
2367
  const primaryTrackedPaths = primary ? primary.stateDb.listPaths() : [];
@@ -2408,6 +2494,7 @@ export {
2408
2494
  bindingConfigFile,
2409
2495
  readBindingConfig,
2410
2496
  writeBindingConfig,
2497
+ isSyncPaused,
2411
2498
  NotInitializedError,
2412
2499
  RelayError,
2413
2500
  createBinding,
@@ -2454,4 +2541,4 @@ export {
2454
2541
  scanAndPush,
2455
2542
  start
2456
2543
  };
2457
- //# sourceMappingURL=chunk-RKOWUM3D.js.map
2544
+ //# sourceMappingURL=chunk-F3HYZR2Y.js.map