@minnovate/shadow-publisher 0.11.3 → 0.11.5

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.
@@ -55,7 +55,9 @@ function ulid(now = Date.now()) {
55
55
  }
56
56
  const rnd = (0, import_node_crypto.randomBytes)(16);
57
57
  let rand = "";
58
- for (let i = 0; i < 16; i++) rand += ALPHABET[rnd[i] % 32];
58
+ for (let i = 0; i < 16; i++) {
59
+ rand += ALPHABET[rnd[i] % 32];
60
+ }
59
61
  return timeChars.join("") + rand;
60
62
  }
61
63
  function newPublicationId() {
@@ -70,13 +72,19 @@ function canonicalJson(value) {
70
72
  return JSON.stringify(sortValue(value));
71
73
  }
72
74
  function sortValue(value) {
73
- if (value === null || typeof value !== "object") return value;
74
- if (Array.isArray(value)) return value.map(sortValue);
75
+ if (value === null || typeof value !== "object") {
76
+ return value;
77
+ }
78
+ if (Array.isArray(value)) {
79
+ return value.map(sortValue);
80
+ }
75
81
  const obj = value;
76
82
  const out = {};
77
83
  for (const key of Object.keys(obj).sort()) {
78
84
  const v = obj[key];
79
- if (v !== void 0) out[key] = sortValue(v);
85
+ if (v !== void 0) {
86
+ out[key] = sortValue(v);
87
+ }
80
88
  }
81
89
  return out;
82
90
  }
@@ -193,7 +201,9 @@ var PublisherError = class _PublisherError extends Error {
193
201
  }
194
202
  toBody() {
195
203
  const error2 = { code: this.code, message: this.message, retryable: this.retryable };
196
- if (this.details) error2.details = this.details;
204
+ if (this.details) {
205
+ error2.details = this.details;
206
+ }
197
207
  return { error: error2 };
198
208
  }
199
209
  static isPublisherError(e) {
@@ -2988,10 +2998,17 @@ function sanitizedGitEnv(opts = {}) {
2988
2998
  GIT_NO_LAZY_FETCH: "1"
2989
2999
  // never let a parent process's git context leak into the child
2990
3000
  };
2991
- if (process.env["GIT_EXEC_PATH"]) env["GIT_EXEC_PATH"] = process.env["GIT_EXEC_PATH"];
2992
- if (process.env["GITPUB_GIT_TEMPLATE_DIR"] !== void 0) env["GIT_TEMPLATE_DIR"] = process.env["GITPUB_GIT_TEMPLATE_DIR"];
2993
- else env["GIT_TEMPLATE_DIR"] = "";
2994
- if (opts.extra) Object.assign(env, opts.extra);
3001
+ if (process.env["GIT_EXEC_PATH"]) {
3002
+ env["GIT_EXEC_PATH"] = process.env["GIT_EXEC_PATH"];
3003
+ }
3004
+ if (process.env["GITPUB_GIT_TEMPLATE_DIR"] !== void 0) {
3005
+ env["GIT_TEMPLATE_DIR"] = process.env["GITPUB_GIT_TEMPLATE_DIR"];
3006
+ } else {
3007
+ env["GIT_TEMPLATE_DIR"] = "";
3008
+ }
3009
+ if (opts.extra) {
3010
+ Object.assign(env, opts.extra);
3011
+ }
2995
3012
  return env;
2996
3013
  }
2997
3014
  var GIT_BIN = process.env["GITPUB_GIT_BIN"] ?? "git";
@@ -3000,7 +3017,9 @@ function neutralCwd() {
3000
3017
  }
3001
3018
  function startFailure(label, error2, cwd) {
3002
3019
  const opts = { retryable: true, cause: error2 };
3003
- if (error2.code !== "ENOENT") return new PublisherError("UNAVAILABLE", `${label} could not be started: ${error2.message}`, opts);
3020
+ if (error2.code !== "ENOENT") {
3021
+ return new PublisherError("UNAVAILABLE", `${label} could not be started: ${error2.message}`, opts);
3022
+ }
3004
3023
  if (!isDirectory(cwd)) {
3005
3024
  const which = cwd === (0, import_node_os.tmpdir)() ? "the temporary directory (TMPDIR)" : "its working directory";
3006
3025
  return new PublisherError("UNAVAILABLE", `${label} could not be started: ${which} ${cwd} does not exist`, { ...opts, details: { missing: "cwd", cwd } });
@@ -3050,21 +3069,31 @@ function clearTimersOf(lc) {
3050
3069
  function notifyWaiters(lc) {
3051
3070
  const ws = [...lc.waiters];
3052
3071
  lc.waiters.clear();
3053
- for (const w of ws) w();
3072
+ for (const w of ws) {
3073
+ w();
3074
+ }
3054
3075
  }
3055
3076
  function markIgnored(child) {
3056
- if (childClosed(child)) return;
3077
+ if (childClosed(child)) {
3078
+ return;
3079
+ }
3057
3080
  const lc = lifecycleOf(child);
3058
- if (lc.ignored) return;
3081
+ if (lc.ignored) {
3082
+ return;
3083
+ }
3059
3084
  lc.ignored = true;
3060
3085
  clearTimersOf(lc);
3061
3086
  notifyWaiters(lc);
3062
3087
  }
3063
3088
  function armCloseBound(child, boundMs) {
3064
3089
  const lc = lifecycleOf(child);
3065
- if (childClosed(child) || lc.ignored) return;
3090
+ if (childClosed(child) || lc.ignored) {
3091
+ return;
3092
+ }
3066
3093
  const deadline = Date.now() + boundMs;
3067
- if (lc.boundTimer && deadline >= lc.boundDeadline) return;
3094
+ if (lc.boundTimer && deadline >= lc.boundDeadline) {
3095
+ return;
3096
+ }
3068
3097
  if (lc.boundTimer) {
3069
3098
  clearTimeout(lc.boundTimer);
3070
3099
  lc.timers.delete(lc.boundTimer);
@@ -3085,7 +3114,9 @@ function track(child, boundMs = CLEANUP_BOUND_MS) {
3085
3114
  const lc = lifecycleOf(child);
3086
3115
  lc.boundMs = boundMs;
3087
3116
  child.on("error", (e) => {
3088
- if (lc.error === null) lc.error = e;
3117
+ if (lc.error === null) {
3118
+ lc.error = e;
3119
+ }
3089
3120
  });
3090
3121
  child.once("close", () => {
3091
3122
  closedChildren.add(child);
@@ -3101,7 +3132,9 @@ var defaultSignalGroup = (pid, signal) => process.kill(-pid, signal);
3101
3132
  var spawnImpl = import_node_child_process.spawn;
3102
3133
  var signalGroupImpl = defaultSignalGroup;
3103
3134
  function spawnFailure(child) {
3104
- if (child.pid !== void 0) return null;
3135
+ if (child.pid !== void 0) {
3136
+ return null;
3137
+ }
3105
3138
  const e = lifecycles.get(child)?.error;
3106
3139
  return e instanceof Error ? e : e ? new Error(String(e)) : null;
3107
3140
  }
@@ -3109,9 +3142,13 @@ function childExited(child) {
3109
3142
  return child.exitCode !== null || child.signalCode !== null;
3110
3143
  }
3111
3144
  function closeOrIgnored(child) {
3112
- if (childClosed(child)) return Promise.resolve(true);
3145
+ if (childClosed(child)) {
3146
+ return Promise.resolve(true);
3147
+ }
3113
3148
  const lc = lifecycleOf(child);
3114
- if (lc.ignored) return Promise.resolve(false);
3149
+ if (lc.ignored) {
3150
+ return Promise.resolve(false);
3151
+ }
3115
3152
  return new Promise((resolve3) => {
3116
3153
  lc.waiters.add(() => resolve3(childClosed(child)));
3117
3154
  });
@@ -3126,16 +3163,22 @@ function childClosed(child) {
3126
3163
  }
3127
3164
  function killAllGitProcesses() {
3128
3165
  const n = liveChildren.size;
3129
- for (const child of liveChildren) killProcessGroup(child);
3166
+ for (const child of liveChildren) {
3167
+ killProcessGroup(child);
3168
+ }
3130
3169
  return n;
3131
3170
  }
3132
3171
  function killProcessGroup(child) {
3133
- if (child.pid === void 0 || childClosed(child)) return;
3172
+ if (child.pid === void 0 || childClosed(child)) {
3173
+ return;
3174
+ }
3134
3175
  signalChildGroup(child, "SIGKILL");
3135
3176
  }
3136
3177
  function signalChildGroup(child, signal) {
3137
3178
  try {
3138
- if (child.pid === void 0) throw new Error("no pid");
3179
+ if (child.pid === void 0) {
3180
+ throw new Error("no pid");
3181
+ }
3139
3182
  signalGroupImpl(child.pid, signal);
3140
3183
  } catch {
3141
3184
  try {
@@ -3145,19 +3188,29 @@ function signalChildGroup(child, signal) {
3145
3188
  }
3146
3189
  }
3147
3190
  function waitWithin(start, ms, stop) {
3148
- if (ms <= 0) return Promise.resolve({ status: "timeout" });
3149
- if (stop?.aborted) return Promise.resolve({ status: "stopped" });
3191
+ if (ms <= 0) {
3192
+ return Promise.resolve({ status: "timeout" });
3193
+ }
3194
+ if (stop?.aborted) {
3195
+ return Promise.resolve({ status: "stopped" });
3196
+ }
3150
3197
  const ac = new AbortController();
3151
3198
  return new Promise((resolve3) => {
3152
3199
  let timer = null;
3153
3200
  let done = false;
3154
3201
  const onStop = () => settle({ status: "stopped" });
3155
3202
  const settle = (r) => {
3156
- if (done) return;
3203
+ if (done) {
3204
+ return;
3205
+ }
3157
3206
  done = true;
3158
- if (timer) clearTimeout(timer);
3207
+ if (timer) {
3208
+ clearTimeout(timer);
3209
+ }
3159
3210
  stop?.removeEventListener("abort", onStop);
3160
- if (r.status !== "value" && r.status !== "error") ac.abort();
3211
+ if (r.status !== "value" && r.status !== "error") {
3212
+ ac.abort();
3213
+ }
3161
3214
  resolve3(r);
3162
3215
  };
3163
3216
  let p;
@@ -3171,7 +3224,9 @@ function waitWithin(start, ms, stop) {
3171
3224
  (value) => settle({ status: "value", value }),
3172
3225
  (error2) => settle({ status: "error", error: error2 })
3173
3226
  );
3174
- if (done) return;
3227
+ if (done) {
3228
+ return;
3229
+ }
3175
3230
  timer = setTimeout(() => settle({ status: "timeout" }), ms);
3176
3231
  timer.unref();
3177
3232
  stop?.addEventListener("abort", onStop, { once: true });
@@ -3179,8 +3234,12 @@ function waitWithin(start, ms, stop) {
3179
3234
  }
3180
3235
  function spawnTracked(args, opts) {
3181
3236
  for (const a of args) {
3182
- if (typeof a !== "string") throw new Error("git args must be strings");
3183
- if (a.includes("\0")) throw new PublisherError("INVALID_REQUEST", "NUL in git argument");
3237
+ if (typeof a !== "string") {
3238
+ throw new Error("git args must be strings");
3239
+ }
3240
+ if (a.includes("\0")) {
3241
+ throw new PublisherError("INVALID_REQUEST", "NUL in git argument");
3242
+ }
3184
3243
  }
3185
3244
  const cwd = opts.cwd ?? neutralCwd();
3186
3245
  const child = spawnImpl(GIT_BIN, args, { cwd, env: sanitizedGitEnv(opts.env), stdio: ["pipe", "pipe", "pipe"], windowsHide: true, detached: true });
@@ -3232,7 +3291,9 @@ function killedError(reason, detail, args, timeoutMs, maxOut) {
3232
3291
  }
3233
3292
  }
3234
3293
  async function runGit(args, opts = {}) {
3235
- if (opts.maxDiskBytes !== void 0 && !opts.diskDir) throw new Error("maxDiskBytes requires diskDir");
3294
+ if (opts.maxDiskBytes !== void 0 && !opts.diskDir) {
3295
+ throw new Error("maxDiskBytes requires diskDir");
3296
+ }
3236
3297
  const started = Date.now();
3237
3298
  const timeoutMs = opts.timeoutMs ?? 12e4;
3238
3299
  const maxOut = opts.maxStdoutBytes ?? 64 * 1024 * 1024;
@@ -3245,7 +3306,9 @@ async function runGit(args, opts = {}) {
3245
3306
  let killedDetail = "";
3246
3307
  let closed = false;
3247
3308
  const kill = (reason, detail = "") => {
3248
- if (killedReason || closed) return;
3309
+ if (killedReason || closed) {
3310
+ return;
3311
+ }
3249
3312
  killedReason = reason;
3250
3313
  killedDetail = detail;
3251
3314
  terminate(child);
@@ -3253,17 +3316,25 @@ async function runGit(args, opts = {}) {
3253
3316
  const timer = setTimeout(() => kill("timeout"), timeoutMs);
3254
3317
  const onAbort = () => kill("cancelled");
3255
3318
  if (opts.signal) {
3256
- if (opts.signal.aborted) onAbort();
3257
- else opts.signal.addEventListener("abort", onAbort, { once: true });
3319
+ if (opts.signal.aborted) {
3320
+ onAbort();
3321
+ } else {
3322
+ opts.signal.addEventListener("abort", onAbort, { once: true });
3323
+ }
3258
3324
  }
3259
3325
  const watchdog = startWatchdog(child, opts, kill, () => closed);
3260
3326
  child.stdout.on("data", (c) => {
3261
3327
  outBytes += c.length;
3262
- if (outBytes > maxOut) kill("output-limit");
3263
- else stdoutChunks.push(c);
3328
+ if (outBytes > maxOut) {
3329
+ kill("output-limit");
3330
+ } else {
3331
+ stdoutChunks.push(c);
3332
+ }
3264
3333
  });
3265
3334
  child.stderr.on("data", (c) => {
3266
- if (stderr.length < 64 * 1024) stderr += c.toString("utf8");
3335
+ if (stderr.length < 64 * 1024) {
3336
+ stderr += c.toString("utf8");
3337
+ }
3267
3338
  });
3268
3339
  const stdin = feedStdin(child, opts.input, () => kill("input-error"));
3269
3340
  const ended = await endedOrIgnored(child).finally(() => {
@@ -3285,14 +3356,24 @@ async function runGit(args, opts = {}) {
3285
3356
  const code = ended.code;
3286
3357
  const result = { code, stdout: Buffer.concat(stdoutChunks), stderr, durationMs };
3287
3358
  const cleanup = await reapChild(child, { boundMs: cleanupBoundMs, ...opts.groupObserver ? { observer: opts.groupObserver } : {} });
3288
- if (!reapSucceeded(cleanup)) throw cleanupFailure(`git ${args[0]}`, cleanup, killedReason ?? void 0);
3289
- if (ended.error) throw startFailure(`git ${args[0]}`, ended.error, cwd);
3290
- if (killedReason) throw killedError(killedReason, killedDetail, args, timeoutMs, maxOut);
3291
- if (code !== 0 && !opts.allowFailure) throw new GitCommandError(args, code, stderr, opts.label);
3359
+ if (!reapSucceeded(cleanup)) {
3360
+ throw cleanupFailure(`git ${args[0]}`, cleanup, killedReason ?? void 0);
3361
+ }
3362
+ if (ended.error) {
3363
+ throw startFailure(`git ${args[0]}`, ended.error, cwd);
3364
+ }
3365
+ if (killedReason) {
3366
+ throw killedError(killedReason, killedDetail, args, timeoutMs, maxOut);
3367
+ }
3368
+ if (code !== 0 && !opts.allowFailure) {
3369
+ throw new GitCommandError(args, code, stderr, opts.label);
3370
+ }
3292
3371
  return result;
3293
3372
  }
3294
3373
  function startWatchdog(child, opts, kill, isClosed) {
3295
- if (opts.maxMemoryBytes === void 0 && opts.maxDiskBytes === void 0) return { stop: () => void 0, done: Promise.resolve() };
3374
+ if (opts.maxMemoryBytes === void 0 && opts.maxDiskBytes === void 0) {
3375
+ return { stop: () => void 0, done: Promise.resolve() };
3376
+ }
3296
3377
  const sampler = opts.sampler ?? defaultResourceSampler;
3297
3378
  const interval2 = Math.max(10, opts.sampleIntervalMs ?? 500);
3298
3379
  const sampleBoundMs = opts.cleanupBoundMs ?? CLEANUP_BOUND_MS;
@@ -3311,10 +3392,17 @@ function startWatchdog(child, opts, kill, isClosed) {
3311
3392
  });
3312
3393
  const sample = async (what, start) => {
3313
3394
  const r = await waitWithin(start, sampleBoundMs, stopper.signal);
3314
- if (isClosed() || stopped) return null;
3315
- if (r.status === "value") return r.value;
3316
- if (r.status === "error") kill("monitor", `resource monitor failed: ${r.error.message}`);
3317
- else kill("monitor", `resource sample (${what}) did not complete within ${sampleBoundMs}ms`);
3395
+ if (isClosed() || stopped) {
3396
+ return null;
3397
+ }
3398
+ if (r.status === "value") {
3399
+ return r.value;
3400
+ }
3401
+ if (r.status === "error") {
3402
+ kill("monitor", `resource monitor failed: ${r.error.message}`);
3403
+ } else {
3404
+ kill("monitor", `resource sample (${what}) did not complete within ${sampleBoundMs}ms`);
3405
+ }
3318
3406
  return null;
3319
3407
  };
3320
3408
  const done = (async () => {
@@ -3325,10 +3413,14 @@ function startWatchdog(child, opts, kill, isClosed) {
3325
3413
  let tick = 0;
3326
3414
  while (!stopped) {
3327
3415
  await sleep2(interval2);
3328
- if (stopped) return;
3416
+ if (stopped) {
3417
+ return;
3418
+ }
3329
3419
  if (opts.maxMemoryBytes !== void 0) {
3330
3420
  const rss = await sample("memory", (signal) => sampler.groupRss(pgid, signal));
3331
- if (rss === null) return;
3421
+ if (rss === null) {
3422
+ return;
3423
+ }
3332
3424
  if (rss > opts.maxMemoryBytes) {
3333
3425
  kill("memory", `process group uses ${rss} bytes of memory; limit ${opts.maxMemoryBytes}`);
3334
3426
  return;
@@ -3337,7 +3429,9 @@ function startWatchdog(child, opts, kill, isClosed) {
3337
3429
  if (opts.maxDiskBytes !== void 0 && opts.diskDir && tick % 2 === 1) {
3338
3430
  const dir = opts.diskDir;
3339
3431
  const bytes = await sample("disk", (signal) => sampler.dirBytes(dir, signal));
3340
- if (bytes === null) return;
3432
+ if (bytes === null) {
3433
+ return;
3434
+ }
3341
3435
  if (bytes > opts.maxDiskBytes) {
3342
3436
  kill("disk", `scratch directory holds ${bytes} bytes; limit ${opts.maxDiskBytes}`);
3343
3437
  return;
@@ -3356,17 +3450,25 @@ async function scanProcessGroup(pgid, signal) {
3356
3450
  const members2 = [];
3357
3451
  if (process.platform === "linux") {
3358
3452
  for (const name of await (0, import_promises.readdir)("/proc")) {
3359
- if (signal?.aborted) throw new Error("process-group scan abandoned by its caller");
3360
- if (!/^\d+$/.test(name)) continue;
3453
+ if (signal?.aborted) {
3454
+ throw new Error("process-group scan abandoned by its caller");
3455
+ }
3456
+ if (!/^\d+$/.test(name)) {
3457
+ continue;
3458
+ }
3361
3459
  try {
3362
3460
  const stat4 = await (0, import_promises.readFile)(`/proc/${name}/stat`, "utf8");
3363
3461
  const rest = stat4.slice(stat4.lastIndexOf(")") + 2).split(" ");
3364
- if (Number(rest[2]) !== pgid) continue;
3462
+ if (Number(rest[2]) !== pgid) {
3463
+ continue;
3464
+ }
3365
3465
  const status = await (0, import_promises.readFile)(`/proc/${name}/status`, "utf8");
3366
3466
  members2.push({ pid: Number(name), rss: Number(/^VmRSS:\s+(\d+)/m.exec(status)?.[1] ?? 0) * 1024 });
3367
3467
  } catch (e) {
3368
3468
  const code = e.code;
3369
- if (code === "ENOENT" || code === "ESRCH") continue;
3469
+ if (code === "ENOENT" || code === "ESRCH") {
3470
+ continue;
3471
+ }
3370
3472
  throw e;
3371
3473
  }
3372
3474
  }
@@ -3380,7 +3482,9 @@ async function scanProcessGroup(pgid, signal) {
3380
3482
  });
3381
3483
  for (const line of stdout.split("\n")) {
3382
3484
  const [g, pid, rss] = line.trim().split(/\s+/);
3383
- if (Number(g) === pgid) members2.push({ pid: Number(pid), rss: Number(rss) * 1024 });
3485
+ if (Number(g) === pgid) {
3486
+ members2.push({ pid: Number(pid), rss: Number(rss) * 1024 });
3487
+ }
3384
3488
  }
3385
3489
  return members2;
3386
3490
  }
@@ -3390,7 +3494,9 @@ async function processGroupRss(pgid, signal) {
3390
3494
  return (await scanProcessGroup(pgid, signal)).reduce((sum, m) => sum + m.rss, 0);
3391
3495
  }
3392
3496
  async function processGroupMembers(pgid, signal) {
3393
- if (!groupMayHaveMembers(pgid)) return [];
3497
+ if (!groupMayHaveMembers(pgid)) {
3498
+ return [];
3499
+ }
3394
3500
  return (await scanProcessGroup(pgid, signal)).map((m) => m.pid);
3395
3501
  }
3396
3502
  function groupMayHaveMembers(pgid) {
@@ -3405,23 +3511,30 @@ async function directoryBytes(dir, signal) {
3405
3511
  let total = 0;
3406
3512
  const stack = [dir];
3407
3513
  while (stack.length) {
3408
- if (signal?.aborted) throw new Error("directory scan abandoned by its caller");
3514
+ if (signal?.aborted) {
3515
+ throw new Error("directory scan abandoned by its caller");
3516
+ }
3409
3517
  const d = stack.pop();
3410
3518
  let entries;
3411
3519
  try {
3412
3520
  entries = await (0, import_promises.readdir)(d, { withFileTypes: true });
3413
3521
  } catch (e) {
3414
- if (e.code === "ENOENT") continue;
3522
+ if (e.code === "ENOENT") {
3523
+ continue;
3524
+ }
3415
3525
  throw e;
3416
3526
  }
3417
3527
  for (const ent of entries) {
3418
3528
  const p = (0, import_node_path.join)(d, ent.name);
3419
- if (ent.isDirectory()) stack.push(p);
3420
- else if (ent.isFile()) {
3529
+ if (ent.isDirectory()) {
3530
+ stack.push(p);
3531
+ } else if (ent.isFile()) {
3421
3532
  try {
3422
3533
  total += (await (0, import_promises.lstat)(p)).size;
3423
3534
  } catch (e) {
3424
- if (e.code !== "ENOENT") throw e;
3535
+ if (e.code !== "ENOENT") {
3536
+ throw e;
3537
+ }
3425
3538
  }
3426
3539
  }
3427
3540
  }
@@ -3454,7 +3567,9 @@ function spawnGit(args, opts = {}) {
3454
3567
  child,
3455
3568
  opts,
3456
3569
  (reason) => {
3457
- if (killed || closed) return;
3570
+ if (killed || closed) {
3571
+ return;
3572
+ }
3458
3573
  killed = reason;
3459
3574
  terminate(child);
3460
3575
  },
@@ -3466,25 +3581,38 @@ function spawnGit(args, opts = {}) {
3466
3581
  }
3467
3582
  function terminate(child, opts = {}) {
3468
3583
  const lc = lifecycleOf(child);
3469
- if (childClosed(child) || lc.ignored) return;
3584
+ if (childClosed(child) || lc.ignored) {
3585
+ return;
3586
+ }
3470
3587
  const boundMs = opts.boundMs ?? lc.boundMs;
3471
3588
  armCloseBound(child, boundMs);
3472
- if (lc.terminated) return;
3589
+ if (lc.terminated) {
3590
+ return;
3591
+ }
3473
3592
  lc.terminated = true;
3474
3593
  const drain = () => {
3475
- for (const stream of [child.stdout, child.stderr]) stream?.resume();
3594
+ for (const stream of [child.stdout, child.stderr]) {
3595
+ stream?.resume();
3596
+ }
3476
3597
  };
3477
- if (childExited(child)) drain();
3478
- else child.once("exit", drain);
3598
+ if (childExited(child)) {
3599
+ drain();
3600
+ } else {
3601
+ child.once("exit", drain);
3602
+ }
3479
3603
  killProcessGroup(child);
3480
- if (!childClosed(child)) scheduleFor(child, () => killProcessGroup(child), 250, true);
3604
+ if (!childClosed(child)) {
3605
+ scheduleFor(child, () => killProcessGroup(child), 250, true);
3606
+ }
3481
3607
  }
3482
3608
  async function reapChild(child, opts = {}) {
3483
3609
  const boundMs = opts.boundMs ?? lifecycleOf(child).boundMs;
3484
3610
  const deadline = Date.now() + boundMs;
3485
3611
  let timedOut = false;
3486
3612
  if (!childClosed(child)) {
3487
- if (!lifecycleOf(child).ignored) terminate(child, { boundMs });
3613
+ if (!lifecycleOf(child).ignored) {
3614
+ terminate(child, { boundMs });
3615
+ }
3488
3616
  timedOut = !await closeOrIgnored(child);
3489
3617
  }
3490
3618
  let groupCleared = true;
@@ -3501,17 +3629,23 @@ async function reapChild(child, opts = {}) {
3501
3629
  break;
3502
3630
  }
3503
3631
  if (r.status !== "value") {
3504
- if (!observed) groupCleared = null;
3632
+ if (!observed) {
3633
+ groupCleared = null;
3634
+ }
3505
3635
  timedOut = true;
3506
3636
  break;
3507
3637
  }
3508
3638
  observed = true;
3509
3639
  survivors = r.value;
3510
3640
  groupCleared = survivors.length === 0;
3511
- if (groupCleared || !childClosed(child) || Date.now() >= deadline) break;
3641
+ if (groupCleared || !childClosed(child) || Date.now() >= deadline) {
3642
+ break;
3643
+ }
3512
3644
  await new Promise((resolve3) => setTimeout(resolve3, Math.min(25, deadline - Date.now())));
3513
3645
  }
3514
- if (groupCleared === false) timedOut = true;
3646
+ if (groupCleared === false) {
3647
+ timedOut = true;
3648
+ }
3515
3649
  }
3516
3650
  return { closed: childClosed(child), groupCleared, timedOut, survivors };
3517
3651
  }
@@ -3521,7 +3655,9 @@ function reapSucceeded(outcome) {
3521
3655
  function cleanupFailure(what, outcome, cause) {
3522
3656
  const why = !outcome.closed ? "the process did not close within the cleanup bound" : outcome.groupCleared === null ? "its process group could not be observed" : `its process group still has ${outcome.survivors.length} member(s)`;
3523
3657
  const cleanup = { closed: outcome.closed, groupCleared: outcome.groupCleared, timedOut: outcome.timedOut, survivors: outcome.survivors };
3524
- if (typeof cause === "string") cleanup["preempted"] = cause;
3658
+ if (typeof cause === "string") {
3659
+ cleanup["preempted"] = cause;
3660
+ }
3525
3661
  return new PublisherError("UNAVAILABLE", `${what}: ${why}`, {
3526
3662
  retryable: true,
3527
3663
  details: { cleanup },
@@ -3530,10 +3666,14 @@ function cleanupFailure(what, outcome, cause) {
3530
3666
  }
3531
3667
  var cachedVersion = null;
3532
3668
  async function gitVersion() {
3533
- if (cachedVersion) return cachedVersion;
3669
+ if (cachedVersion) {
3670
+ return cachedVersion;
3671
+ }
3534
3672
  const { stdout } = await execFileP(GIT_BIN, ["--version"], { env: sanitizedGitEnv(), timeout: 3e4 });
3535
3673
  const m = /git version (\d+\.\d+\.\d+)/.exec(stdout);
3536
- if (!m) throw new PublisherError("GIT", `cannot parse git version: ${stdout.trim()}`);
3674
+ if (!m) {
3675
+ throw new PublisherError("GIT", `cannot parse git version: ${stdout.trim()}`);
3676
+ }
3537
3677
  cachedVersion = m[1];
3538
3678
  return cachedVersion;
3539
3679
  }
@@ -3542,7 +3682,9 @@ function compareVersions(a, b) {
3542
3682
  const pb = b.split(".").map(Number);
3543
3683
  for (let i = 0; i < 3; i++) {
3544
3684
  const d = (pa[i] ?? 0) - (pb[i] ?? 0);
3545
- if (d !== 0) return d;
3685
+ if (d !== 0) {
3686
+ return d;
3687
+ }
3546
3688
  }
3547
3689
  return 0;
3548
3690
  }
@@ -3562,7 +3704,9 @@ async function sha256File(path) {
3562
3704
  }).on("error", reject).on("end", () => resolve3());
3563
3705
  });
3564
3706
  const st = await (0, import_promises2.stat)(path);
3565
- if (st.size !== size) throw new Error("file changed while hashing");
3707
+ if (st.size !== size) {
3708
+ throw new Error("file changed while hashing");
3709
+ }
3566
3710
  return { sha256: h.digest("hex"), size };
3567
3711
  }
3568
3712
 
@@ -3570,32 +3714,47 @@ async function sha256File(path) {
3570
3714
  var import_node_fs3 = require("node:fs");
3571
3715
  async function indexPackFromFile(dir, packPath, opts = {}) {
3572
3716
  const args = ["index-pack", "--stdin", ...opts.keep ?? true ? ["--keep=gitpub"] : []];
3573
- if (opts.strict ?? true) args.push("--strict", "--fsck-objects");
3574
- if (opts.maxInputBytes) args.push(`--max-input-size=${opts.maxInputBytes}`);
3717
+ if (opts.strict ?? true) {
3718
+ args.push("--strict", "--fsck-objects");
3719
+ }
3720
+ if (opts.maxInputBytes) {
3721
+ args.push(`--max-input-size=${opts.maxInputBytes}`);
3722
+ }
3575
3723
  const run = { cwd: dir, input: (0, import_node_fs3.createReadStream)(packPath), label: "index-pack", ...opts };
3576
3724
  const res = await runGit(args, { ...run, allowFailure: true });
3577
3725
  if (res.code !== 0) {
3578
3726
  const msg = res.stderr.trim().split("\n").pop() ?? "index-pack failed";
3579
3727
  const missing = /did not receive expected object|not a valid|missing/i.test(res.stderr);
3580
3728
  const environment = /No space left|Permission denied|Input\/output error|cannot open|unable to (?:open|read|create|write)|Cannot allocate memory|Too many open files|Killed/i.test(res.stderr);
3581
- if (environment) throw new PublisherError("UNAVAILABLE", `index-pack failed: ${sanitizeGitMessage(msg)}`, { retryable: true });
3729
+ if (environment) {
3730
+ throw new PublisherError("UNAVAILABLE", `index-pack failed: ${sanitizeGitMessage(msg)}`, { retryable: true });
3731
+ }
3582
3732
  throw new PublisherError(missing ? "MISSING_OBJECTS" : "PACK_INVALID", sanitizeGitMessage(msg));
3583
3733
  }
3584
3734
  const m = /^(?:pack|keep)\t([0-9a-f]{40,64})/m.exec(res.stdout.toString("utf8"));
3585
- if (!m) throw new PublisherError("PACK_INVALID", "index-pack produced no pack name");
3735
+ if (!m) {
3736
+ throw new PublisherError("PACK_INVALID", "index-pack produced no pack name");
3737
+ }
3586
3738
  return { packName: m[1] };
3587
3739
  }
3588
3740
  function sanitizeGitMessage(msg) {
3589
3741
  return msg.replace(/\/[^\s:]+/g, "<path>").replace(/https?:\/\/\S+/g, "<url>").slice(0, 500);
3590
3742
  }
3591
3743
  async function refTransaction(dir, updates, opts = {}) {
3592
- if (updates.length === 0) return;
3744
+ if (updates.length === 0) {
3745
+ return;
3746
+ }
3593
3747
  const lines = ["start"];
3594
3748
  for (const u of updates) {
3595
- if (u.ref.includes("\n") || u.ref.includes("\0")) throw new PublisherError("INVALID_REF_NAME", "newline in ref");
3749
+ if (u.ref.includes("\n") || u.ref.includes("\0")) {
3750
+ throw new PublisherError("INVALID_REF_NAME", "newline in ref");
3751
+ }
3596
3752
  const oldPart = u.old === void 0 ? "" : ` ${u.old ?? "0".repeat(40)}`;
3597
- if (u.new === null) lines.push(`delete ${u.ref}${oldPart}`);
3598
- else lines.push(`update ${u.ref} ${u.new}${oldPart}`);
3753
+ if (u.new === null) {
3754
+ lines.push(`delete ${u.ref}${oldPart}`);
3755
+ } else {
3756
+ lines.push(`update ${u.ref} ${u.new}${oldPart}`);
3757
+ }
3599
3758
  }
3600
3759
  lines.push("prepare", "commit", "");
3601
3760
  await runGit(["update-ref", "--stdin"], { cwd: dir, input: lines.join("\n"), label: "update-ref", ...opts });
@@ -3606,14 +3765,18 @@ async function batchCheck(dir, oids, opts = {}) {
3606
3765
  const { stdout } = await runGit(["cat-file", "--batch-check=%(objectname) %(objecttype) %(objectsize)"], run);
3607
3766
  const out = [];
3608
3767
  for (const line of stdout.toString("utf8").split("\n")) {
3609
- if (!line) continue;
3768
+ if (!line) {
3769
+ continue;
3770
+ }
3610
3771
  const [oid, type, size] = line.split(" ");
3611
3772
  out.push({ oid, type: type ?? "missing", size: type === "missing" ? 0 : Number(size) });
3612
3773
  }
3613
3774
  return out;
3614
3775
  }
3615
3776
  async function resolveRev(dir, rev, peel) {
3616
- if (rev.startsWith("-")) return null;
3777
+ if (rev.startsWith("-")) {
3778
+ return null;
3779
+ }
3617
3780
  const r = await runGit(["rev-parse", "--verify", "-q", peel ? `${rev}^{}` : rev], { cwd: dir, allowFailure: true });
3618
3781
  return r.code === 0 ? r.stdout.toString("utf8").trim() : null;
3619
3782
  }
@@ -3622,14 +3785,19 @@ async function resolveRevs(dir, revs, opts = {}) {
3622
3785
  (r) => r.startsWith("-") ? null : r.includes("\0") ? new PublisherError("INVALID_REQUEST", "NUL in git argument") : null
3623
3786
  );
3624
3787
  const ask4 = revs.flatMap((r, i) => out[i] === null && !r.startsWith("-") ? [i] : []);
3625
- if (ask4.length === 0) return out;
3788
+ if (ask4.length === 0) {
3789
+ return out;
3790
+ }
3626
3791
  const { stdout } = await runGit(["cat-file", "--batch-check=%(objectname)", "-Z"], { cwd: dir, input: ask4.map((i) => revs[i]).join("\0") + "\0", ...opts });
3627
3792
  const records = stdout.toString("utf8").split("\0");
3628
3793
  const misses = [];
3629
3794
  for (const [j, i] of ask4.entries()) {
3630
3795
  const record2 = records[j] ?? "";
3631
- if (record2 && !/ (missing|ambiguous)$/.test(record2)) out[i] = record2;
3632
- else if (!revs[i].includes("^{")) misses.push(i);
3796
+ if (record2 && !/ (missing|ambiguous)$/.test(record2)) {
3797
+ out[i] = record2;
3798
+ } else if (!revs[i].includes("^{")) {
3799
+ misses.push(i);
3800
+ }
3633
3801
  }
3634
3802
  await Promise.all(misses.map(async (i) => out[i] = await resolveRev(dir, revs[i], false)));
3635
3803
  return out;
@@ -3677,10 +3845,18 @@ async function packObjectsToFile(repoDir, extraArgs, stdinLines, opts) {
3677
3845
  }
3678
3846
  }
3679
3847
  const code = ended.code;
3680
- if (ended.error) throw startFailure("git pack-objects", ended.error, repoDir);
3681
- if (opts.signal?.aborted) throw new PublisherError("CANCELLED", "pack creation cancelled");
3682
- if (timedOut) throw new PublisherError("GIT", `pack-objects timed out after ${timeoutMs}ms`, { retryable: true });
3683
- if (code !== 0) throw new PublisherError("GIT", `pack-objects failed: ${stderr.trim().split("\n").pop() ?? ""}`);
3848
+ if (ended.error) {
3849
+ throw startFailure("git pack-objects", ended.error, repoDir);
3850
+ }
3851
+ if (opts.signal?.aborted) {
3852
+ throw new PublisherError("CANCELLED", "pack creation cancelled");
3853
+ }
3854
+ if (timedOut) {
3855
+ throw new PublisherError("GIT", `pack-objects timed out after ${timeoutMs}ms`, { retryable: true });
3856
+ }
3857
+ if (code !== 0) {
3858
+ throw new PublisherError("GIT", `pack-objects failed: ${stderr.trim().split("\n").pop() ?? ""}`);
3859
+ }
3684
3860
  } catch (e) {
3685
3861
  failure = e;
3686
3862
  } finally {
@@ -3689,8 +3865,12 @@ async function packObjectsToFile(repoDir, extraArgs, stdinLines, opts) {
3689
3865
  out.close();
3690
3866
  }
3691
3867
  const cleanup = await reapChild(child, opts.groupObserver ? { observer: opts.groupObserver } : {});
3692
- if (!reapSucceeded(cleanup)) throw cleanupFailure("git pack-objects", cleanup, failure ?? void 0);
3693
- if (failure) throw failure;
3868
+ if (!reapSucceeded(cleanup)) {
3869
+ throw cleanupFailure("git pack-objects", cleanup, failure ?? void 0);
3870
+ }
3871
+ if (failure) {
3872
+ throw failure;
3873
+ }
3694
3874
  const { sha256, size } = await sha256File(opts.outPath);
3695
3875
  return { sha256, size, objectCount: packObjectCount(await readPackHeader(opts.outPath)) };
3696
3876
  }
@@ -3715,21 +3895,31 @@ async function readPackHeader(path) {
3715
3895
  }
3716
3896
  }
3717
3897
  function packObjectCount(header) {
3718
- if (header.length < 12 || header.toString("latin1", 0, 4) !== "PACK") throw new PublisherError("PACK_INVALID", "not a pack file");
3898
+ if (header.length < 12 || header.toString("latin1", 0, 4) !== "PACK") {
3899
+ throw new PublisherError("PACK_INVALID", "not a pack file");
3900
+ }
3719
3901
  const version2 = header.readUInt32BE(4);
3720
- if (version2 !== 2 && version2 !== 3) throw new PublisherError("PACK_INVALID", `unsupported pack version ${version2}`);
3902
+ if (version2 !== 2 && version2 !== 3) {
3903
+ throw new PublisherError("PACK_INVALID", `unsupported pack version ${version2}`);
3904
+ }
3721
3905
  return header.readUInt32BE(8);
3722
3906
  }
3723
3907
 
3724
3908
  // ../git-core/src/bundle.ts
3725
3909
  async function bundleUnbundleObjects(repoDir, bundlePath, opts = {}) {
3726
3910
  const r = await runGit(["bundle", "unbundle", bundlePath], { cwd: repoDir, allowFailure: true, ...opts });
3727
- if (r.code !== 0) throw new PublisherError("PACK_INVALID", `bundle unbundle failed: ${sanitizeGitMessage(r.stderr.trim().split("\n").pop() ?? "")}`);
3911
+ if (r.code !== 0) {
3912
+ throw new PublisherError("PACK_INVALID", `bundle unbundle failed: ${sanitizeGitMessage(r.stderr.trim().split("\n").pop() ?? "")}`);
3913
+ }
3728
3914
  const refs = {};
3729
3915
  for (const line of r.stdout.toString("utf8").split("\n")) {
3730
- if (!line) continue;
3916
+ if (!line) {
3917
+ continue;
3918
+ }
3731
3919
  const [oid, name] = line.split(" ");
3732
- if (name && name !== "HEAD") refs[name] = oid;
3920
+ if (name && name !== "HEAD") {
3921
+ refs[name] = oid;
3922
+ }
3733
3923
  }
3734
3924
  return refs;
3735
3925
  }
@@ -3750,12 +3940,19 @@ async function getConfig(dir, key) {
3750
3940
  async function getConfigSection(dir, section) {
3751
3941
  const r = await runGit(["config", "--local", "-z", "--get-regexp", `^${section.replace(/\./g, "\\.")}\\.`], { cwd: dir, allowFailure: true });
3752
3942
  const out = /* @__PURE__ */ new Map();
3753
- if (r.code !== 0) return out;
3943
+ if (r.code !== 0) {
3944
+ return out;
3945
+ }
3754
3946
  for (const record2 of r.stdout.toString("utf8").split("\0")) {
3755
- if (!record2) continue;
3947
+ if (!record2) {
3948
+ continue;
3949
+ }
3756
3950
  const nl = record2.indexOf("\n");
3757
- if (nl < 0) out.set(record2, "");
3758
- else out.set(record2.slice(0, nl), record2.slice(nl + 1).trim());
3951
+ if (nl < 0) {
3952
+ out.set(record2, "");
3953
+ } else {
3954
+ out.set(record2.slice(0, nl), record2.slice(nl + 1).trim());
3955
+ }
3759
3956
  }
3760
3957
  return out;
3761
3958
  }
@@ -3766,14 +3963,19 @@ async function remoteUrl(dir, name) {
3766
3963
  return getConfig(dir, `remote.${name}.url`);
3767
3964
  }
3768
3965
  async function ensureRemote(dir, name, url2) {
3769
- if (await remoteUrl(dir, name) !== null) return "exists";
3966
+ if (await remoteUrl(dir, name) !== null) {
3967
+ return "exists";
3968
+ }
3770
3969
  await runGit(["remote", "add", name, url2], { cwd: dir });
3771
3970
  await runGit(["config", "--local", `remote.${name}.pushurl`, "no_push://publisher-uses-the-publish-command"], { cwd: dir });
3772
3971
  return "added";
3773
3972
  }
3774
3973
  async function updateTrackingRef(dir, ref, oid) {
3775
- if (oid === null) await runGit(["update-ref", "-d", ref], { cwd: dir, allowFailure: true });
3776
- else await runGit(["update-ref", ref, oid], { cwd: dir });
3974
+ if (oid === null) {
3975
+ await runGit(["update-ref", "-d", ref], { cwd: dir, allowFailure: true });
3976
+ } else {
3977
+ await runGit(["update-ref", ref, oid], { cwd: dir });
3978
+ }
3777
3979
  }
3778
3980
  async function currentBranch(dir) {
3779
3981
  const r = await runGit(["symbolic-ref", "-q", "HEAD"], { cwd: dir, allowFailure: true });
@@ -3787,7 +3989,9 @@ async function localRefs(dir, prefix = "refs/") {
3787
3989
  const r = await runGit(["for-each-ref", "--format=%(objectname) %(refname)", prefix], { cwd: dir });
3788
3990
  const out = {};
3789
3991
  for (const line of r.stdout.toString("utf8").split("\n")) {
3790
- if (!line) continue;
3992
+ if (!line) {
3993
+ continue;
3994
+ }
3791
3995
  const sp = line.indexOf(" ");
3792
3996
  out[line.slice(sp + 1)] = line.slice(0, sp);
3793
3997
  }
@@ -3803,11 +4007,15 @@ async function statusPorcelain(dir) {
3803
4007
  const parts = r.stdout.toString("utf8").split("\0");
3804
4008
  for (let i = 0; i < parts.length; i++) {
3805
4009
  const p = parts[i];
3806
- if (!p) continue;
4010
+ if (!p) {
4011
+ continue;
4012
+ }
3807
4013
  const code = p.slice(0, 2);
3808
4014
  const path = p.slice(3);
3809
4015
  out.push({ code, path });
3810
- if (code[0] === "R" || code[0] === "C") i++;
4016
+ if (code[0] === "R" || code[0] === "C") {
4017
+ i++;
4018
+ }
3811
4019
  }
3812
4020
  return out;
3813
4021
  }
@@ -3815,13 +4023,19 @@ async function initWorkRepo(dir, branch = "main") {
3815
4023
  await runGit(["init", "-q", `--initial-branch=${branch}`, dir]);
3816
4024
  }
3817
4025
  async function commitPaths(dir, paths, opts) {
3818
- if (paths.length === 0) throw new PublisherError("LOCAL_STATE", "no files selected to commit");
4026
+ if (paths.length === 0) {
4027
+ throw new PublisherError("LOCAL_STATE", "no files selected to commit");
4028
+ }
3819
4029
  const run = { cwd: dir, env: authorEnv(opts) };
3820
- if (opts.signal) run.signal = opts.signal;
4030
+ if (opts.signal) {
4031
+ run.signal = opts.signal;
4032
+ }
3821
4033
  await runGit(["add", "--pathspec-from-file=-", "--pathspec-file-nul"], { ...run, input: paths.join("\0") + "\0" });
3822
4034
  await runGit(["commit", "-q", "--no-verify", "-m", opts.message], run);
3823
4035
  const head = await headCommit(dir);
3824
- if (!head) throw new PublisherError("GIT", "commit did not produce HEAD");
4036
+ if (!head) {
4037
+ throw new PublisherError("GIT", "commit did not produce HEAD");
4038
+ }
3825
4039
  return head;
3826
4040
  }
3827
4041
  async function mergeCheck(dir, ours, theirs) {
@@ -3829,25 +4043,37 @@ async function mergeCheck(dir, ours, theirs) {
3829
4043
  const mergeBase = base.code === 0 ? base.stdout.toString("utf8").trim() : null;
3830
4044
  const oursOid = (await runGit(["rev-parse", "--verify", `${ours}^{commit}`], { cwd: dir })).stdout.toString("utf8").trim();
3831
4045
  const theirsOid = (await runGit(["rev-parse", "--verify", `${theirs}^{commit}`], { cwd: dir })).stdout.toString("utf8").trim();
3832
- if (mergeBase === theirsOid) return { ok: true, tree: null, conflicts: [], mergeBase, fastForward: "ours" };
3833
- if (mergeBase === oursOid) return { ok: true, tree: null, conflicts: [], mergeBase, fastForward: "theirs" };
4046
+ if (mergeBase === theirsOid) {
4047
+ return { ok: true, tree: null, conflicts: [], mergeBase, fastForward: "ours" };
4048
+ }
4049
+ if (mergeBase === oursOid) {
4050
+ return { ok: true, tree: null, conflicts: [], mergeBase, fastForward: "theirs" };
4051
+ }
3834
4052
  const r = await runGit(["merge-tree", "--write-tree", "-z", "--name-only", "--no-messages", ours, theirs], { cwd: dir, allowFailure: true });
3835
- if (r.code !== 0 && r.code !== 1) throw new PublisherError("GIT", `merge-tree failed: ${sanitizeGitMessage(r.stderr.trim())}`);
4053
+ if (r.code !== 0 && r.code !== 1) {
4054
+ throw new PublisherError("GIT", `merge-tree failed: ${sanitizeGitMessage(r.stderr.trim())}`);
4055
+ }
3836
4056
  const out = r.stdout.toString("utf8");
3837
4057
  const parts = out.split("\0");
3838
4058
  const tree = parts[0] ?? null;
3839
- if (r.code === 0) return { ok: true, tree, conflicts: [], mergeBase, fastForward: null };
4059
+ if (r.code === 0) {
4060
+ return { ok: true, tree, conflicts: [], mergeBase, fastForward: null };
4061
+ }
3840
4062
  const conflicts = [];
3841
4063
  for (let i = 1; i < parts.length; i++) {
3842
4064
  const p = parts[i];
3843
- if (p === "") break;
4065
+ if (p === "") {
4066
+ break;
4067
+ }
3844
4068
  conflicts.push({ path: p, kind: "content" });
3845
4069
  }
3846
4070
  return { ok: false, tree, conflicts, mergeBase, fastForward: null };
3847
4071
  }
3848
4072
  async function commitTree(dir, tree, parents, message, opts = {}) {
3849
4073
  const args = ["commit-tree", tree, "-m", message];
3850
- for (const p of parents) args.push("-p", p);
4074
+ for (const p of parents) {
4075
+ args.push("-p", p);
4076
+ }
3851
4077
  const r = await runGit(args, { cwd: dir, env: authorEnv(opts) });
3852
4078
  return r.stdout.toString("utf8").trim();
3853
4079
  }
@@ -3864,7 +4090,9 @@ async function readAssociation(repoDir) {
3864
4090
  function associationFrom(section) {
3865
4091
  const endpoint = section.get("publisher.endpoint");
3866
4092
  const repoId = section.get("publisher.repoid");
3867
- if (!endpoint || !repoId) return null;
4093
+ if (!endpoint || !repoId) {
4094
+ return null;
4095
+ }
3868
4096
  return { endpoint, repoId, remote: section.get("publisher.remote") ?? "publisher" };
3869
4097
  }
3870
4098
  async function writeAssociation(repoDir, a) {
@@ -3883,8 +4111,12 @@ async function mergeRemote(opts) {
3883
4111
  const { repoDir, ours, theirs } = opts;
3884
4112
  const oursOid = await revParse(repoDir, ours);
3885
4113
  const theirsOid = await revParse(repoDir, theirs);
3886
- if (!oursOid) throw new PublisherError("LOCAL_STATE", `unknown local ref ${ours}`);
3887
- if (!theirsOid) throw new PublisherError("LOCAL_STATE", `unknown ref ${theirs}; fetch first`);
4114
+ if (!oursOid) {
4115
+ throw new PublisherError("LOCAL_STATE", `unknown local ref ${ours}`);
4116
+ }
4117
+ if (!theirsOid) {
4118
+ throw new PublisherError("LOCAL_STATE", `unknown ref ${theirs}; fetch first`);
4119
+ }
3888
4120
  const check = await mergeCheck(repoDir, oursOid, theirsOid);
3889
4121
  const base = { ok: check.ok, applied: false, fastForward: check.fastForward, mergeBase: check.mergeBase, mergeCommit: null, conflicts: check.conflicts, hint: "" };
3890
4122
  if (!check.ok) {
@@ -3893,16 +4125,21 @@ async function mergeRemote(opts) {
3893
4125
  hint: `conflicts in ${check.conflicts.map((c) => c.path).join(", ")}; resolve them with git merge ${theirs} in a working copy, or keep both versions and publish later`
3894
4126
  };
3895
4127
  }
3896
- if (check.fastForward === "ours") return { ...base, hint: "local branch already contains the fetched history" };
3897
- if (!opts.apply)
4128
+ if (check.fastForward === "ours") {
4129
+ return { ...base, hint: "local branch already contains the fetched history" };
4130
+ }
4131
+ if (!opts.apply) {
3898
4132
  return {
3899
4133
  ...base,
3900
4134
  hint: check.fastForward === "theirs" ? "fast-forward possible; run with apply to update the branch" : "clean merge possible; run with apply to create the merge commit"
3901
4135
  };
4136
+ }
3902
4137
  const checkedOut = await currentBranch(repoDir);
3903
4138
  if (checkedOut === ours) {
3904
4139
  const dirty = (await statusPorcelain(repoDir)).filter((s) => s.code !== "??");
3905
- if (dirty.length > 0) throw new PublisherError("LOCAL_STATE", "the working tree has uncommitted changes; commit or stash them before applying the merge");
4140
+ if (dirty.length > 0) {
4141
+ throw new PublisherError("LOCAL_STATE", "the working tree has uncommitted changes; commit or stash them before applying the merge");
4142
+ }
3906
4143
  if (check.fastForward === "theirs") {
3907
4144
  await runGit(["merge", "--ff-only", "--quiet", theirsOid], { cwd: repoDir });
3908
4145
  return { ...base, applied: true, mergeCommit: theirsOid, hint: "fast-forwarded" };
@@ -3946,10 +4183,14 @@ async function openPending(repoDir) {
3946
4183
  list: async () => {
3947
4184
  const out = [];
3948
4185
  for (const f of await (0, import_promises3.readdir)(dir)) {
3949
- if (!f.endsWith(".json")) continue;
4186
+ if (!f.endsWith(".json")) {
4187
+ continue;
4188
+ }
3950
4189
  try {
3951
4190
  const p = JSON.parse(await (0, import_promises3.readFile)((0, import_node_path2.join)(dir, f), "utf8"));
3952
- if (p.version === 1) out.push(p);
4191
+ if (p.version === 1) {
4192
+ out.push(p);
4193
+ }
3953
4194
  } catch {
3954
4195
  }
3955
4196
  }
@@ -3977,16 +4218,22 @@ var PARTIAL_MARKER = ".gitpub-checkout.json";
3977
4218
  async function getWorkspaceMapping(directory) {
3978
4219
  const dir = (0, import_node_path3.resolve)(directory);
3979
4220
  const section = await getConfigSection(dir, "publisher").catch(() => null);
3980
- if (!section) return null;
4221
+ if (!section) {
4222
+ return null;
4223
+ }
3981
4224
  const a = associationFrom(section);
3982
- if (!a) return null;
4225
+ if (!a) {
4226
+ return null;
4227
+ }
3983
4228
  const get = (k) => section.get(`${NS}.${k}`) ?? null;
3984
4229
  const branch = get("branch");
3985
4230
  const baseOid = get("baseoid");
3986
4231
  const baseGeneration = get("basegeneration");
3987
4232
  const checkedOutAt = get("checkedoutat");
3988
4233
  const baseAdvancedAt = get("baseadvancedat");
3989
- if (!branch || baseGeneration === null || !checkedOutAt) return null;
4234
+ if (!branch || baseGeneration === null || !checkedOutAt) {
4235
+ return null;
4236
+ }
3990
4237
  return {
3991
4238
  directory: dir,
3992
4239
  endpoint: a.endpoint,
@@ -4009,9 +4256,15 @@ async function writeMapping(dir, m) {
4009
4256
  }
4010
4257
  async function advanceWorkspaceBase(directory, next, now = /* @__PURE__ */ new Date()) {
4011
4258
  const m = await getWorkspaceMapping(directory);
4012
- if (!m) throw new PublisherError("LOCAL_STATE", "not a workspace (no publisher.workspace mapping)");
4013
- if (next.generation < m.baseGeneration) return m;
4014
- if (next.generation === m.baseGeneration && next.oid === m.baseOid) return m;
4259
+ if (!m) {
4260
+ throw new PublisherError("LOCAL_STATE", "not a workspace (no publisher.workspace mapping)");
4261
+ }
4262
+ if (next.generation < m.baseGeneration) {
4263
+ return m;
4264
+ }
4265
+ if (next.generation === m.baseGeneration && next.oid === m.baseOid) {
4266
+ return m;
4267
+ }
4015
4268
  const updated = { ...m, baseOid: next.oid, baseGeneration: next.generation, baseAdvancedAt: now.toISOString() };
4016
4269
  await setConfig(m.directory, `${NS}.baseoid`, updated.baseOid ?? "");
4017
4270
  await setConfig(m.directory, `${NS}.basegeneration`, String(updated.baseGeneration));
@@ -4019,29 +4272,43 @@ async function advanceWorkspaceBase(directory, next, now = /* @__PURE__ */ new D
4019
4272
  return updated;
4020
4273
  }
4021
4274
  async function noteAcceptedPublication(directory, outcome, now = /* @__PURE__ */ new Date()) {
4022
- if (outcome.state !== "accepted" || outcome.resultGeneration === null) return;
4275
+ if (outcome.state !== "accepted" || outcome.resultGeneration === null) {
4276
+ return;
4277
+ }
4023
4278
  const m = await getWorkspaceMapping(directory).catch(() => null);
4024
- if (!m || m.repoId !== outcome.repoId) return;
4279
+ if (!m || m.repoId !== outcome.repoId) {
4280
+ return;
4281
+ }
4025
4282
  const oid = outcome.refs?.[`refs/heads/${m.branch}`];
4026
- if (!oid) return;
4283
+ if (!oid) {
4284
+ return;
4285
+ }
4027
4286
  await advanceWorkspaceBase(directory, { oid, generation: outcome.resultGeneration }, now);
4028
4287
  }
4029
4288
  async function adoptWorkspace(client, directory, call2 = {}, now = /* @__PURE__ */ new Date()) {
4030
4289
  const dir = (0, import_node_path3.resolve)(directory);
4031
4290
  const existing = await getWorkspaceMapping(dir);
4032
- if (existing) return existing;
4291
+ if (existing) {
4292
+ return existing;
4293
+ }
4033
4294
  const section = await getConfigSection(dir, "publisher").catch(() => null);
4034
4295
  const a = section ? associationFrom(section) : null;
4035
- if (!a) throw new PublisherError("LOCAL_STATE", "this folder is not associated with a published repository; run init first");
4296
+ if (!a) {
4297
+ throw new PublisherError("LOCAL_STATE", "this folder is not associated with a published repository; run init first");
4298
+ }
4036
4299
  const branch = (await currentBranch(dir))?.replace(/^refs\/heads\//, "") ?? null;
4037
- if (!branch) throw new PublisherError("LOCAL_STATE", "HEAD is detached; check out the branch this folder publishes, then run sync again");
4300
+ if (!branch) {
4301
+ throw new PublisherError("LOCAL_STATE", "HEAD is detached; check out the branch this folder publishes, then run sync again");
4302
+ }
4038
4303
  const repo = await client.getRepository(a.repoId, call2);
4039
4304
  const remoteOid = repo.refs[`refs/heads/${branch}`] ?? null;
4040
4305
  const tip = await revParse(dir, `refs/heads/${branch}`);
4041
4306
  let baseOid = null;
4042
4307
  let baseGeneration = 0;
4043
4308
  if (remoteOid) {
4044
- if (!await objectExists(dir, remoteOid)) await client.fetch({ repoDir: dir, repoId: a.repoId, remote: a.remote }, call2);
4309
+ if (!await objectExists(dir, remoteOid)) {
4310
+ await client.fetch({ repoDir: dir, repoId: a.repoId, remote: a.remote }, call2);
4311
+ }
4045
4312
  const haveRemote = await objectExists(dir, remoteOid);
4046
4313
  if (!tip) {
4047
4314
  baseOid = haveRemote ? remoteOid : null;
@@ -4071,8 +4338,12 @@ async function isEmptyDir(p) {
4071
4338
  try {
4072
4339
  return (await (0, import_promises4.readdir)(p)).length === 0;
4073
4340
  } catch (e) {
4074
- if (e.code === "ENOENT") return null;
4075
- if (e.code === "ENOTDIR") return false;
4341
+ if (e.code === "ENOENT") {
4342
+ return null;
4343
+ }
4344
+ if (e.code === "ENOTDIR") {
4345
+ return false;
4346
+ }
4076
4347
  throw e;
4077
4348
  }
4078
4349
  }
@@ -4087,11 +4358,15 @@ async function removeStalePartials(target, repoId) {
4087
4358
  return removed;
4088
4359
  }
4089
4360
  for (const name of entries) {
4090
- if (!name.startsWith(prefix)) continue;
4361
+ if (!name.startsWith(prefix)) {
4362
+ continue;
4363
+ }
4091
4364
  const p = (0, import_node_path3.join)(parent, name);
4092
4365
  try {
4093
4366
  const marker = JSON.parse(await (0, import_promises4.readFile)((0, import_node_path3.join)(p, PARTIAL_MARKER), "utf8"));
4094
- if (marker.target !== target || marker.repoId !== repoId) continue;
4367
+ if (marker.target !== target || marker.repoId !== repoId) {
4368
+ continue;
4369
+ }
4095
4370
  } catch {
4096
4371
  continue;
4097
4372
  }
@@ -4104,14 +4379,20 @@ async function checkoutWorkspace(client, opts, call2 = {}, now = /* @__PURE__ */
4104
4379
  const target = (0, import_node_path3.resolve)(opts.directory);
4105
4380
  const remote = opts.remote ?? "publisher";
4106
4381
  const empty2 = await isEmptyDir(target);
4107
- if (empty2 === false) throw new PublisherError("LOCAL_STATE", `${target} exists and is not empty; checkout never overlays an existing folder`);
4382
+ if (empty2 === false) {
4383
+ throw new PublisherError("LOCAL_STATE", `${target} exists and is not empty; checkout never overlays an existing folder`);
4384
+ }
4108
4385
  await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(target), { recursive: true });
4109
4386
  const removed = await removeStalePartials(target, opts.repoId);
4110
- if (removed.length) call2.onProgress?.({ phase: "checkout", message: `removed ${removed.length} interrupted checkout(s)` });
4387
+ if (removed.length) {
4388
+ call2.onProgress?.({ phase: "checkout", message: `removed ${removed.length} interrupted checkout(s)` });
4389
+ }
4111
4390
  const repo = await client.getRepository(opts.repoId, call2);
4112
4391
  const branch = opts.branch ?? repo.head.symbolic.replace(/^refs\/heads\//, "");
4113
4392
  const tip = repo.refs[`refs/heads/${branch}`] ?? null;
4114
- if (!tip && Object.keys(repo.refs).length > 0) throw new PublisherError("LOCAL_STATE", `branch ${branch} does not exist on the server`);
4393
+ if (!tip && Object.keys(repo.refs).length > 0) {
4394
+ throw new PublisherError("LOCAL_STATE", `branch ${branch} does not exist on the server`);
4395
+ }
4115
4396
  const partial2 = (0, import_node_path3.join)((0, import_node_path3.dirname)(target), `.${(0, import_node_path3.basename)(target)}.partial-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`);
4116
4397
  await (0, import_promises4.mkdir)(partial2);
4117
4398
  try {
@@ -4122,7 +4403,9 @@ async function checkoutWorkspace(client, opts, call2 = {}, now = /* @__PURE__ */
4122
4403
  await client.fetch({ repoDir: partial2, repoId: opts.repoId, remote }, call2);
4123
4404
  const tracking = `refs/remotes/${remote}/${branch}`;
4124
4405
  const have = await revParse(partial2, tracking);
4125
- if (have !== tip) throw new PublisherError("LOCAL_STATE", `fetched ${tracking} is ${have ?? "missing"}, expected ${tip}; retry the checkout`);
4406
+ if (have !== tip) {
4407
+ throw new PublisherError("LOCAL_STATE", `fetched ${tracking} is ${have ?? "missing"}, expected ${tip}; retry the checkout`);
4408
+ }
4126
4409
  await runGit(["branch", "-q", "--no-track", branch, tip], { cwd: partial2 });
4127
4410
  await runGit(["checkout", "-q", branch], { cwd: partial2 });
4128
4411
  await runGit(["branch", `--set-upstream-to=${tracking}`, branch], { cwd: partial2, allowFailure: true });
@@ -4138,7 +4421,9 @@ async function checkoutWorkspace(client, opts, call2 = {}, now = /* @__PURE__ */
4138
4421
  baseAdvancedAt: now.toISOString()
4139
4422
  });
4140
4423
  await (0, import_promises4.rm)((0, import_node_path3.join)(partial2, PARTIAL_MARKER), { force: true });
4141
- if (empty2 === true) await (0, import_promises4.rm)(target, { recursive: false, force: true }).catch(() => void 0);
4424
+ if (empty2 === true) {
4425
+ await (0, import_promises4.rm)(target, { recursive: false, force: true }).catch(() => void 0);
4426
+ }
4142
4427
  await (0, import_promises4.rename)(partial2, target);
4143
4428
  } catch (e) {
4144
4429
  await (0, import_promises4.rm)(partial2, { recursive: true, force: true }).catch(() => void 0);
@@ -4161,7 +4446,7 @@ async function inspectWorkspace(client, directory, call2 = {}) {
4161
4446
  const dir = (0, import_node_path3.resolve)(directory);
4162
4447
  const mapping = await getWorkspaceMapping(dir);
4163
4448
  const pending = await listPending(dir).catch(() => []);
4164
- if (!mapping)
4449
+ if (!mapping) {
4165
4450
  return {
4166
4451
  state: "unassociated",
4167
4452
  mapping: null,
@@ -4171,6 +4456,7 @@ async function inspectWorkspace(client, directory, call2 = {}) {
4171
4456
  conflicts: [],
4172
4457
  hint: "not a workspace yet; run sync here (an associated folder adopts itself), or checkout to create one"
4173
4458
  };
4459
+ }
4174
4460
  const branchRef = `refs/heads/${mapping.branch}`;
4175
4461
  const tip = await revParse(dir, branchRef);
4176
4462
  const head = await revParse(dir, "HEAD");
@@ -4183,7 +4469,9 @@ async function inspectWorkspace(client, directory, call2 = {}) {
4183
4469
  const repo = await client.getRepository(mapping.repoId, call2);
4184
4470
  const remoteOid = repo.refs[branchRef] ?? null;
4185
4471
  const remote = { oid: remoteOid, generation: repo.generation };
4186
- if (mapping.baseOid && tip) local.commitsAheadOfBase = await countCommits(dir, `${mapping.baseOid}..${tip}`);
4472
+ if (mapping.baseOid && tip) {
4473
+ local.commitsAheadOfBase = await countCommits(dir, `${mapping.baseOid}..${tip}`);
4474
+ }
4187
4475
  const done = (state, hint, conflicts = []) => ({ state, mapping, local, remote, pending, conflicts, hint });
4188
4476
  const work = dirty && untrackedPaths.length > 0 ? "uncommitted and untracked files" : dirty ? "uncommitted changes" : `${untrackedPaths.length} untracked file(s)`;
4189
4477
  if (checkedOut !== mapping.branch && !(checkedOut === null && head === null && tip === null)) {
@@ -4193,32 +4481,42 @@ async function inspectWorkspace(client, directory, call2 = {}) {
4193
4481
  );
4194
4482
  }
4195
4483
  if (!remoteOid) {
4196
- if (!tip) return done(hasLocalWork ? "local_changes" : "up_to_date", hasLocalWork ? `${work}; publisher sync records and publishes them` : "empty on both sides");
4484
+ if (!tip) {
4485
+ return done(hasLocalWork ? "local_changes" : "up_to_date", hasLocalWork ? `${work}; publisher sync records and publishes them` : "empty on both sides");
4486
+ }
4197
4487
  return done("local_changes", "the server has no such branch yet; publisher sync creates it");
4198
4488
  }
4199
- if (!tip) return done("remote_ahead", hasLocalWork ? `local branch is unborn and there are ${work}; move them aside, then sync` : "local branch is unborn; sync to fast-forward");
4489
+ if (!tip) {
4490
+ return done("remote_ahead", hasLocalWork ? `local branch is unborn and there are ${work}; move them aside, then sync` : "local branch is unborn; sync to fast-forward");
4491
+ }
4200
4492
  if (!await objectExists(dir, remoteOid)) {
4201
4493
  await client.fetch({ repoDir: dir, repoId: mapping.repoId, remote: mapping.remote }, call2);
4202
- if (!await objectExists(dir, remoteOid)) return done("remote_ahead", "server tip could not be fetched; retry");
4494
+ if (!await objectExists(dir, remoteOid)) {
4495
+ return done("remote_ahead", "server tip could not be fetched; retry");
4496
+ }
4203
4497
  }
4204
- if (remoteOid === tip)
4498
+ if (remoteOid === tip) {
4205
4499
  return done(hasLocalWork ? "local_changes" : "up_to_date", hasLocalWork ? `${work}; publisher sync records and publishes them` : "in sync with the server");
4206
- if (await isAncestor(dir, remoteOid, tip))
4500
+ }
4501
+ if (await isAncestor(dir, remoteOid, tip)) {
4207
4502
  return done(
4208
4503
  "local_changes",
4209
4504
  hasLocalWork ? `local commits and ${work}; publisher sync records and publishes them` : "local commits not yet published; publisher sync publishes them"
4210
4505
  );
4211
- if (await isAncestor(dir, tip, remoteOid))
4506
+ }
4507
+ if (await isAncestor(dir, tip, remoteOid)) {
4212
4508
  return done(
4213
4509
  "remote_ahead",
4214
4510
  hasLocalWork ? `server moved ahead and there are ${work}; publisher sync records them, brings the server's changes in and publishes` : "server moved ahead; publisher sync brings it in"
4215
4511
  );
4512
+ }
4216
4513
  const merge2 = await mergeRemote({ repoDir: dir, ours: branchRef, theirs: remoteOid, apply: false });
4217
- if (merge2.ok)
4514
+ if (merge2.ok) {
4218
4515
  return done(
4219
4516
  "diverged_clean_merge",
4220
4517
  hasLocalWork ? `both sides changed, merge is clean; publisher sync records the ${work}, merges and publishes` : "both sides changed, merge is clean; publisher sync merges and publishes"
4221
4518
  );
4519
+ }
4222
4520
  return done(
4223
4521
  "conflict",
4224
4522
  `both sides changed ${merge2.conflicts.map((c) => c.path).join(", ")}; resolve with git merge ${remoteOid} in the workspace, then publish`,
@@ -4229,19 +4527,27 @@ async function syncWorkspace(client, opts, call2 = {}, now = /* @__PURE__ */ new
4229
4527
  const dir = (0, import_node_path3.resolve)(opts.directory);
4230
4528
  await adoptWorkspace(client, dir, call2, now);
4231
4529
  const before = await inspectWorkspace(client, dir, call2);
4232
- if (!before.mapping) throw new PublisherError("LOCAL_STATE", "not a workspace; run checkout");
4530
+ if (!before.mapping) {
4531
+ throw new PublisherError("LOCAL_STATE", "not a workspace; run checkout");
4532
+ }
4233
4533
  const mapping = before.mapping;
4234
4534
  const branchRef = `refs/heads/${mapping.branch}`;
4235
4535
  let applied = null;
4236
- if (before.state === "detached") throw new PublisherError("LOCAL_STATE", before.hint);
4536
+ if (before.state === "detached") {
4537
+ throw new PublisherError("LOCAL_STATE", before.hint);
4538
+ }
4237
4539
  if (opts.apply && before.remote?.oid && (before.state === "remote_ahead" || before.state === "diverged_clean_merge")) {
4238
- if (before.local?.dirty) throw new PublisherError("LOCAL_STATE", "the working tree has uncommitted changes; record them first (publisher sync does)");
4540
+ if (before.local?.dirty) {
4541
+ throw new PublisherError("LOCAL_STATE", "the working tree has uncommitted changes; record them first (publisher sync does)");
4542
+ }
4239
4543
  if (!before.local?.tip) {
4240
4544
  await runGit(["checkout", "-q", "-B", mapping.branch, before.remote.oid], { cwd: dir });
4241
4545
  applied = "fast-forward";
4242
4546
  } else {
4243
4547
  const r = await mergeRemote({ repoDir: dir, ours: branchRef, theirs: before.remote.oid, apply: true, ...opts.message ? { message: opts.message } : {} });
4244
- if (!r.applied) throw new PublisherError("LOCAL_STATE", r.hint);
4548
+ if (!r.applied) {
4549
+ throw new PublisherError("LOCAL_STATE", r.hint);
4550
+ }
4245
4551
  applied = r.fastForward === "theirs" ? "fast-forward" : "merge";
4246
4552
  }
4247
4553
  }
@@ -4284,7 +4590,9 @@ function credentialsPath() {
4284
4590
  }
4285
4591
  function credentialsLocation() {
4286
4592
  const explicit = process.env["GIT_PUBLISHER_CREDENTIALS"];
4287
- if (explicit) return { path: explicit, from: "GIT_PUBLISHER_CREDENTIALS" };
4593
+ if (explicit) {
4594
+ return { path: explicit, from: "GIT_PUBLISHER_CREDENTIALS" };
4595
+ }
4288
4596
  const xdg = process.env["XDG_CONFIG_HOME"];
4289
4597
  return { path: (0, import_node_path4.join)(xdg ?? (0, import_node_path4.join)((0, import_node_os2.homedir)(), ".config"), "git-publisher", "credentials.json"), from: xdg ? "XDG_CONFIG_HOME" : "HOME" };
4290
4598
  }
@@ -4331,28 +4639,46 @@ function hasReadableName(endpoint) {
4331
4639
  } catch {
4332
4640
  return false;
4333
4641
  }
4334
- if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host) || host.includes(":")) return false;
4335
- if (/\.lambda-url\.[a-z0-9-]+\.on\.aws$/.test(host)) return false;
4642
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host) || host.includes(":")) {
4643
+ return false;
4644
+ }
4645
+ if (/\.lambda-url\.[a-z0-9-]+\.on\.aws$/.test(host)) {
4646
+ return false;
4647
+ }
4336
4648
  return Boolean(slug(host.split(".")[0] ?? ""));
4337
4649
  }
4338
4650
  function profileNameFor(endpoint, taken) {
4339
4651
  const host = hasReadableName(endpoint) ? new URL(endpoint).hostname : "";
4340
4652
  const candidates = host ? [slug(host.split(".")[0] ?? ""), slug(host)] : ["default"];
4341
- for (const c of candidates) if (c && !taken.has(c)) return c;
4653
+ for (const c of candidates) {
4654
+ if (c && !taken.has(c)) {
4655
+ return c;
4656
+ }
4657
+ }
4342
4658
  const base = candidates.filter(Boolean).pop() ?? "default";
4343
- for (let n = 2; ; n++) if (!taken.has(`${base}-${n}`)) return `${base}-${n}`;
4659
+ for (let n = 2; ; n++) {
4660
+ if (!taken.has(`${base}-${n}`)) {
4661
+ return `${base}-${n}`;
4662
+ }
4663
+ }
4344
4664
  }
4345
4665
  var empty = () => ({ version: 1, endpoints: {}, profiles: {} });
4346
4666
  function parse2(raw) {
4347
- if (!raw || typeof raw !== "object") return empty();
4667
+ if (!raw || typeof raw !== "object") {
4668
+ return empty();
4669
+ }
4348
4670
  const r = raw;
4349
- if (r.version !== 1) return empty();
4671
+ if (r.version !== 1) {
4672
+ return empty();
4673
+ }
4350
4674
  const out = {
4351
4675
  version: 1,
4352
4676
  endpoints: r.endpoints && typeof r.endpoints === "object" ? r.endpoints : {},
4353
4677
  profiles: r.profiles && typeof r.profiles === "object" ? r.profiles : {}
4354
4678
  };
4355
- if (typeof r.defaultProfile === "string") out.defaultProfile = r.defaultProfile;
4679
+ if (typeof r.defaultProfile === "string") {
4680
+ out.defaultProfile = r.defaultProfile;
4681
+ }
4356
4682
  return out;
4357
4683
  }
4358
4684
  async function readCredentials() {
@@ -4380,7 +4706,9 @@ async function writeSecretJson(path, value) {
4380
4706
  return path;
4381
4707
  }
4382
4708
  function pruneDefault(file) {
4383
- if (file.defaultProfile && !file.profiles[file.defaultProfile]) delete file.defaultProfile;
4709
+ if (file.defaultProfile && !file.profiles[file.defaultProfile]) {
4710
+ delete file.defaultProfile;
4711
+ }
4384
4712
  return file;
4385
4713
  }
4386
4714
  async function saveCredential(endpoint, token, principal, opts = {}) {
@@ -4403,7 +4731,9 @@ async function store(url2, entry, opts) {
4403
4731
  const existing = Object.entries(file.profiles).find(([, p]) => normalize(p.endpoint) === url2)?.[0];
4404
4732
  const name = opts.profile ?? existing ?? profileNameFor(url2, new Set(Object.keys(file.profiles)));
4405
4733
  file.profiles[name] = { endpoint: url2 };
4406
- if (opts.setDefault || !file.defaultProfile) file.defaultProfile = name;
4734
+ if (opts.setDefault || !file.defaultProfile) {
4735
+ file.defaultProfile = name;
4736
+ }
4407
4737
  return writeCredentials(pruneDefault(file));
4408
4738
  }
4409
4739
  async function removeCredential(endpoint, opts = {}) {
@@ -4411,14 +4741,20 @@ async function removeCredential(endpoint, opts = {}) {
4411
4741
  const url2 = normalize(endpoint);
4412
4742
  const revoked = await revokeEntry(file.endpoints[url2], opts);
4413
4743
  delete file.endpoints[url2];
4414
- for (const [name, p] of Object.entries(file.profiles)) if (normalize(p.endpoint) === url2) delete file.profiles[name];
4744
+ for (const [name, p] of Object.entries(file.profiles)) {
4745
+ if (normalize(p.endpoint) === url2) {
4746
+ delete file.profiles[name];
4747
+ }
4748
+ }
4415
4749
  await writeCredentials(pruneDefault(file));
4416
4750
  return { revoked };
4417
4751
  }
4418
4752
  async function removeProfile(name, opts = {}) {
4419
4753
  const file = await readCredentials();
4420
4754
  const entry = file.profiles[name];
4421
- if (!entry) throw new PublisherError("LOCAL_STATE", `no such profile: ${name}`, { details: { profiles: Object.keys(file.profiles) } });
4755
+ if (!entry) {
4756
+ throw new PublisherError("LOCAL_STATE", `no such profile: ${name}`, { details: { profiles: Object.keys(file.profiles) } });
4757
+ }
4422
4758
  delete file.profiles[name];
4423
4759
  const url2 = normalize(entry.endpoint);
4424
4760
  let revoked = false;
@@ -4430,7 +4766,9 @@ async function removeProfile(name, opts = {}) {
4430
4766
  return { revoked };
4431
4767
  }
4432
4768
  async function revokeEntry(entry, opts) {
4433
- if (!opts.revoke || !entry?.refreshToken || !entry.authEndpoint) return false;
4769
+ if (!opts.revoke || !entry?.refreshToken || !entry.authEndpoint) {
4770
+ return false;
4771
+ }
4434
4772
  try {
4435
4773
  return (await postForm(entry.authEndpoint, "/v1/auth/revoke", { token: entry.refreshToken }, opts.fetch)).status === 200;
4436
4774
  } catch {
@@ -4439,7 +4777,9 @@ async function revokeEntry(entry, opts) {
4439
4777
  }
4440
4778
  async function setDefaultProfile(name) {
4441
4779
  const file = await readCredentials();
4442
- if (!file.profiles[name]) throw new PublisherError("LOCAL_STATE", `no such profile: ${name}`, { details: { profiles: Object.keys(file.profiles) } });
4780
+ if (!file.profiles[name]) {
4781
+ throw new PublisherError("LOCAL_STATE", `no such profile: ${name}`, { details: { profiles: Object.keys(file.profiles) } });
4782
+ }
4443
4783
  file.defaultProfile = name;
4444
4784
  await writeCredentials(file);
4445
4785
  }
@@ -4452,14 +4792,30 @@ function resolveEndpoint(input) {
4452
4792
  const p = input.file.profiles[name];
4453
4793
  return p ? { kind: "resolved", endpoint: normalize(p.endpoint), source, profile: name } : { kind: "unknown-profile", name, profiles: names };
4454
4794
  };
4455
- if (input.endpoint) return { kind: "resolved", endpoint: normalize(input.endpoint), source: "flag" };
4456
- if (input.profile) return byName(input.profile, "profile-flag");
4457
- if (input.env["GIT_PUBLISHER_ENDPOINT"]) return { kind: "resolved", endpoint: normalize(input.env["GIT_PUBLISHER_ENDPOINT"]), source: "env-endpoint" };
4458
- if (input.env["GIT_PUBLISHER_PROFILE"]) return byName(input.env["GIT_PUBLISHER_PROFILE"], "env-profile");
4459
- if (input.association) return { kind: "resolved", endpoint: normalize(input.association), source: "association" };
4460
- if (input.file.defaultProfile && input.file.profiles[input.file.defaultProfile]) return byName(input.file.defaultProfile, "default-profile");
4461
- if (names.length === 1) return byName(names[0], "sole-profile");
4462
- if (names.length > 1) return { kind: "ambiguous", profiles: names };
4795
+ if (input.endpoint) {
4796
+ return { kind: "resolved", endpoint: normalize(input.endpoint), source: "flag" };
4797
+ }
4798
+ if (input.profile) {
4799
+ return byName(input.profile, "profile-flag");
4800
+ }
4801
+ if (input.env["GIT_PUBLISHER_ENDPOINT"]) {
4802
+ return { kind: "resolved", endpoint: normalize(input.env["GIT_PUBLISHER_ENDPOINT"]), source: "env-endpoint" };
4803
+ }
4804
+ if (input.env["GIT_PUBLISHER_PROFILE"]) {
4805
+ return byName(input.env["GIT_PUBLISHER_PROFILE"], "env-profile");
4806
+ }
4807
+ if (input.association) {
4808
+ return { kind: "resolved", endpoint: normalize(input.association), source: "association" };
4809
+ }
4810
+ if (input.file.defaultProfile && input.file.profiles[input.file.defaultProfile]) {
4811
+ return byName(input.file.defaultProfile, "default-profile");
4812
+ }
4813
+ if (names.length === 1) {
4814
+ return byName(names[0], "sole-profile");
4815
+ }
4816
+ if (names.length > 1) {
4817
+ return { kind: "ambiguous", profiles: names };
4818
+ }
4463
4819
  return { kind: "none" };
4464
4820
  }
4465
4821
  function credentialStatus(input) {
@@ -4476,16 +4832,21 @@ function credentialStatus(input) {
4476
4832
  function nextStep(status) {
4477
4833
  const profiles = status.profiles.map((p) => p.name);
4478
4834
  const r = status.resolution;
4479
- if (status.credentials === "ok") return { action: "ready", ask: null, command: null, profiles };
4480
- if (status.credentials === "unbound") return { action: "bind-endpoint", ask: null, command: null, profiles };
4481
- if (r.kind === "ambiguous" || r.kind === "unknown-profile")
4835
+ if (status.credentials === "ok") {
4836
+ return { action: "ready", ask: null, command: null, profiles };
4837
+ }
4838
+ if (status.credentials === "unbound") {
4839
+ return { action: "bind-endpoint", ask: null, command: null, profiles };
4840
+ }
4841
+ if (r.kind === "ambiguous" || r.kind === "unknown-profile") {
4482
4842
  return {
4483
4843
  action: "choose-profile",
4484
4844
  ask: "which of these places to publish to",
4485
4845
  command: "publisher profile use <name> --json",
4486
4846
  profiles
4487
4847
  };
4488
- if (r.kind === "resolved")
4848
+ }
4849
+ if (r.kind === "resolved") {
4489
4850
  return {
4490
4851
  action: "reauthenticate",
4491
4852
  // Nothing to ask: the sign-in opens a browser and asks them there.
@@ -4493,6 +4854,7 @@ function nextStep(status) {
4493
4854
  command: r.profile ? `publisher login --profile ${r.profile} --json` : `publisher login --endpoint ${r.endpoint} --json`,
4494
4855
  profiles
4495
4856
  };
4857
+ }
4496
4858
  return { action: "sign-in", ask: null, command: "publisher login --json", profiles };
4497
4859
  }
4498
4860
  function resolveLoginEndpoint(input) {
@@ -4501,7 +4863,9 @@ function resolveLoginEndpoint(input) {
4501
4863
  return endpoint ? { endpoint: normalize(endpoint) } : { discover: true };
4502
4864
  }
4503
4865
  function profileForEndpoint(file, endpoint, requested) {
4504
- if (requested && file.profiles[requested]) return requested;
4866
+ if (requested && file.profiles[requested]) {
4867
+ return requested;
4868
+ }
4505
4869
  const url2 = normalize(endpoint);
4506
4870
  return Object.keys(file.profiles).find((n) => normalize(file.profiles[n].endpoint) === url2) ?? null;
4507
4871
  }
@@ -4516,7 +4880,9 @@ async function resolveToken(endpoint, explicit, opts = {}) {
4516
4880
  { details: { endpoint: url3, endpointSource: opts.endpointSource, next: { action: "bind-endpoint", ask: null, command: null, profiles: [] } } }
4517
4881
  );
4518
4882
  }
4519
- if (given) return given;
4883
+ if (given) {
4884
+ return given;
4885
+ }
4520
4886
  const url2 = normalize(endpoint);
4521
4887
  const entry = (await readCredentials()).endpoints[url2];
4522
4888
  if (!entry) {
@@ -4527,14 +4893,20 @@ async function resolveToken(endpoint, explicit, opts = {}) {
4527
4893
  }
4528
4894
  const now = (opts.now ?? Date.now)();
4529
4895
  const lapsed = entry.expiresAt !== void 0 && Date.parse(entry.expiresAt) - REFRESH_EARLY_MS <= now;
4530
- if (entry.refreshToken && entry.authEndpoint && lapsed) return refreshCredential(url2, entry, opts);
4896
+ if (entry.refreshToken && entry.authEndpoint && lapsed) {
4897
+ return refreshCredential(url2, entry, opts);
4898
+ }
4531
4899
  return entry.token;
4532
4900
  }
4533
4901
  async function refreshStoredCredential(endpoint, opts = {}) {
4534
- if (process.env["GIT_PUBLISHER_TOKEN"]) return false;
4902
+ if (process.env["GIT_PUBLISHER_TOKEN"]) {
4903
+ return false;
4904
+ }
4535
4905
  const url2 = normalize(endpoint);
4536
4906
  const entry = (await readCredentials()).endpoints[url2];
4537
- if (!entry?.refreshToken || !entry.authEndpoint) return false;
4907
+ if (!entry?.refreshToken || !entry.authEndpoint) {
4908
+ return false;
4909
+ }
4538
4910
  await refreshCredential(url2, entry, opts);
4539
4911
  return true;
4540
4912
  }
@@ -4554,18 +4926,25 @@ async function refreshCredential(url2, entry, opts) {
4554
4926
  return access_token;
4555
4927
  }
4556
4928
  const rotated = res.status === 400 && res.body["error"] === "refresh_token_rotated";
4557
- if (!rotated && (res.status !== 400 || res.body["error"] !== "invalid_grant"))
4929
+ if (!rotated && (res.status !== 400 || res.body["error"] !== "invalid_grant")) {
4558
4930
  throw new PublisherError("UNAVAILABLE", `the credentials service answered ${res.status}`, { retryable: true });
4931
+ }
4559
4932
  const current = (await readCredentials()).endpoints[url2];
4560
- if (current?.refreshToken && current.refreshToken !== entry.refreshToken) return current.token;
4561
- if (rotated) throw new PublisherError("UNAVAILABLE", `another process is refreshing the sign-in for ${url2}; retry`, { retryable: true });
4933
+ if (current?.refreshToken && current.refreshToken !== entry.refreshToken) {
4934
+ return current.token;
4935
+ }
4936
+ if (rotated) {
4937
+ throw new PublisherError("UNAVAILABLE", `another process is refreshing the sign-in for ${url2}; retry`, { retryable: true });
4938
+ }
4562
4939
  await updateEntry(url2, ({ refreshToken: _dropped, ...rest }) => rest);
4563
4940
  throw new PublisherError("UNAUTHORIZED", `the sign-in for ${url2} has ended; run "publisher login" again`, { details: { signIn: "ended" } });
4564
4941
  }
4565
4942
  async function updateEntry(url2, change) {
4566
4943
  const file = await readCredentials();
4567
4944
  const entry = file.endpoints[url2];
4568
- if (!entry) return;
4945
+ if (!entry) {
4946
+ return;
4947
+ }
4569
4948
  file.endpoints[url2] = change(entry);
4570
4949
  await writeCredentials(file);
4571
4950
  }
@@ -4587,19 +4966,31 @@ async function createApplication(input, opts) {
4587
4966
  const answer = await post(fetchImpl, url2, await opts.token(), body);
4588
4967
  if (answer.status === 401 && !refreshed && opts.refresh !== void 0) {
4589
4968
  refreshed = true;
4590
- if (await opts.refresh()) continue;
4969
+ if (await opts.refresh()) {
4970
+ continue;
4971
+ }
4972
+ }
4973
+ if (answer.status === 200 || answer.status === 201) {
4974
+ return read(answer.body, answer.status === 201);
4591
4975
  }
4592
- if (answer.status === 200 || answer.status === 201) return read(answer.body, answer.status === 201);
4593
4976
  const code = isRecord(answer.body) && typeof answer.body["error"] === "string" ? answer.body["error"] : "";
4594
- if (answer.status === 401) throw new PublisherError("UNAUTHORIZED", 'the portal did not accept this credential; run "publisher login" again');
4595
- if (answer.status === 403) throw new PublisherError("FORBIDDEN", `the portal refused to make an application here (${code || "forbidden"})`);
4596
- if (answer.status === 409 && REFUSALS[code] !== void 0)
4977
+ if (answer.status === 401) {
4978
+ throw new PublisherError("UNAUTHORIZED", 'the portal did not accept this credential; run "publisher login" again');
4979
+ }
4980
+ if (answer.status === 403) {
4981
+ throw new PublisherError("FORBIDDEN", `the portal refused to make an application here (${code || "forbidden"})`);
4982
+ }
4983
+ if (answer.status === 409 && REFUSALS[code] !== void 0) {
4597
4984
  throw new PublisherError(REFUSALS[code], `the portal refused the repository (${code})`, { details: { portal: code } });
4598
- if (answer.status === 400 || answer.status === 409)
4985
+ }
4986
+ if (answer.status === 400 || answer.status === 409) {
4599
4987
  throw new PublisherError("INVALID_REQUEST", `the portal refused the request (${code || answer.status})`, { details: { portal: code } });
4988
+ }
4600
4989
  lastOutage = answer.status === 0 ? "the portal could not be reached" : `the portal answered ${answer.status}`;
4601
4990
  attempt += 1;
4602
- if (attempt < ATTEMPTS) await new Promise((resolve3) => setTimeout(resolve3, (opts.retryDelayMs ?? 1e3) * attempt));
4991
+ if (attempt < ATTEMPTS) {
4992
+ await new Promise((resolve3) => setTimeout(resolve3, (opts.retryDelayMs ?? 1e3) * attempt));
4993
+ }
4603
4994
  }
4604
4995
  throw new PublisherError("UNAVAILABLE", `could not make the application: ${lastOutage}; run init again`, { retryable: true });
4605
4996
  }
@@ -4666,9 +5057,13 @@ var Transport = class {
4666
5057
  } catch (e) {
4667
5058
  if (e instanceof PublisherError && e.httpStatus === 401 && !refreshed && this.opts.refresh) {
4668
5059
  refreshed = true;
4669
- if (await this.opts.refresh()) continue;
5060
+ if (await this.opts.refresh()) {
5061
+ continue;
5062
+ }
5063
+ }
5064
+ if (!(e instanceof PublisherError) || !e.retryable || attempt > retries || ro.signal?.aborted) {
5065
+ throw e;
4670
5066
  }
4671
- if (!(e instanceof PublisherError) || !e.retryable || attempt > retries || ro.signal?.aborted) throw e;
4672
5067
  const delay2 = (this.opts.retryDelayMs ?? 300) * 2 ** (attempt - 1) * (0.5 + Math.random());
4673
5068
  await sleep(Math.min(delay2, 1e4), ro.signal);
4674
5069
  }
@@ -4681,7 +5076,9 @@ var Transport = class {
4681
5076
  const timer = setTimeout(() => controller.abort(new PublisherError("NETWORK", "request timed out", { retryable: true })), this.opts.timeoutMs ?? 6e4);
4682
5077
  const onAbort = () => controller.abort(new PublisherError("CANCELLED", "cancelled"));
4683
5078
  ro.signal?.addEventListener("abort", onAbort, { once: true });
4684
- if (ro.signal?.aborted) onAbort();
5079
+ if (ro.signal?.aborted) {
5080
+ onAbort();
5081
+ }
4685
5082
  try {
4686
5083
  let res;
4687
5084
  try {
@@ -4698,7 +5095,9 @@ var Transport = class {
4698
5095
  signal: controller.signal
4699
5096
  });
4700
5097
  } catch (e) {
4701
- if (controller.signal.aborted && controller.signal.reason instanceof PublisherError) throw controller.signal.reason;
5098
+ if (controller.signal.aborted && controller.signal.reason instanceof PublisherError) {
5099
+ throw controller.signal.reason;
5100
+ }
4702
5101
  throw new PublisherError("NETWORK", `request failed: ${e.message}`, { retryable: true, cause: e });
4703
5102
  }
4704
5103
  const text = await res.text();
@@ -4710,7 +5109,9 @@ var Transport = class {
4710
5109
  parsed = null;
4711
5110
  }
4712
5111
  }
4713
- if (res.ok) return { status: res.status, body: parsed, headers: res.headers };
5112
+ if (res.ok) {
5113
+ return { status: res.status, body: parsed, headers: res.headers };
5114
+ }
4714
5115
  const err = parsed?.error;
4715
5116
  const code = err && ERROR_CODES.includes(err.code) ? err.code : fallbackCode(res.status);
4716
5117
  throw new PublisherError(code, err?.message ?? `HTTP ${res.status}`, {
@@ -4725,9 +5126,15 @@ var Transport = class {
4725
5126
  }
4726
5127
  };
4727
5128
  function fallbackCode(status) {
4728
- if (status === 401) return "UNAUTHORIZED";
4729
- if (status === 403) return "FORBIDDEN";
4730
- if (status === 429) return "UNAVAILABLE";
5129
+ if (status === 401) {
5130
+ return "UNAUTHORIZED";
5131
+ }
5132
+ if (status === 403) {
5133
+ return "FORBIDDEN";
5134
+ }
5135
+ if (status === 429) {
5136
+ return "UNAVAILABLE";
5137
+ }
4731
5138
  return status >= 500 ? "UNAVAILABLE" : "INVALID_REQUEST";
4732
5139
  }
4733
5140
  function sleep(ms, signal) {
@@ -4749,27 +5156,47 @@ var RUN_STAGES = ["received", "running", "deploying", "live"];
4749
5156
  var STAGE_WORDS = { received: "received", running: "checked", deploying: "going live", live: "live" };
4750
5157
  var STATES = ["pending", "in-progress", "done", "failed", "skipped"];
4751
5158
  function readStages(run) {
4752
- if (!isRecord2(run)) return { malformed: "a run that is not an object" };
4753
- if (!Object.hasOwn(run, "stages")) return null;
5159
+ if (!isRecord2(run)) {
5160
+ return { malformed: "a run that is not an object" };
5161
+ }
5162
+ if (!Object.hasOwn(run, "stages")) {
5163
+ return null;
5164
+ }
4754
5165
  const stages = run["stages"];
4755
- if (!Array.isArray(stages) || stages.length !== RUN_STAGES.length) return { malformed: "stages that are not exactly four" };
5166
+ if (!Array.isArray(stages) || stages.length !== RUN_STAGES.length) {
5167
+ return { malformed: "stages that are not exactly four" };
5168
+ }
4756
5169
  const out = [];
4757
5170
  for (const [index, entry] of stages.entries()) {
4758
5171
  const stage = RUN_STAGES[index];
4759
- if (!isRecord2(entry) || entry["stage"] !== stage) return { malformed: `stage ${index + 1} is not ${stage}` };
5172
+ if (!isRecord2(entry) || entry["stage"] !== stage) {
5173
+ return { malformed: `stage ${index + 1} is not ${stage}` };
5174
+ }
4760
5175
  const state = entry["state"];
4761
- if (!STATES.includes(state)) return { malformed: `stage ${stage} has an unknown state` };
5176
+ if (!STATES.includes(state)) {
5177
+ return { malformed: `stage ${stage} has an unknown state` };
5178
+ }
4762
5179
  const at = entry["at"];
4763
- if (typeof at !== "string" && at !== null) return { malformed: `stage ${stage} has an unreadable time` };
5180
+ if (typeof at !== "string" && at !== null) {
5181
+ return { malformed: `stage ${stage} has an unreadable time` };
5182
+ }
4764
5183
  out.push({ stage, word: STAGE_WORDS[stage], state, at });
4765
5184
  }
4766
5185
  return { stages: out };
4767
5186
  }
4768
5187
  function ending(stages) {
4769
- if (stages.some((s) => s.state === "pending" || s.state === "in-progress")) return null;
4770
- if (stages.some((s) => s.state === "failed")) return "failed";
4771
- if (stages[3].state === "done") return "live";
4772
- if (stages[1].state === "done" && stages[2].state === "skipped") return "not-deployed";
5188
+ if (stages.some((s) => s.state === "pending" || s.state === "in-progress")) {
5189
+ return null;
5190
+ }
5191
+ if (stages.some((s) => s.state === "failed")) {
5192
+ return "failed";
5193
+ }
5194
+ if (stages[3].state === "done") {
5195
+ return "live";
5196
+ }
5197
+ if (stages[1].state === "done" && stages[2].state === "skipped") {
5198
+ return "not-deployed";
5199
+ }
4773
5200
  return "stopped";
4774
5201
  }
4775
5202
  var POLL_INTERVAL_MS = 5e3;
@@ -4791,47 +5218,73 @@ async function followRun(input, opts) {
4791
5218
  const answer = await ask(fetchImpl, url2, await opts.token());
4792
5219
  if (answer.status === 401 && !refreshed && opts.refresh !== void 0) {
4793
5220
  refreshed = true;
4794
- if (await opts.refresh()) continue;
5221
+ if (await opts.refresh()) {
5222
+ continue;
5223
+ }
5224
+ }
5225
+ if (answer.status === 401) {
5226
+ return { kind: "unauthorized" };
5227
+ }
5228
+ if (answer.status === 404) {
5229
+ return { kind: "unavailable", reason: "no-route" };
5230
+ }
5231
+ if (answer.status === 403) {
5232
+ return { kind: "forbidden" };
4795
5233
  }
4796
- if (answer.status === 401) return { kind: "unauthorized" };
4797
- if (answer.status === 404) return { kind: "unavailable", reason: "no-route" };
4798
- if (answer.status === 403) return { kind: "forbidden" };
4799
5234
  if (answer.status === 200) {
4800
5235
  const run = soleRun(answer.body);
4801
- if ("detail" in run) return { kind: "malformed", detail: run.detail };
5236
+ if ("detail" in run) {
5237
+ return { kind: "malformed", detail: run.detail };
5238
+ }
4802
5239
  if (run.run !== null) {
4803
5240
  const read2 = readStages(run.run);
4804
- if (read2 === null) return { kind: "unavailable", reason: "no-stages" };
4805
- if ("malformed" in read2) return { kind: "malformed", detail: read2.malformed };
5241
+ if (read2 === null) {
5242
+ return { kind: "unavailable", reason: "no-stages" };
5243
+ }
5244
+ if ("malformed" in read2) {
5245
+ return { kind: "malformed", detail: read2.malformed };
5246
+ }
4806
5247
  last = read2.stages;
4807
5248
  let moved = false;
4808
5249
  for (const entry of read2.stages) {
4809
- if (entry.state === "pending" || seen.get(entry.stage) === entry.state) continue;
5250
+ if (entry.state === "pending" || seen.get(entry.stage) === entry.state) {
5251
+ continue;
5252
+ }
4810
5253
  seen.set(entry.stage, entry.state);
4811
5254
  opts.onStage?.(entry);
4812
5255
  moved = true;
4813
5256
  }
4814
- if (isRecord2(run.run) && run.run["status"] === "awaiting-approval") return { kind: "waiting", stages: read2.stages };
5257
+ if (isRecord2(run.run) && run.run["status"] === "awaiting-approval") {
5258
+ return { kind: "waiting", stages: read2.stages };
5259
+ }
4815
5260
  const end = ending(read2.stages);
4816
5261
  if (end !== null) {
4817
5262
  const runId = isRecord2(run.run) && typeof run.run["runId"] === "string" ? run.run["runId"] : null;
4818
5263
  return { kind: "settled", ending: end, failedAt: read2.stages.find((s) => s.state === "failed")?.word ?? null, stages: read2.stages, runId };
4819
5264
  }
4820
- if (opts.untilChange === true && moved && answered) return { kind: "moving", stages: read2.stages };
5265
+ if (opts.untilChange === true && moved && answered) {
5266
+ return { kind: "moving", stages: read2.stages };
5267
+ }
4821
5268
  }
4822
5269
  answered = true;
4823
5270
  lastError = null;
4824
5271
  } else {
4825
5272
  lastError = answer.status === 0 ? "the portal could not be reached" : `the portal answered ${answer.status}`;
4826
5273
  }
4827
- if (now() + interval2 > deadline) return { kind: "timed-out", stages: last, lastError };
5274
+ if (now() + interval2 > deadline) {
5275
+ return { kind: "timed-out", stages: last, lastError };
5276
+ }
4828
5277
  await sleep2(interval2);
4829
5278
  }
4830
5279
  }
4831
5280
  function soleRun(body) {
4832
- if (!isRecord2(body) || !Array.isArray(body["runs"])) return { detail: "an answer with no list of runs" };
5281
+ if (!isRecord2(body) || !Array.isArray(body["runs"])) {
5282
+ return { detail: "an answer with no list of runs" };
5283
+ }
4833
5284
  const runs = body["runs"];
4834
- if (runs.length > 1) return { detail: "more than the one run this publication started" };
5285
+ if (runs.length > 1) {
5286
+ return { detail: "more than the one run this publication started" };
5287
+ }
4835
5288
  return { run: runs[0] ?? null };
4836
5289
  }
4837
5290
  async function ask(fetchImpl, url2, token) {
@@ -4842,7 +5295,9 @@ async function ask(fetchImpl, url2, token) {
4842
5295
  try {
4843
5296
  body = text ? JSON.parse(text) : null;
4844
5297
  } catch {
4845
- if (res.status === 200) return { status: 200, body: void 0 };
5298
+ if (res.status === 200) {
5299
+ return { status: 200, body: void 0 };
5300
+ }
4846
5301
  }
4847
5302
  return { status: res.status, body };
4848
5303
  } catch {
@@ -4856,18 +5311,24 @@ function portalForEndpoint(endpoint) {
4856
5311
  } catch {
4857
5312
  return null;
4858
5313
  }
4859
- if (url2.protocol !== "https:" || url2.pathname.replace(/\/+$/, "") !== "/publish") return null;
5314
+ if (url2.protocol !== "https:" || url2.pathname.replace(/\/+$/, "") !== "/publish") {
5315
+ return null;
5316
+ }
4860
5317
  return url2.origin;
4861
5318
  }
4862
5319
  var RUN_PROGRESS = "run-progress";
4863
5320
  async function confirmPortal(portal, endpoint, fetchImpl = fetch) {
4864
5321
  try {
4865
5322
  const res = await fetchImpl(`${portal}/api/v1/config`, { signal: AbortSignal.timeout(1e4) });
4866
- if (!res.ok) return null;
5323
+ if (!res.ok) {
5324
+ return null;
5325
+ }
4867
5326
  const body = await res.json();
4868
5327
  const named = body?.publishingEndpoint;
4869
5328
  const bare = (u) => u.replace(/\/+$/, "");
4870
- if (typeof named !== "string" || bare(named) !== bare(endpoint)) return null;
5329
+ if (typeof named !== "string" || bare(named) !== bare(endpoint)) {
5330
+ return null;
5331
+ }
4871
5332
  const terminal = body?.terminal;
4872
5333
  return { terminal: Array.isArray(terminal) && terminal.every((name) => typeof name === "string") ? terminal : [] };
4873
5334
  } catch {
@@ -4897,11 +5358,19 @@ async function call(input, opts, body) {
4897
5358
  const answer = await ask2(fetchImpl, url2, await opts.token(), body);
4898
5359
  if (answer.status === 401 && !refreshed && opts.refresh !== void 0) {
4899
5360
  refreshed = true;
4900
- if (await opts.refresh()) continue;
5361
+ if (await opts.refresh()) {
5362
+ continue;
5363
+ }
5364
+ }
5365
+ if (answer.status === 401) {
5366
+ return { kind: "unauthorized" };
5367
+ }
5368
+ if (answer.status === 403) {
5369
+ return { kind: "forbidden" };
5370
+ }
5371
+ if (answer.status === 409) {
5372
+ return { kind: "moved-on" };
4901
5373
  }
4902
- if (answer.status === 401) return { kind: "unauthorized" };
4903
- if (answer.status === 403) return { kind: "forbidden" };
4904
- if (answer.status === 409) return { kind: "moved-on" };
4905
5374
  if (answer.status === 404) {
4906
5375
  const code = isRecord3(answer.body) ? answer.body["error"] : void 0;
4907
5376
  return code === "no-such-application" ? { kind: "no-application" } : { kind: "unavailable", detail: "the portal does not serve this address" };
@@ -4914,13 +5383,25 @@ async function call(input, opts, body) {
4914
5383
  }
4915
5384
  }
4916
5385
  function readView(body) {
4917
- if (!isRecord3(body)) return { detail: "an answer that is not a preparation" };
5386
+ if (!isRecord3(body)) {
5387
+ return { detail: "an answer that is not a preparation" };
5388
+ }
4918
5389
  const { id, revision, status, message, questions, publication } = body;
4919
- if (typeof id !== "string" || id === "") return { detail: "a preparation with no id" };
4920
- if (typeof revision !== "number" || !Number.isSafeInteger(revision) || revision < 1) return { detail: "a preparation with no revision" };
4921
- if (!STATUSES.includes(status)) return { detail: "a preparation with an unknown status" };
4922
- if (typeof message !== "string") return { detail: "a preparation with no message" };
4923
- if (!Array.isArray(questions)) return { detail: "a preparation with no list of questions" };
5390
+ if (typeof id !== "string" || id === "") {
5391
+ return { detail: "a preparation with no id" };
5392
+ }
5393
+ if (typeof revision !== "number" || !Number.isSafeInteger(revision) || revision < 1) {
5394
+ return { detail: "a preparation with no revision" };
5395
+ }
5396
+ if (!STATUSES.includes(status)) {
5397
+ return { detail: "a preparation with an unknown status" };
5398
+ }
5399
+ if (typeof message !== "string") {
5400
+ return { detail: "a preparation with no message" };
5401
+ }
5402
+ if (!Array.isArray(questions)) {
5403
+ return { detail: "a preparation with no list of questions" };
5404
+ }
4924
5405
  const read2 = [];
4925
5406
  for (const q of questions) {
4926
5407
  if (!isRecord3(q) || typeof q["id"] !== "string" || typeof q["text"] !== "string" || !Array.isArray(q["options"]) || q["options"].length === 0) {
@@ -4928,7 +5409,9 @@ function readView(body) {
4928
5409
  }
4929
5410
  const options = [];
4930
5411
  for (const o of q["options"]) {
4931
- if (!isRecord3(o) || typeof o["value"] !== "string" || typeof o["label"] !== "string") return { detail: "a question with an unreadable option" };
5412
+ if (!isRecord3(o) || typeof o["value"] !== "string" || typeof o["label"] !== "string") {
5413
+ return { detail: "a question with an unreadable option" };
5414
+ }
4932
5415
  options.push({ value: o["value"], label: o["label"] });
4933
5416
  }
4934
5417
  read2.push({ id: q["id"], text: q["text"], options });
@@ -4940,21 +5423,33 @@ function readView(body) {
4940
5423
  return { id, revision, status, message, questions: read2, publication: pub, findings: readFindings(body["findings"]) };
4941
5424
  }
4942
5425
  function readFindings(value) {
4943
- if (!Array.isArray(value)) return [];
5426
+ if (!Array.isArray(value)) {
5427
+ return [];
5428
+ }
4944
5429
  const out = [];
4945
5430
  const text = (v) => typeof v === "string" && v !== "" ? v.slice(0, MAX_TEXT) : void 0;
4946
5431
  for (const f of value) {
4947
- if (out.length === MAX_FINDINGS) break;
4948
- if (!isRecord3(f)) continue;
5432
+ if (out.length === MAX_FINDINGS) {
5433
+ break;
5434
+ }
5435
+ if (!isRecord3(f)) {
5436
+ continue;
5437
+ }
4949
5438
  const kind = text(f["kind"]);
4950
5439
  const fix = text(f["fix"]);
4951
- if (kind === void 0 || fix === void 0) continue;
5440
+ if (kind === void 0 || fix === void 0) {
5441
+ continue;
5442
+ }
4952
5443
  const finding = { kind, fix };
4953
5444
  for (const field of ["url", "path", "message"]) {
4954
5445
  const value2 = text(f[field]);
4955
- if (value2 !== void 0) finding[field] = value2;
5446
+ if (value2 !== void 0) {
5447
+ finding[field] = value2;
5448
+ }
5449
+ }
5450
+ if (typeof f["status"] === "number" && Number.isInteger(f["status"])) {
5451
+ finding.status = f["status"];
4956
5452
  }
4957
- if (typeof f["status"] === "number" && Number.isInteger(f["status"])) finding.status = f["status"];
4958
5453
  out.push(finding);
4959
5454
  }
4960
5455
  return out;
@@ -5038,7 +5533,9 @@ async function onboardFolder(opts) {
5038
5533
  const extra = policy.exclude ?? [];
5039
5534
  const walk = async (d) => {
5040
5535
  for (const e of await (0, import_promises6.readdir)(d, { withFileTypes: true })) {
5041
- if (opts.signal?.aborted) throw new PublisherError("CANCELLED", "cancelled");
5536
+ if (opts.signal?.aborted) {
5537
+ throw new PublisherError("CANCELLED", "cancelled");
5538
+ }
5042
5539
  const full = (0, import_node_path5.join)(d, e.name);
5043
5540
  const rel = (0, import_node_path5.relative)(dir, full).split(import_node_path5.sep).join("/");
5044
5541
  if (e.isSymbolicLink()) {
@@ -5053,7 +5550,9 @@ async function onboardFolder(opts) {
5053
5550
  await walk(full);
5054
5551
  continue;
5055
5552
  }
5056
- if (!e.isFile()) continue;
5553
+ if (!e.isFile()) {
5554
+ continue;
5555
+ }
5057
5556
  if (excludedFile(rel, e.name, extra)) {
5058
5557
  excluded.push({ path: rel, reason: "excluded by policy" });
5059
5558
  continue;
@@ -5069,8 +5568,12 @@ async function onboardFolder(opts) {
5069
5568
  await walk(dir);
5070
5569
  const ignored = await checkIgnore(dir, candidates);
5071
5570
  const selected = candidates.filter((p) => !ignored.has(p)).sort();
5072
- for (const p of ignored) excluded.push({ path: p, reason: "ignored by .gitignore" });
5073
- if (selected.length === 0) return { repoDir: dir, commit: null, committed: [], excluded, initialized };
5571
+ for (const p of ignored) {
5572
+ excluded.push({ path: p, reason: "ignored by .gitignore" });
5573
+ }
5574
+ if (selected.length === 0) {
5575
+ return { repoDir: dir, commit: null, committed: [], excluded, initialized };
5576
+ }
5074
5577
  const commit = await commitPaths(dir, selected, {
5075
5578
  message: opts.message ?? "Initial publication",
5076
5579
  ...opts.authorName ? { authorName: opts.authorName } : {},
@@ -5087,7 +5590,9 @@ function excludedFile(rel, name, extra) {
5087
5590
  }
5088
5591
  async function recordChanges(opts) {
5089
5592
  const dir = opts.dir;
5090
- if (!await isGitRepo(dir)) throw new PublisherError("LOCAL_STATE", "this folder is not published yet; run publisher init first");
5593
+ if (!await isGitRepo(dir)) {
5594
+ throw new PublisherError("LOCAL_STATE", "this folder is not published yet; run publisher init first");
5595
+ }
5091
5596
  const maxBytes = opts.policy?.maxFileBytes ?? 50 * 1024 * 1024;
5092
5597
  const extra = opts.policy?.exclude ?? [];
5093
5598
  const excluded = [];
@@ -5096,16 +5601,21 @@ async function recordChanges(opts) {
5096
5601
  if (await mergeInProgress(dir)) {
5097
5602
  const marked = [];
5098
5603
  for (const { code, path } of entries) {
5099
- if (!UNMERGED.has(code)) continue;
5604
+ if (!UNMERGED.has(code)) {
5605
+ continue;
5606
+ }
5100
5607
  const text = await (0, import_promises6.readFile)((0, import_node_path5.join)(dir, path), "utf8").catch(() => "");
5101
- if (/^<{7} /m.test(text) && /^>{7} /m.test(text)) marked.push(path);
5608
+ if (/^<{7} /m.test(text) && /^>{7} /m.test(text)) {
5609
+ marked.push(path);
5610
+ }
5102
5611
  }
5103
- if (marked.length)
5612
+ if (marked.length) {
5104
5613
  throw new PublisherError(
5105
5614
  "LOCAL_STATE",
5106
5615
  `still marked as conflicting: ${marked.join(", ")}; keep one version (or both) in each, remove the <<<<<<< ======= >>>>>>> lines, then sync again`,
5107
5616
  { details: { marked } }
5108
5617
  );
5618
+ }
5109
5619
  }
5110
5620
  for (const { code, path } of entries) {
5111
5621
  if (code !== "??") {
@@ -5136,7 +5646,9 @@ async function recordChanges(opts) {
5136
5646
  selected.push(path);
5137
5647
  }
5138
5648
  const unique = dedupe(excluded);
5139
- if (selected.length === 0) return { repoDir: dir, commit: null, committed: [], excluded: unique, initialized: false };
5649
+ if (selected.length === 0) {
5650
+ return { repoDir: dir, commit: null, committed: [], excluded: unique, initialized: false };
5651
+ }
5140
5652
  const commit = await commitPaths(dir, selected.sort(), {
5141
5653
  message: opts.message ?? "Update",
5142
5654
  ...opts.authorName ? { authorName: opts.authorName } : {},
@@ -5163,9 +5675,13 @@ function matches(rel, base, pattern) {
5163
5675
  return base === pattern || rel === pattern || rel.startsWith(pattern.replace(/\/$/, "") + "/");
5164
5676
  }
5165
5677
  async function checkIgnore(dir, paths) {
5166
- if (paths.length === 0) return /* @__PURE__ */ new Set();
5678
+ if (paths.length === 0) {
5679
+ return /* @__PURE__ */ new Set();
5680
+ }
5167
5681
  const r = await runGit(["check-ignore", "--stdin", "-z"], { cwd: dir, input: paths.join("\0") + "\0", allowFailure: true });
5168
- if (r.code !== 0) return /* @__PURE__ */ new Set();
5682
+ if (r.code !== 0) {
5683
+ return /* @__PURE__ */ new Set();
5684
+ }
5169
5685
  return new Set(r.stdout.toString("utf8").split("\0").filter(Boolean));
5170
5686
  }
5171
5687
 
@@ -5185,7 +5701,9 @@ var import_promises7 = require("node:fs/promises");
5185
5701
  var import_node_fs5 = require("node:fs");
5186
5702
  var import_node_stream = require("node:stream");
5187
5703
  async function uploadPack(fetchImpl, upload, packPath, size, opts) {
5188
- if (new Date(upload.expiresAt).getTime() < Date.now() + 5e3) return "expired";
5704
+ if (new Date(upload.expiresAt).getTime() < Date.now() + 5e3) {
5705
+ return "expired";
5706
+ }
5189
5707
  let sent = 0;
5190
5708
  const file = (0, import_node_fs5.createReadStream)(packPath);
5191
5709
  const progress = new TransformStream({
@@ -5206,16 +5724,27 @@ async function uploadPack(fetchImpl, upload, packPath, size, opts) {
5206
5724
  ...opts.signal ? { signal: opts.signal } : {}
5207
5725
  });
5208
5726
  } catch (e) {
5209
- if (opts.signal?.aborted) throw new PublisherError("CANCELLED", "upload cancelled");
5727
+ if (opts.signal?.aborted) {
5728
+ throw new PublisherError("CANCELLED", "upload cancelled");
5729
+ }
5210
5730
  throw new PublisherError("NETWORK", `upload failed: ${e.message}`, { retryable: true, cause: e });
5211
5731
  }
5212
- if (res.ok) return "uploaded";
5732
+ if (res.ok) {
5733
+ return "uploaded";
5734
+ }
5213
5735
  const text = await res.text().catch(() => "");
5214
- if (res.status === 412) return "already-present";
5215
- if (res.status === 403 && /expired|Request has expired|AccessDenied/i.test(text)) return "expired";
5216
- if (res.status === 400 && /checksum|Content-MD5|BadDigest|XAmzContentSHA256Mismatch/i.test(text))
5736
+ if (res.status === 412) {
5737
+ return "already-present";
5738
+ }
5739
+ if (res.status === 403 && /expired|Request has expired|AccessDenied/i.test(text)) {
5740
+ return "expired";
5741
+ }
5742
+ if (res.status === 400 && /checksum|Content-MD5|BadDigest|XAmzContentSHA256Mismatch/i.test(text)) {
5217
5743
  throw new PublisherError("UPLOAD_MISMATCH", "storage rejected the pack checksum");
5218
- if (res.status >= 500 || res.status === 429) throw new PublisherError("NETWORK", `upload failed with HTTP ${res.status}`, { retryable: true });
5744
+ }
5745
+ if (res.status >= 500 || res.status === 429) {
5746
+ throw new PublisherError("NETWORK", `upload failed with HTTP ${res.status}`, { retryable: true });
5747
+ }
5219
5748
  throw new PublisherError("NETWORK", `upload failed with HTTP ${res.status}`);
5220
5749
  }
5221
5750
 
@@ -5233,12 +5762,19 @@ async function publish(ctx, repoId, remote, opts, call2) {
5233
5762
  try {
5234
5763
  refUpdates = await resolveUpdates(repoDir, repo, specs);
5235
5764
  } catch (e) {
5236
- if (e instanceof PublisherError && e.code === "LOCAL_STATE" && /nothing to publish/.test(e.message)) nothingNew = e;
5237
- else throw e;
5765
+ if (e instanceof PublisherError && e.code === "LOCAL_STATE" && /nothing to publish/.test(e.message)) {
5766
+ nothingNew = e;
5767
+ } else {
5768
+ throw e;
5769
+ }
5238
5770
  }
5239
5771
  for (const pending2 of pendings) {
5240
- if (pending2.repoId !== repoId) continue;
5241
- if (opts.publicationId && pending2.publicationId !== opts.publicationId) continue;
5772
+ if (pending2.repoId !== repoId) {
5773
+ continue;
5774
+ }
5775
+ if (opts.publicationId && pending2.publicationId !== opts.publicationId) {
5776
+ continue;
5777
+ }
5242
5778
  const sameIntent = !nothingNew && pending2.baseGeneration === repo.generation && canonicalJson(refUpdates) === canonicalJson(pending2.refUpdates);
5243
5779
  if (sameIntent && (pending2.pack === null || await packFileUsable(pending2))) {
5244
5780
  progress({ phase: "resolve", message: `resuming publication ${pending2.publicationId}` });
@@ -5257,13 +5793,19 @@ async function publish(ctx, repoId, remote, opts, call2) {
5257
5793
  try {
5258
5794
  remaining = await resolveUpdates(repoDir, fresh, specs);
5259
5795
  } catch (e) {
5260
- if (!(e instanceof PublisherError && e.code === "LOCAL_STATE")) throw e;
5796
+ if (!(e instanceof PublisherError && e.code === "LOCAL_STATE")) {
5797
+ throw e;
5798
+ }
5799
+ }
5800
+ if (remaining.length === 0) {
5801
+ return toOutcome(outcome, true, pending2.refUpdates);
5261
5802
  }
5262
- if (remaining.length === 0) return toOutcome(outcome, true, pending2.refUpdates);
5263
5803
  return publish(ctx, repoId, remote, opts, call2);
5264
5804
  }
5265
5805
  }
5266
- if (nothingNew) throw nothingNew;
5806
+ if (nothingNew) {
5807
+ throw nothingNew;
5808
+ }
5267
5809
  const remoteOids = new Set(Object.values(repo.refs));
5268
5810
  const wants = refUpdates.map((u) => u.new).filter((o) => o !== null);
5269
5811
  const needsPack = wants.some((o) => !remoteOids.has(o));
@@ -5272,7 +5814,11 @@ async function publish(ctx, repoId, remote, opts, call2) {
5272
5814
  if (needsPack) {
5273
5815
  progress({ phase: "pack", message: "packing objects" });
5274
5816
  const exclude = [];
5275
- for (const info of await batchCheck(repoDir, remoteOids)) if (info.type !== "missing") exclude.push(info.oid);
5817
+ for (const info of await batchCheck(repoDir, remoteOids)) {
5818
+ if (info.type !== "missing") {
5819
+ exclude.push(info.oid);
5820
+ }
5821
+ }
5276
5822
  const outPath = store2.packPath(publicationId);
5277
5823
  const built = await buildPack(repoDir, { include: wants, exclude, outPath, ...call2.signal ? { signal: call2.signal } : {} });
5278
5824
  pack = { sha256: built.sha256, size: built.size, path: outPath };
@@ -5293,7 +5839,9 @@ async function publish(ctx, repoId, remote, opts, call2) {
5293
5839
  return runPublication(ctx, repoId, remote, repoDir, store2, pending, opts, call2, false);
5294
5840
  }
5295
5841
  async function packFileUsable(p) {
5296
- if (!p.pack) return true;
5842
+ if (!p.pack) {
5843
+ return true;
5844
+ }
5297
5845
  try {
5298
5846
  const h = await sha256File(p.pack.path);
5299
5847
  return h.sha256 === p.pack.sha256 && h.size === p.pack.size;
@@ -5310,8 +5858,12 @@ async function runPublication(ctx, repoId, remote, repoDir, store2, pending, opt
5310
5858
  }
5311
5859
  var UNCONFIRMED = /* @__PURE__ */ new Set(["UNAUTHORIZED", "FORBIDDEN", "NETWORK", "UNAVAILABLE", "INTERNAL"]);
5312
5860
  function unconfirmed(e, publicationId) {
5313
- if (!(e instanceof PublisherError) || !UNCONFIRMED.has(e.code)) return e;
5314
- if (e.code === "UNAUTHORIZED" && e.details?.["signIn"] !== void 0) return e;
5861
+ if (!(e instanceof PublisherError) || !UNCONFIRMED.has(e.code)) {
5862
+ return e;
5863
+ }
5864
+ if (e.code === "UNAUTHORIZED" && e.details?.["signIn"] !== void 0) {
5865
+ return e;
5866
+ }
5315
5867
  return new PublisherError("OUTCOME_UNKNOWN", `publication ${publicationId} was not confirmed (${e.code}: ${e.message}); run status before publishing again`, {
5316
5868
  retryable: true,
5317
5869
  cause: e,
@@ -5338,9 +5890,13 @@ async function sendAndWait(ctx, repoId, remote, repoDir, store2, pending, opts,
5338
5890
  let result = await uploadPack(ctx.fetchImpl, begin.upload, pending.pack.path, pending.pack.size, call2);
5339
5891
  if (result === "expired") {
5340
5892
  begin = (await ctx.transport.request("POST", `/v1/repos/${repoId}/publications`, beginBody, call2)).body;
5341
- if (!begin.upload) throw new PublisherError("UPLOAD_MISSING", "server did not return fresh upload instructions");
5893
+ if (!begin.upload) {
5894
+ throw new PublisherError("UPLOAD_MISSING", "server did not return fresh upload instructions");
5895
+ }
5342
5896
  result = await uploadPack(ctx.fetchImpl, begin.upload, pending.pack.path, pending.pack.size, call2);
5343
- if (result === "expired") throw new PublisherError("NETWORK", "upload authorization expired twice", { retryable: true });
5897
+ if (result === "expired") {
5898
+ throw new PublisherError("NETWORK", "upload authorization expired twice", { retryable: true });
5899
+ }
5344
5900
  }
5345
5901
  }
5346
5902
  progress({ phase: "finalize", message: "finalizing" });
@@ -5362,7 +5918,9 @@ async function sendAndWait(ctx, repoId, remote, repoDir, store2, pending, opts,
5362
5918
  progress({ phase: "done", message: `published generation ${summary.resultGeneration}` });
5363
5919
  } else if (summary.state === "rejected") {
5364
5920
  await store2.remove(pending.publicationId);
5365
- if (pending.pack) await (0, import_promises7.rm)(pending.pack.path, { force: true });
5921
+ if (pending.pack) {
5922
+ await (0, import_promises7.rm)(pending.pack.path, { force: true });
5923
+ }
5366
5924
  }
5367
5925
  return toOutcome(summary, resumed, pending.refUpdates);
5368
5926
  }
@@ -5371,7 +5929,9 @@ async function waitForOutcome(ctx, repoId, publicationId, timeoutMs, call2) {
5371
5929
  let delay2 = 500;
5372
5930
  for (; ; ) {
5373
5931
  const s = await ctx.getStatus(repoId, publicationId, { ...call2, waitSeconds: MAX_WAIT_SECONDS });
5374
- if (s.state === "accepted" || s.state === "rejected") return s;
5932
+ if (s.state === "accepted" || s.state === "rejected") {
5933
+ return s;
5934
+ }
5375
5935
  if (Date.now() > deadline) {
5376
5936
  throw new PublisherError("OUTCOME_UNKNOWN", `publication ${publicationId} has not completed yet; run status later`, { retryable: true, details: { publicationId } });
5377
5937
  }
@@ -5427,7 +5987,9 @@ function toOutcome(s, resumed, updates) {
5427
5987
  }
5428
5988
  var REF_MOVED = /* @__PURE__ */ new Set(["NON_FAST_FORWARD", "EXPECTED_OLD_MISMATCH", "STALE_GENERATION"]);
5429
5989
  function publishNext(rejection, published) {
5430
- if (rejection === null || !REF_MOVED.has(rejection.code)) return null;
5990
+ if (rejection === null || !REF_MOVED.has(rejection.code)) {
5991
+ return null;
5992
+ }
5431
5993
  const named = rejection.details?.["ref"];
5432
5994
  const ref = typeof named === "string" ? named : published;
5433
5995
  const name = ref?.replace(/^refs\/heads\//, "") ?? "main";
@@ -5439,7 +6001,9 @@ function publishNext(rejection, published) {
5439
6001
  }
5440
6002
  async function defaultUpdate(repoDir) {
5441
6003
  const branch = await currentBranch(repoDir);
5442
- if (!branch) throw new PublisherError("LOCAL_STATE", "detached HEAD: specify which ref to publish");
6004
+ if (!branch) {
6005
+ throw new PublisherError("LOCAL_STATE", "detached HEAD: specify which ref to publish");
6006
+ }
5443
6007
  return { ref: branch };
5444
6008
  }
5445
6009
  async function resolveUpdates(repoDir, repo, specs) {
@@ -5451,31 +6015,48 @@ async function resolveUpdates(repoDir, repo, specs) {
5451
6015
  );
5452
6016
  let i = 0;
5453
6017
  for (const spec of specs) {
5454
- if (!spec.ref.startsWith("refs/")) throw new PublisherError("INVALID_REQUEST", `ref must be fully qualified: ${spec.ref}`);
6018
+ if (!spec.ref.startsWith("refs/")) {
6019
+ throw new PublisherError("INVALID_REQUEST", `ref must be fully qualified: ${spec.ref}`);
6020
+ }
5455
6021
  let target;
5456
- if (spec.to === null) target = null;
5457
- else {
6022
+ if (spec.to === null) {
6023
+ target = null;
6024
+ } else {
5458
6025
  const r = resolved[i++] ?? null;
5459
- if (r instanceof PublisherError) throw r;
6026
+ if (r instanceof PublisherError) {
6027
+ throw r;
6028
+ }
5460
6029
  target = r;
5461
- if (!target) throw new PublisherError("LOCAL_STATE", `cannot resolve ${spec.to ?? spec.ref} in ${repoDir}`);
6030
+ if (!target) {
6031
+ throw new PublisherError("LOCAL_STATE", `cannot resolve ${spec.to ?? spec.ref} in ${repoDir}`);
6032
+ }
5462
6033
  }
5463
6034
  const expectedOld = repo.refs[spec.ref] ?? null;
5464
- if (target === null && expectedOld === null) throw new PublisherError("INVALID_REQUEST", `${spec.ref} does not exist on the server`);
5465
- if (target !== null && target === expectedOld) continue;
6035
+ if (target === null && expectedOld === null) {
6036
+ throw new PublisherError("INVALID_REQUEST", `${spec.ref} does not exist on the server`);
6037
+ }
6038
+ if (target !== null && target === expectedOld) {
6039
+ continue;
6040
+ }
5466
6041
  out.push({ ref: spec.ref, expectedOld, new: target, force: spec.force ?? false });
5467
6042
  }
5468
- if (out.length === 0) throw new PublisherError("LOCAL_STATE", "nothing to publish: the server already has these refs");
6043
+ if (out.length === 0) {
6044
+ throw new PublisherError("LOCAL_STATE", "nothing to publish: the server already has these refs");
6045
+ }
5469
6046
  return out;
5470
6047
  }
5471
6048
  async function applyTrackingRefs(repoDir, remote, updates) {
5472
6049
  for (const u of updates) {
5473
6050
  const tracking = trackingRef(remote, u.ref);
5474
- if (tracking) await updateTrackingRef(repoDir, tracking, u.new);
6051
+ if (tracking) {
6052
+ await updateTrackingRef(repoDir, tracking, u.new);
6053
+ }
5475
6054
  }
5476
6055
  }
5477
6056
  function trackingRef(remote, ref) {
5478
- if (ref.startsWith("refs/heads/")) return `refs/remotes/${remote}/${ref.slice("refs/heads/".length)}`;
6057
+ if (ref.startsWith("refs/heads/")) {
6058
+ return `refs/remotes/${remote}/${ref.slice("refs/heads/".length)}`;
6059
+ }
5479
6060
  return null;
5480
6061
  }
5481
6062
 
@@ -5518,7 +6099,9 @@ async function fetchRepository(ctx, repoId, opts, call2) {
5518
6099
  artifacts.filter((a) => installed.has(a.sha256)),
5519
6100
  call2
5520
6101
  );
5521
- if (!await haveAll(opts.repoDir, body.refs)) throw new PublisherError("NETWORK", "the downloaded artifacts do not contain every advertised ref", { retryable: true });
6102
+ if (!await haveAll(opts.repoDir, body.refs)) {
6103
+ throw new PublisherError("NETWORK", "the downloaded artifacts do not contain every advertised ref", { retryable: true });
6104
+ }
5522
6105
  }
5523
6106
  }
5524
6107
  await writeManifest(
@@ -5531,11 +6114,15 @@ async function fetchRepository(ctx, repoId, opts, call2) {
5531
6114
  }
5532
6115
  async function haveAll(repoDir, refs) {
5533
6116
  const oids = new Set(Object.values(refs));
5534
- if (oids.size === 0) return true;
6117
+ if (oids.size === 0) {
6118
+ return true;
6119
+ }
5535
6120
  return (await batchCheck(repoDir, oids)).every((o) => o.type !== "missing");
5536
6121
  }
5537
6122
  async function install(ctx, gd, artifacts, call2) {
5538
- if (artifacts.length === 0) return 0;
6123
+ if (artifacts.length === 0) {
6124
+ return 0;
6125
+ }
5539
6126
  const progress = call2.onProgress ?? (() => void 0);
5540
6127
  const tmp = await (0, import_promises8.mkdtemp)((0, import_node_path6.join)((0, import_node_os3.tmpdir)(), "gitpub-fetch-"));
5541
6128
  let bytes = 0;
@@ -5565,12 +6152,18 @@ async function updateRefs(repoDir, remote, refs) {
5565
6152
  const t = trackingRef(remote, ref);
5566
6153
  if (t) {
5567
6154
  tracking[t] = oid;
5568
- if (before[t] !== oid) updates.push({ ref: t, new: oid });
6155
+ if (before[t] !== oid) {
6156
+ updates.push({ ref: t, new: oid });
6157
+ }
5569
6158
  } else if (ref.startsWith("refs/tags/") && !(ref in before)) {
5570
6159
  updates.push({ ref, new: oid });
5571
6160
  }
5572
6161
  }
5573
- for (const ref of Object.keys(before)) if (ref.startsWith(prefix) && !(ref in tracking)) updates.push({ ref, new: null });
6162
+ for (const ref of Object.keys(before)) {
6163
+ if (ref.startsWith(prefix) && !(ref in tracking)) {
6164
+ updates.push({ ref, new: null });
6165
+ }
6166
+ }
5574
6167
  await refTransaction(repoDir, updates);
5575
6168
  return tracking;
5576
6169
  }
@@ -5581,7 +6174,9 @@ async function download(fetchImpl, url2, dest, sha256, size, call2) {
5581
6174
  } catch (e) {
5582
6175
  throw new PublisherError("NETWORK", `download failed: ${e.message}`, { retryable: true, cause: e });
5583
6176
  }
5584
- if (!res.ok || !res.body) throw new PublisherError("NETWORK", `download failed with HTTP ${res.status}`, { retryable: res.status >= 500 });
6177
+ if (!res.ok || !res.body) {
6178
+ throw new PublisherError("NETWORK", `download failed with HTTP ${res.status}`, { retryable: res.status >= 500 });
6179
+ }
5585
6180
  const hash = (0, import_node_crypto4.createHash)("sha256");
5586
6181
  let n = 0;
5587
6182
  const counted = new TransformStream({
@@ -5593,7 +6188,9 @@ async function download(fetchImpl, url2, dest, sha256, size, call2) {
5593
6188
  }
5594
6189
  });
5595
6190
  await (0, import_promises9.pipeline)(import_node_stream2.Readable.fromWeb(res.body.pipeThrough(counted)), (0, import_node_fs6.createWriteStream)(dest));
5596
- if (n !== size || hash.digest("hex") !== sha256) throw new PublisherError("NETWORK", "downloaded artifact failed checksum verification", { retryable: true });
6191
+ if (n !== size || hash.digest("hex") !== sha256) {
6192
+ throw new PublisherError("NETWORK", "downloaded artifact failed checksum verification", { retryable: true });
6193
+ }
5597
6194
  return n;
5598
6195
  }
5599
6196
 
@@ -5603,7 +6200,9 @@ var CLIENT_VERSION = "0.1.0";
5603
6200
  async function markConflicts(dir, remote) {
5604
6201
  const who = { GIT_AUTHOR_NAME: "Publisher", GIT_AUTHOR_EMAIL: "publisher@localhost", GIT_COMMITTER_NAME: "Publisher", GIT_COMMITTER_EMAIL: "publisher@localhost" };
5605
6202
  const r = await runGit(["merge", "--no-ff", "--no-commit", "--no-verify", remote], { cwd: dir, env: { extra: who }, allowFailure: true });
5606
- if (r.code !== 0 && !await mergeInProgress(dir)) throw new PublisherError("GIT", `could not mark the conflicts: ${r.stderr.trim()}`);
6203
+ if (r.code !== 0 && !await mergeInProgress(dir)) {
6204
+ throw new PublisherError("GIT", `could not mark the conflicts: ${r.stderr.trim()}`);
6205
+ }
5607
6206
  }
5608
6207
  var Publisher = class {
5609
6208
  constructor(opts) {
@@ -5692,9 +6291,15 @@ var Publisher = class {
5692
6291
  /** One page of the repositories the caller created (ADR-0011). An authenticated route, unlike capabilities. */
5693
6292
  async listRepositories(options = {}, call2 = {}) {
5694
6293
  const q = new URLSearchParams();
5695
- if (options.state) q.set("state", options.state);
5696
- if (options.limit !== void 0) q.set("limit", String(options.limit));
5697
- if (options.cursor) q.set("cursor", options.cursor);
6294
+ if (options.state) {
6295
+ q.set("state", options.state);
6296
+ }
6297
+ if (options.limit !== void 0) {
6298
+ q.set("limit", String(options.limit));
6299
+ }
6300
+ if (options.cursor) {
6301
+ q.set("cursor", options.cursor);
6302
+ }
5698
6303
  const qs = q.toString() ? `?${q.toString()}` : "";
5699
6304
  return (await this.transport.request("GET", `/v1/repos${qs}`, void 0, call2)).body;
5700
6305
  }
@@ -5719,8 +6324,12 @@ var Publisher = class {
5719
6324
  }
5720
6325
  async resolveRepo(repoDir, repoId) {
5721
6326
  const a = await readAssociation(repoDir);
5722
- if (repoId) return { repoId, remote: a?.remote ?? "publisher" };
5723
- if (!a) throw new PublisherError("LOCAL_STATE", "this folder is not associated with a published repository; run init first");
6327
+ if (repoId) {
6328
+ return { repoId, remote: a?.remote ?? "publisher" };
6329
+ }
6330
+ if (!a) {
6331
+ throw new PublisherError("LOCAL_STATE", "this folder is not associated with a published repository; run init first");
6332
+ }
5724
6333
  if (a.endpoint !== this.endpoint) {
5725
6334
  throw new PublisherError(
5726
6335
  "LOCAL_STATE",
@@ -5772,20 +6381,27 @@ var Publisher = class {
5772
6381
  const dir = options.directory;
5773
6382
  await this.resolveRepo(dir);
5774
6383
  const branch = (await currentBranch(dir))?.replace(/^refs\/heads\//, "") ?? null;
5775
- if (!branch) throw new PublisherError("LOCAL_STATE", "HEAD is detached; check out the branch this folder publishes, then run sync again");
6384
+ if (!branch) {
6385
+ throw new PublisherError("LOCAL_STATE", "HEAD is detached; check out the branch this folder publishes, then run sync again");
6386
+ }
5776
6387
  const mapped = await getWorkspaceMapping(dir);
5777
- if (mapped && mapped.branch !== branch)
6388
+ if (mapped && mapped.branch !== branch) {
5778
6389
  throw new PublisherError("LOCAL_STATE", `branch ${branch} is checked out, but this folder publishes ${mapped.branch}; check it out, then run sync again`);
6390
+ }
5779
6391
  const recorded = await recordChanges({ dir, ...options.message ? { message: options.message } : {} });
5780
6392
  const reconciled = await syncWorkspace(this, { directory: dir, apply: true }, call2);
5781
6393
  const base = { recorded: { commit: recorded.commit, committed: recorded.committed, excluded: recorded.excluded }, reconciled };
5782
6394
  if (reconciled.after === "conflict") {
5783
6395
  const remote = reconciled.before.remote?.oid ?? null;
5784
- if (options.markConflicts && remote) await markConflicts(dir, remote);
6396
+ if (options.markConflicts && remote) {
6397
+ await markConflicts(dir, remote);
6398
+ }
5785
6399
  return { ...base, state: "conflict", published: null, marked: options.markConflicts === true && remote !== null };
5786
6400
  }
5787
6401
  const tip = await revParse(dir, `refs/heads/${branch}`);
5788
- if (tip === null || tip === (reconciled.before.remote?.oid ?? null)) return { ...base, state: "up_to_date", published: null, marked: false };
6402
+ if (tip === null || tip === (reconciled.before.remote?.oid ?? null)) {
6403
+ return { ...base, state: "up_to_date", published: null, marked: false };
6404
+ }
5789
6405
  const published = await this.publish({ repoDir: dir }, call2);
5790
6406
  return { ...base, state: published.state === "accepted" ? "published" : published.state === "rejected" ? "rejected" : "unknown", published, marked: false };
5791
6407
  }
@@ -5795,7 +6411,9 @@ var Publisher = class {
5795
6411
  const out = [];
5796
6412
  const store2 = await openPending(repoDir);
5797
6413
  for (const p of await store2.list()) {
5798
- if (p.endpoint !== this.endpoint) continue;
6414
+ if (p.endpoint !== this.endpoint) {
6415
+ continue;
6416
+ }
5799
6417
  if (!p.finalized) {
5800
6418
  out.push(await publish(this.publishContext(), p.repoId, remote, { repoDir, publicationId: p.publicationId }, call2).catch((e) => rethrowUnlessResolvable(e, p)));
5801
6419
  continue;
@@ -5808,7 +6426,9 @@ var Publisher = class {
5808
6426
  }
5809
6427
  out.push(toOutcome(s, true, p.refUpdates));
5810
6428
  }
5811
- for (const o of out) await noteAcceptedPublication(repoDir, o);
6429
+ for (const o of out) {
6430
+ await noteAcceptedPublication(repoDir, o);
6431
+ }
5812
6432
  return out;
5813
6433
  }
5814
6434
  async pendingPublications(repoDir) {
@@ -5834,8 +6454,9 @@ var Publisher = class {
5834
6454
  }
5835
6455
  };
5836
6456
  function rethrowUnlessResolvable(e, p) {
5837
- if (e instanceof PublisherError)
6457
+ if (e instanceof PublisherError) {
5838
6458
  throw new PublisherError(e.code, `publication ${p.publicationId}: ${e.message}`, { retryable: e.retryable, details: { ...e.details ?? {}, publicationId: p.publicationId } });
6459
+ }
5839
6460
  throw e;
5840
6461
  }
5841
6462
  function createPublisher(opts) {
@@ -5845,7 +6466,9 @@ function createPublisher(opts) {
5845
6466
  // ../client/src/migrate.ts
5846
6467
  async function fetchCapabilities(endpoint, fetchImpl = fetch, signal) {
5847
6468
  const res = await fetchImpl(`${normalize(endpoint)}/v1/capabilities`, { method: "GET", ...signal ? { signal } : {} });
5848
- if (!res.ok) throw new Error(`answered ${res.status}`);
6469
+ if (!res.ok) {
6470
+ throw new Error(`answered ${res.status}`);
6471
+ }
5849
6472
  return await res.json();
5850
6473
  }
5851
6474
  async function probeEndpoint(endpoint, opts = {}) {
@@ -5904,16 +6527,22 @@ async function startDeviceLogin(opts) {
5904
6527
  } catch (e) {
5905
6528
  throw new PublisherError("UNAVAILABLE", `could not reach ${control}: ${e instanceof Error ? e.message : String(e)}`, { retryable: true });
5906
6529
  }
5907
- if (typeof advertised !== "string" || advertised === "") throw new PublisherError("UNAVAILABLE", "this deployment does not offer device login; obtain a token another way");
6530
+ if (typeof advertised !== "string" || advertised === "") {
6531
+ throw new PublisherError("UNAVAILABLE", "this deployment does not offer device login; obtain a token another way");
6532
+ }
5908
6533
  const base = normalize(advertised);
5909
6534
  assertCredentialEndpoint(base);
5910
6535
  const started = await postForm(base, "/v1/auth/device", { client_id: opts.clientId ?? "gitpub-cli" }, doFetch);
5911
- if (started.status !== 200) throw new PublisherError("UNAVAILABLE", `starting the login failed (${started.status})`, { retryable: true });
6536
+ if (started.status !== 200) {
6537
+ throw new PublisherError("UNAVAILABLE", `starting the login failed (${started.status})`, { retryable: true });
6538
+ }
5912
6539
  const s = started.body;
5913
6540
  const deviceCode = str(s.device_code);
5914
6541
  const userCode = str(s.user_code);
5915
6542
  const uri = str(s.verification_uri_complete) ?? str(s.verification_uri);
5916
- if (!deviceCode || !userCode || !uri) throw new PublisherError("UNAVAILABLE", "the login response was incomplete");
6543
+ if (!deviceCode || !userCode || !uri) {
6544
+ throw new PublisherError("UNAVAILABLE", "the login response was incomplete");
6545
+ }
5917
6546
  const expiresInSeconds = num(s.expires_in, 600);
5918
6547
  return {
5919
6548
  deviceCode,
@@ -5933,25 +6562,41 @@ async function pollDeviceLogin(started, opts) {
5933
6562
  let last = opts.lastPolledAt;
5934
6563
  for (; ; ) {
5935
6564
  const at = Math.max(now(), last === null ? 0 : last + intervalMs);
5936
- if (opts.until !== void 0 && at > opts.until) return null;
5937
- if (at > now()) await sleep2(at - now());
5938
- if (now() >= started.expiresAt) throw new PublisherError("EXPIRED", "the login expired before it was approved");
6565
+ if (opts.until !== void 0 && at > opts.until) {
6566
+ return null;
6567
+ }
6568
+ if (at > now()) {
6569
+ await sleep2(at - now());
6570
+ }
6571
+ if (now() >= started.expiresAt) {
6572
+ throw new PublisherError("EXPIRED", "the login expired before it was approved");
6573
+ }
5939
6574
  const polled = await postForm(started.authEndpoint, "/v1/auth/token", { grant_type: DEVICE_CODE_GRANT, device_code: started.deviceCode }, doFetch);
5940
6575
  last = now();
5941
6576
  if (polled.status === 200) {
5942
6577
  const token = str(polled.body["access_token"]);
5943
- if (!token) throw new PublisherError("UNAVAILABLE", "the login returned no credential");
6578
+ if (!token) {
6579
+ throw new PublisherError("UNAVAILABLE", "the login returned no credential");
6580
+ }
5944
6581
  return { token, refreshToken: str(polled.body["refresh_token"]), expiresInSeconds: num(polled.body["expires_in"], 900), authEndpoint: started.authEndpoint };
5945
6582
  }
5946
6583
  const error2 = str(polled.body["error"]);
5947
- if (error2 === "authorization_pending") continue;
6584
+ if (error2 === "authorization_pending") {
6585
+ continue;
6586
+ }
5948
6587
  if (error2 === "slow_down") {
5949
6588
  intervalMs += 5e3;
5950
6589
  continue;
5951
6590
  }
5952
- if (error2 === "access_denied") throw new PublisherError("FORBIDDEN", "the login was refused");
5953
- if (error2 === "expired_token") throw new PublisherError("EXPIRED", "the login expired before it was approved");
5954
- if (polled.status >= 500) continue;
6591
+ if (error2 === "access_denied") {
6592
+ throw new PublisherError("FORBIDDEN", "the login was refused");
6593
+ }
6594
+ if (error2 === "expired_token") {
6595
+ throw new PublisherError("EXPIRED", "the login expired before it was approved");
6596
+ }
6597
+ if (polled.status >= 500) {
6598
+ continue;
6599
+ }
5955
6600
  throw new PublisherError("UNAVAILABLE", `the login failed (${polled.status}${error2 ? `: ${error2}` : ""})`);
5956
6601
  }
5957
6602
  }
@@ -5979,11 +6624,17 @@ async function readPendingLogin() {
5979
6624
  } catch {
5980
6625
  return null;
5981
6626
  }
5982
- if (typeof raw !== "object" || raw === null) return null;
6627
+ if (typeof raw !== "object" || raw === null) {
6628
+ return null;
6629
+ }
5983
6630
  const r = raw;
5984
6631
  const s = r.started;
5985
- if (r.version !== 1 || typeof r.endpoint !== "string" || !s) return null;
5986
- if (typeof s.deviceCode !== "string" || typeof s.authEndpoint !== "string" || typeof s.expiresAt !== "number" || typeof s.intervalSeconds !== "number") return null;
6632
+ if (r.version !== 1 || typeof r.endpoint !== "string" || !s) {
6633
+ return null;
6634
+ }
6635
+ if (typeof s.deviceCode !== "string" || typeof s.authEndpoint !== "string" || typeof s.expiresAt !== "number" || typeof s.intervalSeconds !== "number") {
6636
+ return null;
6637
+ }
5987
6638
  return {
5988
6639
  endpoint: r.endpoint,
5989
6640
  started: s,
@@ -6012,7 +6663,9 @@ var HEARTBEAT_MS = 3e4;
6012
6663
  var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6013
6664
  function took(ms) {
6014
6665
  const seconds = Math.max(0, Math.floor(ms / 1e3));
6015
- if (seconds < 60) return `${seconds} s`;
6666
+ if (seconds < 60) {
6667
+ return `${seconds} s`;
6668
+ }
6016
6669
  const minutes = Math.floor(seconds / 60);
6017
6670
  return minutes >= 10 ? `${minutes} min` : `${minutes} min ${String(seconds % 60).padStart(2, "0")} s`;
6018
6671
  }
@@ -6044,7 +6697,9 @@ function stageReporter(io) {
6044
6697
  let drawn = false;
6045
6698
  let receivedAt = null;
6046
6699
  const clear = () => {
6047
- if (drawn) io.write("\r\x1B[2K");
6700
+ if (drawn) {
6701
+ io.write("\r\x1B[2K");
6702
+ }
6048
6703
  drawn = false;
6049
6704
  };
6050
6705
  const stopTicking = () => {
@@ -6058,14 +6713,21 @@ function stageReporter(io) {
6058
6713
  };
6059
6714
  return {
6060
6715
  onStage(e) {
6061
- if (e.state === "in-progress" || ticking?.stage === e.stage) stopTicking();
6062
- else clear();
6716
+ if (e.state === "in-progress" || ticking?.stage === e.stage) {
6717
+ stopTicking();
6718
+ } else {
6719
+ clear();
6720
+ }
6063
6721
  const says = SAYS[e.stage];
6064
- if (e.stage === "received" && e.at !== null) receivedAt = since(e);
6722
+ if (e.stage === "received" && e.at !== null) {
6723
+ receivedAt = since(e);
6724
+ }
6065
6725
  if (e.state !== "in-progress") {
6066
6726
  const total = e.stage === "live" && e.state === "done" && receivedAt !== null ? ` (${took(since(e) - receivedAt)} after Shadow received it)` : "";
6067
6727
  const line = settledLine(e, total);
6068
- if (line !== null) io.write(line);
6728
+ if (line !== null) {
6729
+ io.write(line);
6730
+ }
6069
6731
  return;
6070
6732
  }
6071
6733
  io.write(` \u2026 ${e.word.padEnd(10)} ${says.doing}
@@ -6094,13 +6756,17 @@ async function followPublication(p, endpoint, o, opts) {
6094
6756
  const confirmed = derived === null ? null : await confirmPortal(derived, endpoint, opts.fetch);
6095
6757
  const portal = confirmed === null ? null : derived;
6096
6758
  const elsewhere = (reason) => ({ kind: "unavailable", reason, portal, hint: inPortal(portal, "Published.", "Follow it") });
6097
- if (portal === null || confirmed === null) return elsewhere("no-portal");
6759
+ if (portal === null || confirmed === null) {
6760
+ return elsewhere("no-portal");
6761
+ }
6098
6762
  if (!confirmed.terminal.includes(RUN_PROGRESS)) {
6099
6763
  const noRoute = { kind: "unavailable", reason: "no-route" };
6100
6764
  return { ...noRoute, portal, hint: progressHint(noRoute, portal) };
6101
6765
  }
6102
6766
  const refs = Object.entries(o.refs ?? {});
6103
- if (refs.length !== 1) return elsewhere("several-refs");
6767
+ if (refs.length !== 1) {
6768
+ return elsewhere("several-refs");
6769
+ }
6104
6770
  const [ref, commit] = refs[0];
6105
6771
  opts.log("Following it to live: received -> checked -> going live -> live. Ctrl-C stops watching; the publication is saved and carries on without you.");
6106
6772
  const outcome = await p.followRun(
@@ -6123,19 +6789,29 @@ async function followPublication(p, endpoint, o, opts) {
6123
6789
  return { ...outcome, portal, hint: progressHint(outcome, portal, answerable), ...next === void 0 ? {} : { next } };
6124
6790
  }
6125
6791
  async function failedChecks(p, portal, repoId, outcome, served) {
6126
- if (!served || outcome.kind !== "settled" || outcome.ending !== "failed" || outcome.runId === null) return null;
6127
- if (outcome.stages.find((s) => s.state === "failed")?.stage !== "running") return null;
6792
+ if (!served || outcome.kind !== "settled" || outcome.ending !== "failed" || outcome.runId === null) {
6793
+ return null;
6794
+ }
6795
+ if (outcome.stages.find((s) => s.state === "failed")?.stage !== "running") {
6796
+ return null;
6797
+ }
6128
6798
  try {
6129
6799
  const answer = await p.readPreparation({ portal, repoId });
6130
- if (answer.kind !== "view" || answer.view.id !== outcome.runId || answer.view.status !== "blocked") return null;
6800
+ if (answer.kind !== "view" || answer.view.id !== outcome.runId || answer.view.status !== "blocked") {
6801
+ return null;
6802
+ }
6131
6803
  return answer.view.findings.length === 0 ? null : answer.view.findings;
6132
6804
  } catch {
6133
6805
  return null;
6134
6806
  }
6135
6807
  }
6136
6808
  function followTimeoutMs(flag) {
6137
- if (flag === void 0) return FOLLOW_TIMEOUT_MS;
6138
- if (!/^[1-9][0-9]*$/.test(flag)) throw new PublisherError("INVALID_REQUEST", `--timeout takes a whole number of seconds, not ${JSON.stringify(flag)}`);
6809
+ if (flag === void 0) {
6810
+ return FOLLOW_TIMEOUT_MS;
6811
+ }
6812
+ if (!/^[1-9][0-9]*$/.test(flag)) {
6813
+ throw new PublisherError("INVALID_REQUEST", `--timeout takes a whole number of seconds, not ${JSON.stringify(flag)}`);
6814
+ }
6139
6815
  return Math.min(Number(flag) * 1e3, FOLLOW_TIMEOUT_MS);
6140
6816
  }
6141
6817
  function shellWord(path) {
@@ -6144,8 +6820,12 @@ function shellWord(path) {
6144
6820
  function stageEmitter(json, quiet) {
6145
6821
  const nothing = () => {
6146
6822
  };
6147
- if (json) return { onStage: (e) => process.stdout.write(stageLine(e) + "\n"), stopStages: nothing };
6148
- if (quiet) return { onStage: nothing, stopStages: nothing };
6823
+ if (json) {
6824
+ return { onStage: (e) => process.stdout.write(stageLine(e) + "\n"), stopStages: nothing };
6825
+ }
6826
+ if (quiet) {
6827
+ return { onStage: nothing, stopStages: nothing };
6828
+ }
6149
6829
  const { onStage, stop } = stageReporter({ write: (s) => process.stderr.write(s), isTTY: process.stderr.isTTY === true });
6150
6830
  return { onStage, stopStages: stop };
6151
6831
  }
@@ -6210,7 +6890,9 @@ function folderFor(name) {
6210
6890
  // src/init.ts
6211
6891
  async function repositoryForInit(p, endpoint, name, opts = {}) {
6212
6892
  const portal = portalForEndpoint(endpoint);
6213
- if (portal === null) return { repoId: (await p.createRepository({ name, grants: [] })).repoId, appId: null };
6893
+ if (portal === null) {
6894
+ return { repoId: (await p.createRepository({ name, grants: [] })).repoId, appId: null };
6895
+ }
6214
6896
  const confirmed = await confirmPortal(portal, endpoint, opts.fetch);
6215
6897
  if (confirmed === null) {
6216
6898
  throw new PublisherError("UNAVAILABLE", `could not confirm that ${portal} publishes to ${endpoint}; run init again`, { retryable: true });
@@ -6282,7 +6964,9 @@ async function discoverEndpoint(portal, fetchImpl = fetch) {
6282
6964
  }
6283
6965
  body = await response.json();
6284
6966
  } catch (e) {
6285
- if (PublisherError.isPublisherError(e)) throw e;
6967
+ if (PublisherError.isPublisherError(e)) {
6968
+ throw e;
6969
+ }
6286
6970
  throw new PublisherError("NETWORK", `could not reach ${portal}: ${e instanceof Error ? e.message : String(e)}`, { retryable: true });
6287
6971
  }
6288
6972
  const endpoint = body?.publishingEndpoint;
@@ -6305,7 +6989,9 @@ function suggestProfileName(endpoint, taken) {
6305
6989
  }
6306
6990
  function resolveChoice(answer, names) {
6307
6991
  const a = answer.trim();
6308
- if (!a) return null;
6992
+ if (!a) {
6993
+ return null;
6994
+ }
6309
6995
  if (/^\d+$/.test(a)) {
6310
6996
  const i = Number(a);
6311
6997
  return i >= 1 && i <= names.length ? names[i - 1] : null;
@@ -6332,9 +7018,13 @@ ${purpose}
6332
7018
  for (let attempt = 0; attempt < 3; attempt++) {
6333
7019
  const answer = await ask3(`
6334
7020
  Which one? [1-${names.length}, or a name] `);
6335
- if (answer === null) return null;
7021
+ if (answer === null) {
7022
+ return null;
7023
+ }
6336
7024
  const chosen = resolveChoice(answer, names);
6337
- if (chosen) return chosen;
7025
+ if (chosen) {
7026
+ return chosen;
7027
+ }
6338
7028
  process.stderr.write(`Not one of those.
6339
7029
  `);
6340
7030
  }
@@ -6349,9 +7039,13 @@ Name this connection, so you never have to type ${endpoint} again.
6349
7039
  const answer = await ask3(suggested ? `
6350
7040
  Profile name [${suggested}]: ` : `
6351
7041
  Profile name: `);
6352
- if (answer === null) return null;
7042
+ if (answer === null) {
7043
+ return null;
7044
+ }
6353
7045
  const name = answer.trim() || suggested;
6354
- if (name && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) return name;
7046
+ if (name && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) {
7047
+ return name;
7048
+ }
6355
7049
  process.stderr.write(`Use letters, digits, dot, dash or underscore.
6356
7050
  `);
6357
7051
  }
@@ -6439,16 +7133,22 @@ Waiting (it expires in ${Math.round(expiresInSeconds / 60)} minutes)...
6439
7133
  );
6440
7134
  }
6441
7135
  async function login(ctx) {
6442
- if (ctx.flags["continue"] === true) return continueLogin(ctx);
7136
+ if (ctx.flags["continue"] === true) {
7137
+ return continueLogin(ctx);
7138
+ }
6443
7139
  const clock = stopwatch();
6444
7140
  const target = resolveLoginEndpoint(ctx.input);
6445
7141
  const endpoint = "endpoint" in target ? target.endpoint : await discoverEndpoint(portalBase(process.env, str2(ctx.flags["portal"])));
6446
- if (!endpoint) throw new PublisherError("INVALID_REQUEST", "login requires --endpoint (or --profile naming a stored one)");
7142
+ if (!endpoint) {
7143
+ throw new PublisherError("INVALID_REQUEST", "login requires --endpoint (or --profile naming a stored one)");
7144
+ }
6447
7145
  clock.lap("discovery");
6448
7146
  const profile = str2(ctx.flags["profile"]);
6449
7147
  const setDefault = ctx.flags["set-default"] === true;
6450
7148
  const given = str2(ctx.flags["token"]) ?? process.env["GIT_PUBLISHER_TOKEN"];
6451
- if (given) return finish(ctx, { endpoint, token: given, signIn: null, profile, setDefault }, clock);
7149
+ if (given) {
7150
+ return finish(ctx, { endpoint, token: given, signIn: null, profile, setDefault }, clock);
7151
+ }
6452
7152
  if (ctx.flags["no-wait"] === true) {
6453
7153
  const started = await startDeviceLogin({ endpoint });
6454
7154
  clock.lap("start");
@@ -6481,7 +7181,9 @@ async function continueLogin(ctx) {
6481
7181
  try {
6482
7182
  signIn = await pollDeviceLogin(pending.started, { lastPolledAt: null, ...timeout === void 0 ? {} : { until: Date.now() + followTimeoutMs(timeout) } });
6483
7183
  } catch (e) {
6484
- if (e instanceof PublisherError && (e.code === "EXPIRED" || e.code === "FORBIDDEN")) await removePendingLogin();
7184
+ if (e instanceof PublisherError && (e.code === "EXPIRED" || e.code === "FORBIDDEN")) {
7185
+ await removePendingLogin();
7186
+ }
6485
7187
  throw e;
6486
7188
  }
6487
7189
  clock.lap("approval");
@@ -6586,7 +7288,9 @@ async function installSkills({ log }) {
6586
7288
  'Claude Code is not installed, or "claude" is not on PATH. Install it from https://claude.com/claude-code, then run: publisher skills install'
6587
7289
  );
6588
7290
  }
6589
- if (r.code !== 0) throw new PublisherError("LOCAL_STATE", `"claude ${args.slice(0, 3).join(" ")}" failed: ${(r.stderr || r.stdout).trim()}`);
7291
+ if (r.code !== 0) {
7292
+ throw new PublisherError("LOCAL_STATE", `"claude ${args.slice(0, 3).join(" ")}" failed: ${(r.stderr || r.stdout).trim()}`);
7293
+ }
6590
7294
  };
6591
7295
  await step("Adding the publisher to Claude Code\u2026", ["plugin", "marketplace", "add", source, "--scope", "user"]);
6592
7296
  await step("Installing its skills\u2026", ["plugin", "install", `${PLUGIN}@${MARKETPLACE}`, "--scope", "user"]);
@@ -6603,16 +7307,24 @@ async function installSkills({ log }) {
6603
7307
  // src/question.ts
6604
7308
  async function questionAt(p, endpoint, repoId, opts = {}) {
6605
7309
  const at = await portalAt(endpoint, opts);
6606
- if ("reason" in at) return at;
7310
+ if ("reason" in at) {
7311
+ return at;
7312
+ }
6607
7313
  return shown(at.portal, await p.readPreparation({ portal: at.portal, repoId }));
6608
7314
  }
6609
7315
  async function answerAt(p, endpoint, repoId, specs, opts = {}) {
6610
7316
  const answers = parseSpecs(specs);
6611
7317
  const at = await portalAt(endpoint, opts);
6612
- if ("reason" in at) return at;
7318
+ if ("reason" in at) {
7319
+ return at;
7320
+ }
6613
7321
  const read2 = shown(at.portal, await p.readPreparation({ portal: at.portal, repoId }));
6614
- if (read2.kind !== "view") return read2;
6615
- if (read2.questions.length === 0) throw new PublisherError("LOCAL_STATE", `nothing is waiting for an answer (the preparation is ${read2.preparation.status})`);
7322
+ if (read2.kind !== "view") {
7323
+ return read2;
7324
+ }
7325
+ if (read2.questions.length === 0) {
7326
+ throw new PublisherError("LOCAL_STATE", `nothing is waiting for an answer (the preparation is ${read2.preparation.status})`);
7327
+ }
6616
7328
  for (const [id, value] of Object.entries(answers)) {
6617
7329
  const question = read2.questions.find((q) => q.id === id);
6618
7330
  if (question === void 0) {
@@ -6628,11 +7340,15 @@ async function answerAt(p, endpoint, repoId, specs, opts = {}) {
6628
7340
  return shown(at.portal, await p.answerPreparation({ portal: at.portal, repoId, id: read2.preparation.id, revision: read2.preparation.revision, answers }));
6629
7341
  }
6630
7342
  function parseSpecs(specs) {
6631
- if (specs.length === 0) throw new PublisherError("INVALID_REQUEST", "answer takes one or more question=value");
7343
+ if (specs.length === 0) {
7344
+ throw new PublisherError("INVALID_REQUEST", "answer takes one or more question=value");
7345
+ }
6632
7346
  const answers = {};
6633
7347
  for (const spec of specs) {
6634
7348
  const at = spec.indexOf("=");
6635
- if (at <= 0 || at === spec.length - 1) throw new PublisherError("INVALID_REQUEST", `"${spec}" is not question=value`);
7349
+ if (at <= 0 || at === spec.length - 1) {
7350
+ throw new PublisherError("INVALID_REQUEST", `"${spec}" is not question=value`);
7351
+ }
6636
7352
  answers[spec.slice(0, at)] = spec.slice(at + 1);
6637
7353
  }
6638
7354
  return answers;
@@ -6640,7 +7356,9 @@ function parseSpecs(specs) {
6640
7356
  async function portalAt(endpoint, opts) {
6641
7357
  const derived = portalForEndpoint(endpoint);
6642
7358
  const confirmed = derived === null ? null : await confirmPortal(derived, endpoint, opts.fetch);
6643
- if (derived === null || confirmed === null) return { kind: "unavailable", reason: "no-portal", portal: null, hint: "Answer it in the portal." };
7359
+ if (derived === null || confirmed === null) {
7360
+ return { kind: "unavailable", reason: "no-portal", portal: null, hint: "Answer it in the portal." };
7361
+ }
6644
7362
  if (!confirmed.terminal.includes(PREPARATION)) {
6645
7363
  return { kind: "unavailable", reason: "no-route", portal: derived, hint: `This portal cannot show the question in the terminal yet. Answer it in the portal: ${derived}.` };
6646
7364
  }
@@ -6667,7 +7385,9 @@ function shown(portal, r) {
6667
7385
  }
6668
7386
  }
6669
7387
  function hintFor(view) {
6670
- if (view.questions.length === 0) return "Nothing is waiting for an answer.";
7388
+ if (view.questions.length === 0) {
7389
+ return "Nothing is waiting for an answer.";
7390
+ }
6671
7391
  const how = view.questions.map((q) => `${q.id}=<${q.options.map((o) => o.value).join("|")}>`).join(" ");
6672
7392
  return `It is waiting for your answer. Run: publisher answer ${how}`;
6673
7393
  }
@@ -6679,7 +7399,9 @@ var import_node_os4 = require("node:os");
6679
7399
  var FALLBACK_TEMP_DIRS = ["/tmp", "/var/tmp"];
6680
7400
  async function unusable(path) {
6681
7401
  try {
6682
- if (!(await (0, import_promises12.stat)(path)).isDirectory()) return "is not a directory";
7402
+ if (!(await (0, import_promises12.stat)(path)).isDirectory()) {
7403
+ return "is not a directory";
7404
+ }
6683
7405
  } catch {
6684
7406
  return "does not exist";
6685
7407
  }
@@ -6693,7 +7415,9 @@ async function unusable(path) {
6693
7415
  async function ensureTempDir(env = process.env, fallbacks = FALLBACK_TEMP_DIRS) {
6694
7416
  const named = (0, import_node_os4.tmpdir)();
6695
7417
  const reason = await unusable(named);
6696
- if (reason === null) return { path: named, replaced: null };
7418
+ if (reason === null) {
7419
+ return { path: named, replaced: null };
7420
+ }
6697
7421
  for (const candidate of fallbacks) {
6698
7422
  if (candidate !== named && await unusable(candidate) === null) {
6699
7423
  env["TMPDIR"] = candidate;
@@ -6713,10 +7437,47 @@ function replacedLine(t) {
6713
7437
  }
6714
7438
 
6715
7439
  // src/exit-code.ts
7440
+ var EXIT_CODE = {
7441
+ UNAUTHORIZED: 4,
7442
+ FORBIDDEN: 4,
7443
+ ADMIN_REQUIRED: 4,
7444
+ OUTCOME_UNKNOWN: 3,
7445
+ NETWORK: 3,
7446
+ UNAVAILABLE: 3,
7447
+ INVALID_REQUEST: 1,
7448
+ UNSUPPORTED_PROTOCOL_VERSION: 1,
7449
+ UNSUPPORTED_SCHEMA_VERSION: 1,
7450
+ NOT_FOUND: 1,
7451
+ METHOD_NOT_ALLOWED: 1,
7452
+ REF_FORBIDDEN: 1,
7453
+ ORGANISATION_REQUIRED: 1,
7454
+ APPLICATION_REQUIRED: 1,
7455
+ REPOSITORY_NOT_FOUND: 1,
7456
+ REPOSITORY_CONFLICT: 1,
7457
+ REPOSITORY_ARCHIVED: 1,
7458
+ ACCESS_CONFLICT: 1,
7459
+ PUBLICATION_NOT_FOUND: 1,
7460
+ PUBLICATION_CONFLICT: 1,
7461
+ PUBLICATION_EXPIRED: 1,
7462
+ UPLOAD_MISSING: 1,
7463
+ LIMIT_EXCEEDED: 1,
7464
+ STALE_GENERATION: 1,
7465
+ NON_FAST_FORWARD: 1,
7466
+ EXPECTED_OLD_MISMATCH: 1,
7467
+ INVALID_REF_NAME: 1,
7468
+ REF_CONFLICT: 1,
7469
+ PACK_INVALID: 1,
7470
+ MISSING_OBJECTS: 1,
7471
+ UPLOAD_MISMATCH: 1,
7472
+ INVALID_TARGET: 1,
7473
+ EXPIRED: 1,
7474
+ INTERNAL: 1,
7475
+ CANCELLED: 1,
7476
+ LOCAL_STATE: 1,
7477
+ GIT: 1
7478
+ };
6716
7479
  function exitCodeFor(code) {
6717
- if (code === "UNAUTHORIZED" || code === "FORBIDDEN" || code === "ADMIN_REQUIRED") return 4;
6718
- if (code === "OUTCOME_UNKNOWN" || code === "NETWORK" || code === "UNAVAILABLE") return 3;
6719
- return 1;
7480
+ return EXIT_CODE[code];
6720
7481
  }
6721
7482
 
6722
7483
  // src/main.ts
@@ -6796,19 +7557,27 @@ async function main(argv) {
6796
7557
  const quiet = flags["quiet"] === true || json;
6797
7558
  const out = (v) => process.stdout.write((json ? JSON.stringify(v) : formatHuman(v)) + "\n");
6798
7559
  const log = (s) => {
6799
- if (!quiet) process.stderr.write(s + "\n");
7560
+ if (!quiet) {
7561
+ process.stderr.write(s + "\n");
7562
+ }
6800
7563
  };
6801
7564
  const progress = (e) => {
6802
- if (quiet) return;
7565
+ if (quiet) {
7566
+ return;
7567
+ }
6803
7568
  const pct = e.total ? ` ${Math.round((e.bytes ?? 0) / e.total * 100)}%` : "";
6804
7569
  process.stderr.write(`\r[${e.phase}] ${e.message}${pct} `);
6805
- if (e.phase === "done") process.stderr.write("\n");
7570
+ if (e.phase === "done") {
7571
+ process.stderr.write("\n");
7572
+ }
6806
7573
  };
6807
7574
  const dirArg = (i) => (0, import_node_path9.resolve)(cmd[i] ?? ".");
6808
7575
  const following = { ...stageEmitter(json, quiet), log, untilChange: flags["until-change"] === true };
6809
7576
  const resolutionInput = async (dir) => {
6810
7577
  let association;
6811
- if (dir && await isGitRepo(dir)) association = (await readAssociation(dir))?.endpoint;
7578
+ if (dir && await isGitRepo(dir)) {
7579
+ association = (await readAssociation(dir))?.endpoint;
7580
+ }
6812
7581
  return {
6813
7582
  ...optStr(flags, "endpoint"),
6814
7583
  ...optStr(flags, "profile"),
@@ -6870,7 +7639,9 @@ async function main(argv) {
6870
7639
  }
6871
7640
  if (flags["help"] !== true && GIT_COMMANDS.has(cmd[0] ?? "")) {
6872
7641
  const line = replacedLine(await ensureTempDir());
6873
- if (line !== null) process.stderr.write(line + "\n");
7642
+ if (line !== null) {
7643
+ process.stderr.write(line + "\n");
7644
+ }
6874
7645
  }
6875
7646
  switch (flags["help"] === true ? "help" : cmd[0]) {
6876
7647
  case void 0:
@@ -6925,7 +7696,9 @@ async function main(argv) {
6925
7696
  case "logout": {
6926
7697
  const profile = str2(flags["profile"]);
6927
7698
  const endpoint = str2(flags["endpoint"]) ?? process.env["GIT_PUBLISHER_ENDPOINT"];
6928
- if (!profile && !endpoint) throw new PublisherError("INVALID_REQUEST", "logout requires --endpoint or --profile");
7699
+ if (!profile && !endpoint) {
7700
+ throw new PublisherError("INVALID_REQUEST", "logout requires --endpoint or --profile");
7701
+ }
6929
7702
  const { revoked } = profile ? await removeProfile(profile, { revoke: true }) : await removeCredential(endpoint, { revoke: true });
6930
7703
  out({ ok: true, ...profile ? { profile } : { endpoint }, revoked });
6931
7704
  return 0;
@@ -6943,14 +7716,18 @@ async function main(argv) {
6943
7716
  return 0;
6944
7717
  case "use": {
6945
7718
  const name = cmd[2];
6946
- if (!name) throw new PublisherError("INVALID_REQUEST", "profile use requires a name");
7719
+ if (!name) {
7720
+ throw new PublisherError("INVALID_REQUEST", "profile use requires a name");
7721
+ }
6947
7722
  await setDefaultProfile(name);
6948
7723
  out({ ok: true, defaultProfile: name, endpoint: file.profiles[name].endpoint });
6949
7724
  return 0;
6950
7725
  }
6951
7726
  case "remove": {
6952
7727
  const name = cmd[2];
6953
- if (!name) throw new PublisherError("INVALID_REQUEST", "profile remove requires a name");
7728
+ if (!name) {
7729
+ throw new PublisherError("INVALID_REQUEST", "profile remove requires a name");
7730
+ }
6954
7731
  await removeProfile(name);
6955
7732
  out({ ok: true, removed: name });
6956
7733
  return 0;
@@ -6989,7 +7766,9 @@ async function main(argv) {
6989
7766
  const updates = refs.length ? refs.map((r) => ({ ref: r.startsWith("refs/") ? r : `refs/heads/${r}`, force })) : void 0;
6990
7767
  if (!updates && force) {
6991
7768
  const b = await currentBranch(dir);
6992
- if (!b) throw new PublisherError("LOCAL_STATE", "detached HEAD");
7769
+ if (!b) {
7770
+ throw new PublisherError("LOCAL_STATE", "detached HEAD");
7771
+ }
6993
7772
  return finishPublish2(await p.publish({ repoDir: dir, updates: [{ ref: b, force: true }], wait: flags["no-wait"] !== true }, { onProgress: progress }));
6994
7773
  }
6995
7774
  return finishPublish2(await p.publish({ repoDir: dir, ...updates ? { updates } : {}, wait: flags["no-wait"] !== true }, { onProgress: progress }));
@@ -7001,7 +7780,9 @@ async function main(argv) {
7001
7780
  if (pubId) {
7002
7781
  const a = await readAssociation(dir);
7003
7782
  const repoId = str2(flags["repo"]) ?? a?.repoId;
7004
- if (!repoId) throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7783
+ if (!repoId) {
7784
+ throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7785
+ }
7005
7786
  const s = await p.getPublicationStatus(repoId, pubId);
7006
7787
  out(s);
7007
7788
  return s.state === "accepted" ? 0 : s.state === "rejected" ? 2 : 3;
@@ -7037,7 +7818,9 @@ async function main(argv) {
7037
7818
  case "checkout": {
7038
7819
  const dir = dirArg(1);
7039
7820
  const repoId = str2(flags["repo"]);
7040
- if (!repoId) throw new PublisherError("INVALID_REQUEST", "checkout requires --repo <id>");
7821
+ if (!repoId) {
7822
+ throw new PublisherError("INVALID_REQUEST", "checkout requires --repo <id>");
7823
+ }
7041
7824
  const { p } = await client();
7042
7825
  const branch = str2(flags["branch"]);
7043
7826
  const m = await p.checkout({ directory: dir, repoId, ...branch ? { branch } : {} }, { onProgress: progress });
@@ -7103,11 +7886,15 @@ async function main(argv) {
7103
7886
  case "follow": {
7104
7887
  const dir = dirArg(1);
7105
7888
  const publicationId = str2(flags["publication"]);
7106
- if (!publicationId) throw new PublisherError("INVALID_REQUEST", "follow requires --publication <id>");
7889
+ if (!publicationId) {
7890
+ throw new PublisherError("INVALID_REQUEST", "follow requires --publication <id>");
7891
+ }
7107
7892
  const timeoutMs = followTimeoutMs(str2(flags["timeout"]));
7108
7893
  const { p, endpoint } = await client(dir);
7109
7894
  const repoId = str2(flags["repo"]) ?? (await readAssociation(dir))?.repoId;
7110
- if (!repoId) throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7895
+ if (!repoId) {
7896
+ throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7897
+ }
7111
7898
  const publication = await p.getPublicationStatus(repoId, publicationId);
7112
7899
  if (publication.state !== "accepted") {
7113
7900
  throw new PublisherError("LOCAL_STATE", `publication ${publicationId} is ${publication.state}, not accepted; run publisher status`);
@@ -7127,7 +7914,9 @@ async function main(argv) {
7127
7914
  const dir = dirArg(1);
7128
7915
  const { p, endpoint } = await client(dir);
7129
7916
  const repoId = str2(flags["repo"]) ?? (await readAssociation(dir))?.repoId;
7130
- if (!repoId) throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7917
+ if (!repoId) {
7918
+ throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7919
+ }
7131
7920
  out({ repoId, ...await questionAt(p, endpoint, repoId) });
7132
7921
  return 0;
7133
7922
  }
@@ -7136,12 +7925,16 @@ async function main(argv) {
7136
7925
  const dir = (0, import_node_path9.resolve)(".");
7137
7926
  const { p, endpoint } = await client(dir);
7138
7927
  const repoId = str2(flags["repo"]) ?? (await readAssociation(dir))?.repoId;
7139
- if (!repoId) throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7928
+ if (!repoId) {
7929
+ throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7930
+ }
7140
7931
  out({ repoId, ...await answerAt(p, endpoint, repoId, cmd.slice(1)) });
7141
7932
  return 0;
7142
7933
  }
7143
7934
  case "skills": {
7144
- if (cmd[1] !== "install") throw new PublisherError("INVALID_REQUEST", `unknown skills command: ${cmd[1] ?? "(none)"}; expected install`);
7935
+ if (cmd[1] !== "install") {
7936
+ throw new PublisherError("INVALID_REQUEST", `unknown skills command: ${cmd[1] ?? "(none)"}; expected install`);
7937
+ }
7145
7938
  const r = await installSkills({ log });
7146
7939
  out(r);
7147
7940
  return 0;
@@ -7150,7 +7943,9 @@ async function main(argv) {
7150
7943
  const dir = dirArg(1);
7151
7944
  const ours = str2(flags["ours"]);
7152
7945
  const theirs = str2(flags["theirs"]);
7153
- if (!ours || !theirs) throw new PublisherError("INVALID_REQUEST", "merge-check requires --ours and --theirs");
7946
+ if (!ours || !theirs) {
7947
+ throw new PublisherError("INVALID_REQUEST", "merge-check requires --ours and --theirs");
7948
+ }
7154
7949
  const r = await mergeRemote({
7155
7950
  repoDir: dir,
7156
7951
  ours: ours.startsWith("refs/") ? ours : `refs/heads/${ours}`,
@@ -7166,7 +7961,9 @@ async function main(argv) {
7166
7961
  const { p } = await client(dir);
7167
7962
  const a = await readAssociation(dir);
7168
7963
  const repoId = str2(flags["repo"]) ?? a?.repoId;
7169
- if (!repoId) throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7964
+ if (!repoId) {
7965
+ throw new PublisherError("LOCAL_STATE", "no repository association; pass --repo");
7966
+ }
7170
7967
  out(await p.getRepository(repoId));
7171
7968
  return 0;
7172
7969
  }
@@ -7178,7 +7975,9 @@ ${USAGE}`);
7178
7975
  }
7179
7976
  var GIT_COMMANDS = /* @__PURE__ */ new Set(["init", "publish", "status", "fetch", "checkout", "workspace-status", "sync", "merge-check"]);
7180
7977
  async function demand(r, input) {
7181
- if (r.kind === "resolved") return r;
7978
+ if (r.kind === "resolved") {
7979
+ return r;
7980
+ }
7182
7981
  const next = nextStep(credentialStatus(input));
7183
7982
  const details = { profiles: r.kind === "none" ? [] : r.profiles, next };
7184
7983
  const run = next.command === null ? "" : ` Run: ${next.command}`;