@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.
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +5494 -0
- package/build-info.json +4 -4
- package/dist/npm-entry.mjs +309 -149
- package/manifest.json +9 -7
- package/package/SHA256SUMS +6 -4
- package/package/THIRD_PARTY_NOTICES.md +5494 -0
- package/package/dist/binding-worker.mjs +131 -46
- package/package/dist/cli.mjs +260 -133
- package/package/helpers/win32-arm64/sberpay-tpm.exe +0 -0
- package/package/helpers/win32-x64/sberpay-tpm.exe +0 -0
- package/package/package.json +3 -2
- package/package.json +5 -4
package/dist/npm-entry.mjs
CHANGED
|
@@ -708,7 +708,7 @@ var require_graceful_fs = __commonJS({
|
|
|
708
708
|
}
|
|
709
709
|
function ReadStream$open() {
|
|
710
710
|
var that = this;
|
|
711
|
-
|
|
711
|
+
open8(that.path, that.flags, that.mode, function(err, fd) {
|
|
712
712
|
if (err) {
|
|
713
713
|
if (that.autoClose)
|
|
714
714
|
that.destroy();
|
|
@@ -728,7 +728,7 @@ var require_graceful_fs = __commonJS({
|
|
|
728
728
|
}
|
|
729
729
|
function WriteStream$open() {
|
|
730
730
|
var that = this;
|
|
731
|
-
|
|
731
|
+
open8(that.path, that.flags, that.mode, function(err, fd) {
|
|
732
732
|
if (err) {
|
|
733
733
|
that.destroy();
|
|
734
734
|
that.emit("error", err);
|
|
@@ -745,8 +745,8 @@ var require_graceful_fs = __commonJS({
|
|
|
745
745
|
return new fs2.WriteStream(path, options);
|
|
746
746
|
}
|
|
747
747
|
var fs$open = fs2.open;
|
|
748
|
-
fs2.open =
|
|
749
|
-
function
|
|
748
|
+
fs2.open = open8;
|
|
749
|
+
function open8(path, flags, mode, cb) {
|
|
750
750
|
if (typeof mode === "function")
|
|
751
751
|
cb = mode, mode = null;
|
|
752
752
|
return go$open(path, flags, mode, cb);
|
|
@@ -1618,27 +1618,13 @@ var require_proper_lockfile = __commonJS({
|
|
|
1618
1618
|
|
|
1619
1619
|
// scripts/diagnostics/npm-entry.mts
|
|
1620
1620
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
1621
|
-
import { dirname as
|
|
1621
|
+
import { dirname as dirname7, join as join11 } from "node:path";
|
|
1622
1622
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
1623
1623
|
import { homedir as homedir4 } from "node:os";
|
|
1624
1624
|
|
|
1625
|
-
// packages/cli/src/core/
|
|
1626
|
-
import {
|
|
1627
|
-
import {
|
|
1628
|
-
function cliPaths(env = process.env) {
|
|
1629
|
-
const home = env.SBERPAY_CLI_HOME;
|
|
1630
|
-
if (home) return { configDir: join(home, "config"), cacheDir: join(home, "cache"), stateDir: join(home, "state") };
|
|
1631
|
-
const h = homedir();
|
|
1632
|
-
return {
|
|
1633
|
-
configDir: join(env.XDG_CONFIG_HOME ?? join(h, ".config"), "sberpay-cli"),
|
|
1634
|
-
cacheDir: join(env.XDG_CACHE_HOME ?? join(h, ".cache"), "sberpay-cli"),
|
|
1635
|
-
stateDir: join(env.XDG_STATE_HOME ?? join(h, ".local", "state"), "sberpay-cli")
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
// packages/cli/src/paymentMode/state.ts
|
|
1640
|
-
import { lstatSync, readFileSync, openSync as openSync2, closeSync as closeSync2, fstatSync, constants } from "node:fs";
|
|
1641
|
-
import { join as join2 } from "node:path";
|
|
1625
|
+
// packages/cli/src/core/windowsAcl.ts
|
|
1626
|
+
import { spawnSync } from "node:child_process";
|
|
1627
|
+
import { dirname, win32 } from "node:path";
|
|
1642
1628
|
|
|
1643
1629
|
// node_modules/zod/v4/classic/external.js
|
|
1644
1630
|
var external_exports = {};
|
|
@@ -2362,9 +2348,9 @@ function floatSafeRemainder(val, step) {
|
|
|
2362
2348
|
return ratio - roundedRatio;
|
|
2363
2349
|
}
|
|
2364
2350
|
var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
|
|
2365
|
-
function defineLazy(
|
|
2351
|
+
function defineLazy(object2, key, getter) {
|
|
2366
2352
|
let value = void 0;
|
|
2367
|
-
Object.defineProperty(
|
|
2353
|
+
Object.defineProperty(object2, key, {
|
|
2368
2354
|
get() {
|
|
2369
2355
|
if (value === EVALUATING) {
|
|
2370
2356
|
return void 0;
|
|
@@ -2376,7 +2362,7 @@ function defineLazy(object3, key, getter) {
|
|
|
2376
2362
|
return value;
|
|
2377
2363
|
},
|
|
2378
2364
|
set(v) {
|
|
2379
|
-
Object.defineProperty(
|
|
2365
|
+
Object.defineProperty(object2, key, {
|
|
2380
2366
|
value: v
|
|
2381
2367
|
// configurable: true,
|
|
2382
2368
|
});
|
|
@@ -17443,8 +17429,8 @@ function foldObjects(members2) {
|
|
|
17443
17429
|
}
|
|
17444
17430
|
const properties = {};
|
|
17445
17431
|
const required2 = /* @__PURE__ */ new Set();
|
|
17446
|
-
for (const
|
|
17447
|
-
for (const key in
|
|
17432
|
+
for (const object2 of objects) {
|
|
17433
|
+
for (const key in object2.properties) {
|
|
17448
17434
|
if (Object.prototype.hasOwnProperty.call(properties, key))
|
|
17449
17435
|
continue;
|
|
17450
17436
|
const parts = [];
|
|
@@ -17458,18 +17444,18 @@ function foldObjects(members2) {
|
|
|
17458
17444
|
const merged = parts.length === 1 ? parts[0] : foldObjects(parts) ?? { allOf: parts };
|
|
17459
17445
|
assignProp(properties, key, merged);
|
|
17460
17446
|
}
|
|
17461
|
-
for (const key of
|
|
17447
|
+
for (const key of object2.required ?? [])
|
|
17462
17448
|
required2.add(key);
|
|
17463
17449
|
}
|
|
17464
17450
|
const folded = { type: "object", properties };
|
|
17465
17451
|
if (required2.size)
|
|
17466
17452
|
folded.required = [...required2];
|
|
17467
|
-
if (objects.every((
|
|
17453
|
+
if (objects.every((object2) => object2.additionalProperties === false)) {
|
|
17468
17454
|
folded.additionalProperties = false;
|
|
17469
17455
|
} else {
|
|
17470
17456
|
const constraints = [];
|
|
17471
|
-
for (const
|
|
17472
|
-
const constraint = undeclaredConstraint(
|
|
17457
|
+
for (const object2 of objects) {
|
|
17458
|
+
const constraint = undeclaredConstraint(object2);
|
|
17473
17459
|
if (constraint && !constraints.some((seen) => JSON.stringify(seen) === JSON.stringify(constraint)))
|
|
17474
17460
|
constraints.push(constraint);
|
|
17475
17461
|
}
|
|
@@ -21308,12 +21294,135 @@ function date4(params) {
|
|
|
21308
21294
|
return _coercedDate(ZodDate, params);
|
|
21309
21295
|
}
|
|
21310
21296
|
|
|
21297
|
+
// packages/cli/src/core/windowsAcl.ts
|
|
21298
|
+
var Sid = external_exports.string().regex(/^S-1-(?:\d+-)*\d+$/);
|
|
21299
|
+
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) });
|
|
21300
|
+
var WRITE_ACCESS = 852310 | 1342177280;
|
|
21301
|
+
function assertWindowsAcl(value, policy) {
|
|
21302
|
+
const parsed = Inspection.safeParse(value);
|
|
21303
|
+
if (!parsed.success) throw Error("WINDOWS_ACL_UNSAFE");
|
|
21304
|
+
const s = parsed.data, trusted = /* @__PURE__ */ new Set([s.currentUser, "S-1-5-18", "S-1-5-32-544"]);
|
|
21305
|
+
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");
|
|
21306
|
+
}
|
|
21307
|
+
var SCRIPT = String.raw`
|
|
21308
|
+
$ErrorActionPreference='Stop'
|
|
21309
|
+
[Console]::OutputEncoding=New-Object System.Text.UTF8Encoding($false)
|
|
21310
|
+
$p=[IO.Path]::GetFullPath($env:SBERPAY_ACL_PATH)
|
|
21311
|
+
$cursor=$p
|
|
21312
|
+
while($cursor){
|
|
21313
|
+
if(Test-Path -LiteralPath $cursor){
|
|
21314
|
+
$item=Get-Item -LiteralPath $cursor -Force
|
|
21315
|
+
if(($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0){throw 'REPARSE_POINT'}
|
|
21316
|
+
}
|
|
21317
|
+
$next=[IO.Path]::GetDirectoryName($cursor)
|
|
21318
|
+
if($next -eq $cursor){break};$cursor=$next
|
|
21319
|
+
}
|
|
21320
|
+
$sid=[Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
21321
|
+
if($env:SBERPAY_ACL_ACTION -eq 'create' -and !(Test-Path -LiteralPath $p)){
|
|
21322
|
+
$acl=New-Object Security.AccessControl.DirectorySecurity
|
|
21323
|
+
$acl.SetOwner($sid);$acl.SetAccessRuleProtection($true,$false)
|
|
21324
|
+
foreach($id in @($sid.Value,'S-1-5-18','S-1-5-32-544')){
|
|
21325
|
+
$principal=New-Object Security.Principal.SecurityIdentifier($id)
|
|
21326
|
+
$rule=New-Object Security.AccessControl.FileSystemAccessRule($principal,'FullControl','ContainerInherit,ObjectInherit','None','Allow')
|
|
21327
|
+
$acl.AddAccessRule($rule)
|
|
21328
|
+
}
|
|
21329
|
+
[IO.Directory]::CreateDirectory($p,$acl)|Out-Null
|
|
21330
|
+
}
|
|
21331
|
+
$acl=Get-Acl -LiteralPath $p
|
|
21332
|
+
$rules=@($acl.GetAccessRules($true,$true,[Security.Principal.SecurityIdentifier])|ForEach-Object{
|
|
21333
|
+
@{sid=$_.IdentityReference.Value;allow=($_.AccessControlType -eq 'Allow');rights=[int]$_.FileSystemRights}
|
|
21334
|
+
})
|
|
21335
|
+
@{owner=$acl.GetOwner([Security.Principal.SecurityIdentifier]).Value;currentUser=$sid.Value;reparse=$false;rules=$rules}|ConvertTo-Json -Compress -Depth 5
|
|
21336
|
+
`;
|
|
21337
|
+
function windowsAclCommand(path, action, env = process.env) {
|
|
21338
|
+
const root2 = env.SystemRoot;
|
|
21339
|
+
if (!root2 || !win32.isAbsolute(root2)) throw Error("WINDOWS_SYSTEM_ROOT_MISSING");
|
|
21340
|
+
return { file: win32.join(root2, "System32", "WindowsPowerShell", "v1.0", "powershell.exe"), args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(SCRIPT, "utf16le").toString("base64")], env: { SystemRoot: root2, SBERPAY_ACL_PATH: path, SBERPAY_ACL_ACTION: action } };
|
|
21341
|
+
}
|
|
21342
|
+
function inspect(path, policy, action) {
|
|
21343
|
+
const c = windowsAclCommand(path, action);
|
|
21344
|
+
const r = spawnSync(c.file, c.args, { env: c.env, encoding: "utf8", windowsHide: true, timeout: 1e4, maxBuffer: 128 * 1024 });
|
|
21345
|
+
if (r.error || r.status !== 0) throw Error("WINDOWS_ACL_CHECK_FAILED");
|
|
21346
|
+
let value;
|
|
21347
|
+
try {
|
|
21348
|
+
value = JSON.parse(r.stdout.trim().replace(/^\uFEFF/, ""));
|
|
21349
|
+
} catch {
|
|
21350
|
+
throw Error("WINDOWS_ACL_CHECK_FAILED");
|
|
21351
|
+
}
|
|
21352
|
+
assertWindowsAcl(value, policy);
|
|
21353
|
+
}
|
|
21354
|
+
function assertWindowsPrivatePath(path) {
|
|
21355
|
+
inspect(path, "private", "inspect");
|
|
21356
|
+
}
|
|
21357
|
+
function ensureWindowsPrivateDirectory(path) {
|
|
21358
|
+
inspect(path, "private", "create");
|
|
21359
|
+
}
|
|
21360
|
+
|
|
21361
|
+
// packages/cli/src/report/platform.ts
|
|
21362
|
+
import { posix, win32 as win322 } from "node:path";
|
|
21363
|
+
import { createHash } from "node:crypto";
|
|
21364
|
+
var bashQuote = (s) => "'" + s.replaceAll("'", "'\\''") + "'";
|
|
21365
|
+
function diagnosticLauncherCommand(platform, launcher, node2) {
|
|
21366
|
+
return platform === "win32" ? "& " + [node2, launcher].map((s) => "'" + s.replaceAll("'", "''") + "'").join(" ") : bashQuote(launcher);
|
|
21367
|
+
}
|
|
21368
|
+
function skillFileHashes(skill, files, platform = process.platform) {
|
|
21369
|
+
const paths = platform === "win32" ? win322 : posix;
|
|
21370
|
+
return Object.fromEntries(files.flatMap((f) => {
|
|
21371
|
+
const rel = paths.relative(skill, f.path);
|
|
21372
|
+
return rel && !paths.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + paths.sep) ? [[rel.split(paths.sep).join("/"), createHash("sha256").update(f.text).digest("hex")]] : [];
|
|
21373
|
+
}));
|
|
21374
|
+
}
|
|
21375
|
+
function renderDiagnosticSkill(source2, platform, launcher, node2) {
|
|
21376
|
+
if (platform === "win32") source2 = source2.replace(/(\{\{diagnosticLauncher\}\} auth complete --json) <<'TOKEN'\n([\s\S]*?)\nTOKEN/g, "@'\n$2\n'@ | $1").replace(/\\\r?\n\s*/g, " ");
|
|
21377
|
+
return source2.replaceAll("{{diagnosticLauncher}}", diagnosticLauncherCommand(platform, launcher, node2)) + (platform === "win32" ? "\n\u041D\u0430 Windows \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0432\u044B\u0448\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u044E\u0442\u0441\u044F \u0432 PowerShell. \u0414\u043B\u044F Claude Code SessionStart hook \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F Git Bash; CLAUDE_ENV_FILE \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 Bash export, \u0430 \u043D\u0435 PowerShell.\n" : "");
|
|
21378
|
+
}
|
|
21379
|
+
|
|
21380
|
+
// packages/cli/src/core/paths.ts
|
|
21381
|
+
import { homedir } from "node:os";
|
|
21382
|
+
import { join } from "node:path";
|
|
21383
|
+
function cliPaths(env = process.env) {
|
|
21384
|
+
const home = env.SBERPAY_CLI_HOME;
|
|
21385
|
+
if (home) return { configDir: join(home, "config"), cacheDir: join(home, "cache"), stateDir: join(home, "state") };
|
|
21386
|
+
const h = homedir();
|
|
21387
|
+
return {
|
|
21388
|
+
configDir: join(env.XDG_CONFIG_HOME ?? join(h, ".config"), "sberpay-cli"),
|
|
21389
|
+
cacheDir: join(env.XDG_CACHE_HOME ?? join(h, ".cache"), "sberpay-cli"),
|
|
21390
|
+
stateDir: join(env.XDG_STATE_HOME ?? join(h, ".local", "state"), "sberpay-cli")
|
|
21391
|
+
};
|
|
21392
|
+
}
|
|
21393
|
+
|
|
21394
|
+
// packages/cli/src/core/privatePath.ts
|
|
21395
|
+
import { lstatSync } from "node:fs";
|
|
21396
|
+
import { open as open2 } from "node:fs/promises";
|
|
21397
|
+
function assertPrivateFile(path, info) {
|
|
21398
|
+
const named = lstatSync(path);
|
|
21399
|
+
if (!info.isFile() || !named.isFile() || named.isSymbolicLink() || info.ino !== named.ino || info.dev !== named.dev) throw Error("UNSAFE_FILE");
|
|
21400
|
+
if (process.platform === "win32") assertWindowsPrivatePath(path);
|
|
21401
|
+
else if (process.getuid && info.uid !== process.getuid() || info.mode & 63) throw Error("UNSAFE_FILE");
|
|
21402
|
+
}
|
|
21403
|
+
async function syncDirectory(path) {
|
|
21404
|
+
if (process.platform === "win32") return;
|
|
21405
|
+
const f = await open2(path, "r");
|
|
21406
|
+
try {
|
|
21407
|
+
await f.sync();
|
|
21408
|
+
} finally {
|
|
21409
|
+
await f.close();
|
|
21410
|
+
}
|
|
21411
|
+
}
|
|
21412
|
+
|
|
21413
|
+
// packages/cli/src/paymentMode/state.ts
|
|
21414
|
+
import { lstatSync as lstatSync2, readFileSync, openSync as openSync2, closeSync as closeSync2, fstatSync, constants } from "node:fs";
|
|
21415
|
+
import { join as join2 } from "node:path";
|
|
21416
|
+
|
|
21311
21417
|
// packages/cli/src/core/atomicFile.ts
|
|
21312
|
-
import { mkdirSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, rmSync } from "node:fs";
|
|
21313
|
-
import { dirname } from "node:path";
|
|
21418
|
+
import { mkdirSync, existsSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, rmSync } from "node:fs";
|
|
21419
|
+
import { dirname as dirname2 } from "node:path";
|
|
21314
21420
|
import { randomUUID } from "node:crypto";
|
|
21315
21421
|
function atomicJson(path, value) {
|
|
21316
|
-
|
|
21422
|
+
if (process.platform === "win32") {
|
|
21423
|
+
ensureWindowsPrivateDirectory(dirname2(path));
|
|
21424
|
+
if (existsSync(path)) assertWindowsPrivatePath(path);
|
|
21425
|
+
} else mkdirSync(dirname2(path), { recursive: true, mode: 448 });
|
|
21317
21426
|
const temp = `${path}.${randomUUID()}.tmp`;
|
|
21318
21427
|
try {
|
|
21319
21428
|
const fd = openSync(temp, "wx", 384);
|
|
@@ -21325,7 +21434,7 @@ function atomicJson(path, value) {
|
|
|
21325
21434
|
}
|
|
21326
21435
|
renameSync(temp, path);
|
|
21327
21436
|
if (process.platform !== "win32") {
|
|
21328
|
-
const dir = openSync(
|
|
21437
|
+
const dir = openSync(dirname2(path), "r");
|
|
21329
21438
|
try {
|
|
21330
21439
|
fsyncSync(dir);
|
|
21331
21440
|
} finally {
|
|
@@ -21384,8 +21493,9 @@ function invalid() {
|
|
|
21384
21493
|
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.");
|
|
21385
21494
|
}
|
|
21386
21495
|
function checkDir(paths) {
|
|
21387
|
-
const s =
|
|
21388
|
-
if (!s.isDirectory() || s.isSymbolicLink() || (s.mode & 63) !== 0) invalid();
|
|
21496
|
+
const s = lstatSync2(paths.configDir);
|
|
21497
|
+
if (!s.isDirectory() || s.isSymbolicLink() || process.platform !== "win32" && (s.mode & 63) !== 0) invalid();
|
|
21498
|
+
if (process.platform === "win32") assertWindowsPrivatePath(paths.configDir);
|
|
21389
21499
|
}
|
|
21390
21500
|
function readPaymentMode(paths) {
|
|
21391
21501
|
try {
|
|
@@ -21393,7 +21503,8 @@ function readPaymentMode(paths) {
|
|
|
21393
21503
|
const fd = openSync2(modeFile(paths), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
21394
21504
|
try {
|
|
21395
21505
|
const s = fstatSync(fd);
|
|
21396
|
-
|
|
21506
|
+
assertPrivateFile(modeFile(paths), s);
|
|
21507
|
+
if (s.size > 4096) invalid();
|
|
21397
21508
|
return PaymentModeStateSchema.parse(JSON.parse(readFileSync(fd, "utf8")));
|
|
21398
21509
|
} finally {
|
|
21399
21510
|
closeSync2(fd);
|
|
@@ -21404,8 +21515,8 @@ function readPaymentMode(paths) {
|
|
|
21404
21515
|
}
|
|
21405
21516
|
|
|
21406
21517
|
// packages/cli/src/core/fileLock.ts
|
|
21407
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, rmSync as rmSync2, renameSync as renameSync2, existsSync } from "node:fs";
|
|
21408
|
-
import { dirname as
|
|
21518
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, rmSync as rmSync2, renameSync as renameSync2, existsSync as existsSync2 } from "node:fs";
|
|
21519
|
+
import { dirname as dirname3, join as join3 } from "node:path";
|
|
21409
21520
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
21410
21521
|
function processAlive(pid) {
|
|
21411
21522
|
if (!Number.isSafeInteger(pid) || pid <= 0) return void 0;
|
|
@@ -21442,7 +21553,7 @@ function owner(path) {
|
|
|
21442
21553
|
}
|
|
21443
21554
|
}
|
|
21444
21555
|
async function withFileLock(path, fn, timeoutMs = 5e3) {
|
|
21445
|
-
mkdirSync2(
|
|
21556
|
+
mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
|
|
21446
21557
|
const nonce = randomUUID2(), deadline = Date.now() + timeoutMs;
|
|
21447
21558
|
for (; ; ) {
|
|
21448
21559
|
try {
|
|
@@ -21469,7 +21580,7 @@ async function withFileLock(path, fn, timeoutMs = 5e3) {
|
|
|
21469
21580
|
} finally {
|
|
21470
21581
|
if (acquired) rmSync2(reaper, { recursive: true, force: true });
|
|
21471
21582
|
}
|
|
21472
|
-
if (!
|
|
21583
|
+
if (!existsSync2(path)) continue;
|
|
21473
21584
|
}
|
|
21474
21585
|
if (Date.now() >= deadline)
|
|
21475
21586
|
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.");
|
|
@@ -21485,7 +21596,7 @@ async function withFileLock(path, fn, timeoutMs = 5e3) {
|
|
|
21485
21596
|
|
|
21486
21597
|
// packages/cli/src/probe/journal.ts
|
|
21487
21598
|
import {
|
|
21488
|
-
existsSync as
|
|
21599
|
+
existsSync as existsSync3,
|
|
21489
21600
|
mkdirSync as mkdirSync4,
|
|
21490
21601
|
readFileSync as readFileSync4,
|
|
21491
21602
|
rmSync as rmSync3,
|
|
@@ -21493,7 +21604,7 @@ import {
|
|
|
21493
21604
|
openSync as openSync4,
|
|
21494
21605
|
fsyncSync as fsyncSync3,
|
|
21495
21606
|
closeSync as closeSync4,
|
|
21496
|
-
lstatSync as
|
|
21607
|
+
lstatSync as lstatSync4
|
|
21497
21608
|
} from "node:fs";
|
|
21498
21609
|
import { join as join5 } from "node:path";
|
|
21499
21610
|
|
|
@@ -21519,7 +21630,7 @@ import {
|
|
|
21519
21630
|
closeSync as closeSync3,
|
|
21520
21631
|
fsyncSync as fsyncSync2,
|
|
21521
21632
|
fstatSync as fstatSync2,
|
|
21522
|
-
lstatSync as
|
|
21633
|
+
lstatSync as lstatSync3,
|
|
21523
21634
|
mkdirSync as mkdirSync3,
|
|
21524
21635
|
openSync as openSync3,
|
|
21525
21636
|
readFileSync as readFileSync3,
|
|
@@ -21536,14 +21647,16 @@ function journalError() {
|
|
|
21536
21647
|
);
|
|
21537
21648
|
}
|
|
21538
21649
|
function privateDir(path) {
|
|
21539
|
-
|
|
21540
|
-
|
|
21650
|
+
if (process.platform === "win32") ensureWindowsPrivateDirectory(path);
|
|
21651
|
+
else mkdirSync3(path, { recursive: true, mode: 448 });
|
|
21652
|
+
const s = lstatSync3(path);
|
|
21541
21653
|
if (!s.isDirectory() || s.isSymbolicLink() || process.platform !== "win32" && ((s.mode & 63) !== 0 || s.uid !== process.getuid?.()))
|
|
21542
21654
|
journalError();
|
|
21543
21655
|
}
|
|
21544
21656
|
function registryDir(paths) {
|
|
21545
|
-
|
|
21546
|
-
|
|
21657
|
+
if (process.platform === "win32") ensureWindowsPrivateDirectory(paths.stateDir);
|
|
21658
|
+
else mkdirSync3(paths.stateDir, { recursive: true, mode: 448 });
|
|
21659
|
+
if (lstatSync3(paths.stateDir).isSymbolicLink()) journalError();
|
|
21547
21660
|
const dir = join4(paths.stateDir, "payment-probes");
|
|
21548
21661
|
privateDir(dir);
|
|
21549
21662
|
return dir;
|
|
@@ -21560,6 +21673,12 @@ function syncDir(dir) {
|
|
|
21560
21673
|
function openPrivate(path, flags) {
|
|
21561
21674
|
const fd = openSync3(path, flags | (constants2.O_NOFOLLOW ?? 0), 384);
|
|
21562
21675
|
const s = fstatSync2(fd);
|
|
21676
|
+
try {
|
|
21677
|
+
assertPrivateFile(path, s);
|
|
21678
|
+
} catch {
|
|
21679
|
+
closeSync3(fd);
|
|
21680
|
+
journalError();
|
|
21681
|
+
}
|
|
21563
21682
|
if (!s.isFile() || s.nlink !== 1 || s.size > MAX_FILE || process.platform !== "win32" && ((s.mode & 63) !== 0 || s.uid !== process.getuid?.())) {
|
|
21564
21683
|
closeSync3(fd);
|
|
21565
21684
|
journalError();
|
|
@@ -21710,7 +21829,7 @@ function lockError(code) {
|
|
|
21710
21829
|
}
|
|
21711
21830
|
function ownerAlive(lock) {
|
|
21712
21831
|
try {
|
|
21713
|
-
if (
|
|
21832
|
+
if (lstatSync4(lock).isSymbolicLink()) journalError();
|
|
21714
21833
|
const raw = readFileSync4(join5(lock, "owner.json"), "utf8");
|
|
21715
21834
|
if (raw.length > 256) journalError();
|
|
21716
21835
|
const pid = JSON.parse(raw).pid;
|
|
@@ -21729,7 +21848,7 @@ function ownerAlive(lock) {
|
|
|
21729
21848
|
async function exclusive(paths, recover, fn, installing2 = false) {
|
|
21730
21849
|
const dir = registryDir(paths), lock = join5(dir, ".lock");
|
|
21731
21850
|
let recovered = false;
|
|
21732
|
-
if (
|
|
21851
|
+
if (existsSync3(lock)) {
|
|
21733
21852
|
if (ownerAlive(lock)) lockError("PROBE_BUSY");
|
|
21734
21853
|
if (!recover) lockError("PROBE_STALE_LOCK");
|
|
21735
21854
|
try {
|
|
@@ -21765,7 +21884,7 @@ async function exclusive(paths, recover, fn, installing2 = false) {
|
|
|
21765
21884
|
}
|
|
21766
21885
|
syncDir(lock);
|
|
21767
21886
|
syncDir(dir);
|
|
21768
|
-
if (!installing2 &&
|
|
21887
|
+
if (!installing2 && existsSync3(join5(paths.configDir, "../..", "install-pending.json")))
|
|
21769
21888
|
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");
|
|
21770
21889
|
return await fn();
|
|
21771
21890
|
} finally {
|
|
@@ -21780,29 +21899,8 @@ var withPaymentLock = (paths, fn, installing2 = false) => exclusive(paths, insta
|
|
|
21780
21899
|
return fn();
|
|
21781
21900
|
}, installing2);
|
|
21782
21901
|
|
|
21783
|
-
// packages/cli/src/report/installTransaction.ts
|
|
21784
|
-
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
21785
|
-
import { mkdir as mkdir2, open as open3, rename as rename2, rm as rm2, lstat as lstat2, readFile } from "node:fs/promises";
|
|
21786
|
-
import { join as join6, dirname as dirname3 } from "node:path";
|
|
21787
|
-
import { createHash, randomUUID as randomUUID3 } from "node:crypto";
|
|
21788
|
-
|
|
21789
|
-
// packages/cli/src/report/transport.ts
|
|
21790
|
-
import { constants as constants3 } from "node:fs";
|
|
21791
|
-
import { open as open2, lstat, rename, rm, mkdir } from "node:fs/promises";
|
|
21792
|
-
|
|
21793
|
-
// packages/case-protocol/src/index.ts
|
|
21794
|
-
var MAX_ZIP = 20 * 1024 * 1024;
|
|
21795
|
-
var MAX_EXPANDED = 100 * 1024 * 1024;
|
|
21796
|
-
var CaseId = external_exports.uuid();
|
|
21797
|
-
var Receipt = external_exports.object({ schemaVersion: external_exports.literal(1), caseId: CaseId, sha256: external_exports.string().regex(/^[a-f0-9]{64}$/), bytes: external_exports.number().int().positive().max(MAX_ZIP), status: external_exports.literal("accepted"), acceptedAt: external_exports.iso.datetime() }).strict();
|
|
21798
|
-
var ConversationSource = external_exports.union([
|
|
21799
|
-
external_exports.object({ attached: external_exports.literal(true).optional(), identity: external_exports.literal("verified"), coverage: external_exports.enum(["partial", "complete"]) }),
|
|
21800
|
-
external_exports.object({ attached: external_exports.literal(false), identity: external_exports.enum(["verified", "ambiguous", "unavailable"]), coverage: external_exports.enum(["unavailable", "unsupported", "failed"]), warnings: external_exports.array(external_exports.string()).min(1).refine((items) => items.includes("HISTORY_NOT_ATTACHED")) })
|
|
21801
|
-
]);
|
|
21802
|
-
var Manifest = external_exports.object({ schemaVersion: external_exports.union([external_exports.literal(1), external_exports.literal(2)]), caseId: CaseId, scope: external_exports.enum(["current_session", "purchase_episode"]), sources: external_exports.object({ conversation: ConversationSource, cli: external_exports.object({ coverage: external_exports.enum(["partial", "unavailable"]) }) }), redaction: external_exports.object({ version: external_exports.literal(1), status: external_exports.literal("best_effort") }), files: external_exports.array(external_exports.object({ path: external_exports.string(), bytes: external_exports.number().int().nonnegative(), sha256: external_exports.string().regex(/^[a-f0-9]{64}$/) }).strict()).length(5) });
|
|
21803
|
-
|
|
21804
21902
|
// packages/cli/src/report/storage.ts
|
|
21805
|
-
import { lstatSync as
|
|
21903
|
+
import { lstatSync as lstatSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync2, unlinkSync } from "node:fs";
|
|
21806
21904
|
|
|
21807
21905
|
// packages/cli/src/report/bindingFiles.ts
|
|
21808
21906
|
var BindingError = class extends Error {
|
|
@@ -21819,18 +21917,41 @@ var BindingError = class extends Error {
|
|
|
21819
21917
|
|
|
21820
21918
|
// packages/cli/src/report/storage.ts
|
|
21821
21919
|
function privateDir2(path) {
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21920
|
+
if (process.platform === "win32") ensureWindowsPrivateDirectory(path);
|
|
21921
|
+
else mkdirSync5(path, { recursive: true, mode: 448 });
|
|
21922
|
+
const info = lstatSync5(path);
|
|
21923
|
+
if (!info.isDirectory() || info.isSymbolicLink() || process.getuid && info.uid !== process.getuid() || process.platform !== "win32" && info.mode & 63) throw new BindingError("UNSAFE_REPORT_DIRECTORY");
|
|
21825
21924
|
return path;
|
|
21826
21925
|
}
|
|
21827
21926
|
|
|
21927
|
+
// packages/cli/src/report/installTransaction.ts
|
|
21928
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
21929
|
+
import { mkdir as mkdir2, open as open4, rename as rename2, rm as rm2, lstat as lstat2, readFile } from "node:fs/promises";
|
|
21930
|
+
import { join as join6, dirname as dirname4 } from "node:path";
|
|
21931
|
+
import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
|
|
21932
|
+
|
|
21933
|
+
// packages/cli/src/report/transport.ts
|
|
21934
|
+
import { constants as constants3 } from "node:fs";
|
|
21935
|
+
import { open as open3, lstat, rename, rm, mkdir } from "node:fs/promises";
|
|
21936
|
+
|
|
21937
|
+
// packages/case-protocol/src/index.ts
|
|
21938
|
+
var MAX_ZIP = 20 * 1024 * 1024;
|
|
21939
|
+
var MAX_EXPANDED = 100 * 1024 * 1024;
|
|
21940
|
+
var CaseId = external_exports.uuid();
|
|
21941
|
+
var Receipt = external_exports.object({ schemaVersion: external_exports.literal(1), caseId: CaseId, sha256: external_exports.string().regex(/^[a-f0-9]{64}$/), bytes: external_exports.number().int().positive().max(MAX_ZIP), status: external_exports.literal("accepted"), acceptedAt: external_exports.iso.datetime() }).strict();
|
|
21942
|
+
var ConversationSource = external_exports.union([
|
|
21943
|
+
external_exports.object({ attached: external_exports.literal(true).optional(), identity: external_exports.literal("verified"), coverage: external_exports.enum(["partial", "complete"]) }),
|
|
21944
|
+
external_exports.object({ attached: external_exports.literal(false), identity: external_exports.enum(["verified", "ambiguous", "unavailable"]), coverage: external_exports.enum(["unavailable", "unsupported", "failed"]), warnings: external_exports.array(external_exports.string()).min(1).refine((items) => items.includes("HISTORY_NOT_ATTACHED")) })
|
|
21945
|
+
]);
|
|
21946
|
+
var Manifest = external_exports.object({ schemaVersion: external_exports.union([external_exports.literal(1), external_exports.literal(2)]), caseId: CaseId, scope: external_exports.enum(["current_session", "purchase_episode"]), sources: external_exports.object({ conversation: ConversationSource, cli: external_exports.object({ coverage: external_exports.enum(["partial", "unavailable"]) }) }), redaction: external_exports.object({ version: external_exports.literal(1), status: external_exports.literal("best_effort") }), files: external_exports.array(external_exports.object({ path: external_exports.string(), bytes: external_exports.number().int().nonnegative(), sha256: external_exports.string().regex(/^[a-f0-9]{64}$/) }).strict()).length(5) });
|
|
21947
|
+
|
|
21828
21948
|
// packages/cli/src/report/transport.ts
|
|
21829
21949
|
async function privateRead(path, limit) {
|
|
21830
|
-
const file2 = await
|
|
21950
|
+
const file2 = await open3(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
|
|
21831
21951
|
try {
|
|
21832
21952
|
const info = await file2.stat();
|
|
21833
|
-
|
|
21953
|
+
assertPrivateFile(path, info);
|
|
21954
|
+
if (info.size > limit) throw Error("UNSAFE_FILE");
|
|
21834
21955
|
const buffer = Buffer.alloc(info.size);
|
|
21835
21956
|
let at = 0;
|
|
21836
21957
|
while (at < buffer.length) {
|
|
@@ -21846,12 +21967,13 @@ async function privateRead(path, limit) {
|
|
|
21846
21967
|
var configSchema = external_exports.object({ endpoint: external_exports.string().url(), token: external_exports.string().min(32).max(512).regex(/^[A-Za-z0-9_-]+$/) }).strict();
|
|
21847
21968
|
|
|
21848
21969
|
// packages/cli/src/report/installTransaction.ts
|
|
21849
|
-
var hash2 = (s) =>
|
|
21970
|
+
var hash2 = (s) => createHash2("sha256").update(s).digest("hex");
|
|
21850
21971
|
async function durableWrite(path, text, mode = 384) {
|
|
21851
|
-
|
|
21972
|
+
if (process.platform === "win32") privateDir2(dirname4(path));
|
|
21973
|
+
else await mkdir2(dirname4(path), { recursive: true, mode: 448 });
|
|
21852
21974
|
const temp = path + "." + randomUUID3() + ".tmp";
|
|
21853
21975
|
try {
|
|
21854
|
-
const f = await
|
|
21976
|
+
const f = await open4(temp, "wx", mode);
|
|
21855
21977
|
try {
|
|
21856
21978
|
await f.writeFile(text);
|
|
21857
21979
|
await f.sync();
|
|
@@ -21859,21 +21981,16 @@ async function durableWrite(path, text, mode = 384) {
|
|
|
21859
21981
|
await f.close();
|
|
21860
21982
|
}
|
|
21861
21983
|
await rename2(temp, path);
|
|
21862
|
-
|
|
21863
|
-
try {
|
|
21864
|
-
await d.sync();
|
|
21865
|
-
} finally {
|
|
21866
|
-
await d.close();
|
|
21867
|
-
}
|
|
21984
|
+
await syncDirectory(dirname4(path));
|
|
21868
21985
|
} finally {
|
|
21869
21986
|
await rm2(temp, { force: true });
|
|
21870
21987
|
}
|
|
21871
21988
|
}
|
|
21872
21989
|
async function withInstallLock(root2, fn) {
|
|
21873
|
-
|
|
21990
|
+
privateDir2(root2);
|
|
21874
21991
|
let release;
|
|
21875
21992
|
try {
|
|
21876
|
-
release = await import_proper_lockfile.default.lock(root2, { lockfilePath: join6(root2, ".setup-lock"), realpath: false, stale: 5e3, update: 1e3, retries: 0 });
|
|
21993
|
+
release = await import_proper_lockfile.default.lock(root2, { lockfilePath: join6(root2, ".setup-lock"), realpath: false, stale: process.platform === "win32" ? 12e4 : 5e3, update: 1e3, retries: 0 });
|
|
21877
21994
|
} catch (e) {
|
|
21878
21995
|
if (e.code === "ELOCKED") throw Error("INSTALL_BUSY");
|
|
21879
21996
|
throw e;
|
|
@@ -21935,22 +22052,17 @@ async function applyInstallFiles(root2, buildId, files, finish) {
|
|
|
21935
22052
|
for (const file2 of files) await durableWrite(file2.path, file2.text, file2.mode);
|
|
21936
22053
|
await finish();
|
|
21937
22054
|
await rm2(journal);
|
|
21938
|
-
|
|
21939
|
-
try {
|
|
21940
|
-
await d.sync();
|
|
21941
|
-
} finally {
|
|
21942
|
-
await d.close();
|
|
21943
|
-
}
|
|
22055
|
+
await syncDirectory(root2);
|
|
21944
22056
|
}
|
|
21945
22057
|
|
|
21946
22058
|
// packages/cli/src/report/openEnrollment.ts
|
|
21947
22059
|
import { generateKeyPairSync as generateKeyPairSync2, createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2, randomUUID as randomUUID5, sign as sign2 } from "node:crypto";
|
|
21948
|
-
import { open as
|
|
22060
|
+
import { open as open6, rename as rename4, rm as rm4, lstat as lstat3 } from "node:fs/promises";
|
|
21949
22061
|
import { join as join8 } from "node:path";
|
|
21950
22062
|
|
|
21951
22063
|
// packages/cli/src/report/enrollment.ts
|
|
21952
|
-
import { generateKeyPairSync, createHash as
|
|
21953
|
-
import { open as
|
|
22064
|
+
import { generateKeyPairSync, createHash as createHash3, createPrivateKey, createPublicKey, randomUUID as randomUUID4, sign } from "node:crypto";
|
|
22065
|
+
import { open as open5, rename as rename3, rm as rm3 } from "node:fs/promises";
|
|
21954
22066
|
import { join as join7 } from "node:path";
|
|
21955
22067
|
import { request as httpsRequest } from "node:https";
|
|
21956
22068
|
var DIAGNOSTIC_ENDPOINT = "https://aiplatilka.ru/case-reports";
|
|
@@ -21984,36 +22096,28 @@ var enrollmentPost = (path, body) => new Promise((resolve2, reject) => {
|
|
|
21984
22096
|
request.on("error", reject);
|
|
21985
22097
|
request.end(bytes);
|
|
21986
22098
|
});
|
|
21987
|
-
async function syncDir2(dir) {
|
|
21988
|
-
const f = await open4(dir, "r");
|
|
21989
|
-
try {
|
|
21990
|
-
await f.sync();
|
|
21991
|
-
} finally {
|
|
21992
|
-
await f.close();
|
|
21993
|
-
}
|
|
21994
|
-
}
|
|
21995
22099
|
async function enrollInvitation(path, env = process.env, request = enrollmentPost) {
|
|
21996
22100
|
try {
|
|
21997
22101
|
const invite = Invitation.parse(JSON.parse((await privateRead(path, 8192)).toString("utf8")));
|
|
21998
|
-
const hash4 =
|
|
22102
|
+
const hash4 = createHash3("sha256").update(invite.token).digest("hex");
|
|
21999
22103
|
const dir = privateDir2(cliPaths(env).configDir);
|
|
22000
22104
|
const statePath = join7(dir, "report-installation.json");
|
|
22001
22105
|
try {
|
|
22002
22106
|
const pair = generateKeyPairSync("ed25519");
|
|
22003
|
-
const file2 = await
|
|
22107
|
+
const file2 = await open5(statePath, "wx", 384);
|
|
22004
22108
|
try {
|
|
22005
22109
|
await file2.writeFile(JSON.stringify({ invitationHash: hash4, installationId: randomUUID4(), privateKey: pair.privateKey.export({ format: "pem", type: "pkcs8" }), publicKey: pair.publicKey.export({ format: "pem", type: "spki" }) }));
|
|
22006
22110
|
await file2.sync();
|
|
22007
22111
|
} finally {
|
|
22008
22112
|
await file2.close();
|
|
22009
22113
|
}
|
|
22010
|
-
await
|
|
22114
|
+
await syncDirectory(dir);
|
|
22011
22115
|
} catch (error62) {
|
|
22012
22116
|
if (error62.code !== "EEXIST") throw error62;
|
|
22013
22117
|
}
|
|
22014
22118
|
const state = State.parse(JSON.parse((await privateRead(statePath, 8192)).toString("utf8")));
|
|
22015
22119
|
if (state.invitationHash !== hash4 || createPublicKey(state.privateKey).export({ format: "pem", type: "spki" }).toString() !== state.publicKey) throw Error("INSTALLATION_CONFLICT");
|
|
22016
|
-
await
|
|
22120
|
+
await syncDirectory(dir);
|
|
22017
22121
|
const body = { inviteToken: invite.token, installationId: state.installationId, publicKey: state.publicKey };
|
|
22018
22122
|
const challenge = external_exports.object({ challenge: external_exports.string().max(2048) }).strict().parse(await request("/v1/enroll/challenge", body));
|
|
22019
22123
|
const signature = sign(null, Buffer.from("sberpay-enroll-v1\n" + challenge.challenge), createPrivateKey(state.privateKey)).toString("base64url");
|
|
@@ -22021,7 +22125,7 @@ async function enrollInvitation(path, env = process.env, request = enrollmentPos
|
|
|
22021
22125
|
if (response.installationId !== state.installationId) throw Error("INSTALLATION_MISMATCH");
|
|
22022
22126
|
const temp = join7(dir, `.upload-${randomUUID4()}.tmp`);
|
|
22023
22127
|
try {
|
|
22024
|
-
const file2 = await
|
|
22128
|
+
const file2 = await open5(temp, "wx", 384);
|
|
22025
22129
|
try {
|
|
22026
22130
|
await file2.writeFile(JSON.stringify({ endpoint: DIAGNOSTIC_ENDPOINT, token: response.token }));
|
|
22027
22131
|
await file2.sync();
|
|
@@ -22029,7 +22133,7 @@ async function enrollInvitation(path, env = process.env, request = enrollmentPos
|
|
|
22029
22133
|
await file2.close();
|
|
22030
22134
|
}
|
|
22031
22135
|
await rename3(temp, join7(dir, "report-upload.json"));
|
|
22032
|
-
await
|
|
22136
|
+
await syncDirectory(dir);
|
|
22033
22137
|
} finally {
|
|
22034
22138
|
await rm3(temp, { force: true });
|
|
22035
22139
|
}
|
|
@@ -22043,14 +22147,6 @@ async function enrollInvitation(path, env = process.env, request = enrollmentPos
|
|
|
22043
22147
|
var State2 = external_exports.object({ schemaVersion: external_exports.literal(1), installationId: external_exports.uuid(), privateKey: external_exports.string().max(256), publicKey: external_exports.string().max(256) }).strict();
|
|
22044
22148
|
var Credential2 = external_exports.object({ schemaVersion: external_exports.literal(1), installationId: external_exports.uuid(), owner: external_exports.string(), token: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/) }).strict();
|
|
22045
22149
|
var Upload = external_exports.object({ endpoint: external_exports.literal(DIAGNOSTIC_ENDPOINT), token: external_exports.string().min(32).max(512).regex(/^[A-Za-z0-9_-]+$/) }).strict();
|
|
22046
|
-
async function syncDir3(dir) {
|
|
22047
|
-
const f = await open5(dir, "r");
|
|
22048
|
-
try {
|
|
22049
|
-
await f.sync();
|
|
22050
|
-
} finally {
|
|
22051
|
-
await f.close();
|
|
22052
|
-
}
|
|
22053
|
-
}
|
|
22054
22150
|
async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
22055
22151
|
const dir = privateDir2(cliPaths(env).configDir), statePath = join8(dir, "report-open-installation.json");
|
|
22056
22152
|
try {
|
|
@@ -22071,7 +22167,7 @@ async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
|
22071
22167
|
if (e.code !== "ENOENT") throw e;
|
|
22072
22168
|
const pair = generateKeyPairSync2("ed25519"), temp = statePath + "." + randomUUID5() + ".tmp";
|
|
22073
22169
|
try {
|
|
22074
|
-
const f = await
|
|
22170
|
+
const f = await open6(temp, "wx", 384);
|
|
22075
22171
|
try {
|
|
22076
22172
|
await f.writeFile(JSON.stringify({ schemaVersion: 1, installationId: randomUUID5(), privateKey: pair.privateKey.export({ format: "pem", type: "pkcs8" }), publicKey: pair.publicKey.export({ format: "pem", type: "spki" }) }));
|
|
22077
22173
|
await f.sync();
|
|
@@ -22079,7 +22175,7 @@ async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
|
22079
22175
|
await f.close();
|
|
22080
22176
|
}
|
|
22081
22177
|
await rename4(temp, statePath);
|
|
22082
|
-
await
|
|
22178
|
+
await syncDirectory(dir);
|
|
22083
22179
|
} finally {
|
|
22084
22180
|
await rm4(temp, { force: true });
|
|
22085
22181
|
}
|
|
@@ -22091,7 +22187,7 @@ async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
|
22091
22187
|
} catch {
|
|
22092
22188
|
throw Error("INSTALLATION_STATE_INVALID");
|
|
22093
22189
|
}
|
|
22094
|
-
await
|
|
22190
|
+
await syncDirectory(dir);
|
|
22095
22191
|
try {
|
|
22096
22192
|
const body = { installationId: state.installationId, publicKey: state.publicKey };
|
|
22097
22193
|
const c = external_exports.object({ challenge: external_exports.string().max(2048) }).strict().parse(await request("/v2/enroll/challenge", body));
|
|
@@ -22100,7 +22196,7 @@ async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
|
22100
22196
|
if (response.installationId !== state.installationId || response.owner !== "installation:" + state.installationId) throw Error("INSTALLATION_MISMATCH");
|
|
22101
22197
|
const temp = join8(dir, ".upload-" + randomUUID5() + ".tmp");
|
|
22102
22198
|
try {
|
|
22103
|
-
const f = await
|
|
22199
|
+
const f = await open6(temp, "wx", 384);
|
|
22104
22200
|
try {
|
|
22105
22201
|
await f.writeFile(JSON.stringify({ endpoint: DIAGNOSTIC_ENDPOINT, token: response.token }));
|
|
22106
22202
|
await f.sync();
|
|
@@ -22108,7 +22204,7 @@ async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
|
22108
22204
|
await f.close();
|
|
22109
22205
|
}
|
|
22110
22206
|
await rename4(temp, join8(dir, "report-upload.json"));
|
|
22111
|
-
await
|
|
22207
|
+
await syncDirectory(dir);
|
|
22112
22208
|
} finally {
|
|
22113
22209
|
await rm4(temp, { force: true });
|
|
22114
22210
|
}
|
|
@@ -22118,8 +22214,65 @@ async function enrollOpen(env = process.env, request = enrollmentPost) {
|
|
|
22118
22214
|
}
|
|
22119
22215
|
}
|
|
22120
22216
|
|
|
22217
|
+
// packages/cli/src/report/windowsSender.ts
|
|
22218
|
+
import { win32 as win323 } from "node:path";
|
|
22219
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
22220
|
+
var windowsArgument = (s) => '"' + s.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
|
|
22221
|
+
function windowsSenderConfig(home, launcher, node2) {
|
|
22222
|
+
if (!win323.isAbsolute(launcher) || !win323.isAbsolute(node2) || /[\0\r\n]/.test(launcher + node2)) throw Error("INVALID_SENDER_PATH");
|
|
22223
|
+
return { path: win323.join(home, ".local", "share", "sberpay-diagnostic", "sender-task.json"), text: JSON.stringify({ name: "SberPay.Diagnostic." + createHash4("sha256").update(launcher.toLowerCase()).digest("hex").slice(0, 24), node: node2, launcher, arguments: windowsArgument(launcher) + " report flush --json" }) };
|
|
22224
|
+
}
|
|
22225
|
+
var SCRIPT2 = String.raw`
|
|
22226
|
+
$ErrorActionPreference='Stop'
|
|
22227
|
+
[Console]::OutputEncoding=New-Object System.Text.UTF8Encoding($false)
|
|
22228
|
+
$c=Get-Content -LiteralPath $env:SBERPAY_SENDER_CONFIG -Raw -Encoding UTF8|ConvertFrom-Json
|
|
22229
|
+
$sid=[Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
|
22230
|
+
$service=New-Object -ComObject 'Schedule.Service'
|
|
22231
|
+
$service.Connect()
|
|
22232
|
+
$folder=$service.GetFolder('\')
|
|
22233
|
+
$source='sberpay-diagnostic:'+ $c.launcher
|
|
22234
|
+
$existing=$null
|
|
22235
|
+
try{$existing=$folder.GetTask($c.name)}catch{$e=$_.Exception;while($e.InnerException){$e=$e.InnerException};if($e.HResult -ne -2147024894){throw}}
|
|
22236
|
+
if($existing){
|
|
22237
|
+
if($existing.Definition.RegistrationInfo.Source -cne $source -or $existing.Definition.Principal.UserId -ne $sid){throw 'SENDER_TASK_CONFLICT'}
|
|
22238
|
+
}
|
|
22239
|
+
$task=$service.NewTask(0)
|
|
22240
|
+
$task.RegistrationInfo.Source=$source
|
|
22241
|
+
$task.RegistrationInfo.Description='Deliver queued SberPay diagnostic cases'
|
|
22242
|
+
$task.Principal.UserId=$sid
|
|
22243
|
+
$task.Principal.LogonType=3
|
|
22244
|
+
$task.Principal.RunLevel=0
|
|
22245
|
+
$task.Settings.Enabled=$true
|
|
22246
|
+
$task.Settings.StartWhenAvailable=$true
|
|
22247
|
+
$task.Settings.DisallowStartIfOnBatteries=$false
|
|
22248
|
+
$task.Settings.StopIfGoingOnBatteries=$false
|
|
22249
|
+
$task.Settings.MultipleInstances=2
|
|
22250
|
+
# Each upload has its own deadline; never kill a sequential queue before later cases.
|
|
22251
|
+
$task.Settings.ExecutionTimeLimit='PT0S'
|
|
22252
|
+
$timer=$task.Triggers.Create(1)
|
|
22253
|
+
$timer.StartBoundary=(Get-Date).AddMinutes(1).ToString('yyyy-MM-ddTHH:mm:ss')
|
|
22254
|
+
$timer.Repetition.Interval='PT5M'
|
|
22255
|
+
$timer.Enabled=$true
|
|
22256
|
+
$logon=$task.Triggers.Create(9)
|
|
22257
|
+
$logon.UserId=$sid
|
|
22258
|
+
$logon.Enabled=$true
|
|
22259
|
+
$action=$task.Actions.Create(0)
|
|
22260
|
+
$action.Path=$c.node
|
|
22261
|
+
$action.Arguments=$c.arguments
|
|
22262
|
+
$action.WorkingDirectory=[IO.Path]::GetDirectoryName($c.launcher)
|
|
22263
|
+
$registered=$folder.RegisterTaskDefinition($c.name,$task,6,$sid,$null,3,$null)
|
|
22264
|
+
$read=$folder.GetTask($c.name)
|
|
22265
|
+
$d=$read.Definition
|
|
22266
|
+
if($d.Settings.ExecutionTimeLimit -ne 'PT0S' -or $d.Settings.MultipleInstances -ne 2 -or !$read.Enabled -or $d.Principal.UserId -ne $sid -or $d.Principal.LogonType -ne 3 -or $d.Principal.RunLevel -ne 0 -or $d.Actions.Count -ne 1 -or $d.Actions.Item(1).Path -cne $c.node -or $d.Actions.Item(1).Arguments -cne $c.arguments -or $d.Triggers.Count -ne 2 -or $d.Triggers.Item(1).Repetition.Interval -ne 'PT5M'){throw 'SENDER_TASK_NOT_ACTIVE'}
|
|
22267
|
+
@{status='active';taskName=$c.name}|ConvertTo-Json -Compress
|
|
22268
|
+
`;
|
|
22269
|
+
function windowsSenderCommand(path, env = process.env) {
|
|
22270
|
+
if (!env.SystemRoot || !win323.isAbsolute(env.SystemRoot)) throw Error("WINDOWS_SYSTEM_ROOT_MISSING");
|
|
22271
|
+
return { file: win323.join(env.SystemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe"), args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(SCRIPT2, "utf16le").toString("base64")], env: { SystemRoot: env.SystemRoot, SBERPAY_SENDER_CONFIG: path } };
|
|
22272
|
+
}
|
|
22273
|
+
|
|
22121
22274
|
// packages/cli/src/report/sender.ts
|
|
22122
|
-
import { join as join9, dirname as
|
|
22275
|
+
import { join as join9, dirname as dirname5 } from "node:path";
|
|
22123
22276
|
import { homedir as homedir2 } from "node:os";
|
|
22124
22277
|
import { mkdir as mkdir3, writeFile as writeFile2, lstat as lstat4, rename as rename5, rm as rm5 } from "node:fs/promises";
|
|
22125
22278
|
import { execFile } from "node:child_process";
|
|
@@ -22148,15 +22301,18 @@ Persistent=true
|
|
|
22148
22301
|
[Install]
|
|
22149
22302
|
WantedBy=timers.target
|
|
22150
22303
|
` }];
|
|
22304
|
+
if (platform === "win32") return [windowsSenderConfig(home, launcher, node2)];
|
|
22151
22305
|
return [];
|
|
22152
22306
|
}
|
|
22153
22307
|
async function installSender(home, launcher) {
|
|
22154
22308
|
const files = senderConfig(process.platform, home, launcher, process.execPath);
|
|
22155
22309
|
for (const f of files) {
|
|
22156
|
-
|
|
22310
|
+
if (process.platform === "win32") privateDir2(dirname5(f.path));
|
|
22311
|
+
else await mkdir3(dirname5(f.path), { recursive: true, mode: 448 });
|
|
22157
22312
|
try {
|
|
22158
22313
|
const s = await lstat4(f.path);
|
|
22159
22314
|
if (!s.isFile() || s.isSymbolicLink()) throw Error("UNSAFE_SENDER_PATH");
|
|
22315
|
+
if (process.platform === "win32") assertWindowsPrivatePath(f.path);
|
|
22160
22316
|
} catch (e) {
|
|
22161
22317
|
if (e.code !== "ENOENT") throw e;
|
|
22162
22318
|
}
|
|
@@ -22175,6 +22331,10 @@ async function installSender(home, launcher) {
|
|
|
22175
22331
|
await run("launchctl", ["bootout", domain2 + "/" + label]).catch(() => {
|
|
22176
22332
|
});
|
|
22177
22333
|
await run("launchctl", ["bootstrap", domain2, files[0].path]);
|
|
22334
|
+
} else if (process.platform === "win32") {
|
|
22335
|
+
const c = windowsSenderCommand(files[0].path);
|
|
22336
|
+
const result = await run(c.file, c.args, { env: c.env, windowsHide: true, timeout: 3e4, maxBuffer: 65536 });
|
|
22337
|
+
if (JSON.parse(result.stdout.trim().replace(/^\uFEFF/, "")).status !== "active") throw Error("SENDER_TASK_NOT_ACTIVE");
|
|
22178
22338
|
} else {
|
|
22179
22339
|
await run("systemctl", ["--user", "daemon-reload"]);
|
|
22180
22340
|
await run("systemctl", ["--user", "enable", "--now", label + ".timer"]);
|
|
@@ -22193,15 +22353,10 @@ var LAST_LISTED_MAJOR = 24;
|
|
|
22193
22353
|
import { constants as constants4 } from "node:fs";
|
|
22194
22354
|
import { pathToFileURL } from "node:url";
|
|
22195
22355
|
import { homedir as homedir3 } from "node:os";
|
|
22196
|
-
import { join as join10, resolve, dirname as
|
|
22197
|
-
import { mkdir as mkdir4, readFile as readFile2, writeFile as writeFile3, lstat as lstat5, rename as rename6, rm as rm6, cp, open as
|
|
22198
|
-
import { createHash as
|
|
22199
|
-
|
|
22200
|
-
// packages/cli/src/report/claudeHook.ts
|
|
22201
|
-
var shellQuote = (text) => `'${text.replace(/'/g, "'\\''")}'`;
|
|
22202
|
-
|
|
22203
|
-
// packages/cli/src/report/installer.ts
|
|
22204
|
-
var hash3 = (text) => createHash3("sha256").update(text).digest("hex");
|
|
22356
|
+
import { join as join10, resolve, dirname as dirname6 } from "node:path";
|
|
22357
|
+
import { mkdir as mkdir4, readFile as readFile2, writeFile as writeFile3, lstat as lstat5, rename as rename6, rm as rm6, cp, open as open7, chmod } from "node:fs/promises";
|
|
22358
|
+
import { createHash as createHash5, randomUUID as randomUUID7 } from "node:crypto";
|
|
22359
|
+
var hash3 = (text) => createHash5("sha256").update(text).digest("hex");
|
|
22205
22360
|
var Manifest2 = external_exports.object({ schemaVersion: external_exports.literal(1), buildId: external_exports.string().regex(/^[a-f0-9]{64}$/), setupHash: external_exports.string().regex(/^[a-f0-9]{64}$/).optional(), files: external_exports.record(external_exports.string(), external_exports.string().regex(/^[a-f0-9]{64}$/)) }).strict();
|
|
22206
22361
|
async function regular(path) {
|
|
22207
22362
|
const s = await lstat5(path);
|
|
@@ -22223,7 +22378,7 @@ async function installDiagnostic(source2, home = homedir3(), options = {}) {
|
|
|
22223
22378
|
async function installLocked(source2, home, options) {
|
|
22224
22379
|
const enroll = typeof options === "function" ? options : options.enrollInvitation ?? enrollInvitation;
|
|
22225
22380
|
const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
|
|
22226
|
-
if (!(major > LAST_LISTED_MAJOR || MIN_NODE_MINOR[major] !== void 0 && minor >= MIN_NODE_MINOR[major])
|
|
22381
|
+
if (!(major > LAST_LISTED_MAJOR || MIN_NODE_MINOR[major] !== void 0 && minor >= MIN_NODE_MINOR[major])) throw Error("UNSUPPORTED_RUNTIME");
|
|
22227
22382
|
source2 = resolve(source2);
|
|
22228
22383
|
try {
|
|
22229
22384
|
const info = JSON.parse(await readFile2(join10(source2, "build-info.json"), "utf8"));
|
|
@@ -22249,6 +22404,7 @@ async function installLocked(source2, home, options) {
|
|
|
22249
22404
|
await regular(join10(packageRoot, path));
|
|
22250
22405
|
if (hash3(await readFile2(join10(packageRoot, path))) !== digest) throw Error("PACKAGE_HASH_MISMATCH");
|
|
22251
22406
|
}
|
|
22407
|
+
if (process.platform === "win32" && !manifest.files[`helpers/win32-${process.arch}/sberpay-tpm.exe`]) throw Error("WINDOWS_HELPER_NOT_PACKAGED");
|
|
22252
22408
|
const root2 = privateDir2(join10(home, ".local", "share", "sberpay-diagnostic"));
|
|
22253
22409
|
const skill = join10(home, ".agents", "skills", "sberpay-diagnostic");
|
|
22254
22410
|
const markerPath = join10(root2, "installed.json");
|
|
@@ -22319,9 +22475,9 @@ async function installLocked(source2, home, options) {
|
|
|
22319
22475
|
try {
|
|
22320
22476
|
for (const [path] of entries) {
|
|
22321
22477
|
const target = join10(staged, path);
|
|
22322
|
-
await mkdir4(
|
|
22478
|
+
await mkdir4(dirname6(target), { recursive: true, mode: 448 });
|
|
22323
22479
|
await cp(join10(packageRoot, path), target, { force: false, errorOnExist: true });
|
|
22324
|
-
await chmod(target, /^helpers\/[^/]+\/sberpay-(se|tpm)
|
|
22480
|
+
await chmod(target, /^helpers\/[^/]+\/sberpay-(se|tpm)(\.exe)?$/.test(path) ? 448 : 384);
|
|
22325
22481
|
}
|
|
22326
22482
|
await rename6(staged, release);
|
|
22327
22483
|
} finally {
|
|
@@ -22337,11 +22493,12 @@ async function installLocked(source2, home, options) {
|
|
|
22337
22493
|
if (error62.code !== "ENOENT") throw error62;
|
|
22338
22494
|
}
|
|
22339
22495
|
if (hasInvitation) {
|
|
22340
|
-
const invitationFile = await
|
|
22496
|
+
const invitationFile = await open7(join10(source2, "invitation.json"), constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
22341
22497
|
try {
|
|
22342
22498
|
const info = await invitationFile.stat();
|
|
22343
22499
|
if (!info.isFile() || process.getuid && info.uid !== process.getuid()) throw Error("UNSAFE_INVITATION");
|
|
22344
|
-
|
|
22500
|
+
if (process.platform === "win32") assertWindowsPrivatePath(join10(source2, "invitation.json"));
|
|
22501
|
+
else await invitationFile.chmod(384);
|
|
22345
22502
|
} finally {
|
|
22346
22503
|
await invitationFile.close();
|
|
22347
22504
|
}
|
|
@@ -22385,11 +22542,14 @@ process.env.SBERPAY_DIAGNOSTIC_CAPTURE="1";
|
|
|
22385
22542
|
await import(${JSON.stringify(pathToFileURL(join10(release, "bin", "sberpay-cli.mjs")).href)});
|
|
22386
22543
|
`;
|
|
22387
22544
|
const original = await readFile2(join10(release, "skill", "sberpay", "SKILL.md"), "utf8");
|
|
22388
|
-
const text = original.
|
|
22389
|
-
|
|
22390
|
-
|
|
22391
|
-
|
|
22392
|
-
|
|
22545
|
+
const text = renderDiagnosticSkill(original, process.platform, launcher, process.execPath);
|
|
22546
|
+
if (process.platform === "win32") privateDir2(skill);
|
|
22547
|
+
else {
|
|
22548
|
+
await mkdir4(dirname6(skill), { recursive: true, mode: 448 });
|
|
22549
|
+
await mkdir4(skill, { mode: 448 }).catch((e) => {
|
|
22550
|
+
if (e.code !== "EEXIST") throw e;
|
|
22551
|
+
});
|
|
22552
|
+
}
|
|
22393
22553
|
const managed = [{ path: paymentModeFile, text: JSON.stringify(modeState), mode: 384 }, { path: launcher, text: launcherText, mode: 448 }, { path: join10(skill, "SKILL.md"), text, mode: 384 }];
|
|
22394
22554
|
for (const [path] of entries) {
|
|
22395
22555
|
if (!path.startsWith("skill/sberpay/") || path === "skill/sberpay/SKILL.md") continue;
|
|
@@ -22420,7 +22580,7 @@ await import(${JSON.stringify(pathToFileURL(join10(release, "bin", "sberpay-cli.
|
|
|
22420
22580
|
}
|
|
22421
22581
|
managed.push({ path: target, text: await readFile2(join10(release, path), "utf8"), mode: 384 });
|
|
22422
22582
|
}
|
|
22423
|
-
const skillFiles =
|
|
22583
|
+
const skillFiles = skillFileHashes(skill, managed);
|
|
22424
22584
|
const marker = { buildId: manifest.buildId, stateFormat: 2, skillHash: hash3(text), skillFiles, launcher, profile };
|
|
22425
22585
|
let sender;
|
|
22426
22586
|
await applyInstallFiles(root2, manifest.buildId, managed, async () => {
|
|
@@ -22432,7 +22592,7 @@ await import(${JSON.stringify(pathToFileURL(join10(release, "bin", "sberpay-cli.
|
|
|
22432
22592
|
}
|
|
22433
22593
|
|
|
22434
22594
|
// scripts/diagnostics/npm-entry.mts
|
|
22435
|
-
var source =
|
|
22595
|
+
var source = dirname7(dirname7(fileURLToPath2(import.meta.url)));
|
|
22436
22596
|
var root = join11(homedir4(), ".local/share/sberpay-diagnostic");
|
|
22437
22597
|
try {
|
|
22438
22598
|
if (process.argv[2] === "setup") {
|