@sberpay-cli/cli-diagnostic 0.4.0-dev.4 → 0.4.0-dev.7

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.
@@ -7375,7 +7375,7 @@ import { fileURLToPath } from "node:url";
7375
7375
  var NPM_PACKAGE = true ? "@sberpay-cli/cli-diagnostic" : "@sberpay-cli/cli";
7376
7376
  var kind = true ? "release" : "dev";
7377
7377
  var BUILD = {
7378
- sourceCommit: true ? "69476eab9e2bcd3f503aa72e038d52d8cafc2752" : "dev",
7378
+ sourceCommit: true ? "9a9b74aaa8ed8a80225fe2dd94e6205b2c99352e" : "dev",
7379
7379
  profile: true ? "diagnostic" : "standard",
7380
7380
  kind,
7381
7381
  // Бандл — dist/cli.mjs в корне пакета; этот файл под tsx — packages/cli/src/core/.
@@ -7383,9 +7383,13 @@ var BUILD = {
7383
7383
  };
7384
7384
  var REINSTALL_HINT = `\u041F\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 sberpay-cli: npm i -g ${NPM_PACKAGE}`;
7385
7385
 
7386
- // packages/cli/src/paymentMode/state.ts
7387
- import { lstatSync, readFileSync, openSync as openSync2, closeSync as closeSync2, fstatSync, constants } from "node:fs";
7388
- import { join } from "node:path";
7386
+ // packages/cli/src/core/privatePath.ts
7387
+ import { lstatSync } from "node:fs";
7388
+ import { open as open2 } from "node:fs/promises";
7389
+
7390
+ // packages/cli/src/core/windowsAcl.ts
7391
+ import { spawnSync } from "node:child_process";
7392
+ import { dirname, win32 } from "node:path";
7389
7393
 
7390
7394
  // node_modules/zod/v4/classic/external.js
7391
7395
  var external_exports = {};
@@ -27055,12 +27059,104 @@ function date4(params) {
27055
27059
  return _coercedDate(ZodDate, params);
27056
27060
  }
27057
27061
 
27062
+ // packages/cli/src/core/windowsAcl.ts
27063
+ var Sid = external_exports.string().regex(/^S-1-(?:\d+-)*\d+$/);
27064
+ var Inspection = external_exports.object({ owner: Sid, currentUser: Sid, reparse: external_exports.literal(false), rules: external_exports.array(external_exports.object({ sid: Sid, allow: external_exports.boolean(), rights: external_exports.number().int() })).min(1) });
27065
+ var WRITE_ACCESS = 852310 | 1342177280;
27066
+ function assertWindowsAcl(value, policy) {
27067
+ const parsed = Inspection.safeParse(value);
27068
+ if (!parsed.success) throw Error("WINDOWS_ACL_UNSAFE");
27069
+ const s = parsed.data, trusted = /* @__PURE__ */ new Set([s.currentUser, "S-1-5-18", "S-1-5-32-544"]);
27070
+ if (!trusted.has(s.owner) || s.rules.some((r) => r.allow && !trusted.has(r.sid) && (policy === "private" ? r.rights !== 0 : (r.rights & WRITE_ACCESS) !== 0))) throw Error("WINDOWS_ACL_UNSAFE");
27071
+ }
27072
+ var SCRIPT = String.raw`
27073
+ $ErrorActionPreference='Stop'
27074
+ [Console]::OutputEncoding=New-Object System.Text.UTF8Encoding($false)
27075
+ $p=[IO.Path]::GetFullPath($env:SBERPAY_ACL_PATH)
27076
+ $cursor=$p
27077
+ while($cursor){
27078
+ if(Test-Path -LiteralPath $cursor){
27079
+ $item=Get-Item -LiteralPath $cursor -Force
27080
+ if(($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0){throw 'REPARSE_POINT'}
27081
+ }
27082
+ $next=[IO.Path]::GetDirectoryName($cursor)
27083
+ if($next -eq $cursor){break};$cursor=$next
27084
+ }
27085
+ $sid=[Security.Principal.WindowsIdentity]::GetCurrent().User
27086
+ if($env:SBERPAY_ACL_ACTION -eq 'create' -and !(Test-Path -LiteralPath $p)){
27087
+ $acl=New-Object Security.AccessControl.DirectorySecurity
27088
+ $acl.SetOwner($sid);$acl.SetAccessRuleProtection($true,$false)
27089
+ foreach($id in @($sid.Value,'S-1-5-18','S-1-5-32-544')){
27090
+ $principal=New-Object Security.Principal.SecurityIdentifier($id)
27091
+ $rule=New-Object Security.AccessControl.FileSystemAccessRule($principal,'FullControl','ContainerInherit,ObjectInherit','None','Allow')
27092
+ $acl.AddAccessRule($rule)
27093
+ }
27094
+ [IO.Directory]::CreateDirectory($p,$acl)|Out-Null
27095
+ }
27096
+ $acl=Get-Acl -LiteralPath $p
27097
+ $rules=@($acl.GetAccessRules($true,$true,[Security.Principal.SecurityIdentifier])|ForEach-Object{
27098
+ @{sid=$_.IdentityReference.Value;allow=($_.AccessControlType -eq 'Allow');rights=[int]$_.FileSystemRights}
27099
+ })
27100
+ @{owner=$acl.GetOwner([Security.Principal.SecurityIdentifier]).Value;currentUser=$sid.Value;reparse=$false;rules=$rules}|ConvertTo-Json -Compress -Depth 5
27101
+ `;
27102
+ function windowsAclCommand(path2, action2, env = process.env) {
27103
+ const root = env.SystemRoot;
27104
+ if (!root || !win32.isAbsolute(root)) throw Error("WINDOWS_SYSTEM_ROOT_MISSING");
27105
+ return { file: win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe"), args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(SCRIPT, "utf16le").toString("base64")], env: { SystemRoot: root, SBERPAY_ACL_PATH: path2, SBERPAY_ACL_ACTION: action2 } };
27106
+ }
27107
+ function inspect(path2, policy, action2) {
27108
+ const c = windowsAclCommand(path2, action2);
27109
+ const r = spawnSync(c.file, c.args, { env: c.env, encoding: "utf8", windowsHide: true, timeout: 1e4, maxBuffer: 128 * 1024 });
27110
+ if (r.error || r.status !== 0) throw Error("WINDOWS_ACL_CHECK_FAILED");
27111
+ let value;
27112
+ try {
27113
+ value = JSON.parse(r.stdout.trim().replace(/^\uFEFF/, ""));
27114
+ } catch {
27115
+ throw Error("WINDOWS_ACL_CHECK_FAILED");
27116
+ }
27117
+ assertWindowsAcl(value, policy);
27118
+ }
27119
+ function assertWindowsPrivatePath(path2) {
27120
+ inspect(path2, "private", "inspect");
27121
+ }
27122
+ function ensureWindowsPrivateDirectory(path2) {
27123
+ inspect(path2, "private", "create");
27124
+ }
27125
+ function assertWindowsHelperPath(path2) {
27126
+ inspect(path2, "binary", "inspect");
27127
+ inspect(dirname(path2), "binary", "inspect");
27128
+ }
27129
+
27130
+ // packages/cli/src/core/privatePath.ts
27131
+ function assertPrivateFile(path2, info) {
27132
+ const named = lstatSync(path2);
27133
+ if (!info.isFile() || !named.isFile() || named.isSymbolicLink() || info.ino !== named.ino || info.dev !== named.dev) throw Error("UNSAFE_FILE");
27134
+ if (process.platform === "win32") assertWindowsPrivatePath(path2);
27135
+ else if (process.getuid && info.uid !== process.getuid() || info.mode & 63) throw Error("UNSAFE_FILE");
27136
+ }
27137
+ async function syncDirectory(path2) {
27138
+ if (process.platform === "win32") return;
27139
+ const f = await open2(path2, "r");
27140
+ try {
27141
+ await f.sync();
27142
+ } finally {
27143
+ await f.close();
27144
+ }
27145
+ }
27146
+
27147
+ // packages/cli/src/paymentMode/state.ts
27148
+ import { lstatSync as lstatSync2, readFileSync, openSync as openSync2, closeSync as closeSync2, fstatSync, constants } from "node:fs";
27149
+ import { join } from "node:path";
27150
+
27058
27151
  // packages/cli/src/core/atomicFile.ts
27059
- import { mkdirSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, rmSync } from "node:fs";
27060
- import { dirname } from "node:path";
27152
+ import { mkdirSync, existsSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, rmSync } from "node:fs";
27153
+ import { dirname as dirname2 } from "node:path";
27061
27154
  import { randomUUID } from "node:crypto";
27062
27155
  function atomicJson(path2, value) {
27063
- mkdirSync(dirname(path2), { recursive: true, mode: 448 });
27156
+ if (process.platform === "win32") {
27157
+ ensureWindowsPrivateDirectory(dirname2(path2));
27158
+ if (existsSync(path2)) assertWindowsPrivatePath(path2);
27159
+ } else mkdirSync(dirname2(path2), { recursive: true, mode: 448 });
27064
27160
  const temp = `${path2}.${randomUUID()}.tmp`;
27065
27161
  try {
27066
27162
  const fd2 = openSync(temp, "wx", 384);
@@ -27072,7 +27168,7 @@ function atomicJson(path2, value) {
27072
27168
  }
27073
27169
  renameSync(temp, path2);
27074
27170
  if (process.platform !== "win32") {
27075
- const dir2 = openSync(dirname(path2), "r");
27171
+ const dir2 = openSync(dirname2(path2), "r");
27076
27172
  try {
27077
27173
  fsyncSync(dir2);
27078
27174
  } finally {
@@ -27182,8 +27278,9 @@ function invalid() {
27182
27278
  throw new CliError(EXIT.CONFIG_OR_NETWORK, "PAYMENT_MODE_INVALID", "PAYMENT_MODE_INVALID: \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u0440\u0435\u0436\u0438\u043C\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043B\u0438 \u043F\u043E\u0432\u0440\u0435\u0436\u0434\u0435\u043D\u0430; \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 payment-mode set.");
27183
27279
  }
27184
27280
  function checkDir(paths) {
27185
- const s = lstatSync(paths.configDir);
27186
- if (!s.isDirectory() || s.isSymbolicLink() || (s.mode & 63) !== 0) invalid();
27281
+ const s = lstatSync2(paths.configDir);
27282
+ if (!s.isDirectory() || s.isSymbolicLink() || process.platform !== "win32" && (s.mode & 63) !== 0) invalid();
27283
+ if (process.platform === "win32") assertWindowsPrivatePath(paths.configDir);
27187
27284
  }
27188
27285
  function readPaymentMode(paths) {
27189
27286
  try {
@@ -27191,7 +27288,8 @@ function readPaymentMode(paths) {
27191
27288
  const fd2 = openSync2(modeFile(paths), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
27192
27289
  try {
27193
27290
  const s = fstatSync(fd2);
27194
- if (!s.isFile() || s.size > 4096 || (s.mode & 63) !== 0) invalid();
27291
+ assertPrivateFile(modeFile(paths), s);
27292
+ if (s.size > 4096) invalid();
27195
27293
  return PaymentModeStateSchema.parse(JSON.parse(readFileSync(fd2, "utf8")));
27196
27294
  } finally {
27197
27295
  closeSync2(fd2);
@@ -27209,7 +27307,7 @@ async function writePaymentMode(paths, state) {
27209
27307
  if (e.code !== "ENOENT") throw e;
27210
27308
  }
27211
27309
  try {
27212
- const s = lstatSync(modeFile(paths));
27310
+ const s = lstatSync2(modeFile(paths));
27213
27311
  if (!s.isFile() || s.isSymbolicLink()) invalid();
27214
27312
  } catch (e) {
27215
27313
  if (e.code !== "ENOENT") throw e;
@@ -27222,8 +27320,8 @@ async function writePaymentMode(paths, state) {
27222
27320
  var modeLabel = { live: "\u0420\u0435\u0430\u043B\u044C\u043D\u044B\u0435 \u043F\u043B\u0430\u0442\u0435\u0436\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u044B", blocked: "\u041E\u043F\u043B\u0430\u0442\u0430 \u043E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u0430", "invalid-token": "\u041F\u0440\u043E\u0431\u0430 \u0441 \u043F\u043E\u0432\u0440\u0435\u0436\u0434\u0451\u043D\u043D\u044B\u043C \u0442\u043E\u043A\u0435\u043D\u043E\u043C. \u041E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0441\u043F\u0438\u0441\u0430\u043D\u0438\u044F \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043E" };
27223
27321
 
27224
27322
  // packages/cli/src/core/fileLock.ts
27225
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, rmSync as rmSync2, renameSync as renameSync2, existsSync } from "node:fs";
27226
- import { dirname as dirname2, join as join2 } from "node:path";
27323
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, rmSync as rmSync2, renameSync as renameSync2, existsSync as existsSync2 } from "node:fs";
27324
+ import { dirname as dirname3, join as join2 } from "node:path";
27227
27325
  import { randomUUID as randomUUID2 } from "node:crypto";
27228
27326
  function processAlive(pid) {
27229
27327
  if (!Number.isSafeInteger(pid) || pid <= 0) return void 0;
@@ -27260,7 +27358,7 @@ function owner(path2) {
27260
27358
  }
27261
27359
  }
27262
27360
  async function withFileLock(path2, fn, timeoutMs = 5e3) {
27263
- mkdirSync2(dirname2(path2), { recursive: true, mode: 448 });
27361
+ mkdirSync2(dirname3(path2), { recursive: true, mode: 448 });
27264
27362
  const nonce2 = randomUUID2(), deadline = Date.now() + timeoutMs;
27265
27363
  for (; ; ) {
27266
27364
  try {
@@ -27287,7 +27385,7 @@ async function withFileLock(path2, fn, timeoutMs = 5e3) {
27287
27385
  } finally {
27288
27386
  if (acquired) rmSync2(reaper, { recursive: true, force: true });
27289
27387
  }
27290
- if (!existsSync(path2)) continue;
27388
+ if (!existsSync2(path2)) continue;
27291
27389
  }
27292
27390
  if (Date.now() >= deadline)
27293
27391
  throw new CliError(EXIT.CONFIG_OR_NETWORK, "BINDING_BUSY", "\u0414\u0440\u0443\u0433\u0430\u044F \u043A\u043E\u043C\u0430\u043D\u0434\u0430 \u0432\u043B\u0430\u0434\u0435\u0435\u0442 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435\u043C \u0438\u043B\u0438 \u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D. \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043F\u043E\u0437\u0436\u0435.");
@@ -27304,7 +27402,7 @@ async function withFileLock(path2, fn, timeoutMs = 5e3) {
27304
27402
  // packages/cli/src/probe/journal.ts
27305
27403
  import { randomUUID as randomUUID3 } from "node:crypto";
27306
27404
  import {
27307
- existsSync as existsSync2,
27405
+ existsSync as existsSync3,
27308
27406
  mkdirSync as mkdirSync4,
27309
27407
  readFileSync as readFileSync4,
27310
27408
  rmSync as rmSync3,
@@ -27312,7 +27410,7 @@ import {
27312
27410
  openSync as openSync4,
27313
27411
  fsyncSync as fsyncSync3,
27314
27412
  closeSync as closeSync4,
27315
- lstatSync as lstatSync3
27413
+ lstatSync as lstatSync4
27316
27414
  } from "node:fs";
27317
27415
  import { join as join4 } from "node:path";
27318
27416
 
@@ -27364,7 +27462,7 @@ import {
27364
27462
  closeSync as closeSync3,
27365
27463
  fsyncSync as fsyncSync2,
27366
27464
  fstatSync as fstatSync2,
27367
- lstatSync as lstatSync2,
27465
+ lstatSync as lstatSync3,
27368
27466
  mkdirSync as mkdirSync3,
27369
27467
  openSync as openSync3,
27370
27468
  readFileSync as readFileSync3,
@@ -27381,14 +27479,16 @@ function journalError() {
27381
27479
  );
27382
27480
  }
27383
27481
  function privateDir(path2) {
27384
- mkdirSync3(path2, { recursive: true, mode: 448 });
27385
- const s = lstatSync2(path2);
27482
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(path2);
27483
+ else mkdirSync3(path2, { recursive: true, mode: 448 });
27484
+ const s = lstatSync3(path2);
27386
27485
  if (!s.isDirectory() || s.isSymbolicLink() || process.platform !== "win32" && ((s.mode & 63) !== 0 || s.uid !== process.getuid?.()))
27387
27486
  journalError();
27388
27487
  }
27389
27488
  function registryDir(paths) {
27390
- mkdirSync3(paths.stateDir, { recursive: true, mode: 448 });
27391
- if (lstatSync2(paths.stateDir).isSymbolicLink()) journalError();
27489
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(paths.stateDir);
27490
+ else mkdirSync3(paths.stateDir, { recursive: true, mode: 448 });
27491
+ if (lstatSync3(paths.stateDir).isSymbolicLink()) journalError();
27392
27492
  const dir2 = join3(paths.stateDir, "payment-probes");
27393
27493
  privateDir(dir2);
27394
27494
  return dir2;
@@ -27405,6 +27505,12 @@ function syncDir(dir2) {
27405
27505
  function openPrivate(path2, flags) {
27406
27506
  const fd2 = openSync3(path2, flags | (constants2.O_NOFOLLOW ?? 0), 384);
27407
27507
  const s = fstatSync2(fd2);
27508
+ try {
27509
+ assertPrivateFile(path2, s);
27510
+ } catch {
27511
+ closeSync3(fd2);
27512
+ journalError();
27513
+ }
27408
27514
  if (!s.isFile() || s.nlink !== 1 || s.size > MAX_FILE || process.platform !== "win32" && ((s.mode & 63) !== 0 || s.uid !== process.getuid?.())) {
27409
27515
  closeSync3(fd2);
27410
27516
  journalError();
@@ -27649,7 +27755,7 @@ function lockError(code) {
27649
27755
  }
27650
27756
  function ownerAlive(lock) {
27651
27757
  try {
27652
- if (lstatSync3(lock).isSymbolicLink()) journalError();
27758
+ if (lstatSync4(lock).isSymbolicLink()) journalError();
27653
27759
  const raw = readFileSync4(join4(lock, "owner.json"), "utf8");
27654
27760
  if (raw.length > 256) journalError();
27655
27761
  const pid = JSON.parse(raw).pid;
@@ -27668,7 +27774,7 @@ function ownerAlive(lock) {
27668
27774
  async function exclusive(paths, recover, fn, installing2 = false) {
27669
27775
  const dir2 = registryDir(paths), lock = join4(dir2, ".lock");
27670
27776
  let recovered = false;
27671
- if (existsSync2(lock)) {
27777
+ if (existsSync3(lock)) {
27672
27778
  if (ownerAlive(lock)) lockError("PROBE_BUSY");
27673
27779
  if (!recover) lockError("PROBE_STALE_LOCK");
27674
27780
  try {
@@ -27704,7 +27810,7 @@ async function exclusive(paths, recover, fn, installing2 = false) {
27704
27810
  }
27705
27811
  syncDir(lock);
27706
27812
  syncDir(dir2);
27707
- if (!installing2 && existsSync2(join4(paths.configDir, "../..", "install-pending.json")))
27813
+ if (!installing2 && existsSync3(join4(paths.configDir, "../..", "install-pending.json")))
27708
27814
  throw new CliError(EXIT.CONFIG_OR_NETWORK, "INSTALL_IN_PROGRESS", "\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043D\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0430");
27709
27815
  return await fn();
27710
27816
  } finally {
@@ -28054,13 +28160,13 @@ function cliPaths(env = process.env) {
28054
28160
  }
28055
28161
 
28056
28162
  // packages/cli/src/report/storage.ts
28057
- import { lstatSync as lstatSync4, mkdirSync as mkdirSync6, readdirSync as readdirSync2, unlinkSync } from "node:fs";
28163
+ import { lstatSync as lstatSync5, mkdirSync as mkdirSync6, readdirSync as readdirSync2, unlinkSync } from "node:fs";
28058
28164
  import { join as join7 } from "node:path";
28059
28165
 
28060
28166
  // packages/cli/src/report/bindingFiles.ts
28061
- import { open as open2, realpath, stat } from "node:fs/promises";
28167
+ import { open as open3, realpath, stat } from "node:fs/promises";
28062
28168
  import { constants as constants3 } from "node:fs";
28063
- import { dirname as dirname3, isAbsolute, relative, resolve } from "node:path";
28169
+ import { dirname as dirname4, isAbsolute, relative, resolve } from "node:path";
28064
28170
  var BindingError = class extends Error {
28065
28171
  constructor(code, hint, reasonCode) {
28066
28172
  super(code);
@@ -28090,7 +28196,7 @@ async function futurePath(root, path2) {
28090
28196
  return target;
28091
28197
  } catch (error62) {
28092
28198
  if (error62.code !== "ENOENT") throw error62;
28093
- const parent = dirname3(ancestor);
28199
+ const parent = dirname4(ancestor);
28094
28200
  if (parent === ancestor) throw new BindingError("PATH_OUTSIDE_ROOT");
28095
28201
  ancestor = parent;
28096
28202
  }
@@ -28100,9 +28206,10 @@ async function readPrefix(root, path2, maxBytes = 256 * 1024) {
28100
28206
  const canonicalRoot = await realpath(root);
28101
28207
  const canonical = await realpath(path2);
28102
28208
  if (!contained(canonicalRoot, canonical)) throw new BindingError("PATH_OUTSIDE_ROOT");
28209
+ if (process.platform === "win32") assertWindowsHelperPath(canonical);
28103
28210
  const before = await stat(canonical);
28104
28211
  if (!before.isFile() || process.getuid && before.uid !== process.getuid()) throw new BindingError("UNSAFE_SOURCE");
28105
- const file2 = await open2(canonical, constants3.O_RDONLY | (constants3.O_NOFOLLOW ?? 0) | (constants3.O_NONBLOCK ?? 0));
28212
+ const file2 = await open3(canonical, constants3.O_RDONLY | (constants3.O_NOFOLLOW ?? 0) | (constants3.O_NONBLOCK ?? 0));
28106
28213
  try {
28107
28214
  const now = await file2.stat();
28108
28215
  if (!now.isFile() || now.ino !== before.ino || now.dev !== before.dev) throw new BindingError("SOURCE_CHANGED");
@@ -28121,9 +28228,10 @@ async function readPrefix(root, path2, maxBytes = 256 * 1024) {
28121
28228
 
28122
28229
  // packages/cli/src/report/storage.ts
28123
28230
  function privateDir2(path2) {
28124
- mkdirSync6(path2, { recursive: true, mode: 448 });
28125
- const info = lstatSync4(path2);
28126
- if (!info.isDirectory() || info.isSymbolicLink() || process.getuid && info.uid !== process.getuid() || info.mode & 63) throw new BindingError("UNSAFE_REPORT_DIRECTORY");
28231
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(path2);
28232
+ else mkdirSync6(path2, { recursive: true, mode: 448 });
28233
+ const info = lstatSync5(path2);
28234
+ if (!info.isDirectory() || info.isSymbolicLink() || process.getuid && info.uid !== process.getuid() || process.platform !== "win32" && info.mode & 63) throw new BindingError("UNSAFE_REPORT_DIRECTORY");
28127
28235
  return path2;
28128
28236
  }
28129
28237
  function retain(dir2, pattern, maxBytes) {
@@ -28131,7 +28239,7 @@ function retain(dir2, pattern, maxBytes) {
28131
28239
  if (entries.length > 1e4) throw new BindingError("REPORT_STORAGE_ENTRY_LIMIT");
28132
28240
  const files = entries.filter((name) => pattern.test(name)).flatMap((name) => {
28133
28241
  const path2 = join7(dir2, name);
28134
- const info = lstatSync4(path2);
28242
+ const info = lstatSync5(path2);
28135
28243
  return info.isFile() && !info.isSymbolicLink() ? [{ path: path2, size: info.size, mtime: info.mtimeMs }] : [];
28136
28244
  }).sort((a, b) => b.mtime - a.mtime);
28137
28245
  let total = 0;
@@ -28143,7 +28251,7 @@ function retain(dir2, pattern, maxBytes) {
28143
28251
 
28144
28252
  // packages/cli/src/report/transport.ts
28145
28253
  import { constants as constants4 } from "node:fs";
28146
- import { open as open3, lstat, rename, rm, mkdir } from "node:fs/promises";
28254
+ import { open as open4, lstat, rename, rm, mkdir } from "node:fs/promises";
28147
28255
  import { join as join8 } from "node:path";
28148
28256
  import { request as httpsRequest } from "node:https";
28149
28257
  import { randomUUID as randomUUID4 } from "node:crypto";
@@ -28223,10 +28331,11 @@ function validatePackage(bytes, caseId) {
28223
28331
 
28224
28332
  // packages/cli/src/report/transport.ts
28225
28333
  async function privateRead(path2, limit) {
28226
- const file2 = await open3(path2, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
28334
+ const file2 = await open4(path2, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
28227
28335
  try {
28228
28336
  const info = await file2.stat();
28229
- if (!info.isFile() || process.getuid && info.uid !== process.getuid() || info.mode & 63 || info.size > limit) throw Error("UNSAFE_FILE");
28337
+ assertPrivateFile(path2, info);
28338
+ if (info.size > limit) throw Error("UNSAFE_FILE");
28230
28339
  const buffer = Buffer.alloc(info.size);
28231
28340
  let at = 0;
28232
28341
  while (at < buffer.length) {
@@ -28275,7 +28384,7 @@ async function save(dir2, state) {
28275
28384
  const temp = join8(dir2, `.${randomUUID4()}.tmp`);
28276
28385
  const path2 = join8(dir2, `${state.caseId}.json`);
28277
28386
  try {
28278
- const file2 = await open3(temp, "wx", 384);
28387
+ const file2 = await open4(temp, "wx", 384);
28279
28388
  try {
28280
28389
  await file2.writeFile(JSON.stringify({ ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }));
28281
28390
  await file2.sync();
@@ -28392,7 +28501,7 @@ import { homedir as homedir3 } from "node:os";
28392
28501
  import { join as join9 } from "node:path";
28393
28502
 
28394
28503
  // packages/cli/src/report/adapters/transcript.ts
28395
- import { open as open4, realpath as realpath2, stat as stat2 } from "node:fs/promises";
28504
+ import { open as open5, realpath as realpath2, stat as stat2 } from "node:fs/promises";
28396
28505
  import { constants as constants5 } from "node:fs";
28397
28506
  import { relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
28398
28507
  import { createHash as createHash3 } from "node:crypto";
@@ -28495,13 +28604,14 @@ async function collectTranscript(agent, parser3, binding, options = {}) {
28495
28604
  warn(result, "PATH_OUTSIDE_ROOT");
28496
28605
  return result;
28497
28606
  }
28607
+ if (process.platform === "win32") assertWindowsHelperPath(path2);
28498
28608
  const before = await stat2(path2);
28499
28609
  if (!before.isFile()) {
28500
28610
  result.coverage = "failed";
28501
28611
  warn(result, "UNSAFE_SOURCE");
28502
28612
  return result;
28503
28613
  }
28504
- handle = await open4(path2, constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0) | (constants5.O_NONBLOCK ?? 0));
28614
+ handle = await open5(path2, constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0) | (constants5.O_NONBLOCK ?? 0));
28505
28615
  const snapshot = await handle.stat();
28506
28616
  if (!snapshot.isFile() || snapshot.ino !== before.ino || snapshot.dev !== before.dev || process.getuid && snapshot.uid !== process.getuid()) {
28507
28617
  result.coverage = "failed";
@@ -28783,6 +28893,7 @@ async function codexBinding(env) {
28783
28893
  const dbPath = await realpath3(join9(home, name));
28784
28894
  const info = await stat3(dbPath);
28785
28895
  if (!contained(home, dbPath) || !info.isFile() || process.getuid && info.uid !== process.getuid()) throw new BindingError("UNSAFE_INDEX");
28896
+ if (process.platform === "win32") assertWindowsHelperPath(dbPath);
28786
28897
  const db = new DatabaseSync(dbPath, { readOnly: true });
28787
28898
  try {
28788
28899
  db.exec("PRAGMA query_only=ON; PRAGMA busy_timeout=500");
@@ -29587,7 +29698,7 @@ function zipSync(data, opts) {
29587
29698
  }
29588
29699
 
29589
29700
  // packages/cli/src/core/version.ts
29590
- var CLI_VERSION = "0.4.0-dev.4";
29701
+ var CLI_VERSION = "0.4.0-dev.7";
29591
29702
 
29592
29703
  // packages/cli/src/report/journal.ts
29593
29704
  import { closeSync as closeSync5, constants as constants6, openSync as openSync5, writeSync as writeSync2 } from "node:fs";
@@ -30606,7 +30717,7 @@ function registerPaymentModeCommands(program3) {
30606
30717
 
30607
30718
  // packages/cli/src/report/enrollment.ts
30608
30719
  import { generateKeyPairSync, createHash as createHash8, createPrivateKey, createPublicKey, randomUUID as randomUUID8, sign } from "node:crypto";
30609
- import { open as open5, rename as rename4, rm as rm4 } from "node:fs/promises";
30720
+ import { open as open6, rename as rename4, rm as rm4 } from "node:fs/promises";
30610
30721
  import { join as join14 } from "node:path";
30611
30722
  import { request as httpsRequest2 } from "node:https";
30612
30723
  var DIAGNOSTIC_ENDPOINT = "https://aiplatilka.ru/case-reports";
@@ -30640,14 +30751,6 @@ var enrollmentPost = (path2, body) => new Promise((resolve6, reject) => {
30640
30751
  request.on("error", reject);
30641
30752
  request.end(bytes);
30642
30753
  });
30643
- async function syncDir2(dir2) {
30644
- const f = await open5(dir2, "r");
30645
- try {
30646
- await f.sync();
30647
- } finally {
30648
- await f.close();
30649
- }
30650
- }
30651
30754
  async function enrollInvitation(path2, env = process.env, request = enrollmentPost) {
30652
30755
  try {
30653
30756
  const invite = Invitation.parse(JSON.parse((await privateRead(path2, 8192)).toString("utf8")));
@@ -30656,20 +30759,20 @@ async function enrollInvitation(path2, env = process.env, request = enrollmentPo
30656
30759
  const statePath = join14(dir2, "report-installation.json");
30657
30760
  try {
30658
30761
  const pair = generateKeyPairSync("ed25519");
30659
- const file2 = await open5(statePath, "wx", 384);
30762
+ const file2 = await open6(statePath, "wx", 384);
30660
30763
  try {
30661
30764
  await file2.writeFile(JSON.stringify({ invitationHash: hash3, installationId: randomUUID8(), privateKey: pair.privateKey.export({ format: "pem", type: "pkcs8" }), publicKey: pair.publicKey.export({ format: "pem", type: "spki" }) }));
30662
30765
  await file2.sync();
30663
30766
  } finally {
30664
30767
  await file2.close();
30665
30768
  }
30666
- await syncDir2(dir2);
30769
+ await syncDirectory(dir2);
30667
30770
  } catch (error62) {
30668
30771
  if (error62.code !== "EEXIST") throw error62;
30669
30772
  }
30670
30773
  const state = State.parse(JSON.parse((await privateRead(statePath, 8192)).toString("utf8")));
30671
30774
  if (state.invitationHash !== hash3 || createPublicKey(state.privateKey).export({ format: "pem", type: "spki" }).toString() !== state.publicKey) throw Error("INSTALLATION_CONFLICT");
30672
- await syncDir2(dir2);
30775
+ await syncDirectory(dir2);
30673
30776
  const body = { inviteToken: invite.token, installationId: state.installationId, publicKey: state.publicKey };
30674
30777
  const challenge = external_exports.object({ challenge: external_exports.string().max(2048) }).strict().parse(await request("/v1/enroll/challenge", body));
30675
30778
  const signature = sign(null, Buffer.from("sberpay-enroll-v1\n" + challenge.challenge), createPrivateKey(state.privateKey)).toString("base64url");
@@ -30677,7 +30780,7 @@ async function enrollInvitation(path2, env = process.env, request = enrollmentPo
30677
30780
  if (response.installationId !== state.installationId) throw Error("INSTALLATION_MISMATCH");
30678
30781
  const temp = join14(dir2, `.upload-${randomUUID8()}.tmp`);
30679
30782
  try {
30680
- const file2 = await open5(temp, "wx", 384);
30783
+ const file2 = await open6(temp, "wx", 384);
30681
30784
  try {
30682
30785
  await file2.writeFile(JSON.stringify({ endpoint: DIAGNOSTIC_ENDPOINT, token: response.token }));
30683
30786
  await file2.sync();
@@ -30685,7 +30788,7 @@ async function enrollInvitation(path2, env = process.env, request = enrollmentPo
30685
30788
  await file2.close();
30686
30789
  }
30687
30790
  await rename4(temp, join14(dir2, "report-upload.json"));
30688
- await syncDir2(dir2);
30791
+ await syncDirectory(dir2);
30689
30792
  } finally {
30690
30793
  await rm4(temp, { force: true });
30691
30794
  }
@@ -34065,10 +34168,11 @@ var program = new Command();
34065
34168
 
34066
34169
  // packages/cli/src/report/command.ts
34067
34170
  import { homedir as homedir5 } from "node:os";
34068
- import { join as join16, dirname as dirname4, resolve as resolve2 } from "node:path";
34171
+ import { join as join16, dirname as dirname6, resolve as resolve2 } from "node:path";
34069
34172
 
34070
34173
  // packages/cli/src/report/claudeHook.ts
34071
- import { open as open6, chmod, lstat as lstat3, mkdir as mkdir2, readFile as readFile2, realpath as realpath4, rename as rename5, writeFile as writeFile4 } from "node:fs/promises";
34174
+ import { dirname as dirname5 } from "node:path";
34175
+ import { open as open7, chmod, lstat as lstat3, mkdir as mkdir2, readFile as readFile2, realpath as realpath4, rename as rename5, writeFile as writeFile4 } from "node:fs/promises";
34072
34176
  import { constants as constants7 } from "node:fs";
34073
34177
  import { homedir as homedir4 } from "node:os";
34074
34178
  import { join as join15 } from "node:path";
@@ -34085,7 +34189,16 @@ async function captureClaudeBinding(input2, env = process.env) {
34085
34189
  if (/[\r\n\0]/.test(path2 + config2)) throw new BindingError("INVALID_HOOK_PATH");
34086
34190
  const lines = [["SBERPAY_CLAUDE_SESSION_ID", data.session_id], ["SBERPAY_CLAUDE_TRANSCRIPT", path2], ["SBERPAY_CLAUDE_CONFIG_DIR", config2]].map(([key, value]) => `export ${key}=${shellQuote(value)}
34087
34191
  `).join("");
34088
- const file2 = await open6(env.CLAUDE_ENV_FILE, constants7.O_WRONLY | constants7.O_APPEND | constants7.O_CREAT | (constants7.O_NOFOLLOW ?? 0) | (constants7.O_NONBLOCK ?? 0), 384);
34192
+ if (process.platform === "win32") {
34193
+ assertWindowsPrivatePath(dirname5(env.CLAUDE_ENV_FILE));
34194
+ try {
34195
+ await lstat3(env.CLAUDE_ENV_FILE);
34196
+ assertWindowsPrivatePath(env.CLAUDE_ENV_FILE);
34197
+ } catch (e) {
34198
+ if (e.code !== "ENOENT") throw e;
34199
+ }
34200
+ }
34201
+ const file2 = await open7(env.CLAUDE_ENV_FILE, constants7.O_WRONLY | constants7.O_APPEND | constants7.O_CREAT | (constants7.O_NOFOLLOW ?? 0) | (constants7.O_NONBLOCK ?? 0), 384);
34089
34202
  try {
34090
34203
  const info = await file2.stat();
34091
34204
  if (!info.isFile() || process.getuid && info.uid !== process.getuid()) throw new BindingError("UNSAFE_ENV_FILE");
@@ -34095,12 +34208,14 @@ async function captureClaudeBinding(input2, env = process.env) {
34095
34208
  }
34096
34209
  }
34097
34210
  async function installClaudeHook(configDir, command) {
34098
- await mkdir2(configDir, { recursive: true, mode: 448 });
34211
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(configDir);
34212
+ else await mkdir2(configDir, { recursive: true, mode: 448 });
34099
34213
  const path2 = join15(configDir, "settings.json");
34100
34214
  let original;
34101
34215
  try {
34102
34216
  const info = await lstat3(path2);
34103
34217
  if (!info.isFile() || info.isSymbolicLink()) throw new BindingError("UNSAFE_SETTINGS");
34218
+ if (process.platform === "win32") assertWindowsPrivatePath(path2);
34104
34219
  original = await readFile2(path2, "utf8");
34105
34220
  } catch (error62) {
34106
34221
  if (error62.code !== "ENOENT") throw error62;
@@ -34132,7 +34247,7 @@ async function installClaudeHook(configDir, command) {
34132
34247
  // packages/cli/src/report/command.ts
34133
34248
  function claudeHookCommand() {
34134
34249
  const args = BUILD.kind === "release" ? [process.execPath, join16(BUILD.root, "dist", "cli.mjs")] : [process.execPath, "--import", import.meta.resolve("tsx"), join16(BUILD.root, "packages", "cli", "src", "main.ts")];
34135
- return [...args, "report", "claude-hook"].map(shellQuote).join(" ");
34250
+ return [...args, "report", "claude-hook"].map((s) => shellQuote(process.platform === "win32" ? s.replaceAll("\\", "/") : s)).join(" ");
34136
34251
  }
34137
34252
  async function hookInput() {
34138
34253
  const chunks = [];
@@ -34196,7 +34311,7 @@ function registerReportCommands(program3) {
34196
34311
  for (const name of ["collect", "submit"]) report2.command(name).description(name === "collect" ? "\u0421\u043E\u0431\u0440\u0430\u0442\u044C \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439 ZIP \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0447\u0430\u0442\u0430" : "\u0421\u043E\u0431\u0440\u0430\u0442\u044C \u043A\u0435\u0439\u0441 \u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 HTTPS-\u043F\u0440\u0438\u0451\u043C\u043D\u0438\u043A").requiredOption("--input <path>", "JSON: title, scope=current_session, \u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 request/expected/observed/agentSummary/hypotheses").addOption(new Option("--agent <agent>", "\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u0441\u0435\u0441\u0441\u0438\u0438").choices(["auto", "codex", "claude"]).default("auto")).action(async (opts) => {
34197
34312
  try {
34198
34313
  const path2 = resolve2(opts.input);
34199
- const text2 = await readPrefix(dirname4(path2), path2, 65537);
34314
+ const text2 = await readPrefix(dirname6(path2), path2, 65537);
34200
34315
  if (Buffer.byteLength(text2) > 65536) throw new BindingError("CASE_INPUT_LIMIT");
34201
34316
  let input2;
34202
34317
  try {
@@ -34429,7 +34544,7 @@ function softwareDeviceKeys(storage, where = "os") {
34429
34544
  }
34430
34545
 
34431
34546
  // packages/device/src/helper.ts
34432
- import { spawn, spawnSync } from "node:child_process";
34547
+ import { spawn, spawnSync as spawnSync2 } from "node:child_process";
34433
34548
  var HELPER_PROTOCOL = 1;
34434
34549
  var TIMEOUT_MS = 15e3;
34435
34550
  var MAX_OUTPUT_BYTES = 64 * 1024;
@@ -34497,7 +34612,7 @@ async function callHelper(path2, request, schema) {
34497
34612
  return parseReply(request.op, code, stdout, schema);
34498
34613
  }
34499
34614
  function callHelperSync(path2, request, schema) {
34500
- const result = spawnSync(path2, [], {
34615
+ const result = spawnSync2(path2, [], {
34501
34616
  input: encode3(request),
34502
34617
  env: helperEnv(),
34503
34618
  stdio: ["pipe", "pipe", "ignore"],
@@ -34527,8 +34642,8 @@ function helperSecrets(helper) {
34527
34642
 
34528
34643
  // packages/device/src/hardware.ts
34529
34644
  import { createPublicKey as createPublicKey3, verify } from "node:crypto";
34530
- import { chmodSync, closeSync as closeSync6, existsSync as existsSync3, fsyncSync as fsyncSync4, linkSync, mkdirSync as mkdirSync7, openSync as openSync6, readFileSync as readFileSync6, rmSync as rmSync4, writeSync as writeSync3 } from "node:fs";
34531
- import { dirname as dirname5 } from "node:path";
34645
+ import { chmodSync, closeSync as closeSync6, existsSync as existsSync4, fsyncSync as fsyncSync4, linkSync, mkdirSync as mkdirSync7, openSync as openSync6, readFileSync as readFileSync6, rmSync as rmSync4, writeSync as writeSync3 } from "node:fs";
34646
+ import { dirname as dirname7 } from "node:path";
34532
34647
  var B64URL2 = external_exports.string().max(4096).regex(/^[A-Za-z0-9_-]+$/);
34533
34648
  var Point = external_exports.object({ x: B64URL2, y: B64URL2 });
34534
34649
  var Blobs = external_exports.object({ signKey: B64URL2, encKey: B64URL2 });
@@ -34544,7 +34659,7 @@ function toPublicKeys(pub) {
34544
34659
  return { deviceId: jwkThumbprint(publicKey), publicKey, encKey: jwk(pub.encPublicKey, "enc") };
34545
34660
  }
34546
34661
  function readBlobs(file2, kind2) {
34547
- if (!existsSync3(file2)) return void 0;
34662
+ if (!existsSync4(file2)) return void 0;
34548
34663
  const parsed = KeyFile.safeParse((() => {
34549
34664
  try {
34550
34665
  return JSON.parse(readFileSync6(file2, "utf8"));
@@ -34556,7 +34671,7 @@ function readBlobs(file2, kind2) {
34556
34671
  return { signKey: parsed.data.signKey, encKey: parsed.data.encKey };
34557
34672
  }
34558
34673
  function saveNewBlobs(file2, kind2, blobs) {
34559
- mkdirSync7(dirname5(file2), { recursive: true, mode: 448 });
34674
+ mkdirSync7(dirname7(file2), { recursive: true, mode: 448 });
34560
34675
  const tmp = `${file2}.${process.pid}.${Date.now()}.tmp`;
34561
34676
  const fd2 = openSync6(tmp, "wx", 384);
34562
34677
  try {
@@ -34589,7 +34704,7 @@ function checkSignature(pub, data, signature) {
34589
34704
  return signature;
34590
34705
  }
34591
34706
  async function hardwareAvailable(helper) {
34592
- if (!existsSync3(helper)) return false;
34707
+ if (!existsSync4(helper)) return false;
34593
34708
  try {
34594
34709
  return (await callHelper(helper, { op: "status" }, external_exports.object({ available: external_exports.boolean() }))).available;
34595
34710
  } catch {
@@ -34619,7 +34734,7 @@ function hardwareDeviceKeys({ kind: kind2, helper, file: file2 }) {
34619
34734
  return {
34620
34735
  kind: kind2,
34621
34736
  storage: "hardware",
34622
- exists: () => Boolean(blobs) || existsSync3(file2),
34737
+ exists: () => Boolean(blobs) || existsSync4(file2),
34623
34738
  ensure: publicKeys,
34624
34739
  async sign(data) {
34625
34740
  const signKey = required2().signKey;
@@ -34653,7 +34768,7 @@ function hardwareDeviceKeys({ kind: kind2, helper, file: file2 }) {
34653
34768
  }
34654
34769
 
34655
34770
  // packages/cli/src/core/context.ts
34656
- import { appendFileSync, mkdirSync as mkdirSync9 } from "node:fs";
34771
+ import { appendFileSync, mkdirSync as mkdirSync9, existsSync as existsSync8 } from "node:fs";
34657
34772
  import { join as join20 } from "node:path";
34658
34773
 
34659
34774
  // packages/netlog/src/masking.ts
@@ -34829,7 +34944,7 @@ async function loggedFetch(logger, meta3, url2, init = {}) {
34829
34944
  }
34830
34945
 
34831
34946
  // packages/cli/src/core/config.ts
34832
- import { existsSync as existsSync4, readFileSync as readFileSync8 } from "node:fs";
34947
+ import { existsSync as existsSync5, readFileSync as readFileSync8 } from "node:fs";
34833
34948
  import { join as join17 } from "node:path";
34834
34949
  var STAND_NAMES = ["local", "ift", "prod"];
34835
34950
  var KEY_STORAGE_PREFERENCES = [
@@ -34853,7 +34968,7 @@ var DEFAULT_STANDS = {
34853
34968
  ift: { allowSoftwareKeys: true },
34854
34969
  // Шлюз ЭК ПРОМ (ЭлКом вышел на ПРОМ 07.10.2026). Реестр ФП временно на aiplatilka.ru. Кабинет под tsx — в config.json:
34855
34970
  // cabinetMockUrl для токена, выпущенного ЭлКом вручную, или cabinetOrigins и cabinetBaseUrl.
34856
- prod: { gatewayUrl: PROD_GATEWAY, merchantsUrl: PROD_MERCHANTS, addressesUrl: "https://aiplatilka.ru", addressesMode: "pilot-json", allowSoftwareKeys: false }
34971
+ prod: { gatewayUrl: PROD_GATEWAY, merchantsUrl: PROD_MERCHANTS, addressesUrl: "https://aiplatilka.ru", addressesMode: "pilot-json", allowSoftwareKeys: true }
34857
34972
  };
34858
34973
  var RELEASE_PROD = {
34859
34974
  gatewayUrl: PROD_GATEWAY,
@@ -34863,7 +34978,7 @@ var RELEASE_PROD = {
34863
34978
  cabinetOrigins: [PROD_CABINET],
34864
34979
  cabinetBaseUrl: PROD_CABINET,
34865
34980
  staticUrl: PROD_CABINET,
34866
- allowSoftwareKeys: false
34981
+ allowSoftwareKeys: true
34867
34982
  };
34868
34983
  var RELEASE_LOCKED = {
34869
34984
  local: ["cabinetMockUrl"],
@@ -34890,8 +35005,9 @@ function isStand(value) {
34890
35005
  }
34891
35006
  function loadConfig(paths, build = BUILD) {
34892
35007
  const file2 = join17(paths.configDir, "config.json");
34893
- if (!existsSync4(file2)) return defaultConfig(build);
35008
+ if (!existsSync5(file2)) return defaultConfig(build);
34894
35009
  try {
35010
+ if (process.platform === "win32") assertWindowsPrivatePath(file2);
34895
35011
  return { ...defaultConfig(build), ...JSON.parse(readFileSync8(file2, "utf8")) };
34896
35012
  } catch (error62) {
34897
35013
  throw new CliError(
@@ -35004,7 +35120,7 @@ function resolveStand(config2, name, build = BUILD) {
35004
35120
  if (merged.cabinetBaseUrl && !realOrigins.includes(new URL(merged.cabinetBaseUrl).origin)) {
35005
35121
  invalidField(name, "cabinetBaseUrl", "\u0430\u0434\u0440\u0435\u0441 \u043A\u0430\u0431\u0438\u043D\u0435\u0442\u0430 \u0441 origin \u0438\u0437 cabinetOrigins");
35006
35122
  }
35007
- const allowSoftwareKeys = defaults.allowSoftwareKeys === true && merged.allowSoftwareKeys !== false;
35123
+ const allowSoftwareKeys = merged.allowSoftwareKeys !== false;
35008
35124
  return { ...merged, cabinetOrigins: mock ? [...realOrigins, mock] : realOrigins, allowSoftwareKeys };
35009
35125
  }
35010
35126
  async function updateConfig(paths, transform3) {
@@ -35018,7 +35134,7 @@ async function updateConfig(paths, transform3) {
35018
35134
  // packages/cli/src/core/secrets.ts
35019
35135
  import {
35020
35136
  chmodSync as chmodSync2,
35021
- existsSync as existsSync6,
35137
+ existsSync as existsSync7,
35022
35138
  mkdirSync as mkdirSync8,
35023
35139
  readFileSync as readFileSync9,
35024
35140
  renameSync as renameSync4,
@@ -35028,10 +35144,10 @@ import {
35028
35144
  import { join as join19 } from "node:path";
35029
35145
 
35030
35146
  // packages/cli/src/core/keyHelper.ts
35031
- import { spawnSync as spawnSync2 } from "node:child_process";
35032
- import { existsSync as existsSync5, realpathSync as realpathSync2, statSync } from "node:fs";
35033
- import { dirname as dirname6, isAbsolute as isAbsolute3, join as join18 } from "node:path";
35034
- var PACKAGED = { "darwin-arm64": "darwin", "darwin-x64": "darwin", "linux-x64": "linux-x64", "linux-arm64": "linux-arm64" };
35147
+ import { spawnSync as spawnSync3 } from "node:child_process";
35148
+ import { existsSync as existsSync6, realpathSync as realpathSync2, statSync } from "node:fs";
35149
+ import { dirname as dirname8, isAbsolute as isAbsolute3, join as join18 } from "node:path";
35150
+ var PACKAGED = { "darwin-arm64": "darwin", "darwin-x64": "darwin", "linux-x64": "linux-x64", "linux-arm64": "linux-arm64", "win32-x64": "win32-x64", "win32-arm64": "win32-arm64" };
35035
35151
  function chipOf(platform2) {
35036
35152
  if (platform2 === "darwin") return "secure-enclave";
35037
35153
  return platform2 === "linux" || platform2 === "win32" ? "tpm" : void 0;
@@ -35057,17 +35173,25 @@ var TPM_LIBRARIES_HINT = "\u041F\u043E\u0441\u0442\u0430\u0432\u044C\u0442\u0435
35057
35173
  var LDD = "/usr/bin/ldd";
35058
35174
  var LDD_TIMEOUT_MS = 5e3;
35059
35175
  function missingLibraries(path2, platform2 = process.platform) {
35060
- if (platform2 !== "linux" || !existsSync5(LDD)) return [];
35061
- const result = spawnSync2(LDD, [path2], { encoding: "utf8", timeout: LDD_TIMEOUT_MS, env: { PATH: "/usr/bin:/bin" } });
35176
+ if (platform2 !== "linux" || !existsSync6(LDD)) return [];
35177
+ const result = spawnSync3(LDD, [path2], { encoding: "utf8", timeout: LDD_TIMEOUT_MS, env: { PATH: "/usr/bin:/bin" } });
35062
35178
  if (typeof result.stdout !== "string") return [];
35063
35179
  return result.stdout.split("\n").filter((line) => line.includes("=> not found")).map((line) => line.trim().split(/\s+/)[0] ?? "").filter(Boolean);
35064
35180
  }
35065
35181
  var WRITABLE_BY_GROUP = 16;
35066
35182
  var WRITABLE_BY_OTHERS = 2;
35067
35183
  function isTrustedFile(path2) {
35184
+ if (process.platform === "win32") {
35185
+ try {
35186
+ assertWindowsHelperPath(path2);
35187
+ return true;
35188
+ } catch {
35189
+ return false;
35190
+ }
35191
+ }
35068
35192
  const real = realpathSync2(path2);
35069
35193
  const uid = process.getuid?.() ?? 0;
35070
- return [real, dirname6(real)].every((p) => {
35194
+ return [real, dirname8(real)].every((p) => {
35071
35195
  const st = statSync(p);
35072
35196
  const groupOk = (st.mode & WRITABLE_BY_GROUP) === 0;
35073
35197
  return (st.uid === uid || st.uid === 0) && (st.mode & WRITABLE_BY_OTHERS) === 0 && groupOk;
@@ -35079,9 +35203,9 @@ function unavailable(message2, hint) {
35079
35203
  function findKeyHelper(opts) {
35080
35204
  const path2 = opts.override ?? opts.installed;
35081
35205
  if (!isAbsolute3(path2)) throw unavailable(`\u041F\u0443\u0442\u044C \u043A \u0445\u0435\u043B\u043F\u0435\u0440\u0443 ${path2} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0430\u0431\u0441\u043E\u043B\u044E\u0442\u043D\u044B\u043C`, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u043E\u043B\u043D\u044B\u0439 \u043F\u0443\u0442\u044C \u0432 SBERPAY_KEY_HELPER");
35082
- if (!existsSync5(path2)) return void 0;
35206
+ if (!existsSync6(path2)) return void 0;
35083
35207
  if (!isTrustedFile(path2)) {
35084
- throw unavailable(`\u0425\u0435\u043B\u043F\u0435\u0440 ${path2} \u043D\u0435 \u043F\u0440\u0438\u043D\u0430\u0434\u043B\u0435\u0436\u0438\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0438\u043B\u0438 \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u043D\u0430 \u0437\u0430\u043F\u0438\u0441\u044C \u0434\u0440\u0443\u0433\u0438\u043C`, "\u041F\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 sberpay-cli; \u043F\u0440\u0430\u0432\u0430 \u043D\u0430 \u0445\u0435\u043B\u043F\u0435\u0440 \u0438 \u0435\u0433\u043E \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u2014 0755, \u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 \u2014 \u0432\u044B \u0438\u043B\u0438 root");
35208
+ throw unavailable(`\u0425\u0435\u043B\u043F\u0435\u0440 ${path2} \u043D\u0435 \u043F\u0440\u0438\u043D\u0430\u0434\u043B\u0435\u0436\u0438\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0438\u043B\u0438 \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u043D\u0430 \u0437\u0430\u043F\u0438\u0441\u044C \u0434\u0440\u0443\u0433\u0438\u043C`, "\u041F\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 sberpay-cli; \u043F\u0440\u0430\u0432\u0430 \u043D\u0430 \u0445\u0435\u043B\u043F\u0435\u0440 \u0438 \u0435\u0433\u043E \u043A\u0430\u0442\u0430\u043B\u043E\u0433: Unix 0755; Windows \u2014 \u0437\u0430\u043F\u0438\u0441\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0443, SYSTEM \u0438 Administrators");
35085
35209
  }
35086
35210
  return path2;
35087
35211
  }
@@ -35112,7 +35236,7 @@ function helperError(action2, error62, softwareAllowed) {
35112
35236
  function osSecretStore(standName, stand, opts = {}) {
35113
35237
  const { env = process.env, platform: platform2 = process.platform } = opts;
35114
35238
  let secrets;
35115
- const open7 = () => {
35239
+ const open8 = () => {
35116
35240
  if (secrets) return secrets;
35117
35241
  const backend = keyHelperBackend(platform2);
35118
35242
  if (!backend) throw keyringError(`\u041D\u0430 ${platform2} \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043E\u0432 \u041E\u0421 \u043D\u0435\u0442`, FILE_HINT);
@@ -35125,7 +35249,7 @@ function osSecretStore(standName, stand, opts = {}) {
35125
35249
  return secrets;
35126
35250
  };
35127
35251
  const call = (action2, fn, name) => {
35128
- const store = open7();
35252
+ const store = open8();
35129
35253
  try {
35130
35254
  return fn(store, `${standName}:${name}`);
35131
35255
  } catch (error62) {
@@ -35147,9 +35271,14 @@ function osSecretStore(standName, stand, opts = {}) {
35147
35271
  }
35148
35272
  function fileSecretStore(paths, stand) {
35149
35273
  const file2 = join19(paths.configDir, `secrets.${stand}.json`);
35150
- const read = () => existsSync6(file2) ? JSON.parse(readFileSync9(file2, "utf8")) : {};
35274
+ const read = () => {
35275
+ if (!existsSync7(file2)) return {};
35276
+ if (process.platform === "win32") assertWindowsPrivatePath(file2);
35277
+ return JSON.parse(readFileSync9(file2, "utf8"));
35278
+ };
35151
35279
  const write = (data) => {
35152
- mkdirSync8(paths.configDir, { recursive: true, mode: 448 });
35280
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(paths.configDir);
35281
+ else mkdirSync8(paths.configDir, { recursive: true, mode: 448 });
35153
35282
  if (Object.keys(data).length === 0) return rmSync5(file2, { force: true });
35154
35283
  const tmp = `${file2}.${process.pid}.tmp`;
35155
35284
  writeFileSync4(tmp, JSON.stringify(data), { mode: 384 });
@@ -35170,22 +35299,18 @@ function openSecretStore(paths, standName, stand, opts = {}) {
35170
35299
  const env = opts.env ?? process.env;
35171
35300
  if (env.SBERPAY_CLI_SECRETS !== "file")
35172
35301
  return osSecretStore(standName, stand, opts);
35173
- if (standName === "prod") {
35174
- throw new CliError(
35175
- EXIT.CONFIG_OR_NETWORK,
35176
- "INSECURE_SECRETS",
35177
- "\u041D\u0430 \u0441\u0442\u0435\u043D\u0434\u0435 prod \u0441\u0435\u043A\u0440\u0435\u0442\u044B \u0445\u0440\u0430\u043D\u044F\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u041E\u0421",
35178
- { hint: "\u0423\u0431\u0435\u0440\u0438\u0442\u0435 SBERPAY_CLI_SECRETS=file" }
35179
- );
35180
- }
35181
35302
  return fileSecretStore(paths, standName);
35182
35303
  }
35183
35304
 
35184
35305
  // packages/cli/src/core/context.ts
35185
35306
  var DEFAULT_LOGGING = join20(BUILD.root, "config", "logging.yaml");
35186
35307
  function fileSink(paths, verbose) {
35187
- mkdirSync9(paths.stateDir, { recursive: true, mode: 448 });
35308
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(paths.stateDir);
35309
+ else mkdirSync9(paths.stateDir, { recursive: true, mode: 448 });
35188
35310
  const logFile = join20(paths.stateDir, "cli.log");
35311
+ if (process.platform === "win32") {
35312
+ if (existsSync8(logFile)) assertWindowsPrivatePath(logFile);
35313
+ }
35189
35314
  return (line) => {
35190
35315
  appendFileSync(logFile, `${line}
35191
35316
  `, { mode: 384 });
@@ -35207,6 +35332,7 @@ function fileLogger(paths, verbose) {
35207
35332
  function buildCoreContext(opts, overridePaths) {
35208
35333
  const out = createOutput(Boolean(opts.json));
35209
35334
  const paths = overridePaths ?? cliPaths();
35335
+ if (process.platform === "win32") for (const path2 of Object.values(paths)) ensureWindowsPrivateDirectory(path2);
35210
35336
  const config2 = loadConfig(paths);
35211
35337
  const requested = opts.stand ?? config2.stand;
35212
35338
  if (!isStand(requested)) throw new CliError(EXIT.VALIDATION, "INVALID_ARGUMENT", `\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0441\u0442\u0435\u043D\u0434 \xAB${requested}\xBB: ${STAND_NAMES.join(", ")}`);
@@ -35235,7 +35361,7 @@ function buildCoreContext(opts, overridePaths) {
35235
35361
  }
35236
35362
 
35237
35363
  // packages/cli/src/schemes/v2/deviceKeys.ts
35238
- import { existsSync as existsSync7 } from "node:fs";
35364
+ import { existsSync as existsSync9 } from "node:fs";
35239
35365
  import { join as join21 } from "node:path";
35240
35366
  var DEVICE_SECRETS = ["deviceSignKey", "deviceEncKey"];
35241
35367
  var SOFTWARE_ORDER = ["hardware", "os", "file"];
@@ -35267,12 +35393,13 @@ async function selectDeviceKeys(core, sel = {}) {
35267
35393
  if (pref !== "auto" && !allowed.includes(pref)) {
35268
35394
  throw unavailable2(
35269
35395
  `\u0421\u0442\u0435\u043D\u0434 ${core.standName}: \u043A\u043B\u044E\u0447\u0438 \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0430 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 Secure Enclave \u0438\u043B\u0438 TPM, \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 ${pref} \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u043E`,
35270
- "\u0414\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0431\u0435\u0437 \u0447\u0438\u043F\u0430 \u2014 \u0441\u0442\u0435\u043D\u0434 local \u0438\u043B\u0438 ift (OQ-131)"
35396
+ "\u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u0431\u0435\u0437 \u0447\u0438\u043F\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u043D\u044B\u0435 \u043A\u043B\u044E\u0447\u0438: allowSoftwareKeys: true"
35271
35397
  );
35272
35398
  }
35273
35399
  const backend = keyHelperBackend(platform2);
35274
35400
  const hint = backend ? keyHelperBuildHint(backend) : `\u041D\u0430 ${platform2} \u0430\u043F\u043F\u0430\u0440\u0430\u0442\u043D\u044B\u0445 \u043A\u043B\u044E\u0447\u0435\u0439 \u043D\u0435\u0442`;
35275
35401
  const hardwareFile = backend && hardwareKeyFile(core, backend.kind);
35402
+ if (process.platform === "win32" && hardwareFile && existsSync9(hardwareFile)) assertWindowsPrivatePath(hardwareFile);
35276
35403
  let helperLookup;
35277
35404
  const keyHelper = () => {
35278
35405
  helperLookup ??= { path: backend && findKeyHelper({ override: overrides.SBERPAY_KEY_HELPER, installed: sel.installedHelper ?? backend.path }) };
@@ -35291,7 +35418,7 @@ async function selectDeviceKeys(core, sel = {}) {
35291
35418
  const cached2 = probes.get(storage);
35292
35419
  if (cached2) return cached2;
35293
35420
  const result = (() => {
35294
- if (storage === "hardware") return { ok: true, hasKeys: Boolean(hardwareFile && existsSync7(hardwareFile)) };
35421
+ if (storage === "hardware") return { ok: true, hasKeys: Boolean(hardwareFile && existsSync9(hardwareFile)) };
35295
35422
  try {
35296
35423
  return { ok: true, hasKeys: stores[storage]().get(SIGN_KEY_NAME) !== void 0 };
35297
35424
  } catch {
@@ -35349,7 +35476,7 @@ async function selectDeviceKeys(core, sel = {}) {
35349
35476
  throw unavailable2("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u041E\u0421 (keyring) \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E", "\u041D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435 \u0431\u0435\u0437 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043A\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438: sberpay-cli auth login --key-storage file");
35350
35477
  throw unavailable2(
35351
35478
  softwareAllowed ? "\u041D\u0435\u0442 \u043D\u0438 \u0447\u0438\u043F\u0430, \u043D\u0438 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u043A\u043B\u044E\u0447\u0435\u0439" : `\u0421\u0442\u0435\u043D\u0434 ${core.standName}: \u043D\u0443\u0436\u0435\u043D \u043A\u043B\u044E\u0447 \u0432 Secure Enclave \u0438\u043B\u0438 TPM, \u0430 \u0447\u0438\u043F \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D`,
35352
- softwareAllowed ? hint : `${hint}. \u0414\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0431\u0435\u0437 \u0447\u0438\u043F\u0430 \u2014 \u0441\u0442\u0435\u043D\u0434 local \u0438\u043B\u0438 ift (OQ-131)`
35479
+ softwareAllowed ? hint : `${hint}. \u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u0431\u0435\u0437 \u0447\u0438\u043F\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u043D\u044B\u0435 \u043A\u043B\u044E\u0447\u0438: allowSoftwareKeys: true`
35353
35480
  );
35354
35481
  }
35355
35482
  async function keyHelperStatus(platform2 = process.platform, installedHelper) {
@@ -35369,11 +35496,11 @@ async function keyHelperStatus(platform2 = process.platform, installedHelper) {
35369
35496
  }
35370
35497
  function deviceKeysExist(core, platform2 = process.platform, env = process.env) {
35371
35498
  const backend = keyHelperBackend(platform2);
35372
- if (backend && existsSync7(hardwareKeyFile(core, backend.kind))) return true;
35499
+ if (backend && existsSync9(hardwareKeyFile(core, backend.kind))) return true;
35373
35500
  if (!core.stand.allowSoftwareKeys) return false;
35374
- const has = (open7) => {
35501
+ const has = (open8) => {
35375
35502
  try {
35376
- return open7().get(SIGN_KEY_NAME) !== void 0;
35503
+ return open8().get(SIGN_KEY_NAME) !== void 0;
35377
35504
  } catch {
35378
35505
  return false;
35379
35506
  }
@@ -38229,7 +38356,7 @@ async function prepareBinding(ctx, mode) {
38229
38356
  // packages/cli/src/schemes/v2/binding/launcher.ts
38230
38357
  import { spawn as spawn3 } from "node:child_process";
38231
38358
  import { openSync as openSync7, closeSync as closeSync7, mkdirSync as mkdirSync11 } from "node:fs";
38232
- import { dirname as dirname7, join as join23 } from "node:path";
38359
+ import { dirname as dirname9, join as join23 } from "node:path";
38233
38360
  import { fileURLToPath as fileURLToPath2 } from "node:url";
38234
38361
  var Reply = external_exports.discriminatedUnion("type", [
38235
38362
  external_exports.object({ type: external_exports.literal("READY"), generation: external_exports.string() }),
@@ -38238,8 +38365,8 @@ var Reply = external_exports.discriminatedUnion("type", [
38238
38365
  ]);
38239
38366
  async function startLocalBinding(ctx, opts) {
38240
38367
  const scope = bindingScope(ctx);
38241
- const log = join23(dirname7(scope.recordPath), "worker.log");
38242
- mkdirSync11(dirname7(log), { recursive: true, mode: 448 });
38368
+ const log = join23(dirname9(scope.recordPath), "worker.log");
38369
+ mkdirSync11(dirname9(log), { recursive: true, mode: 448 });
38243
38370
  const fd2 = openSync7(log, "a", 384);
38244
38371
  let child;
38245
38372
  try {
@@ -38876,19 +39003,19 @@ function createScheme(core) {
38876
39003
  }
38877
39004
 
38878
39005
  // packages/cli/src/setup/command.ts
38879
- import { spawnSync as spawnSync3 } from "node:child_process";
39006
+ import { spawnSync as spawnSync4 } from "node:child_process";
38880
39007
  import { createInterface } from "node:readline/promises";
38881
39008
 
38882
39009
  // packages/cli/src/setup/collect.ts
38883
- import { existsSync as existsSync10 } from "node:fs";
39010
+ import { existsSync as existsSync12 } from "node:fs";
38884
39011
  import { homedir as homedir7 } from "node:os";
38885
39012
  import { resolve as resolve5 } from "node:path";
38886
39013
 
38887
39014
  // packages/cli/src/ca/rootCa.ts
38888
39015
  import { randomBytes as randomBytes3, X509Certificate as X509Certificate2 } from "node:crypto";
38889
- import { closeSync as closeSync8, existsSync as existsSync8, fchmodSync, lstatSync as lstatSync5, mkdirSync as mkdirSync12, mkdtempSync, openSync as openSync8, readFileSync as readFileSync12, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync5, writeSync as writeSync4 } from "node:fs";
39016
+ import { closeSync as closeSync8, existsSync as existsSync10, fchmodSync, lstatSync as lstatSync6, mkdirSync as mkdirSync12, mkdtempSync, openSync as openSync8, readFileSync as readFileSync12, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync5, writeSync as writeSync4 } from "node:fs";
38890
39017
  import { tmpdir } from "node:os";
38891
- import { dirname as dirname8, join as join24, resolve as resolve3 } from "node:path";
39018
+ import { dirname as dirname10, join as join24, resolve as resolve3 } from "node:path";
38892
39019
  var FETCH_TIMEOUT_MS = 15e3;
38893
39020
  var LOGIN_KEYCHAIN = "Library/Keychains/login.keychain-db";
38894
39021
  var SECURITY_BIN = "/usr/bin/security";
@@ -38920,11 +39047,11 @@ function verifyRootCert(data, root, now = /* @__PURE__ */ new Date()) {
38920
39047
  }
38921
39048
  function readFetchedRoot(paths, root = RUSSIAN_TRUSTED_ROOT_CA) {
38922
39049
  const file2 = rootCaFile(paths, root);
38923
- return existsSync8(file2) ? verifyRootCert(readFileSync12(file2), root) : void 0;
39050
+ return existsSync10(file2) ? verifyRootCert(readFileSync12(file2), root) : void 0;
38924
39051
  }
38925
39052
  function ensureCaDir(dir2) {
38926
39053
  mkdirSync12(dir2, { recursive: true, mode: 448 });
38927
- const stat4 = lstatSync5(dir2);
39054
+ const stat4 = lstatSync6(dir2);
38928
39055
  const foreign = typeof process.getuid === "function" && stat4.uid !== process.getuid();
38929
39056
  if (stat4.isSymbolicLink() || !stat4.isDirectory() || foreign) {
38930
39057
  throw new CliError(EXIT.CONFIG_OR_NETWORK, "CA_DIR_UNSAFE", `${dir2} \u2014 \u043D\u0435 \u0441\u0432\u043E\u0439 \u043A\u0430\u0442\u0430\u043B\u043E\u0433 (\u0441\u0438\u043C\u043B\u0438\u043D\u043A \u0438\u043B\u0438 \u0447\u0443\u0436\u043E\u0439 \u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446): \u0444\u0430\u0439\u043B \u043A\u043E\u0440\u043D\u044F \u0442\u0443\u0434\u0430 \u043D\u0435 \u043F\u0438\u0448\u0435\u043C`, {
@@ -38933,7 +39060,7 @@ function ensureCaDir(dir2) {
38933
39060
  }
38934
39061
  }
38935
39062
  function writeAtomically(path2, data, mode) {
38936
- const tmp = join24(dirname8(path2), `.${randomBytes3(6).toString("hex")}.tmp`);
39063
+ const tmp = join24(dirname10(path2), `.${randomBytes3(6).toString("hex")}.tmp`);
38937
39064
  const fd2 = openSync8(tmp, "wx", mode);
38938
39065
  try {
38939
39066
  fchmodSync(fd2, mode);
@@ -38953,7 +39080,7 @@ async function fetchRootCa(deps) {
38953
39080
  const data = await callBytes(deps.logger, { op: `\u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u0440\u043D\u044F ${root.name}`, peer: "\u0413\u043E\u0441\u0443\u0441\u043B\u0443\u0433\u0438", url: root.sourceUrl, timeoutMs: FETCH_TIMEOUT_MS });
38954
39081
  const cert = verifyRootCert(data, root);
38955
39082
  const path2 = rootCaFile(deps.paths, root);
38956
- ensureCaDir(dirname8(path2));
39083
+ ensureCaDir(dirname10(path2));
38957
39084
  writeAtomically(path2, cert.toString(), 420);
38958
39085
  return { path: path2, jwkThumbprint: root.jwkThumbprint, fingerprint256: cert.fingerprint256, validTo: new Date(cert.validTo).toISOString(), sourceUrl: root.sourceUrl };
38959
39086
  }
@@ -39033,9 +39160,9 @@ function installRootCa(deps) {
39033
39160
 
39034
39161
  // packages/cli/src/setup/skill.ts
39035
39162
  import { createHash as createHash16 } from "node:crypto";
39036
- import { cpSync, existsSync as existsSync9, lstatSync as lstatSync6, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as readFileSync13, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync6, rmSync as rmSync8, statSync as statSync2, symlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
39163
+ import { cpSync, existsSync as existsSync11, lstatSync as lstatSync7, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as readFileSync13, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync6, rmSync as rmSync8, statSync as statSync2, symlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
39037
39164
  import { homedir as homedir6 } from "node:os";
39038
- import { basename, dirname as dirname9, join as join25, relative as relative3, resolve as resolve4 } from "node:path";
39165
+ import { basename, dirname as dirname11, join as join25, relative as relative3, resolve as resolve4 } from "node:path";
39039
39166
  var SKILL_NAME = "sberpay";
39040
39167
  var MANIFEST = ".sberpay-cli.json";
39041
39168
  var WORK_DIR = ".sberpay-cli";
@@ -39068,14 +39195,14 @@ function sameDir(a, b) {
39068
39195
  }
39069
39196
  function isLink(path2) {
39070
39197
  try {
39071
- return lstatSync6(path2).isSymbolicLink();
39198
+ return lstatSync7(path2).isSymbolicLink();
39072
39199
  } catch {
39073
39200
  return false;
39074
39201
  }
39075
39202
  }
39076
39203
  function readManifest(target) {
39077
39204
  const file2 = join25(target, MANIFEST);
39078
- if (!existsSync9(file2)) return void 0;
39205
+ if (!existsSync11(file2)) return void 0;
39079
39206
  try {
39080
39207
  const data = JSON.parse(readFileSync13(file2, "utf8"));
39081
39208
  return typeof data.version === "string" && data.files && typeof data.files === "object" ? data : void 0;
@@ -39083,13 +39210,13 @@ function readManifest(target) {
39083
39210
  return void 0;
39084
39211
  }
39085
39212
  }
39086
- var isStaleOwnLink = (target) => !existsSync9(target) && readlinkSync(target).replace(/[\\/]+$/, "").endsWith(join25("skill", SKILL_NAME));
39213
+ var isStaleOwnLink = (target) => !existsSync11(target) && readlinkSync(target).replace(/[\\/]+$/, "").endsWith(join25("skill", SKILL_NAME));
39087
39214
  function inspectSkill(source, target) {
39088
39215
  if (isLink(target)) {
39089
- if (existsSync9(target)) return sameDir(target, source) ? { state: "current", mode: "link" } : { state: "foreign" };
39216
+ if (existsSync11(target)) return sameDir(target, source) ? { state: "current", mode: "link" } : { state: "foreign" };
39090
39217
  return isStaleOwnLink(target) ? { state: "outdated", mode: "link" } : { state: "foreign" };
39091
39218
  }
39092
- if (!existsSync9(target)) return { state: "missing" };
39219
+ if (!existsSync11(target)) return { state: "missing" };
39093
39220
  const manifest = readManifest(target);
39094
39221
  if (!manifest) return { state: "foreign" };
39095
39222
  if (!sameFiles(hashFiles(target), manifest.files)) return { state: "modified", mode: "copy" };
@@ -39109,7 +39236,7 @@ function prepare(source, work, mode, version2) {
39109
39236
  return fresh;
39110
39237
  }
39111
39238
  function swap(fresh, target, aside, work) {
39112
- const previous = existsSync9(target) || isLink(target) ? aside ?? join25(work, `old-${process.pid}`) : void 0;
39239
+ const previous = existsSync11(target) || isLink(target) ? aside ?? join25(work, `old-${process.pid}`) : void 0;
39113
39240
  if (previous) renameSync6(target, previous);
39114
39241
  try {
39115
39242
  renameSync6(fresh, target);
@@ -39129,7 +39256,7 @@ function installSkill(source, target, opts) {
39129
39256
  hint: "\u041F\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C: sberpay-cli setup --force-skill \u2014 \u043F\u0440\u0435\u0436\u043D\u0438\u0439 \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u0443\u0439\u0434\u0451\u0442 \u0432 \u0431\u044D\u043A\u0430\u043F"
39130
39257
  });
39131
39258
  }
39132
- const work = join25(dirname9(target), WORK_DIR);
39259
+ const work = join25(dirname11(target), WORK_DIR);
39133
39260
  mkdirSync13(work, { recursive: true });
39134
39261
  const backup = ours ? void 0 : join25(work, `backup-${basename(target)}-${(opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`);
39135
39262
  const fresh = prepare(source, work, opts.mode, opts.version);
@@ -39511,7 +39638,7 @@ function rootStep(stand, paths, root) {
39511
39638
  platform: process.platform,
39512
39639
  file: rootCaFile(paths, root),
39513
39640
  home: homedir7(),
39514
- exists: existsSync10,
39641
+ exists: existsSync12,
39515
39642
  cert
39516
39643
  });
39517
39644
  return rootCaStep({
@@ -39608,10 +39735,10 @@ function run2(argv) {
39608
39735
  const self = process.argv[1];
39609
39736
  if (!head || head === "sberpay-cli" && !self) return false;
39610
39737
  const nested = head === "sberpay-cli" && rest.includes("setup");
39611
- const result = head === "sberpay-cli" ? spawnSync3(process.execPath, [...process.execArgv, self, ...rest, ...nested ? ["--yes", "--json"] : []], {
39738
+ const result = head === "sberpay-cli" ? spawnSync4(process.execPath, [...process.execArgv, self, ...rest, ...nested ? ["--yes", "--json"] : []], {
39612
39739
  stdio: nested ? ["inherit", "pipe", "inherit"] : "inherit",
39613
39740
  encoding: "utf8"
39614
- }) : spawnSync3(head, rest, { stdio: "inherit", cwd: BUILD.root, shell: process.platform === "win32" });
39741
+ }) : spawnSync4(head, rest, { stdio: "inherit", cwd: BUILD.root, shell: process.platform === "win32" });
39615
39742
  if (result.error) process.stderr.write(`\u2717 \u041D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B\u043E\u0441\u044C ${argv.join(" ")}: ${result.error.message}
39616
39743
  `);
39617
39744
  if (nested && typeof result.stdout === "string") reportNestedError(result.stdout);
@@ -39665,14 +39792,14 @@ async function setupCommand(globals, opts) {
39665
39792
  }
39666
39793
 
39667
39794
  // packages/cli/src/ca/command.ts
39668
- import { spawnSync as spawnSync4 } from "node:child_process";
39669
- import { existsSync as existsSync11 } from "node:fs";
39795
+ import { spawnSync as spawnSync5 } from "node:child_process";
39796
+ import { existsSync as existsSync13 } from "node:fs";
39670
39797
  import { homedir as homedir8 } from "node:os";
39671
39798
  var INSTALL_TIMEOUT_MS = 12e4;
39672
39799
  var WHERE = { system: "\u0432 \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0445 \u043A\u043E\u0440\u043D\u044F\u0445 \u0441\u0438\u0441\u0442\u0435\u043C\u044B", extra: "\u0438\u0437 NODE_EXTRA_CA_CERTS (\u0441\u0438\u0441\u0442\u0435\u043C\u0430 \u0435\u0433\u043E \u043D\u0435 \u0437\u043D\u0430\u0435\u0442)" };
39673
39800
  function runSecurity(argv) {
39674
39801
  const [head = "", ...rest] = argv;
39675
- const result = spawnSync4(head, rest, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: INSTALL_TIMEOUT_MS });
39802
+ const result = spawnSync5(head, rest, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: INSTALL_TIMEOUT_MS });
39676
39803
  return { status: result.status, stderr: result.error ? result.error.message : result.stderr };
39677
39804
  }
39678
39805
  function caStatusCommand(globals) {
@@ -39707,7 +39834,7 @@ async function caFetchCommand(globals) {
39707
39834
  function caInstallCommand(globals) {
39708
39835
  const out = createOutput(Boolean(globals.json));
39709
39836
  out.progress("\u0414\u043E\u0431\u0430\u0432\u043B\u044F\u044E \u043A\u043E\u0440\u0435\u043D\u044C \u0432 \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0435 \u043A\u043E\u0440\u043D\u0438 \u0441\u0438\u0441\u0442\u0435\u043C\u044B \u2014 \u0441\u0438\u0441\u0442\u0435\u043C\u0430 \u043C\u043E\u0436\u0435\u0442 \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C\u2026");
39710
- const result = installRootCa({ paths: cliPaths(), platform: process.platform, home: homedir8(), exists: existsSync11, run: runSecurity });
39837
+ const result = installRootCa({ paths: cliPaths(), platform: process.platform, home: homedir8(), exists: existsSync13, run: runSecurity });
39711
39838
  const human = result.installed ? `\u2713 ${result.say}` : [`\u041A\u043E\u043C\u0430\u043D\u0434\u0443 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A: ${result.command ?? "\u2014"}`, ` ${result.say}`].join("\n");
39712
39839
  out.result(result, human);
39713
39840
  }