atris 3.74.29 → 3.76.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.
@@ -26,8 +26,6 @@ const GB = 1e9;
26
26
  // fail (swap, updates, builds), so start refuses to add another copy.
27
27
  const DEFAULT_REAP_BELOW_GB = 25;
28
28
  const DEFAULT_REFUSE_BELOW_GB = 10;
29
- const DEPS_CACHE_KEEP = 3;
30
- const PARTIAL_MAX_AGE_MS = 60 * 60 * 1000;
31
29
  const AGENT_COPIES_DIR = '.agent-worktrees';
32
30
  const DEPS_DIR = '.deps';
33
31
  const CLONE_TIMEOUT_MS = 10 * 60 * 1000;
@@ -224,6 +222,8 @@ function ensureCachedInstall({ workspace, repoName, hash, lockFile, sourceDir, c
224
222
  const entry = depsCacheEntry(workspace, repoName, hash);
225
223
  const cached = path.join(entry, 'node_modules');
226
224
  if (installedMatchesLock(lockFile, cached)) return cached;
225
+ // A mismatched existing entry may contain local changes. Do not replace it.
226
+ if (pathExists(entry)) return null;
227
227
  if (!sourceDir || !installedMatchesLock(lockFile, sourceDir)) return null;
228
228
  const partial = path.join(depsRepoDir(workspace, repoName), `.partial-${hash}-${process.pid}-${Date.now()}`);
229
229
  try {
@@ -233,8 +233,6 @@ function ensureCachedInstall({ workspace, repoName, hash, lockFile, sourceDir, c
233
233
  // Build caches are not part of the install and only grow the store.
234
234
  removeTree(path.join(partial, 'node_modules', '.cache'));
235
235
  if (!installedMatchesLock(lockFile, path.join(partial, 'node_modules'))) return null;
236
- // An entry that no longer matches its own lockfile was changed by hand.
237
- if (pathExists(entry) && !installedMatchesLock(lockFile, cached)) removeTree(entry);
238
236
  try {
239
237
  fs.renameSync(partial, entry);
240
238
  } catch {
@@ -253,49 +251,12 @@ function touch(target) {
253
251
  } catch {}
254
252
  }
255
253
 
256
- // Keeps the `keep` most recently used installs per repo and drops partial
257
- // entries a crashed start left behind.
258
- function pruneDepsCache({ workspace, repoName, keep = DEPS_CACHE_KEEP, now = Date.now() } = {}) {
259
- const dir = depsRepoDir(workspace, repoName);
260
- let names = [];
261
- try {
262
- names = fs.readdirSync(dir);
263
- } catch {
264
- return [];
265
- }
266
- const removed = [];
267
- const entries = [];
268
- for (const name of names) {
269
- const full = path.join(dir, name);
270
- let mtimeMs = 0;
271
- try {
272
- mtimeMs = fs.statSync(full).mtimeMs;
273
- } catch {
274
- continue;
275
- }
276
- if (name.startsWith('.partial-')) {
277
- if (now - mtimeMs > PARTIAL_MAX_AGE_MS) {
278
- removeTree(full);
279
- removed.push(full);
280
- }
281
- continue;
282
- }
283
- if (!name.startsWith('.')) entries.push({ full, mtimeMs });
284
- }
285
- entries.sort((a, b) => b.mtimeMs - a.mtimeMs);
286
- for (const old of entries.slice(keep)) {
287
- removeTree(old.full);
288
- removed.push(old.full);
289
- }
290
- return removed;
291
- }
292
-
293
254
  // Gives a new build copy its node_modules as a clone of a matching install,
294
255
  // so the agent skips `npm ci`. Looks in the shared store first, then in the
295
256
  // main checkout and other copies of the same repo. Never fails the start:
296
257
  // any miss returns { status: 'skipped', reason } and the agent installs as
297
258
  // before.
298
- function seedNodeModules({ target, workspace, repoName, sources = [], clone = cloneTree, keep = DEPS_CACHE_KEEP, isIgnored = () => true } = {}) {
259
+ function seedNodeModules({ target, workspace, repoName, sources = [], clone = cloneTree, isIgnored = () => true } = {}) {
299
260
  const startedAt = Date.now();
300
261
  const result = (status, reason, extra = {}) => ({ status, reason, ms: Date.now() - startedAt, ...extra });
301
262
  const lockFile = path.join(target, 'package-lock.json');
@@ -327,14 +288,13 @@ function seedNodeModules({ target, workspace, repoName, sources = [], clone = cl
327
288
  }
328
289
  }
329
290
  if (!cached) return result('skipped', 'no matching install to clone yet; run npm ci, and later copies will clone it', { hash });
330
- // Mark the entry used before cloning so a parallel prune keeps it.
291
+ // Record use of the entry before cloning it.
331
292
  touch(path.dirname(cached));
332
293
  const cloned = clone(cached, modules);
333
294
  if (!cloned.ok || !installedMatchesLock(lockFile, modules)) {
334
295
  removeTree(modules);
335
296
  return result('skipped', `clone failed: ${cloned.error || 'install did not match after cloning'}`, { hash });
336
297
  }
337
- pruneDepsCache({ workspace, repoName, keep });
338
298
  return result('cloned', '', { hash, method: cloned.method, source: cached });
339
299
  }
340
300
 
@@ -351,7 +311,6 @@ module.exports = {
351
311
  isInside,
352
312
  isScratchPath,
353
313
  lockHash,
354
- pruneDepsCache,
355
314
  seedNodeModules,
356
315
  spaceLimits,
357
316
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atris",
3
- "version": "3.74.29",
3
+ "version": "3.76.0",
4
4
  "description": "you say what you want in plain words. atris builds it, checks it, and shows you proof.",
5
5
  "mcpName": "io.github.atrislabs/atris",
6
6
  "main": "bin/atris.js",