copilot-relay 0.4.7 → 0.4.8

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/README.md CHANGED
@@ -72,7 +72,7 @@ scripts. It asks GitHub with the stored token, so no relay needs to run.
72
72
 
73
73
  - [Configure models and deep checks](wiki/EN-Configuration.md) · [中文](wiki/ZH-Configuration.md)
74
74
  - Run at login: [macOS](wiki/EN-macOS-LaunchAgent.md) · [Windows](wiki/EN-Windows-Service.md) · [Linux](wiki/EN-Linux-systemd.md)
75
- - [Troubleshoot](wiki/EN-Logging-Troubleshooting.md) · [Understand the architecture](wiki/EN-Architecture.md) · [Contribute](wiki/EN-Development.md)
75
+ - [Commands](wiki/EN-Commands.md) · [Prompt caching](wiki/EN-Prompt-Caching.md) · [Troubleshoot](wiki/EN-Logging-Troubleshooting.md) · [Understand the architecture](wiki/EN-Architecture.md) · [Contribute](wiki/EN-Development.md)
76
76
 
77
77
  Unofficial research project; not affiliated with GitHub or Anthropic. Upstream
78
78
  services and compatibility can change. Model and tool support are not guaranteed;
package/dist/main.js CHANGED
@@ -49,6 +49,24 @@ var PromptTooLongError = class extends HTTPError {
49
49
  }
50
50
  };
51
51
 
52
+ //#endregion
53
+ //#region src/lib/file-identity.ts
54
+ /** True when two stats of a path name the same file: the same device and file index. */
55
+ const sameFile$1 = (left, right) => left.dev === right.dev && left.ino === right.ino;
56
+ /**
57
+ * True when a stat of an open handle and a stat of its path name the same file.
58
+ *
59
+ * On Windows the two can disagree on `dev` for the same file: on Node 22.13.1 a path stat
60
+ * reports `dev` 0 while a handle stat reports the volume serial number. There a `dev` of 0 on
61
+ * either side counts as unreported and the file index (`ino`) alone decides, which is weaker
62
+ * evidence than both. Two nonzero `dev` values must still match, and other platforms compare both.
63
+ */
64
+ const sameOpenedFile = (left, right, platform = process.platform) => {
65
+ if (left.ino !== right.ino) return false;
66
+ if (platform === "win32" && (left.dev === 0 || right.dev === 0)) return true;
67
+ return left.dev === right.dev;
68
+ };
69
+
52
70
  //#endregion
53
71
  //#region src/lib/paths.ts
54
72
  const homeDir = os.homedir();
@@ -371,7 +389,6 @@ const formatLogValue = (value) => typeof value === "string" ? value : inspect(va
371
389
  });
372
390
  const escapeLogLineSeparators = (value) => value.replaceAll("\r", "\\r").replaceAll("\n", "\\n").replaceAll(String.fromCodePoint(8232), "\\u2028").replaceAll(String.fromCodePoint(8233), "\\u2029");
373
391
  const isMissing$2 = (error) => error.code === "ENOENT";
