devlyn-cli 4.2.1 → 4.2.2

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.
Files changed (2) hide show
  1. package/bin/devlyn.js +17 -7
  2. package/package.json +1 -1
package/bin/devlyn.js CHANGED
@@ -425,7 +425,10 @@ function readInstallManifest(root) {
425
425
  if (!stat) return {};
426
426
  if (!stat.isFile()) throw new Error(`not a regular install marker: ${markerPath}`);
427
427
  const marker = JSON.parse(fs.readFileSync(markerPath, 'utf8'));
428
- return marker?.package === PKG.name && marker.schemaVersion === 1 ? marker.skills || {} : {};
428
+ if (marker?.package !== PKG.name || marker.schemaVersion !== 1) {
429
+ throw new Error('not a devlyn-cli install marker');
430
+ }
431
+ return marker.skills || {};
429
432
  }
430
433
 
431
434
  // Enumerate every directory this install may replace, migrate or remove, before
@@ -474,7 +477,13 @@ function preflightSkills(roots, optionalNames = [], commandDir = null) {
474
477
  if (stat && !stat.isDirectory()) throw new Error(`not a real directory: ${dir}`);
475
478
  }
476
479
  const tracked = trackedPaths(root);
477
- const manifest = readInstallManifest(root);
480
+ let manifest;
481
+ try {
482
+ manifest = readInstallManifest(root);
483
+ } catch (error) {
484
+ conflicts.push(`${path.join(root, DEVLYN_INSTALL_MARKER)}: ${error.message}`);
485
+ continue;
486
+ }
478
487
  for (const name of plannedSkills(root, optionalNames)) {
479
488
  const dest = path.join(root, name);
480
489
  const isTracked = tracked.some((file) => file.toLowerCase() === dest.toLowerCase()
@@ -542,12 +551,13 @@ function writeInstallMarker(skillsDir, names, previous) {
542
551
  version: PKG.version,
543
552
  skills: { ...previous, ...Object.fromEntries(names.map((name) => [name, fingerprint(path.join(skillsDir, name))])) },
544
553
  };
554
+ const fd = fs.openSync(tempPath, 'wx', 0o600);
545
555
  try {
546
- fs.writeFileSync(tempPath, JSON.stringify(marker, null, 2) + '\n', {
547
- encoding: 'utf8',
548
- flag: 'wx',
549
- mode: 0o600,
550
- });
556
+ try {
557
+ fs.writeFileSync(fd, JSON.stringify(marker, null, 2) + '\n', 'utf8');
558
+ } finally {
559
+ fs.closeSync(fd);
560
+ }
551
561
  fs.renameSync(tempPath, markerPath);
552
562
  } finally {
553
563
  fs.rmSync(tempPath, { force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devlyn-cli",
3
- "version": "4.2.1",
3
+ "version": "4.2.2",
4
4
  "description": "Loop & harness engineering for AI coding agents (Claude Code, Codex, and any AGENTS.md-driven agent) — core engineering principles for CLAUDE.md/AGENTS.md and a loop designer that splits one intent into tasks agents drain hands-free",
5
5
  "homepage": "https://github.com/fysoul17/devlyn-cli#readme",
6
6
  "bin": {