codexport 0.1.5 → 0.1.6

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/dist/index.js +30 -5
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { Command, Option } from "commander";
3
3
  import chokidar from "chokidar";
4
4
  import { createHash, randomBytes } from "node:crypto";
5
5
  import { createServer, request } from "node:http";
6
- import { lstat, mkdir, readFile, readdir, readlink, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
6
+ import { chmod, lstat, mkdir, readFile, readdir, readlink, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
7
7
  import { existsSync } from "node:fs";
8
8
  import { realpathSync } from "node:fs";
9
9
  import { fileURLToPath } from "node:url";
@@ -11,7 +11,7 @@ import { homedir, platform } from "node:os";
11
11
  import path from "node:path";
12
12
  import { spawn } from "node:child_process";
13
13
  import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
14
- const VERSION = "0.1.5";
14
+ const VERSION = "0.1.6";
15
15
  const DEFAULT_PORT = 17342;
16
16
  const DEFAULT_TIMEOUT_MS = 5_000;
17
17
  const CODEXPORT_DIR = ".codexport";
@@ -114,6 +114,31 @@ async function writeJsonAtomic(filePath, value) {
114
114
  await writeFile(tmpPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
115
115
  await rename(tmpPath, filePath);
116
116
  }
117
+ async function writeFileReplacingExisting(filePath, content, options) {
118
+ try {
119
+ await writeFile(filePath, content, options);
120
+ return;
121
+ }
122
+ catch (error) {
123
+ if (!isPermissionError(error))
124
+ throw error;
125
+ }
126
+ if (await pathExists(filePath)) {
127
+ try {
128
+ await chmod(filePath, 0o666);
129
+ }
130
+ catch (error) {
131
+ if (!isPermissionError(error))
132
+ throw error;
133
+ }
134
+ await rm(filePath, { force: true });
135
+ }
136
+ await writeFile(filePath, content, options);
137
+ }
138
+ function isPermissionError(error) {
139
+ const code = error.code;
140
+ return code === "EACCES" || code === "EPERM";
141
+ }
117
142
  function parseTomlObject(text, filePath) {
118
143
  try {
119
144
  const parsed = parseToml(text);
@@ -556,7 +581,7 @@ async function applyBundle(ctx, bundle) {
556
581
  await ensureDir(path.dirname(target));
557
582
  if (file.path === "config.toml")
558
583
  continue;
559
- await writeFile(target, decodeFile(file), { mode: file.mode });
584
+ await writeFileReplacingExisting(target, decodeFile(file), { mode: file.mode });
560
585
  }
561
586
  const configEntry = bundle.files.find((file) => file.path === "config.toml");
562
587
  if (configEntry) {
@@ -568,7 +593,7 @@ async function applyBundle(ctx, bundle) {
568
593
  const backupPath = `${configPath}.codexport-backup-${new Date().toISOString().replace(/[:.]/g, "-")}`;
569
594
  await writeFile(backupPath, await readFile(configPath));
570
595
  }
571
- await writeFile(configPath, generated, "utf8");
596
+ await writeFileReplacingExisting(configPath, generated, "utf8");
572
597
  }
573
598
  const localSkillsDir = path.join(ctx.stateDir, "skills");
574
599
  if (await pathExists(localSkillsDir)) {
@@ -589,7 +614,7 @@ async function copyDirectory(source, target) {
589
614
  }
590
615
  else if (entry.isFile()) {
591
616
  await ensureDir(path.dirname(targetPath));
592
- await writeFile(targetPath, await readFile(sourcePath));
617
+ await writeFileReplacingExisting(targetPath, await readFile(sourcePath));
593
618
  }
594
619
  else if (entry.isSymbolicLink()) {
595
620
  const linkTarget = await readlink(sourcePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexport",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "sync a canonical Codex setup from one master machine to follower machines",
5
5
  "author": "Microck <contact@micr.dev>",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  "automation"
25
25
  ],
26
26
  "bin": {
27
- "codexport": "./dist/index.js"
27
+ "codexport": "dist/index.js"
28
28
  },
29
29
  "files": [
30
30
  "dist",