374
- const sameFile$2 = (left, right) => left.dev === right.dev && left.ino === right.ino;
375
392
  const ensurePrivateDirectory = async (directory) => {
376
393
  await fs.mkdir(directory, { mode: 448 }).catch((error) => {
377
394
  if (error.code !== "EEXIST") throw error;
@@ -382,7 +399,7 @@ const ensurePrivateDirectory = async (directory) => {
382
399
  const handle = await fs.open(directory, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
383
400
  try {
384
401
  const opened = await handle.stat();
385
- if (!opened.isDirectory() || !sameFile$2(observed, opened)) throw new Error("Log directory changed while opening");
402
+ if (!opened.isDirectory() || !sameOpenedFile(observed, opened)) throw new Error("Log directory changed while opening");
386
403
  await handle.chmod(448);
387
404
  } finally {
388
405
  await handle.close();
@@ -401,10 +418,10 @@ let activeLog;
401
418
  let logIdleClose;
402
419
  const maxLogWriteBytes = 256 * 1024;
403
420
  const hasMode = (stats, mode) => process.platform === "win32" || (stats.mode & 511) === mode;
404
- const isSameDirectory = (current, checked) => current !== void 0 && current.isDirectory() && sameFile$2(current, checked) && hasMode(current, 448);
421
+ const isSameDirectory = (current, checked) => current !== void 0 && current.isDirectory() && sameFile$1(current, checked) && hasMode(current, 448);
405
422
  const isStillActive = async (active) => {
406
423
  const [current, ...directories] = await Promise.all([active.filePath, ...logDirectories].map((target) => fs.lstat(target).catch(() => void 0)));
407
- return current !== void 0 && current.isFile() && current.nlink === 1 && sameFile$2(current, active.identity) && hasMode(current, 384) && active.directories.every((checked, index) => isSameDirectory(directories[index], checked));
424
+ return current !== void 0 && current.isFile() && current.nlink === 1 && sameOpenedFile(current, active.identity) && hasMode(current, 384) && active.directories.every((checked, index) => isSameDirectory(directories[index], checked));
408
425
  };
409
426
  const openPrivateLog = async (filePath, directories) => {
410
427
  const observed = await fs.lstat(filePath).catch((error) => {
@@ -416,7 +433,7 @@ const openPrivateLog = async (filePath, directories) => {
416
433
  try {
417
434
  const opened = await handle.stat();
418
435
  const current = await fs.lstat(filePath);
419
- if (!opened.isFile() || opened.nlink !== 1 || current.isSymbolicLink() || !sameFile$2(opened, current) || observed && !sameFile$2(observed, opened)) throw new Error("Log file changed while opening");
436
+ if (!opened.isFile() || opened.nlink !== 1 || current.isSymbolicLink() || !sameOpenedFile(opened, current) || observed && !sameOpenedFile(observed, opened)) throw new Error("Log file changed while opening");
420
437
  if (process.platform !== "win32") await handle.chmod(384);
421
438
  return {
422
439
  filePath,
@@ -2296,7 +2313,6 @@ const markDiscardedResponse = (response) => {
2296
2313
  };
2297
2314
  const credentialPattern = /(?:gh[pousr]_|github_pat_|sk-|eyJ)[A-Za-z0-9_-]+/;
2298
2315
  const uuidPattern = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
2299
- const sameFile$1 = (left, right) => left.dev === right.dev && left.ino === right.ino;
2300
2316
  const noFollow = process.platform === "win32" ? 0 : fs.constants.O_NOFOLLOW;
2301
2317
  const safeValue = (value) => typeof value === "string" && /^[A-Za-z0-9_.:/[\]-]{1,160}$/.test(value) && !/(?:gh[pousr]_|github_pat_|sk-|eyJ)[A-Za-z0-9_-]+/.test(value) ? value : void 0;
2302
2318
  const errorName = (error) => error instanceof Error && [
@@ -2444,7 +2460,7 @@ const privateDirectory = async (directory) => {
2444
2460
  const handle = await fs.open(directory, fs.constants.O_RDONLY | noFollow);
2445
2461
  try {
2446
2462
  const opened = await handle.stat();
2447
- if (!opened.isDirectory() || !sameFile$1(observed, opened)) throw new Error("Capture directory changed.");
2463
+ if (!opened.isDirectory() || !sameOpenedFile(observed, opened)) throw new Error("Capture directory changed.");
2448
2464
  await handle.chmod(448);
2449
2465
  return opened;
2450
2466
  } finally {
@@ -2456,7 +2472,7 @@ const createPrivateFile = async (file) => {
2456
2472
  try {
2457
2473
  const opened = await handle.stat();
2458
2474
  const current = await fs.lstat(file);
2459
- if (!opened.isFile() || opened.nlink !== 1 || current.isSymbolicLink() || !sameFile$1(opened, current)) throw new Error("Unsafe capture file.");
2475
+ if (!opened.isFile() || opened.nlink !== 1 || current.isSymbolicLink() || !sameOpenedFile(opened, current)) throw new Error("Unsafe capture file.");
2460
2476
  return handle;
2461
2477
  } catch (error) {
2462
2478
  await handle.close();
@@ -2914,7 +2930,7 @@ var RequestTrace = class RequestTrace {
2914
2930
  }
2915
2931
  const opened = await handle.stat();
2916
2932
  const current = await fs.lstat(file);
2917
- if (!current.isFile() || current.isSymbolicLink() || opened.nlink !== 1 || !sameFile$1(opened, current)) throw new Error("Capture file changed.");
2933
+ if (!current.isFile() || current.isSymbolicLink() || opened.nlink !== 1 || !sameOpenedFile(opened, current)) throw new Error("Capture file changed.");
2918
2934
  await handle.writeFile(buffer);
2919
2935
  }).catch(() => {
2920
2936
  this.manifest.captureError = "capture_write_failed";
@@ -2967,7 +2983,7 @@ var RequestTrace = class RequestTrace {
2967
2983
  await this.checkDirectories();
2968
2984
  const manifest = path.join(this.captureDirectory, "meta.json");
2969
2985
  const current = await fs.lstat(manifest);
2970
- if (!current.isFile() || current.isSymbolicLink() || current.nlink !== 1 || !this.metadataStat || !sameFile$1(current, this.metadataStat) || current.size !== this.metadataStat.size || current.mtimeMs !== this.metadataStat.mtimeMs || current.ctimeMs !== this.metadataStat.ctimeMs) throw new Error("Unsafe capture metadata.");
2986
+ if (!current.isFile() || current.isSymbolicLink() || current.nlink !== 1 || !this.metadataStat || !sameOpenedFile(current, this.metadataStat) || current.size !== this.metadataStat.size || current.mtimeMs !== this.metadataStat.mtimeMs || current.ctimeMs !== this.metadataStat.ctimeMs) throw new Error("Unsafe capture metadata.");
2971
2987
  await fs.rename(path.join(this.captureDirectory, "meta.next.json"), manifest);
2972
2988
  }
2973
2989
  }).catch(() => {
@@ -3005,7 +3021,7 @@ const readRetentionManifest = async (file) => {
3005
3021
  const handle = await fs.open(file, fs.constants.O_RDONLY | noFollow);
3006
3022
  try {
3007
3023
  const opened = await handle.stat();
3008
- if (!sameFile$1(observed, opened) || opened.nlink !== 1 || opened.size !== observed.size) throw new Error("Capture metadata changed.");
3024
+ if (!sameOpenedFile(observed, opened) || opened.nlink !== 1 || opened.size !== observed.size) throw new Error("Capture metadata changed.");
3009
3025
  const bytes = Buffer.alloc(opened.size);
3010
3026
  let offset = 0;
3011
3027
  while (offset < bytes.length) {
@@ -3014,7 +3030,7 @@ const readRetentionManifest = async (file) => {
3014
3030
  offset += bytesRead;
3015
3031
  }
3016
3032
  const current = await fs.lstat(file);
3017
- if (!sameFile$1(opened, current) || current.size !== opened.size || current.mtimeMs !== opened.mtimeMs) throw new Error("Capture metadata changed.");
3033
+ if (!sameOpenedFile(opened, current) || current.size !== opened.size || current.mtimeMs !== opened.mtimeMs) throw new Error("Capture metadata changed.");
3018
3034
  return JSON.parse(bytes.toString("utf8"));
3019
3035
  } finally {
3020
3036
  await handle.close();
@@ -7741,7 +7757,7 @@ const readCaptureFile = async (directory, file, maximum, optional = false) => {
7741
7757
  const handle = await fs.open(filePath, fs.constants.O_RDONLY | (process.platform === "win32" ? 0 : fs.constants.O_NOFOLLOW));
7742
7758
  try {
7743
7759
  const opened = await handle.stat();
7744
- requireValid(opened.isFile() && opened.ino === before.ino && opened.dev === before.dev && opened.size === before.size);
7760
+ requireValid(opened.isFile() && sameOpenedFile(opened, before) && opened.size === before.size);
7745
7761
  const bytes = Buffer.alloc(opened.size);
7746
7762
  let offset = 0;
7747
7763
  while (offset < bytes.length) {
@@ -7750,7 +7766,7 @@ const readCaptureFile = async (directory, file, maximum, optional = false) => {
7750
7766
  offset += read.bytesRead;
7751
7767
  }
7752
7768
  const after = await fs.lstat(filePath);
7753
- requireValid(!after.isSymbolicLink() && after.ino === opened.ino && after.dev === opened.dev && after.size === opened.size && after.mtimeMs === opened.mtimeMs);
7769
+ requireValid(!after.isSymbolicLink() && sameOpenedFile(after, opened) && after.size === opened.size && after.mtimeMs === opened.mtimeMs);
7754
7770
  return bytes;
7755
7771
  } finally {
7756
7772
  await handle.close();