craftar 0.18.0 → 0.18.1

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/dist/cli.js CHANGED
@@ -37,7 +37,7 @@ process.stdout.on("error", (e) => { if (e.code === "EPIPE")
37
37
  */
38
38
  const DIFF_EXIT_CODE_FETCH_MODE = "sync";
39
39
  const program = new Command();
40
- program.name("craftar").description("Craft, sync and convert AI-coding workspace harnesses.").version("0.18.0");
40
+ program.name("craftar").description("Craft, sync and convert AI-coding workspace harnesses.").version("0.18.1");
41
41
  /* ---------------------------------------------------------------- import */
42
42
  program
43
43
  .command("import")
@@ -5,6 +5,8 @@ import path from "node:path";
5
5
  export function resolveHome(home) {
6
6
  return path.resolve(home || path.join(os.homedir(), ".craftar"));
7
7
  }
8
+ /** How long a Windows EPERM on the lock's acquisition is taken for a release still landing (2 s). */
9
+ const PENDING_DELETE_MS = 2_000;
8
10
  /** Thrown when a lock is busy and the wait has run out. */
9
11
  export class LockBusyError extends Error {
10
12
  holder;
@@ -18,13 +20,17 @@ export class LockBusyError extends Error {
18
20
  * A lock under `$CRAFTAR_HOME` (spec 13 §6.3, spec 21 §6.2): `file` is created exclusively, holding
19
21
  * the PID and a timestamp; a busy one is waited for, then refused naming `label` and the holder; a
20
22
  * stale one is taken over. The directory holding `file` must exist unless `createDir` is set, which
21
- * re-creates it on each attempt.
23
+ * re-creates it on each attempt. On `win32` an EPERM from an attempt is waited out for a short time
24
+ * of its own, as a release still landing, then rethrown. Acquisition only: the body runs once.
22
25
  */
23
26
  export async function withLock(file, label, timing, body) {
24
27
  const waitMs = timing.waitMs ?? 60_000;
25
28
  const pollMs = timing.pollMs ?? 200;
26
29
  const staleMs = timing.staleMs ?? 10 * 60 * 1000;
30
+ const pendingDeleteMs = timing.pendingDeleteMs ?? PENDING_DELETE_MS;
31
+ const windows = (timing.platform ?? process.platform) === "win32";
27
32
  const start = Date.now();
33
+ let pendingSince = null;
28
34
  for (;;) {
29
35
  try {
30
36
  if (timing.createDir)
@@ -36,6 +42,9 @@ export async function withLock(file, label, timing, body) {
36
42
  }
37
43
  catch (e) {
38
44
  const code = e.code;
45
+ // The EPERM wait counts an unbroken run of EPERMs: any other answer starts it over.
46
+ if (code !== "EPERM" || !windows)
47
+ pendingSince = null;
39
48
  // ENOENT under createDir: the directory was removed between mkdir and wx; retry within the wait.
40
49
  if (code === "ENOENT" && timing.createDir) {
41
50
  if (Date.now() - start >= waitMs)
@@ -43,6 +52,17 @@ export async function withLock(file, label, timing, body) {
43
52
  await new Promise((r) => setTimeout(r, pollMs));
44
53
  continue;
45
54
  }
55
+ // windows-latest once answered EPERM, not EEXIST, at this create, as the holder released the lock;
56
+ // the cause is not reproduced. It is taken for that release still in flight and waited out for a
57
+ // short time of its own (the mkdir under createDir shares the try, and the wait). An EPERM that
58
+ // outlasts it is a real refusal — a directory that cannot be written — and is rethrown.
59
+ if (code === "EPERM" && windows) {
60
+ pendingSince ??= Date.now();
61
+ if (Date.now() - pendingSince >= pendingDeleteMs)
62
+ throw e;
63
+ await new Promise((r) => setTimeout(r, pollMs));
64
+ continue;
65
+ }
46
66
  if (code !== "EEXIST")
47
67
  throw e;
48
68
  const stat = await fs.stat(file).catch(() => null);
@@ -1 +1 @@
1
- {"version":3,"file":"home-lock.js","sourceRoot":"","sources":["../../src/core/home-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,0HAA0H;AAC1H,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;AACnE,CAAC;AAyBD,2DAA2D;AAC3D,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,MAAM,CAAS;IACxB,YAAY,OAAe,EAAE,MAAc;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,IAAY,EAAE,KAAa,EAAE,MAAmB,EAAE,IAAsB;IACxG,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,SAAS,CAAC;QACR,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,SAAS;gBAAE,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9E,IAAI,MAAM,CAAC,aAAa;gBAAE,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;YACvD,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzF,MAAM;QACR,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,GAAI,CAA2B,CAAC,IAAI,CAAC;YAC/C,iGAAiG;YACjG,IAAI,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC1C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,MAAM;oBAAE,MAAM,CAAC,CAAC;gBAC1C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;gBAChD,SAAS;YACX,CAAC;YACD,IAAI,IAAI,KAAK,QAAQ;gBAAE,MAAM,CAAC,CAAC;YAC/B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACnD,IAAI,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,CAAC;gBAChD,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnC,SAAS;YACX,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;gBAC5F,MAAM,IAAI,aAAa,CAAC,GAAG,KAAK,IAAI,IAAI,yBAAyB,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC;YAClF,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"home-lock.js","sourceRoot":"","sources":["../../src/core/home-lock.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "craftar",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Craft, sync and convert AI-coding workspace harnesses across clients and tools.",
5
5
  "license": "MIT",
6
6
  "type": "module",