@sberpay-cli/cli-diagnostic 0.4.0-dev.7 → 0.4.0-dev.9
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/build-info.json +4 -4
- package/dist/npm-entry.mjs +191 -100
- package/manifest.json +8 -7
- package/package/SHA256SUMS +5 -4
- package/package/dist/binding-worker.mjs +29 -8
- package/package/dist/cli.mjs +600 -97
- package/package/package.json +1 -1
- package/package/skill/sberpay/SKILL.md +27 -2
- package/package/skill/sberpay/scripts/approved-message.mjs +79 -0
- package/package.json +1 -1
package/package/dist/cli.mjs
CHANGED
|
@@ -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 ? "
|
|
7378
|
+
sourceCommit: true ? "db0ec0c6594c1d28d55158cde8f6e5d564251e46" : "dev",
|
|
7379
7379
|
profile: true ? "diagnostic" : "standard",
|
|
7380
7380
|
kind,
|
|
7381
7381
|
// Бандл — dist/cli.mjs в корне пакета; этот файл под tsx — packages/cli/src/core/.
|
|
@@ -27152,7 +27152,7 @@ import { join } from "node:path";
|
|
|
27152
27152
|
import { mkdirSync, existsSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, rmSync } from "node:fs";
|
|
27153
27153
|
import { dirname as dirname2 } from "node:path";
|
|
27154
27154
|
import { randomUUID } from "node:crypto";
|
|
27155
|
-
function atomicJson(path2, value) {
|
|
27155
|
+
function atomicJson(path2, value, options = {}) {
|
|
27156
27156
|
if (process.platform === "win32") {
|
|
27157
27157
|
ensureWindowsPrivateDirectory(dirname2(path2));
|
|
27158
27158
|
if (existsSync(path2)) assertWindowsPrivatePath(path2);
|
|
@@ -27161,7 +27161,7 @@ function atomicJson(path2, value) {
|
|
|
27161
27161
|
try {
|
|
27162
27162
|
const fd2 = openSync(temp, "wx", 384);
|
|
27163
27163
|
try {
|
|
27164
|
-
writeFileSync(fd2, JSON.stringify(value, null, 2) + "\n");
|
|
27164
|
+
writeFileSync(fd2, (options.compact ? JSON.stringify(value) : JSON.stringify(value, null, 2)) + "\n");
|
|
27165
27165
|
fsyncSync(fd2);
|
|
27166
27166
|
} finally {
|
|
27167
27167
|
closeSync(fd2);
|
|
@@ -27802,7 +27802,7 @@ async function exclusive(paths, recover, fn, installing2 = false) {
|
|
|
27802
27802
|
JSON.stringify({ pid: process.pid }),
|
|
27803
27803
|
{ mode: 384, flag: "wx" }
|
|
27804
27804
|
);
|
|
27805
|
-
const fd2 = openSync4(join4(lock, "owner.json"), "r");
|
|
27805
|
+
const fd2 = openSync4(join4(lock, "owner.json"), "r+");
|
|
27806
27806
|
try {
|
|
27807
27807
|
fsyncSync3(fd2);
|
|
27808
27808
|
} finally {
|
|
@@ -28040,17 +28040,17 @@ async function probePay(ctx, opts, order, purchaseContext) {
|
|
|
28040
28040
|
try {
|
|
28041
28041
|
const store = await credentialStoreFor(ctx);
|
|
28042
28042
|
await (async () => {
|
|
28043
|
-
const
|
|
28043
|
+
const snapshot2 = await withBindingLock(
|
|
28044
28044
|
bindingScope(ctx),
|
|
28045
28045
|
async () => store.read()
|
|
28046
28046
|
);
|
|
28047
|
-
if (!
|
|
28047
|
+
if (!snapshot2)
|
|
28048
28048
|
throw new CliError(
|
|
28049
28049
|
EXIT.AUTH,
|
|
28050
28050
|
"NO_CARD",
|
|
28051
28051
|
"\u041A\u0430\u0440\u0442\u0430 \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u0430 \u043D\u0435 \u043F\u0440\u0438\u0432\u044F\u0437\u0430\u043D\u0430"
|
|
28052
28052
|
);
|
|
28053
|
-
const prepared3 = prepareProbeToken(
|
|
28053
|
+
const prepared3 = prepareProbeToken(snapshot2.value.agentToken);
|
|
28054
28054
|
mutationApplied = true;
|
|
28055
28055
|
journal.bindScope(store.scopeHash);
|
|
28056
28056
|
try {
|
|
@@ -28496,7 +28496,7 @@ async function sendCase(caseId, env = process.env, deps = {}) {
|
|
|
28496
28496
|
}
|
|
28497
28497
|
|
|
28498
28498
|
// packages/cli/src/report/binding.ts
|
|
28499
|
-
import { readdir, realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
28499
|
+
import { lstat as lstat2, readdir, realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
28500
28500
|
import { homedir as homedir3 } from "node:os";
|
|
28501
28501
|
import { join as join9 } from "node:path";
|
|
28502
28502
|
|
|
@@ -28612,13 +28612,13 @@ async function collectTranscript(agent, parser3, binding, options = {}) {
|
|
|
28612
28612
|
return result;
|
|
28613
28613
|
}
|
|
28614
28614
|
handle = await open5(path2, constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0) | (constants5.O_NONBLOCK ?? 0));
|
|
28615
|
-
const
|
|
28616
|
-
if (!
|
|
28615
|
+
const snapshot2 = await handle.stat();
|
|
28616
|
+
if (!snapshot2.isFile() || snapshot2.ino !== before.ino || snapshot2.dev !== before.dev || process.getuid && snapshot2.uid !== process.getuid()) {
|
|
28617
28617
|
result.coverage = "failed";
|
|
28618
28618
|
warn(result, "UNSAFE_SOURCE");
|
|
28619
28619
|
return result;
|
|
28620
28620
|
}
|
|
28621
|
-
const length = Math.min(
|
|
28621
|
+
const length = Math.min(snapshot2.size, maxBytes);
|
|
28622
28622
|
const buffer = Buffer.alloc(length);
|
|
28623
28623
|
let offset = 0;
|
|
28624
28624
|
while (offset < length) {
|
|
@@ -28632,10 +28632,10 @@ async function collectTranscript(agent, parser3, binding, options = {}) {
|
|
|
28632
28632
|
offset += bytesRead;
|
|
28633
28633
|
}
|
|
28634
28634
|
result.snapshotBytes = offset;
|
|
28635
|
-
if (
|
|
28635
|
+
if (snapshot2.size > maxBytes) warn(result, "SIZE_LIMIT");
|
|
28636
28636
|
if (offset < length) warn(result, "SOURCE_CHANGED");
|
|
28637
28637
|
const after = await handle.stat();
|
|
28638
|
-
if (after.size <
|
|
28638
|
+
if (after.size < snapshot2.size || after.size === snapshot2.size && after.mtimeMs !== snapshot2.mtimeMs) warn(result, "SOURCE_CHANGED");
|
|
28639
28639
|
const lines = buffer.subarray(0, offset).toString("utf8").split("\n");
|
|
28640
28640
|
if (lines.at(-1) !== "") {
|
|
28641
28641
|
lines.pop();
|
|
@@ -28920,12 +28920,34 @@ async function codexBinding(env) {
|
|
|
28920
28920
|
return { sessionId, transcriptPath, allowedRoot, sourceVersion: runtimeVersion(meta3.cli_version) };
|
|
28921
28921
|
}
|
|
28922
28922
|
async function claudeBinding(env) {
|
|
28923
|
-
const
|
|
28923
|
+
const hookId = env.SBERPAY_CLAUDE_SESSION_ID, hostId = env.CLAUDE_CODE_SESSION_ID;
|
|
28924
|
+
if (hookId && hostId && hookId !== hostId) throw new BindingError("CONFLICTING_SESSION_IDS");
|
|
28925
|
+
if (!hookId || hostId && (!env.SBERPAY_CLAUDE_TRANSCRIPT || !env.SBERPAY_CLAUDE_CONFIG_DIR)) return claudeHostBinding(env);
|
|
28926
|
+
const sessionId = requireId(hookId);
|
|
28924
28927
|
if (!env.SBERPAY_CLAUDE_TRANSCRIPT || !env.SBERPAY_CLAUDE_CONFIG_DIR) throw new BindingError("CLAUDE_HOOK_NOT_ACTIVE");
|
|
28925
28928
|
const home = await realpath3(env.SBERPAY_CLAUDE_CONFIG_DIR);
|
|
28926
28929
|
if (env.CLAUDE_CONFIG_DIR && await realpath3(env.CLAUDE_CONFIG_DIR) !== home) throw new BindingError("PROFILE_MISMATCH");
|
|
28930
|
+
return claudeTranscript(sessionId, env.SBERPAY_CLAUDE_TRANSCRIPT, join9(home, "projects"));
|
|
28931
|
+
}
|
|
28932
|
+
async function claudeHostBinding(env) {
|
|
28933
|
+
const sessionId = requireId(env.CLAUDE_CODE_SESSION_ID);
|
|
28934
|
+
const home = await realpath3(env.CLAUDE_CONFIG_DIR || join9(homedir3(), ".claude"));
|
|
28927
28935
|
const allowedRoot = join9(home, "projects");
|
|
28928
|
-
const
|
|
28936
|
+
const matches = [];
|
|
28937
|
+
for (const entry of await readdir(allowedRoot, { withFileTypes: true })) {
|
|
28938
|
+
if (!entry.isDirectory()) continue;
|
|
28939
|
+
const candidate = join9(allowedRoot, entry.name, `${sessionId}.jsonl`);
|
|
28940
|
+
try {
|
|
28941
|
+
if ((await lstat2(candidate)).isFile()) matches.push(candidate);
|
|
28942
|
+
} catch (error62) {
|
|
28943
|
+
if (error62.code !== "ENOENT") throw error62;
|
|
28944
|
+
}
|
|
28945
|
+
if (matches.length > 1) throw new BindingError("AMBIGUOUS_SESSION_SOURCE");
|
|
28946
|
+
}
|
|
28947
|
+
if (!matches.length) throw new BindingError("SOURCE_NOT_FOUND");
|
|
28948
|
+
return claudeTranscript(sessionId, matches[0], allowedRoot);
|
|
28949
|
+
}
|
|
28950
|
+
async function claudeTranscript(sessionId, transcriptPath, allowedRoot) {
|
|
28929
28951
|
const prefix = await readPrefix(allowedRoot, transcriptPath);
|
|
28930
28952
|
const lines = prefix.split("\n");
|
|
28931
28953
|
lines.pop();
|
|
@@ -28941,7 +28963,7 @@ async function claudeBinding(env) {
|
|
|
28941
28963
|
async function resolveCurrentBinding(agent = "auto", env = process.env) {
|
|
28942
28964
|
try {
|
|
28943
28965
|
const hasCodex = !!(env.CODEX_THREAD_ID || env.CODEX_SESSION_ID);
|
|
28944
|
-
const hasClaude = !!env.SBERPAY_CLAUDE_SESSION_ID;
|
|
28966
|
+
const hasClaude = !!(env.SBERPAY_CLAUDE_SESSION_ID || env.CLAUDE_CODE_SESSION_ID);
|
|
28945
28967
|
if (agent === "auto") {
|
|
28946
28968
|
if (hasCodex && hasClaude) throw new BindingError("AMBIGUOUS_HOST");
|
|
28947
28969
|
if (!hasCodex && !hasClaude) throw new BindingError("HOST_NOT_DETECTED");
|
|
@@ -28978,7 +29000,7 @@ function sessionSummary(result) {
|
|
|
28978
29000
|
|
|
28979
29001
|
// packages/cli/src/report/package.ts
|
|
28980
29002
|
import { createHash as createHash5, randomUUID as randomUUID6 } from "node:crypto";
|
|
28981
|
-
import { lstat as
|
|
29003
|
+
import { lstat as lstat3, readdir as readdir2, writeFile as writeFile2, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
28982
29004
|
import { join as join11 } from "node:path";
|
|
28983
29005
|
|
|
28984
29006
|
// node_modules/fflate/esm/index.mjs
|
|
@@ -29698,7 +29720,7 @@ function zipSync(data, opts) {
|
|
|
29698
29720
|
}
|
|
29699
29721
|
|
|
29700
29722
|
// packages/cli/src/core/version.ts
|
|
29701
|
-
var CLI_VERSION = "0.4.0-dev.
|
|
29723
|
+
var CLI_VERSION = "0.4.0-dev.9";
|
|
29702
29724
|
|
|
29703
29725
|
// packages/cli/src/report/journal.ts
|
|
29704
29726
|
import { closeSync as closeSync5, constants as constants6, openSync as openSync5, writeSync as writeSync2 } from "node:fs";
|
|
@@ -29798,7 +29820,7 @@ async function logs(dir2, sourceId) {
|
|
|
29798
29820
|
for (const name of matching.slice(0, 1e3)) {
|
|
29799
29821
|
try {
|
|
29800
29822
|
const path2 = join11(dir2, name);
|
|
29801
|
-
const info = await
|
|
29823
|
+
const info = await lstat3(path2);
|
|
29802
29824
|
if (!info.isFile() || info.isSymbolicLink() || info.size > 256 * 1024) throw new Error("unsafe");
|
|
29803
29825
|
if (bytes + info.size > 8 * 1024 * 1024) {
|
|
29804
29826
|
warnings.push("BYTE_LIMIT");
|
|
@@ -29879,9 +29901,11 @@ var enabled = (env = process.env) => env.SBERPAY_DIAGNOSTIC_CAPTURE === "1";
|
|
|
29879
29901
|
function dir(env) {
|
|
29880
29902
|
return privateDir2(join12(privateDir2(join12(cliPaths(env).stateDir, "diagnostics")), "episodes"));
|
|
29881
29903
|
}
|
|
29904
|
+
var SESSION_HINT = "CLI \u043D\u0435 \u043D\u0430\u0448\u0451\u043B \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0447\u0430\u0442\u0430: \u043F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 report session --json \u0438 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438\u0442\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0443 \u043A\u043E\u0434. \u0412\u0440\u0443\u0447\u043D\u0443\u044E \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043D\u0435 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0439\u0442\u0435";
|
|
29882
29905
|
async function session(env) {
|
|
29883
29906
|
const s = await collectCurrentSession("auto", env);
|
|
29884
|
-
if (s.status !== "bound"
|
|
29907
|
+
if (s.status !== "bound") throw new BindingError("EPISODE_SESSION_UNAVAILABLE", SESSION_HINT, s.code);
|
|
29908
|
+
if (s.transcript.identity !== "verified") throw new BindingError("EPISODE_SESSION_UNAVAILABLE", SESSION_HINT, "IDENTITY_" + String(s.transcript.identity).toUpperCase());
|
|
29885
29909
|
return s;
|
|
29886
29910
|
}
|
|
29887
29911
|
async function atomic(path2, value) {
|
|
@@ -30535,11 +30559,11 @@ async function livePay(ctx, opts) {
|
|
|
30535
30559
|
const order = validatePayOptions(opts);
|
|
30536
30560
|
const purchaseContext = parseContext(opts.context);
|
|
30537
30561
|
const store = await credentialStoreFor(ctx);
|
|
30538
|
-
const
|
|
30562
|
+
const snapshot2 = await withBindingLock(
|
|
30539
30563
|
bindingScope(ctx),
|
|
30540
30564
|
async () => store.read()
|
|
30541
30565
|
);
|
|
30542
|
-
if (!
|
|
30566
|
+
if (!snapshot2)
|
|
30543
30567
|
throw new CliError(EXIT.AUTH, "NO_CARD", "\u041A\u0430\u0440\u0442\u0430 \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u0430 \u043D\u0435 \u043F\u0440\u0438\u0432\u044F\u0437\u0430\u043D\u0430", {
|
|
30544
30568
|
hint: RELINK_HINT
|
|
30545
30569
|
});
|
|
@@ -30550,7 +30574,7 @@ async function livePay(ctx, opts) {
|
|
|
30550
30574
|
currency: "643",
|
|
30551
30575
|
...purchaseContext ? { purchaseContext } : {}
|
|
30552
30576
|
};
|
|
30553
|
-
const res = await ctx.elcomV3.pay(input2,
|
|
30577
|
+
const res = await ctx.elcomV3.pay(input2, snapshot2.value.agentToken).catch(withOutcomeHint);
|
|
30554
30578
|
if (res.status === "SUCCESS") {
|
|
30555
30579
|
try {
|
|
30556
30580
|
await recordPayment(res.mdOrder ?? order.mdOrder, process.env, opts.merchant);
|
|
@@ -30570,7 +30594,7 @@ async function livePay(ctx, opts) {
|
|
|
30570
30594
|
}
|
|
30571
30595
|
const reason = res.reasonCode;
|
|
30572
30596
|
if (reason === "TOKEN_EXPIRED" || reason === "TOKEN_REVOKED")
|
|
30573
|
-
await forgetLocalToken(ctx,
|
|
30597
|
+
await forgetLocalToken(ctx, snapshot2.fingerprint);
|
|
30574
30598
|
const hint = reason ? HINTS[reason] ?? unknownReasonHint(reason) : void 0;
|
|
30575
30599
|
ctx.out.result(
|
|
30576
30600
|
{
|
|
@@ -34168,11 +34192,11 @@ var program = new Command();
|
|
|
34168
34192
|
|
|
34169
34193
|
// packages/cli/src/report/command.ts
|
|
34170
34194
|
import { homedir as homedir5 } from "node:os";
|
|
34171
|
-
import { join as join16, dirname as dirname6, resolve as resolve2 } from "node:path";
|
|
34195
|
+
import { join as join16, dirname as dirname6, resolve as resolve2, isAbsolute as isAbsolute3 } from "node:path";
|
|
34172
34196
|
|
|
34173
34197
|
// packages/cli/src/report/claudeHook.ts
|
|
34174
34198
|
import { dirname as dirname5 } from "node:path";
|
|
34175
|
-
import { open as open7, chmod, lstat as
|
|
34199
|
+
import { open as open7, chmod, lstat as lstat4, mkdir as mkdir2, readFile as readFile2, realpath as realpath4, rename as rename5, writeFile as writeFile4 } from "node:fs/promises";
|
|
34176
34200
|
import { constants as constants7 } from "node:fs";
|
|
34177
34201
|
import { homedir as homedir4 } from "node:os";
|
|
34178
34202
|
import { join as join15 } from "node:path";
|
|
@@ -34192,7 +34216,7 @@ async function captureClaudeBinding(input2, env = process.env) {
|
|
|
34192
34216
|
if (process.platform === "win32") {
|
|
34193
34217
|
assertWindowsPrivatePath(dirname5(env.CLAUDE_ENV_FILE));
|
|
34194
34218
|
try {
|
|
34195
|
-
await
|
|
34219
|
+
await lstat4(env.CLAUDE_ENV_FILE);
|
|
34196
34220
|
assertWindowsPrivatePath(env.CLAUDE_ENV_FILE);
|
|
34197
34221
|
} catch (e) {
|
|
34198
34222
|
if (e.code !== "ENOENT") throw e;
|
|
@@ -34207,13 +34231,16 @@ async function captureClaudeBinding(input2, env = process.env) {
|
|
|
34207
34231
|
await file2.close();
|
|
34208
34232
|
}
|
|
34209
34233
|
}
|
|
34210
|
-
|
|
34211
|
-
|
|
34212
|
-
|
|
34234
|
+
var claudeHookCommandFor = (args) => [...args, "report", "claude-hook"].map((s) => shellQuote(process.platform === "win32" ? s.replaceAll("\\", "/") : s)).join(" ");
|
|
34235
|
+
async function readSettings(configDir, create2) {
|
|
34236
|
+
if (create2) {
|
|
34237
|
+
if (process.platform === "win32") ensureWindowsPrivateDirectory(configDir);
|
|
34238
|
+
else await mkdir2(configDir, { recursive: true, mode: 448 });
|
|
34239
|
+
}
|
|
34213
34240
|
const path2 = join15(configDir, "settings.json");
|
|
34214
34241
|
let original;
|
|
34215
34242
|
try {
|
|
34216
|
-
const info = await
|
|
34243
|
+
const info = await lstat4(path2);
|
|
34217
34244
|
if (!info.isFile() || info.isSymbolicLink()) throw new BindingError("UNSAFE_SETTINGS");
|
|
34218
34245
|
if (process.platform === "win32") assertWindowsPrivatePath(path2);
|
|
34219
34246
|
original = await readFile2(path2, "utf8");
|
|
@@ -34226,6 +34253,18 @@ async function installClaudeHook(configDir, command) {
|
|
|
34226
34253
|
if (!hooks) throw new BindingError("INVALID_HOOK_SETTINGS");
|
|
34227
34254
|
const start = hooks.SessionStart === void 0 ? [] : hooks.SessionStart;
|
|
34228
34255
|
if (!Array.isArray(start)) throw new BindingError("INVALID_HOOK_SETTINGS");
|
|
34256
|
+
return { path: path2, original, settings, hooks, start };
|
|
34257
|
+
}
|
|
34258
|
+
async function writeSettings(path2, original, settings) {
|
|
34259
|
+
const suffix = randomUUID9();
|
|
34260
|
+
if (original !== void 0) await writeFile4(`${path2}.sberpay-${suffix}.bak`, original, { flag: "wx", mode: 384 });
|
|
34261
|
+
const temp = `${path2}.sberpay-${suffix}.tmp`;
|
|
34262
|
+
await writeFile4(temp, JSON.stringify(settings, null, 2) + "\n", { flag: "wx", mode: 384 });
|
|
34263
|
+
await rename5(temp, path2);
|
|
34264
|
+
await chmod(path2, 384);
|
|
34265
|
+
}
|
|
34266
|
+
async function installClaudeHook(configDir, command) {
|
|
34267
|
+
const { path: path2, original, settings, hooks, start } = await readSettings(configDir, true);
|
|
34229
34268
|
if (start.some((entry) => {
|
|
34230
34269
|
const group = object2(entry);
|
|
34231
34270
|
if (!group || group.matcher !== void 0 || !Array.isArray(group.hooks)) return false;
|
|
@@ -34236,18 +34275,14 @@ async function installClaudeHook(configDir, command) {
|
|
|
34236
34275
|
})) return;
|
|
34237
34276
|
hooks.SessionStart = [...start, { hooks: [{ type: "command", command, timeout: 10 }] }];
|
|
34238
34277
|
settings.hooks = hooks;
|
|
34239
|
-
|
|
34240
|
-
if (original !== void 0) await writeFile4(`${path2}.sberpay-${suffix}.bak`, original, { flag: "wx", mode: 384 });
|
|
34241
|
-
const temp = `${path2}.sberpay-${suffix}.tmp`;
|
|
34242
|
-
await writeFile4(temp, JSON.stringify(settings, null, 2) + "\n", { flag: "wx", mode: 384 });
|
|
34243
|
-
await rename5(temp, path2);
|
|
34244
|
-
await chmod(path2, 384);
|
|
34278
|
+
await writeSettings(path2, original, settings);
|
|
34245
34279
|
}
|
|
34246
34280
|
|
|
34247
34281
|
// packages/cli/src/report/command.ts
|
|
34248
|
-
function claudeHookCommand() {
|
|
34249
|
-
const
|
|
34250
|
-
|
|
34282
|
+
function claudeHookCommand(env = process.env) {
|
|
34283
|
+
const launcher = env.SBERPAY_DIAGNOSTIC_LAUNCHER;
|
|
34284
|
+
const args = BUILD.kind === "release" ? [process.execPath, launcher && isAbsolute3(launcher) ? launcher : join16(BUILD.root, "dist", "cli.mjs")] : [process.execPath, "--import", import.meta.resolve("tsx"), join16(BUILD.root, "packages", "cli", "src", "main.ts")];
|
|
34285
|
+
return claudeHookCommandFor(args);
|
|
34251
34286
|
}
|
|
34252
34287
|
async function hookInput() {
|
|
34253
34288
|
const chunks = [];
|
|
@@ -34296,7 +34331,7 @@ function registerReportCommands(program3) {
|
|
|
34296
34331
|
});
|
|
34297
34332
|
const output2 = () => createOutput(Boolean(program3.opts().json));
|
|
34298
34333
|
const fail2 = (error62) => {
|
|
34299
|
-
const code = error62 instanceof BindingError ? error62.code : "REPORT_FAILED";
|
|
34334
|
+
const code = error62 instanceof BindingError ? error62.code : error62 instanceof Error && /^[A-Z][A-Z0-9_]{2,63}$/.test(error62.message) ? error62.message : "REPORT_FAILED";
|
|
34300
34335
|
output2().error(new CliError(EXIT.CONFIG_OR_NETWORK, code, "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0434\u0438\u0430\u0433\u043D\u043E\u0441\u0442\u0438\u043A\u0443: " + code, error62 instanceof BindingError ? { hint: error62.hint, reasonCode: error62.reasonCode } : {}));
|
|
34301
34336
|
process.exitCode = EXIT.CONFIG_OR_NETWORK;
|
|
34302
34337
|
};
|
|
@@ -35146,7 +35181,7 @@ import { join as join19 } from "node:path";
|
|
|
35146
35181
|
// packages/cli/src/core/keyHelper.ts
|
|
35147
35182
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
35148
35183
|
import { existsSync as existsSync6, realpathSync as realpathSync2, statSync } from "node:fs";
|
|
35149
|
-
import { dirname as dirname8, isAbsolute as
|
|
35184
|
+
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join18 } from "node:path";
|
|
35150
35185
|
var PACKAGED = { "darwin-arm64": "darwin", "darwin-x64": "darwin", "linux-x64": "linux-x64", "linux-arm64": "linux-arm64", "win32-x64": "win32-x64", "win32-arm64": "win32-arm64" };
|
|
35151
35186
|
function chipOf(platform2) {
|
|
35152
35187
|
if (platform2 === "darwin") return "secure-enclave";
|
|
@@ -35202,7 +35237,7 @@ function unavailable(message2, hint) {
|
|
|
35202
35237
|
}
|
|
35203
35238
|
function findKeyHelper(opts) {
|
|
35204
35239
|
const path2 = opts.override ?? opts.installed;
|
|
35205
|
-
if (!
|
|
35240
|
+
if (!isAbsolute4(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");
|
|
35206
35241
|
if (!existsSync6(path2)) return void 0;
|
|
35207
35242
|
if (!isTrustedFile(path2)) {
|
|
35208
35243
|
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");
|
|
@@ -35717,7 +35752,7 @@ var DeviceRequestClaims = external_exports.discriminatedUnion("op", [
|
|
|
35717
35752
|
);
|
|
35718
35753
|
|
|
35719
35754
|
// packages/contracts/src/v3/merchants.ts
|
|
35720
|
-
var MERCHANT_PATHS = { check: "/merchants/check" };
|
|
35755
|
+
var MERCHANT_PATHS = { check: "/merchants/check", domains: "/merchants/domains" };
|
|
35721
35756
|
var Merchant2 = external_exports.object({
|
|
35722
35757
|
merchantId: external_exports.string(),
|
|
35723
35758
|
name: external_exports.string(),
|
|
@@ -35732,6 +35767,15 @@ var CheckMerchantResponse2 = external_exports.object({
|
|
|
35732
35767
|
supported: external_exports.boolean(),
|
|
35733
35768
|
merchant: Merchant2.optional()
|
|
35734
35769
|
});
|
|
35770
|
+
var MerchantDomain = external_exports.object({
|
|
35771
|
+
domain: external_exports.string().min(1).max(253),
|
|
35772
|
+
includeSubdomains: external_exports.boolean()
|
|
35773
|
+
});
|
|
35774
|
+
var MerchantDomainsResponse = external_exports.object({
|
|
35775
|
+
requestId: external_exports.string(),
|
|
35776
|
+
count: external_exports.number().int().nonnegative(),
|
|
35777
|
+
domains: external_exports.array(MerchantDomain).max(1e6)
|
|
35778
|
+
});
|
|
35735
35779
|
|
|
35736
35780
|
// packages/cli/src/core/trustedRoots.ts
|
|
35737
35781
|
import { createHash as createHash11, X509Certificate } from "node:crypto";
|
|
@@ -37409,8 +37453,9 @@ function createElcomClientV3(core, device2, options = {}) {
|
|
|
37409
37453
|
|
|
37410
37454
|
// packages/cli/src/schemes/v2/merchantsClient.ts
|
|
37411
37455
|
var PEER = "\u0424\u041F \u0423\u043C\u043D\u044B\u0435 \u043F\u043E\u043A\u0443\u043F\u043A\u0438";
|
|
37456
|
+
var DOMAINS_TIMEOUT_MS = 3e4;
|
|
37412
37457
|
function createMerchantsClient(logger, baseUrl) {
|
|
37413
|
-
const post = async (op, path2, body) => {
|
|
37458
|
+
const post = async (op, path2, body, extra = {}) => {
|
|
37414
37459
|
if (!baseUrl) {
|
|
37415
37460
|
throw new CliError(
|
|
37416
37461
|
EXIT.CONFIG_OR_NETWORK,
|
|
@@ -37427,7 +37472,8 @@ function createMerchantsClient(logger, baseUrl) {
|
|
|
37427
37472
|
peer: PEER,
|
|
37428
37473
|
url: `${baseUrl}${path2}`,
|
|
37429
37474
|
body: { requestId, ...body },
|
|
37430
|
-
headers: { [HEADER_REQUEST_ID]: requestId }
|
|
37475
|
+
headers: { [HEADER_REQUEST_ID]: requestId },
|
|
37476
|
+
...extra
|
|
37431
37477
|
});
|
|
37432
37478
|
};
|
|
37433
37479
|
return {
|
|
@@ -37437,7 +37483,17 @@ function createMerchantsClient(logger, baseUrl) {
|
|
|
37437
37483
|
domain: normalizeDomain(domain2)
|
|
37438
37484
|
}),
|
|
37439
37485
|
PEER
|
|
37440
|
-
)
|
|
37486
|
+
),
|
|
37487
|
+
domains: async () => {
|
|
37488
|
+
const res = expectResponse(
|
|
37489
|
+
MerchantDomainsResponse,
|
|
37490
|
+
await post("\u0441\u043F\u0438\u0441\u043E\u043A \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u043C\u0430\u0433\u0430\u0437\u0438\u043D\u043E\u0432", MERCHANT_PATHS.domains, {}, { timeoutMs: DOMAINS_TIMEOUT_MS, sensitive: true }),
|
|
37491
|
+
PEER
|
|
37492
|
+
);
|
|
37493
|
+
if (res.count !== res.domains.length)
|
|
37494
|
+
throw new CliError(EXIT.CONFIG_OR_NETWORK, "INVALID_RESPONSE", `${PEER}: count (${res.count}) \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0435\u0442 \u0441 \u0447\u0438\u0441\u043B\u043E\u043C \u0434\u043E\u043C\u0435\u043D\u043E\u0432 (${res.domains.length})`);
|
|
37495
|
+
return res;
|
|
37496
|
+
}
|
|
37441
37497
|
};
|
|
37442
37498
|
}
|
|
37443
37499
|
function normalizeDomain(input2) {
|
|
@@ -38428,11 +38484,6 @@ async function authLoginCommand(ctx, opts) {
|
|
|
38428
38484
|
session2?.legacy ? "LEGACY_PENDING_NO_LINK" : "LOGIN_STARTING",
|
|
38429
38485
|
"\u0421\u0441\u044B\u043B\u043A\u0430 \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u043F\u043E\u043F\u044B\u0442\u043A\u0438 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 auth status; \u0440\u0430\u043D\u0435\u0435 \u0432\u044B\u0434\u0430\u043D\u043D\u044B\u0439 \u0442\u043E\u043A\u0435\u043D \u043C\u043E\u0436\u043D\u043E \u043F\u0435\u0440\u0435\u0434\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 auth complete."
|
|
38430
38486
|
);
|
|
38431
|
-
process.stderr.write(`
|
|
38432
|
-
\u041C\u0435\u0442\u043A\u0430 \u0441\u0435\u0441\u0441\u0438\u0438:
|
|
38433
|
-
${session2.mark.text}
|
|
38434
|
-
${session2.mark.names}
|
|
38435
|
-
`);
|
|
38436
38487
|
if (ctx.stand.cabinetMockUrl) process.stderr.write("\u041A\u0430\u0431\u0438\u043D\u0435\u0442 \u2014 \u043C\u043E\u043A, \u0430 \u043D\u0435 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0438\u0439 \u043A\u0430\u0431\u0438\u043D\u0435\u0442 \u041A\u0413\u0421.\n");
|
|
38437
38488
|
if (record2.mode === "local") await openInBrowser(session2.link, ctx.out, !opts.open);
|
|
38438
38489
|
const update = updateForVersion(session2.cliLatest);
|
|
@@ -38484,19 +38535,19 @@ async function verifySavedToken(ctx, offline = false) {
|
|
|
38484
38535
|
try {
|
|
38485
38536
|
const store = await credentialStoreFor(ctx), scope = bindingScope(ctx);
|
|
38486
38537
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
38487
|
-
const { snapshot, meta: meta3 } = await withBindingLock(scope, async () => ({
|
|
38538
|
+
const { snapshot: snapshot2, meta: meta3 } = await withBindingLock(scope, async () => ({
|
|
38488
38539
|
snapshot: store.read(),
|
|
38489
38540
|
meta: offline ? loadConfig(ctx.paths).tokenMetaV3?.[store.scopeHash] : void 0
|
|
38490
38541
|
}));
|
|
38491
|
-
if (!
|
|
38492
|
-
const { tokenId, subId } =
|
|
38542
|
+
if (!snapshot2) return { loggedIn: false, canPay: false };
|
|
38543
|
+
const { tokenId, subId } = snapshot2.value;
|
|
38493
38544
|
if (offline) {
|
|
38494
38545
|
return {
|
|
38495
38546
|
loggedIn: true,
|
|
38496
38547
|
canPay: false,
|
|
38497
38548
|
source: "local-cache",
|
|
38498
38549
|
tokenId,
|
|
38499
|
-
...meta3 && meta3.credentialHash ===
|
|
38550
|
+
...meta3 && meta3.credentialHash === snapshot2.fingerprint ? { token: toView({ tokenStatus: "ACTIVE", ...meta3 }) } : {}
|
|
38500
38551
|
};
|
|
38501
38552
|
}
|
|
38502
38553
|
let response, networkError2;
|
|
@@ -38508,7 +38559,7 @@ async function verifySavedToken(ctx, offline = false) {
|
|
|
38508
38559
|
const result = await withBindingLock(
|
|
38509
38560
|
scope,
|
|
38510
38561
|
async () => {
|
|
38511
|
-
if (store.read()?.fingerprint !==
|
|
38562
|
+
if (store.read()?.fingerprint !== snapshot2.fingerprint) return;
|
|
38512
38563
|
if (networkError2)
|
|
38513
38564
|
return failure2(
|
|
38514
38565
|
networkError2 instanceof CliError ? networkError2.code : "TOKEN_STATUS_UNAVAILABLE",
|
|
@@ -38529,7 +38580,7 @@ async function verifySavedToken(ctx, offline = false) {
|
|
|
38529
38580
|
);
|
|
38530
38581
|
const canPay = status.tokenStatus === "ACTIVE";
|
|
38531
38582
|
if (!canPay) {
|
|
38532
|
-
store.deleteIfUnchanged(
|
|
38583
|
+
store.deleteIfUnchanged(snapshot2.fingerprint);
|
|
38533
38584
|
await ctx.updateConfig((c) => {
|
|
38534
38585
|
const meta4 = { ...c.tokenMetaV3 };
|
|
38535
38586
|
delete meta4[store.scopeHash];
|
|
@@ -38541,7 +38592,7 @@ async function verifySavedToken(ctx, offline = false) {
|
|
|
38541
38592
|
tokenMetaV3: {
|
|
38542
38593
|
...c.tokenMetaV3,
|
|
38543
38594
|
[store.scopeHash]: {
|
|
38544
|
-
credentialHash:
|
|
38595
|
+
credentialHash: snapshot2.fingerprint,
|
|
38545
38596
|
cardMask: status.cardMask ?? "",
|
|
38546
38597
|
purchaseLimit: status.purchaseLimit,
|
|
38547
38598
|
dailyLimit: status.dailyLimit,
|
|
@@ -38655,8 +38706,8 @@ async function authLogoutCommand(ctx, opts) {
|
|
|
38655
38706
|
cancelBindingLocked(ctx);
|
|
38656
38707
|
ctx.secrets.delete("agentToken");
|
|
38657
38708
|
const store = ctx.device.exists() ? await credentialStoreFor(ctx) : void 0;
|
|
38658
|
-
const
|
|
38659
|
-
if (
|
|
38709
|
+
const snapshot2 = store?.read();
|
|
38710
|
+
if (snapshot2) store.deleteIfUnchanged(snapshot2.fingerprint);
|
|
38660
38711
|
await ctx.updateConfig((c) => {
|
|
38661
38712
|
const { token: _token, pendingSession: _pending, ...rest } = c;
|
|
38662
38713
|
const tokenMetaV3 = { ...c.tokenMetaV3 };
|
|
@@ -38685,14 +38736,14 @@ var ALREADY = {
|
|
|
38685
38736
|
};
|
|
38686
38737
|
async function cardRevokeCommand(ctx) {
|
|
38687
38738
|
const store = ctx.device.exists() ? await credentialStoreFor(ctx) : void 0;
|
|
38688
|
-
const
|
|
38739
|
+
const snapshot2 = await withBindingLock(bindingScope(ctx), async () => {
|
|
38689
38740
|
cancelBindingLocked(ctx);
|
|
38690
38741
|
return store?.read();
|
|
38691
38742
|
});
|
|
38692
38743
|
const res = await ctx.elcomV3.revoke();
|
|
38693
38744
|
if (res.tokenStatus === "ACTIVE")
|
|
38694
38745
|
throw new Error("\u041E\u0442\u0437\u044B\u0432 \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043D \u0431\u0430\u043D\u043A\u043E\u043C");
|
|
38695
|
-
await forgetLocalToken(ctx,
|
|
38746
|
+
await forgetLocalToken(ctx, snapshot2?.fingerprint);
|
|
38696
38747
|
const concurrent = store?.read();
|
|
38697
38748
|
const verification = concurrent ? await verifySavedToken(ctx) : void 0;
|
|
38698
38749
|
const human = verification ? "\u041E\u0442\u0437\u044B\u0432 \u043F\u043E \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0443 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D. \u041B\u043E\u043A\u0430\u043B\u044C\u043D\u0430\u044F \u043F\u0440\u0438\u0432\u044F\u0437\u043A\u0430 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u0430\u0441\u044C \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u0430; \u0435\u0451 \u0442\u0435\u043A\u0443\u0449\u0430\u044F \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u0430 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E." : res.tokenStatus === "REVOKED" ? "\u2713 \u0414\u043E\u0441\u0442\u0443\u043F \u0430\u0433\u0435\u043D\u0442\u0430 \u043A \u043A\u0430\u0440\u0442\u0435 \u043E\u0442\u043E\u0437\u0432\u0430\u043D, \u043E\u043F\u043B\u0430\u0442\u044B \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u043F\u0440\u043E\u0439\u0434\u0443\u0442." : `\u2713 \u041E\u0442\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: ${ALREADY[res.tokenStatus] ?? res.tokenStatus}. \u041E\u043F\u043B\u0430\u0442\u044B \u0441 \u044D\u0442\u043E\u0433\u043E \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0430 \u043D\u0435 \u043F\u0440\u043E\u0439\u0434\u0443\u0442.`;
|
|
@@ -38706,6 +38757,171 @@ async function cardRevokeCommand(ctx) {
|
|
|
38706
38757
|
);
|
|
38707
38758
|
}
|
|
38708
38759
|
|
|
38760
|
+
// packages/cli/src/schemes/v2/merchantsDomains.ts
|
|
38761
|
+
import { readFileSync as readFileSync12, rmSync as rmSync7 } from "node:fs";
|
|
38762
|
+
import { join as join24 } from "node:path";
|
|
38763
|
+
import { domainToUnicode } from "node:url";
|
|
38764
|
+
var DOMAINS_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
38765
|
+
var REFRESH_BACKOFF_MS = 15 * 60 * 1e3;
|
|
38766
|
+
var LOCK_TIMEOUT_MS = 2e4;
|
|
38767
|
+
var CLOCK_SKEW_MS = 5 * 60 * 1e3;
|
|
38768
|
+
var CacheRecord = external_exports.object({
|
|
38769
|
+
format: external_exports.literal(1),
|
|
38770
|
+
stand: external_exports.string(),
|
|
38771
|
+
merchantsUrl: external_exports.string(),
|
|
38772
|
+
fetchedAt: external_exports.string(),
|
|
38773
|
+
count: external_exports.number().int().nonnegative(),
|
|
38774
|
+
domains: external_exports.array(MerchantDomain)
|
|
38775
|
+
});
|
|
38776
|
+
var AttemptRecord = external_exports.object({
|
|
38777
|
+
format: external_exports.literal(1),
|
|
38778
|
+
merchantsUrl: external_exports.string(),
|
|
38779
|
+
failedAt: external_exports.string(),
|
|
38780
|
+
code: external_exports.string()
|
|
38781
|
+
});
|
|
38782
|
+
function cacheFiles(ctx) {
|
|
38783
|
+
const base2 = join24(ctx.paths.cacheDir, `merchants-domains.${ctx.standName}`);
|
|
38784
|
+
return { data: `${base2}.json`, attempt: `${base2}.attempt.json`, lock: `${base2}.lock` };
|
|
38785
|
+
}
|
|
38786
|
+
function merchantsBase(ctx) {
|
|
38787
|
+
const url2 = ctx.stand.merchantsUrl?.replace(/\/+$/, "");
|
|
38788
|
+
if (!url2)
|
|
38789
|
+
throw new CliError(EXIT.CONFIG_OR_NETWORK, "STAND_NOT_CONFIGURED", "\u041D\u0430 \u044D\u0442\u043E\u043C \u0441\u0442\u0435\u043D\u0434\u0435 \u043D\u0435\u0442 \u0440\u0435\u0435\u0441\u0442\u0440\u0430 \u043C\u0430\u0433\u0430\u0437\u0438\u043D\u043E\u0432 \u0424\u041F (merchantsUrl \u043D\u0435 \u0437\u0430\u0434\u0430\u043D)", {
|
|
38790
|
+
hint: "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 stands.<\u0441\u0442\u0435\u043D\u0434>.merchantsUrl \u0432 config.json"
|
|
38791
|
+
});
|
|
38792
|
+
return url2;
|
|
38793
|
+
}
|
|
38794
|
+
function readJson(file2, schema) {
|
|
38795
|
+
try {
|
|
38796
|
+
const parsed = schema.safeParse(JSON.parse(readFileSync12(file2, "utf8")));
|
|
38797
|
+
return parsed.success ? parsed.data : void 0;
|
|
38798
|
+
} catch {
|
|
38799
|
+
return void 0;
|
|
38800
|
+
}
|
|
38801
|
+
}
|
|
38802
|
+
function readCache(ctx, url2) {
|
|
38803
|
+
const record2 = readJson(cacheFiles(ctx).data, CacheRecord);
|
|
38804
|
+
if (!record2 || record2.stand !== ctx.standName || record2.merchantsUrl !== url2) return void 0;
|
|
38805
|
+
if (record2.count !== record2.domains.length || Number.isNaN(Date.parse(record2.fetchedAt))) return void 0;
|
|
38806
|
+
return record2;
|
|
38807
|
+
}
|
|
38808
|
+
function isFresh(record2, now) {
|
|
38809
|
+
const fetched = Date.parse(record2.fetchedAt);
|
|
38810
|
+
return fetched <= now + CLOCK_SKEW_MS && now - fetched < DOMAINS_TTL_MS;
|
|
38811
|
+
}
|
|
38812
|
+
function snapshot(ctx, record2, source, now, refreshError) {
|
|
38813
|
+
return {
|
|
38814
|
+
stand: ctx.standName,
|
|
38815
|
+
source,
|
|
38816
|
+
fetchedAt: record2.fetchedAt,
|
|
38817
|
+
ageHours: Math.max(0, Math.round((now - Date.parse(record2.fetchedAt)) / 36e5 * 10) / 10),
|
|
38818
|
+
stale: refreshError !== void 0 || !isFresh(record2, now),
|
|
38819
|
+
...refreshError ? { refreshError } : {},
|
|
38820
|
+
count: record2.count,
|
|
38821
|
+
file: cacheFiles(ctx).data,
|
|
38822
|
+
domains: record2.domains
|
|
38823
|
+
};
|
|
38824
|
+
}
|
|
38825
|
+
function backoff(ctx, url2, now) {
|
|
38826
|
+
const attempt = readJson(cacheFiles(ctx).attempt, AttemptRecord);
|
|
38827
|
+
if (!attempt || attempt.merchantsUrl !== url2) return void 0;
|
|
38828
|
+
const until = Date.parse(attempt.failedAt) + REFRESH_BACKOFF_MS;
|
|
38829
|
+
return Number.isNaN(until) || until <= now ? void 0 : { until, code: attempt.code };
|
|
38830
|
+
}
|
|
38831
|
+
async function loadDomains(ctx, opts = {}) {
|
|
38832
|
+
const now = () => ctx.now?.() ?? Date.now();
|
|
38833
|
+
const url2 = merchantsBase(ctx);
|
|
38834
|
+
const files = cacheFiles(ctx);
|
|
38835
|
+
const cached2 = readCache(ctx, url2);
|
|
38836
|
+
if (opts.offline) {
|
|
38837
|
+
if (!cached2)
|
|
38838
|
+
throw new CliError(EXIT.CONFIG_OR_NETWORK, "MERCHANTS_DOMAINS_NOT_CACHED", "\u0421\u043F\u0438\u0441\u043E\u043A \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u0435\u0449\u0451 \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u043D \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435", {
|
|
38839
|
+
hint: "\u0417\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 sberpay-cli merchants domains \u0431\u0435\u0437 --offline"
|
|
38840
|
+
});
|
|
38841
|
+
return snapshot(ctx, cached2, "cache", now());
|
|
38842
|
+
}
|
|
38843
|
+
if (cached2 && !opts.refresh && isFresh(cached2, now())) return snapshot(ctx, cached2, "cache", now());
|
|
38844
|
+
const blocked = backoff(ctx, url2, now());
|
|
38845
|
+
if (blocked) {
|
|
38846
|
+
const refreshError = {
|
|
38847
|
+
code: blocked.code,
|
|
38848
|
+
message: `\u041F\u0440\u043E\u0448\u043B\u043E\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u043F\u0438\u0441\u043A\u0430 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C; \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0430\u044F \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u043F\u043E\u0441\u043B\u0435 ${new Date(blocked.until).toISOString()}`
|
|
38849
|
+
};
|
|
38850
|
+
if (cached2) return snapshot(ctx, cached2, "cache", now(), refreshError);
|
|
38851
|
+
throw new CliError(EXIT.CONFIG_OR_NETWORK, "MERCHANTS_DOMAINS_UNAVAILABLE", `\u0421\u043F\u0438\u0441\u043E\u043A \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D: ${refreshError.message}`, {
|
|
38852
|
+
hint: "\u0414\u043B\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u0430\u0439\u0442\u0430 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 sberpay-cli merchants check <\u0434\u043E\u043C\u0435\u043D>"
|
|
38853
|
+
});
|
|
38854
|
+
}
|
|
38855
|
+
try {
|
|
38856
|
+
return await withFileLock(
|
|
38857
|
+
files.lock,
|
|
38858
|
+
async () => {
|
|
38859
|
+
const latest = readCache(ctx, url2);
|
|
38860
|
+
if (latest && latest.fetchedAt !== cached2?.fetchedAt && isFresh(latest, now())) return snapshot(ctx, latest, "cache", now());
|
|
38861
|
+
let response;
|
|
38862
|
+
try {
|
|
38863
|
+
response = await ctx.merchants.domains();
|
|
38864
|
+
} catch (error62) {
|
|
38865
|
+
if (error62 instanceof CliError)
|
|
38866
|
+
atomicJson(files.attempt, { format: 1, merchantsUrl: url2, failedAt: new Date(now()).toISOString(), code: error62.code });
|
|
38867
|
+
throw error62;
|
|
38868
|
+
}
|
|
38869
|
+
const record2 = {
|
|
38870
|
+
format: 1,
|
|
38871
|
+
stand: ctx.standName,
|
|
38872
|
+
merchantsUrl: url2,
|
|
38873
|
+
fetchedAt: new Date(now()).toISOString(),
|
|
38874
|
+
count: response.count,
|
|
38875
|
+
domains: response.domains
|
|
38876
|
+
};
|
|
38877
|
+
atomicJson(files.data, record2, { compact: true });
|
|
38878
|
+
rmSync7(files.attempt, { force: true });
|
|
38879
|
+
return snapshot(ctx, record2, "network", now());
|
|
38880
|
+
},
|
|
38881
|
+
LOCK_TIMEOUT_MS
|
|
38882
|
+
);
|
|
38883
|
+
} catch (error62) {
|
|
38884
|
+
if (!(error62 instanceof CliError)) throw error62;
|
|
38885
|
+
const latest = error62.code === "BINDING_BUSY" ? readCache(ctx, url2) ?? cached2 : cached2;
|
|
38886
|
+
ctx.warn(`merchants domains: \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u043F\u0438\u0441\u043A\u0430 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C (${error62.code}): ${error62.message}`);
|
|
38887
|
+
if (latest) return snapshot(ctx, latest, "cache", now(), { code: error62.code, message: error62.message });
|
|
38888
|
+
if (error62.code === "BINDING_BUSY")
|
|
38889
|
+
throw new CliError(EXIT.CONFIG_OR_NETWORK, "MERCHANTS_DOMAINS_BUSY", "\u0421\u043F\u0438\u0441\u043E\u043A \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u0441\u0435\u0439\u0447\u0430\u0441 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442 \u0434\u0440\u0443\u0433\u0430\u044F \u043A\u043E\u043C\u0430\u043D\u0434\u0430", {
|
|
38890
|
+
hint: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u0447\u0435\u0440\u0435\u0437 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0435\u043A\u0443\u043D\u0434"
|
|
38891
|
+
});
|
|
38892
|
+
throw error62;
|
|
38893
|
+
}
|
|
38894
|
+
}
|
|
38895
|
+
var indexDomains = (domains) => new Map(domains.map((entry) => [entry.domain, entry.includeSubdomains]));
|
|
38896
|
+
function matchDomain(index, input2) {
|
|
38897
|
+
let domain2;
|
|
38898
|
+
try {
|
|
38899
|
+
domain2 = normalizeDomain(input2);
|
|
38900
|
+
} catch (error62) {
|
|
38901
|
+
return { input: input2, supported: false, error: error62 instanceof CliError ? error62.code : "INVALID_ARGUMENT" };
|
|
38902
|
+
}
|
|
38903
|
+
if (index.has(domain2)) return { input: input2, domain: domain2, supported: true, registryDomain: domain2, matchedBy: "exact" };
|
|
38904
|
+
for (let candidate = domain2; candidate.includes("."); ) {
|
|
38905
|
+
candidate = candidate.slice(candidate.indexOf(".") + 1);
|
|
38906
|
+
if (index.get(candidate) === true) return { input: input2, domain: domain2, supported: true, registryDomain: candidate, matchedBy: "parent" };
|
|
38907
|
+
}
|
|
38908
|
+
return { input: input2, domain: domain2, supported: false };
|
|
38909
|
+
}
|
|
38910
|
+
function searchDomains(domains, query, limit) {
|
|
38911
|
+
const needle = query.trim().toLowerCase();
|
|
38912
|
+
if (!needle) throw new CliError(EXIT.VALIDATION, "INVALID_ARGUMENT", "--search: \u043F\u0443\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u043F\u043E\u0438\u0441\u043A\u0430");
|
|
38913
|
+
const hits = [];
|
|
38914
|
+
let total = 0;
|
|
38915
|
+
for (const entry of domains) {
|
|
38916
|
+
const unicode = entry.domain.includes("xn--") ? domainToUnicode(entry.domain) : entry.domain;
|
|
38917
|
+
if (!entry.domain.includes(needle) && !unicode.toLowerCase().includes(needle)) continue;
|
|
38918
|
+
total++;
|
|
38919
|
+
if (hits.length < limit)
|
|
38920
|
+
hits.push({ domain: entry.domain, ...unicode && unicode !== entry.domain ? { unicode } : {}, includeSubdomains: entry.includeSubdomains });
|
|
38921
|
+
}
|
|
38922
|
+
return { total, truncated: total > hits.length, domains: hits };
|
|
38923
|
+
}
|
|
38924
|
+
|
|
38709
38925
|
// packages/cli/src/schemes/v2/commands/merchants.ts
|
|
38710
38926
|
async function merchantsCheckCommand(ctx, domain2) {
|
|
38711
38927
|
const res = await ctx.merchants.check(domain2);
|
|
@@ -38717,6 +38933,47 @@ ${entry.domain}:
|
|
|
38717
38933
|
${entry.payload}`).join("") ?? "")
|
|
38718
38934
|
);
|
|
38719
38935
|
}
|
|
38936
|
+
var DEFAULT_SEARCH_LIMIT = 50;
|
|
38937
|
+
var MAX_SEARCH_LIMIT = 1e3;
|
|
38938
|
+
var MAX_MATCH_INPUTS = 500;
|
|
38939
|
+
function searchLimit(raw) {
|
|
38940
|
+
if (raw === void 0) return DEFAULT_SEARCH_LIMIT;
|
|
38941
|
+
const limit = Number(raw);
|
|
38942
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_SEARCH_LIMIT)
|
|
38943
|
+
throw new CliError(EXIT.VALIDATION, "INVALID_ARGUMENT", `--limit: \u0446\u0435\u043B\u043E\u0435 \u043E\u0442 1 \u0434\u043E ${MAX_SEARCH_LIMIT}`);
|
|
38944
|
+
return limit;
|
|
38945
|
+
}
|
|
38946
|
+
async function merchantsDomainsCommand(ctx, opts) {
|
|
38947
|
+
const match = opts.match ?? [];
|
|
38948
|
+
if (match.length > MAX_MATCH_INPUTS)
|
|
38949
|
+
throw new CliError(EXIT.VALIDATION, "INVALID_ARGUMENT", `--match: \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${MAX_MATCH_INPUTS} \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u0437\u0430 \u0432\u044B\u0437\u043E\u0432`);
|
|
38950
|
+
if (opts.refresh && opts.offline)
|
|
38951
|
+
throw new CliError(EXIT.VALIDATION, "INVALID_ARGUMENT", "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043E\u0434\u043D\u043E: --refresh \u0438\u043B\u0438 --offline");
|
|
38952
|
+
const limit = searchLimit(opts.limit);
|
|
38953
|
+
const { domains, ...summary } = await loadDomains(ctx, { refresh: opts.refresh, offline: opts.offline });
|
|
38954
|
+
const result = { ...summary };
|
|
38955
|
+
const lines = [
|
|
38956
|
+
`\u041C\u0430\u0433\u0430\u0437\u0438\u043D\u043E\u0432 \u0441 \u043E\u043F\u043B\u0430\u0442\u043E\u0439 \u0430\u0433\u0435\u043D\u0442\u043E\u043C: ${summary.count} (\u0441\u043F\u0438\u0441\u043E\u043A \u043E\u0442 ${summary.fetchedAt}${summary.stale ? ", \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043D\u0435\u043F\u043E\u043B\u043D\u044B\u043C" : ""})`
|
|
38957
|
+
];
|
|
38958
|
+
if (match.length) {
|
|
38959
|
+
const index = indexDomains(domains);
|
|
38960
|
+
const matches = match.map((input2) => matchDomain(index, input2));
|
|
38961
|
+
result.matches = matches;
|
|
38962
|
+
lines.push(
|
|
38963
|
+
...matches.map(
|
|
38964
|
+
(m) => m.error ? `? ${m.input}: \u043D\u0435 \u0434\u043E\u043C\u0435\u043D \u0438 \u043D\u0435 URL` : m.supported ? `\u2713 ${m.domain}${m.matchedBy === "parent" ? ` (\u0447\u0435\u0440\u0435\u0437 ${m.registryDomain})` : ""}` : `\u2717 ${m.domain}`
|
|
38965
|
+
)
|
|
38966
|
+
);
|
|
38967
|
+
}
|
|
38968
|
+
if (opts.search !== void 0) {
|
|
38969
|
+
const found = searchDomains(domains, opts.search, limit);
|
|
38970
|
+
result.search = { query: opts.search, ...found };
|
|
38971
|
+
lines.push(`\u041D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u043E \xAB${opts.search}\xBB: ${found.total}${found.truncated ? ` (\u043F\u043E\u043A\u0430\u0437\u0430\u043D\u044B \u043F\u0435\u0440\u0432\u044B\u0435 ${found.domains.length})` : ""}`);
|
|
38972
|
+
lines.push(...found.domains.map((d) => ` ${d.unicode ?? d.domain}`));
|
|
38973
|
+
}
|
|
38974
|
+
if (!match.length && opts.search === void 0) lines.push(`\u041F\u043E\u043B\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A: ${summary.file}`);
|
|
38975
|
+
ctx.out.result(result, lines.join("\n"));
|
|
38976
|
+
}
|
|
38720
38977
|
|
|
38721
38978
|
// packages/cli/src/schemes/v2/commands/device.ts
|
|
38722
38979
|
async function deviceInfo(ctx) {
|
|
@@ -38833,20 +39090,20 @@ function createAddressesClient(core, device2, credentials, options = {}) {
|
|
|
38833
39090
|
);
|
|
38834
39091
|
if (!device2.exists())
|
|
38835
39092
|
throw new CliError(EXIT.AUTH, "NO_CARD", "\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043F\u0440\u0438\u0432\u044F\u0436\u0438\u0442\u0435 \u043A\u0430\u0440\u0442\u0443");
|
|
38836
|
-
const
|
|
39093
|
+
const snapshot2 = await withBindingLock(
|
|
38837
39094
|
bindingScope(core),
|
|
38838
39095
|
async () => credentials.read()
|
|
38839
39096
|
);
|
|
38840
|
-
if (!
|
|
39097
|
+
if (!snapshot2)
|
|
38841
39098
|
throw new CliError(EXIT.AUTH, "NO_CARD", "\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043F\u0440\u0438\u0432\u044F\u0436\u0438\u0442\u0435 \u043A\u0430\u0440\u0442\u0443");
|
|
38842
|
-
if (!AddressSubId.safeParse(
|
|
39099
|
+
if (!AddressSubId.safeParse(snapshot2.value.subId).success)
|
|
38843
39100
|
throw new CliError(
|
|
38844
39101
|
EXIT.AUTH,
|
|
38845
39102
|
"TOKEN_MALFORMED",
|
|
38846
39103
|
"subId \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u043E\u0439 \u043F\u0440\u0438\u0432\u044F\u0437\u043A\u0438 \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043A\u043E\u043D\u0442\u0440\u0430\u043A\u0442\u0443 \u0424\u041F"
|
|
38847
39104
|
);
|
|
38848
39105
|
if (core.stand.addressesMode === "pilot-json")
|
|
38849
|
-
return sendPilotAddress(core, path2, schema,
|
|
39106
|
+
return sendPilotAddress(core, path2, schema, snapshot2.value.subId, deliveryAddress);
|
|
38850
39107
|
const pub = await device2.ensure(), kid = await calculateJwkThumbprint(pub.encKey);
|
|
38851
39108
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
38852
39109
|
const key = await getEncryptionKey(core, attempt > 0, options), requestId = randomUUID15(), iat = Math.floor(Date.now() / 1e3);
|
|
@@ -38859,7 +39116,7 @@ function createAddressesClient(core, device2, credentials, options = {}) {
|
|
|
38859
39116
|
exp: iat + 60,
|
|
38860
39117
|
jti: randomBytes2(16).toString("base64url"),
|
|
38861
39118
|
body: {
|
|
38862
|
-
subId:
|
|
39119
|
+
subId: snapshot2.value.subId,
|
|
38863
39120
|
...deliveryAddress ? { deliveryAddress } : {}
|
|
38864
39121
|
}
|
|
38865
39122
|
});
|
|
@@ -38997,6 +39254,10 @@ function createScheme(core) {
|
|
|
38997
39254
|
addressGet: run3(addressGetCommand),
|
|
38998
39255
|
addressSet: run3(addressSetCommand),
|
|
38999
39256
|
merchantsCheck: async (domain2) => merchantsCheckCommand(merchantsCtx, domain2),
|
|
39257
|
+
merchantsDomains: async (opts) => merchantsDomainsCommand(
|
|
39258
|
+
{ ...merchantsCtx, paths: core.paths, standName: core.standName, stand: core.stand, warn: (msg) => core.warn(msg) },
|
|
39259
|
+
opts
|
|
39260
|
+
),
|
|
39000
39261
|
deviceShow: run3(deviceShowCommand),
|
|
39001
39262
|
deviceRegister: run3(deviceRegisterCommand)
|
|
39002
39263
|
};
|
|
@@ -39013,9 +39274,9 @@ import { resolve as resolve5 } from "node:path";
|
|
|
39013
39274
|
|
|
39014
39275
|
// packages/cli/src/ca/rootCa.ts
|
|
39015
39276
|
import { randomBytes as randomBytes3, X509Certificate as X509Certificate2 } from "node:crypto";
|
|
39016
|
-
import { closeSync as closeSync8, existsSync as existsSync10, fchmodSync, lstatSync as lstatSync6, mkdirSync as mkdirSync12, mkdtempSync, openSync as openSync8, readFileSync as
|
|
39277
|
+
import { closeSync as closeSync8, existsSync as existsSync10, fchmodSync, lstatSync as lstatSync6, mkdirSync as mkdirSync12, mkdtempSync, openSync as openSync8, readFileSync as readFileSync13, renameSync as renameSync5, rmSync as rmSync8, writeFileSync as writeFileSync5, writeSync as writeSync4 } from "node:fs";
|
|
39017
39278
|
import { tmpdir } from "node:os";
|
|
39018
|
-
import { dirname as dirname10, join as
|
|
39279
|
+
import { dirname as dirname10, join as join25, resolve as resolve3 } from "node:path";
|
|
39019
39280
|
var FETCH_TIMEOUT_MS = 15e3;
|
|
39020
39281
|
var LOGIN_KEYCHAIN = "Library/Keychains/login.keychain-db";
|
|
39021
39282
|
var SECURITY_BIN = "/usr/bin/security";
|
|
@@ -39047,7 +39308,7 @@ function verifyRootCert(data, root, now = /* @__PURE__ */ new Date()) {
|
|
|
39047
39308
|
}
|
|
39048
39309
|
function readFetchedRoot(paths, root = RUSSIAN_TRUSTED_ROOT_CA) {
|
|
39049
39310
|
const file2 = rootCaFile(paths, root);
|
|
39050
|
-
return existsSync10(file2) ? verifyRootCert(
|
|
39311
|
+
return existsSync10(file2) ? verifyRootCert(readFileSync13(file2), root) : void 0;
|
|
39051
39312
|
}
|
|
39052
39313
|
function ensureCaDir(dir2) {
|
|
39053
39314
|
mkdirSync12(dir2, { recursive: true, mode: 448 });
|
|
@@ -39060,7 +39321,7 @@ function ensureCaDir(dir2) {
|
|
|
39060
39321
|
}
|
|
39061
39322
|
}
|
|
39062
39323
|
function writeAtomically(path2, data, mode) {
|
|
39063
|
-
const tmp =
|
|
39324
|
+
const tmp = join25(dirname10(path2), `.${randomBytes3(6).toString("hex")}.tmp`);
|
|
39064
39325
|
const fd2 = openSync8(tmp, "wx", mode);
|
|
39065
39326
|
try {
|
|
39066
39327
|
fchmodSync(fd2, mode);
|
|
@@ -39071,7 +39332,7 @@ function writeAtomically(path2, data, mode) {
|
|
|
39071
39332
|
try {
|
|
39072
39333
|
renameSync5(tmp, path2);
|
|
39073
39334
|
} catch (error62) {
|
|
39074
|
-
|
|
39335
|
+
rmSync8(tmp, { force: true });
|
|
39075
39336
|
throw error62;
|
|
39076
39337
|
}
|
|
39077
39338
|
}
|
|
@@ -39104,7 +39365,7 @@ function installPlan(opts) {
|
|
|
39104
39365
|
if (platform2 === "darwin") {
|
|
39105
39366
|
return {
|
|
39106
39367
|
kind: "run",
|
|
39107
|
-
argv: [SECURITY_BIN, "add-trusted-cert", "-r", "trustRoot", "-p", "ssl", "-k",
|
|
39368
|
+
argv: [SECURITY_BIN, "add-trusted-cert", "-r", "trustRoot", "-p", "ssl", "-k", join25(opts.home, LOGIN_KEYCHAIN), file2],
|
|
39108
39369
|
say: "macOS \u0441\u043F\u0440\u043E\u0441\u0438\u0442 \u043F\u0430\u0440\u043E\u043B\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u2014 \u044D\u0442\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435. \u0414\u043E\u0432\u0435\u0440\u0438\u0435 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F TLS (-p ssl), \u0432 \u0441\u0432\u044F\u0437\u043A\u0435 \xAB\u0432\u0445\u043E\u0434\xBB"
|
|
39109
39370
|
};
|
|
39110
39371
|
}
|
|
@@ -39145,33 +39406,33 @@ function installRootCa(deps) {
|
|
|
39145
39406
|
const planFor = (file2) => installPlan({ platform: deps.platform, file: file2, home: deps.home, exists: deps.exists, cert });
|
|
39146
39407
|
const manual = planFor(rootCaFile(deps.paths, root));
|
|
39147
39408
|
if (manual.kind === "manual") return { installed: false, needsHuman: true, ...manual.command ? { command: manual.command } : {}, say: manual.say };
|
|
39148
|
-
const dir2 = mkdtempSync(
|
|
39409
|
+
const dir2 = mkdtempSync(join25(tmpdir(), "sberpay-ca-"));
|
|
39149
39410
|
try {
|
|
39150
|
-
const copy =
|
|
39411
|
+
const copy = join25(dir2, root.fileName);
|
|
39151
39412
|
writeFileSync5(copy, cert.toString(), { flag: "wx", mode: 384 });
|
|
39152
39413
|
const plan = planFor(copy);
|
|
39153
39414
|
const result = plan.kind === "run" ? deps.run(plan.argv) : { status: 1, stderr: "\u043D\u0435\u0442 \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438" };
|
|
39154
39415
|
if (result.status !== 0) throw securityError(result.stderr);
|
|
39155
39416
|
} finally {
|
|
39156
|
-
|
|
39417
|
+
rmSync8(dir2, { recursive: true, force: true });
|
|
39157
39418
|
}
|
|
39158
39419
|
return { installed: true, already: false, say: `${root.name} \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D \u0432 \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0435 \u043A\u043E\u0440\u043D\u0438. ${CHECK_AFTER}` };
|
|
39159
39420
|
}
|
|
39160
39421
|
|
|
39161
39422
|
// packages/cli/src/setup/skill.ts
|
|
39162
39423
|
import { createHash as createHash16 } from "node:crypto";
|
|
39163
|
-
import { cpSync, existsSync as existsSync11, lstatSync as lstatSync7, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as
|
|
39424
|
+
import { cpSync, existsSync as existsSync11, lstatSync as lstatSync7, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as readFileSync14, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync6, rmSync as rmSync9, statSync as statSync2, symlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
39164
39425
|
import { homedir as homedir6 } from "node:os";
|
|
39165
|
-
import { basename, dirname as dirname11, join as
|
|
39426
|
+
import { basename, dirname as dirname11, join as join26, relative as relative3, resolve as resolve4 } from "node:path";
|
|
39166
39427
|
var SKILL_NAME = "sberpay";
|
|
39167
39428
|
var MANIFEST = ".sberpay-cli.json";
|
|
39168
39429
|
var WORK_DIR = ".sberpay-cli";
|
|
39169
39430
|
function skillSourceDir(build = BUILD) {
|
|
39170
|
-
return
|
|
39431
|
+
return join26(build.root, "skill", SKILL_NAME);
|
|
39171
39432
|
}
|
|
39172
39433
|
function claudeSkillDir(opts = {}) {
|
|
39173
39434
|
const { env = process.env, home = homedir6(), cwd = process.cwd() } = opts;
|
|
39174
|
-
const base2 = opts.project ?
|
|
39435
|
+
const base2 = opts.project ? join26(cwd, ".claude") : env.CLAUDE_CONFIG_DIR || join26(home, ".claude");
|
|
39175
39436
|
return resolve4(base2, "skills", SKILL_NAME);
|
|
39176
39437
|
}
|
|
39177
39438
|
function checkSkillDir(target) {
|
|
@@ -39180,13 +39441,13 @@ function checkSkillDir(target) {
|
|
|
39180
39441
|
}
|
|
39181
39442
|
function listFiles(dir2, root = dir2) {
|
|
39182
39443
|
return readdirSync3(dir2, { withFileTypes: true }).flatMap((entry) => {
|
|
39183
|
-
const path2 =
|
|
39444
|
+
const path2 = join26(dir2, entry.name);
|
|
39184
39445
|
if (entry.isDirectory()) return listFiles(path2, root);
|
|
39185
39446
|
return entry.name === MANIFEST ? [] : [relative3(root, path2)];
|
|
39186
39447
|
});
|
|
39187
39448
|
}
|
|
39188
39449
|
function hashFiles(dir2) {
|
|
39189
|
-
return Object.fromEntries(listFiles(dir2).sort().map((file2) => [file2, createHash16("sha256").update(
|
|
39450
|
+
return Object.fromEntries(listFiles(dir2).sort().map((file2) => [file2, createHash16("sha256").update(readFileSync14(join26(dir2, file2))).digest("hex")]));
|
|
39190
39451
|
}
|
|
39191
39452
|
var sameFiles = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
39192
39453
|
function sameDir(a, b) {
|
|
@@ -39201,16 +39462,16 @@ function isLink(path2) {
|
|
|
39201
39462
|
}
|
|
39202
39463
|
}
|
|
39203
39464
|
function readManifest(target) {
|
|
39204
|
-
const file2 =
|
|
39465
|
+
const file2 = join26(target, MANIFEST);
|
|
39205
39466
|
if (!existsSync11(file2)) return void 0;
|
|
39206
39467
|
try {
|
|
39207
|
-
const data = JSON.parse(
|
|
39468
|
+
const data = JSON.parse(readFileSync14(file2, "utf8"));
|
|
39208
39469
|
return typeof data.version === "string" && data.files && typeof data.files === "object" ? data : void 0;
|
|
39209
39470
|
} catch {
|
|
39210
39471
|
return void 0;
|
|
39211
39472
|
}
|
|
39212
39473
|
}
|
|
39213
|
-
var isStaleOwnLink = (target) => !existsSync11(target) && readlinkSync(target).replace(/[\\/]+$/, "").endsWith(
|
|
39474
|
+
var isStaleOwnLink = (target) => !existsSync11(target) && readlinkSync(target).replace(/[\\/]+$/, "").endsWith(join26("skill", SKILL_NAME));
|
|
39214
39475
|
function inspectSkill(source, target) {
|
|
39215
39476
|
if (isLink(target)) {
|
|
39216
39477
|
if (existsSync11(target)) return sameDir(target, source) ? { state: "current", mode: "link" } : { state: "foreign" };
|
|
@@ -39223,20 +39484,20 @@ function inspectSkill(source, target) {
|
|
|
39223
39484
|
return { state: sameFiles(manifest.files, hashFiles(source)) ? "current" : "outdated", mode: "copy" };
|
|
39224
39485
|
}
|
|
39225
39486
|
function prepare(source, work, mode, version2) {
|
|
39226
|
-
const fresh =
|
|
39227
|
-
|
|
39487
|
+
const fresh = join26(work, `new-${process.pid}`);
|
|
39488
|
+
rmSync9(fresh, { recursive: true, force: true });
|
|
39228
39489
|
if (mode === "link") {
|
|
39229
39490
|
symlinkSync(realpathSync3(source), fresh, process.platform === "win32" ? "junction" : "dir");
|
|
39230
39491
|
return fresh;
|
|
39231
39492
|
}
|
|
39232
39493
|
cpSync(source, fresh, { recursive: true, dereference: true });
|
|
39233
39494
|
const manifest = { version: version2, files: hashFiles(fresh) };
|
|
39234
|
-
writeFileSync6(
|
|
39495
|
+
writeFileSync6(join26(fresh, MANIFEST), `${JSON.stringify(manifest, null, 2)}
|
|
39235
39496
|
`);
|
|
39236
39497
|
return fresh;
|
|
39237
39498
|
}
|
|
39238
39499
|
function swap(fresh, target, aside, work) {
|
|
39239
|
-
const previous = existsSync11(target) || isLink(target) ? aside ??
|
|
39500
|
+
const previous = existsSync11(target) || isLink(target) ? aside ?? join26(work, `old-${process.pid}`) : void 0;
|
|
39240
39501
|
if (previous) renameSync6(target, previous);
|
|
39241
39502
|
try {
|
|
39242
39503
|
renameSync6(fresh, target);
|
|
@@ -39244,7 +39505,7 @@ function swap(fresh, target, aside, work) {
|
|
|
39244
39505
|
if (previous) renameSync6(previous, target);
|
|
39245
39506
|
throw error62;
|
|
39246
39507
|
}
|
|
39247
|
-
if (previous && !aside)
|
|
39508
|
+
if (previous && !aside) rmSync9(previous, { recursive: true, force: true });
|
|
39248
39509
|
}
|
|
39249
39510
|
function installSkill(source, target, opts) {
|
|
39250
39511
|
const found = inspectSkill(source, target);
|
|
@@ -39256,14 +39517,14 @@ function installSkill(source, target, opts) {
|
|
|
39256
39517
|
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"
|
|
39257
39518
|
});
|
|
39258
39519
|
}
|
|
39259
|
-
const work =
|
|
39520
|
+
const work = join26(dirname11(target), WORK_DIR);
|
|
39260
39521
|
mkdirSync13(work, { recursive: true });
|
|
39261
|
-
const backup = ours ? void 0 :
|
|
39522
|
+
const backup = ours ? void 0 : join26(work, `backup-${basename(target)}-${(opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`);
|
|
39262
39523
|
const fresh = prepare(source, work, opts.mode, opts.version);
|
|
39263
39524
|
try {
|
|
39264
39525
|
swap(fresh, target, backup, work);
|
|
39265
39526
|
} finally {
|
|
39266
|
-
|
|
39527
|
+
rmSync9(fresh, { recursive: true, force: true });
|
|
39267
39528
|
}
|
|
39268
39529
|
return { state: "current", mode: opts.mode, changed: true, ...backup ? { backup } : {} };
|
|
39269
39530
|
}
|
|
@@ -39791,10 +40052,237 @@ async function setupCommand(globals, opts) {
|
|
|
39791
40052
|
}
|
|
39792
40053
|
}
|
|
39793
40054
|
|
|
40055
|
+
// packages/cli/src/setup/environment.ts
|
|
40056
|
+
import { accessSync, constants as constants8, existsSync as existsSync13, readFileSync as readFileSync15 } from "node:fs";
|
|
40057
|
+
import { homedir as homedir8, release as release2 } from "node:os";
|
|
40058
|
+
var AGENT_TOKEN = "agentToken";
|
|
40059
|
+
var GATEWAY_CHECK_TIMEOUT_MS2 = 8e3;
|
|
40060
|
+
var OS_NAME = {
|
|
40061
|
+
darwin: "macOS",
|
|
40062
|
+
win32: "Windows",
|
|
40063
|
+
linux: "Linux",
|
|
40064
|
+
aix: void 0,
|
|
40065
|
+
android: void 0,
|
|
40066
|
+
freebsd: void 0,
|
|
40067
|
+
haiku: void 0,
|
|
40068
|
+
openbsd: void 0,
|
|
40069
|
+
sunos: void 0,
|
|
40070
|
+
cygwin: void 0,
|
|
40071
|
+
netbsd: void 0
|
|
40072
|
+
};
|
|
40073
|
+
function hasToken2(core) {
|
|
40074
|
+
try {
|
|
40075
|
+
if (osSecretStore(core.standName, core.stand).get(AGENT_TOKEN) !== void 0) return true;
|
|
40076
|
+
} catch {
|
|
40077
|
+
}
|
|
40078
|
+
try {
|
|
40079
|
+
return fileSecretStore(core.paths, core.standName).get(AGENT_TOKEN) !== void 0;
|
|
40080
|
+
} catch {
|
|
40081
|
+
return false;
|
|
40082
|
+
}
|
|
40083
|
+
}
|
|
40084
|
+
async function probeHelper(platform2) {
|
|
40085
|
+
const status = await keyHelperStatus(platform2);
|
|
40086
|
+
let missing = [];
|
|
40087
|
+
if (status.kind) {
|
|
40088
|
+
try {
|
|
40089
|
+
const backend = keyHelperBackend(platform2);
|
|
40090
|
+
if (backend) {
|
|
40091
|
+
const path2 = findKeyHelper({ installed: backend.path });
|
|
40092
|
+
if (path2) missing = missingLibraries(path2, platform2);
|
|
40093
|
+
}
|
|
40094
|
+
} catch {
|
|
40095
|
+
missing = [];
|
|
40096
|
+
}
|
|
40097
|
+
}
|
|
40098
|
+
return { ...status, missingLibraries: missing };
|
|
40099
|
+
}
|
|
40100
|
+
async function probeStorage(core) {
|
|
40101
|
+
const softwareAllowed = core.stand.allowSoftwareKeys;
|
|
40102
|
+
const helper = await probeHelper(process.platform);
|
|
40103
|
+
let osAvailable = false;
|
|
40104
|
+
try {
|
|
40105
|
+
osSecretStore(core.standName, core.stand).get(AGENT_TOKEN);
|
|
40106
|
+
osAvailable = true;
|
|
40107
|
+
} catch {
|
|
40108
|
+
}
|
|
40109
|
+
let fileWritable = false;
|
|
40110
|
+
try {
|
|
40111
|
+
accessSync(core.paths.configDir, constants8.W_OK);
|
|
40112
|
+
fileWritable = true;
|
|
40113
|
+
} catch {
|
|
40114
|
+
}
|
|
40115
|
+
const candidate = softwareAllowed ? ["hardware", "os", "file"] : ["hardware"];
|
|
40116
|
+
const avail = {
|
|
40117
|
+
hardware: helper.available,
|
|
40118
|
+
os: osAvailable,
|
|
40119
|
+
file: fileWritable
|
|
40120
|
+
};
|
|
40121
|
+
return {
|
|
40122
|
+
hardware: { kind: helper.kind ?? null, available: helper.available },
|
|
40123
|
+
os: { available: osAvailable },
|
|
40124
|
+
file: { writable: fileWritable },
|
|
40125
|
+
recommended: candidate.find((s) => avail[s]) ?? null,
|
|
40126
|
+
helper,
|
|
40127
|
+
softwareAllowed
|
|
40128
|
+
};
|
|
40129
|
+
}
|
|
40130
|
+
function nodeFits(node2) {
|
|
40131
|
+
const [major = 0, minor = 0] = node2.split(".").map(Number);
|
|
40132
|
+
return major > LAST_LISTED_MAJOR || MIN_NODE_MINOR[major] !== void 0 && minor >= MIN_NODE_MINOR[major];
|
|
40133
|
+
}
|
|
40134
|
+
function osMeets(platform2, releaseVersion) {
|
|
40135
|
+
const major = Number(releaseVersion.split(".")[0]);
|
|
40136
|
+
if (!Number.isFinite(major)) return null;
|
|
40137
|
+
if (platform2 === "darwin") return major >= 22;
|
|
40138
|
+
if (platform2 === "win32") return major >= 10;
|
|
40139
|
+
return true;
|
|
40140
|
+
}
|
|
40141
|
+
function targetOf(platform2, arch2) {
|
|
40142
|
+
if (platform2 === "darwin") return arch2 === "arm64" ? "macOS-ARM64" : "macOS-Intel";
|
|
40143
|
+
if (platform2 === "win32") return "Windows";
|
|
40144
|
+
if (platform2 === "linux") return "Linux";
|
|
40145
|
+
return "other";
|
|
40146
|
+
}
|
|
40147
|
+
function probeRootCa(core) {
|
|
40148
|
+
const url2 = new URL(core.stand.gatewayUrl);
|
|
40149
|
+
if (url2.protocol !== "https:") return "not-required";
|
|
40150
|
+
const root = PINNED_ROOTS.find((r) => coversHost(r, url2.hostname));
|
|
40151
|
+
if (!root) return "not-required";
|
|
40152
|
+
const found = findRoot(root);
|
|
40153
|
+
if (!found) return "missing";
|
|
40154
|
+
return found.expired ? "expired" : "present";
|
|
40155
|
+
}
|
|
40156
|
+
function probePersistence() {
|
|
40157
|
+
const home = homedir8();
|
|
40158
|
+
if (/(^|\/)(tmp|var\/tmp|run)(\/|$)/.test(home)) return "likely-ephemeral";
|
|
40159
|
+
try {
|
|
40160
|
+
if (existsSync13("/.dockerenv") || existsSync13("/run/.containerenv")) return "likely-ephemeral";
|
|
40161
|
+
} catch {
|
|
40162
|
+
}
|
|
40163
|
+
return "assumed-persistent";
|
|
40164
|
+
}
|
|
40165
|
+
async function probeGateway(core, offline) {
|
|
40166
|
+
if (offline) return { gateway: "unknown" };
|
|
40167
|
+
try {
|
|
40168
|
+
await getEncryptionKey(core, true, { timeoutMs: GATEWAY_CHECK_TIMEOUT_MS2 });
|
|
40169
|
+
return { gateway: "ok" };
|
|
40170
|
+
} catch (error62) {
|
|
40171
|
+
return { gateway: "fail", gatewayError: error62 instanceof CliError ? error62.code : "UNKNOWN" };
|
|
40172
|
+
}
|
|
40173
|
+
}
|
|
40174
|
+
async function collectEnvironment(core, offline = false) {
|
|
40175
|
+
const platform2 = process.platform;
|
|
40176
|
+
const arch2 = process.arch;
|
|
40177
|
+
const node2 = process.versions.node;
|
|
40178
|
+
const wsl = platform2 === "linux" ? (() => {
|
|
40179
|
+
try {
|
|
40180
|
+
return /microsoft/i.test(readFileSync15("/proc/version", "utf8"));
|
|
40181
|
+
} catch {
|
|
40182
|
+
return null;
|
|
40183
|
+
}
|
|
40184
|
+
})() : null;
|
|
40185
|
+
const environment = {
|
|
40186
|
+
platform: platform2,
|
|
40187
|
+
arch: arch2,
|
|
40188
|
+
osName: OS_NAME[platform2],
|
|
40189
|
+
osVersion: release2(),
|
|
40190
|
+
osMeets: osMeets(platform2, release2()),
|
|
40191
|
+
node: node2,
|
|
40192
|
+
nodeFits: nodeFits(node2),
|
|
40193
|
+
wsl,
|
|
40194
|
+
configDir: core.paths.configDir,
|
|
40195
|
+
configWritable: (() => {
|
|
40196
|
+
try {
|
|
40197
|
+
accessSync(core.paths.configDir, constants8.W_OK);
|
|
40198
|
+
return true;
|
|
40199
|
+
} catch {
|
|
40200
|
+
return false;
|
|
40201
|
+
}
|
|
40202
|
+
})(),
|
|
40203
|
+
persistence: probePersistence()
|
|
40204
|
+
};
|
|
40205
|
+
const storage = await probeStorage(core);
|
|
40206
|
+
const deviceKeys = deviceKeysExist(core);
|
|
40207
|
+
const existing = {
|
|
40208
|
+
deviceKeys,
|
|
40209
|
+
binding: deviceKeys && hasToken2(core),
|
|
40210
|
+
...core.config.deviceKeys?.[core.standName] ? { keyStorage: core.config.deviceKeys[core.standName] } : {}
|
|
40211
|
+
};
|
|
40212
|
+
const rootCa = probeRootCa(core);
|
|
40213
|
+
const network = await probeGateway(core, offline);
|
|
40214
|
+
const target = targetOf(platform2, arch2);
|
|
40215
|
+
const implementation = platform2 === "darwin" || platform2 === "win32" || platform2 === "linux" ? "done" : "none";
|
|
40216
|
+
const e2e = platform2 === "darwin" && arch2 === "arm64" ? "confirmed" : "pending";
|
|
40217
|
+
const reasons = [];
|
|
40218
|
+
let next;
|
|
40219
|
+
let fit = "ok";
|
|
40220
|
+
if (!environment.nodeFits) {
|
|
40221
|
+
fit = "fail";
|
|
40222
|
+
reasons.push(`Node ${node2} \u043D\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u0438\u0442 (\u043D\u0443\u0436\u043D\u043E 22.19+ \u0438\u043B\u0438 24.5+)`);
|
|
40223
|
+
next = "\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 Node \u0434\u043E 22.19+ \u0438\u043B\u0438 24.5+ \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 sberpay-cli setup doctor";
|
|
40224
|
+
}
|
|
40225
|
+
if (platform2 === "darwin" && environment.osMeets === false) {
|
|
40226
|
+
fit = "fail";
|
|
40227
|
+
reasons.push("macOS \u043D\u0438\u0436\u0435 13.0");
|
|
40228
|
+
next = "\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 macOS \u0434\u043E 13.0+ \u0438\u043B\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 Mac \u043D\u0430 \u0431\u043E\u043B\u0435\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438";
|
|
40229
|
+
}
|
|
40230
|
+
if (implementation === "none") {
|
|
40231
|
+
fit = "fail";
|
|
40232
|
+
reasons.push("\u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F");
|
|
40233
|
+
} else if (!storage.softwareAllowed && !storage.hardware.available) {
|
|
40234
|
+
if (!storage.helper.found) {
|
|
40235
|
+
fit = "unknown";
|
|
40236
|
+
reasons.push("\u0445\u0435\u043B\u043F\u0435\u0440 \u043A\u043B\u044E\u0447\u0435\u0439 \u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D, \u0447\u0438\u043F \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043D");
|
|
40237
|
+
next = "\u0421\u043E\u0431\u0435\u0440\u0438\u0442\u0435/\u043F\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0445\u0435\u043B\u043F\u0435\u0440 \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435; \u0438\u043D\u0430\u0447\u0435 \u043D\u0443\u0436\u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0430 \u0441 Secure Enclave/TPM";
|
|
40238
|
+
} else {
|
|
40239
|
+
fit = "fail";
|
|
40240
|
+
reasons.push("\u0447\u0438\u043F \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D, \u0430 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u043D\u044B\u0435 \u043A\u043B\u044E\u0447\u0438 \u043D\u0430 \u0441\u0442\u0435\u043D\u0434\u0435 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B");
|
|
40241
|
+
next = "\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u043C\u0430\u0448\u0438\u043D\u0443 \u0441 Secure Enclave/TPM \u0438\u043B\u0438 \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)";
|
|
40242
|
+
}
|
|
40243
|
+
}
|
|
40244
|
+
const suitable = fit === "fail" ? false : fit === "unknown" ? "unknown" : true;
|
|
40245
|
+
return {
|
|
40246
|
+
schemaVersion: 1,
|
|
40247
|
+
environment,
|
|
40248
|
+
storage,
|
|
40249
|
+
existing,
|
|
40250
|
+
rootCa,
|
|
40251
|
+
network,
|
|
40252
|
+
verdict: {
|
|
40253
|
+
target,
|
|
40254
|
+
implementation,
|
|
40255
|
+
e2e,
|
|
40256
|
+
fit,
|
|
40257
|
+
suitable,
|
|
40258
|
+
...reasons.length ? { reason: reasons.join("; ") } : {},
|
|
40259
|
+
...next ? { next } : {}
|
|
40260
|
+
}
|
|
40261
|
+
};
|
|
40262
|
+
}
|
|
40263
|
+
async function doctorCommand(globals, opts) {
|
|
40264
|
+
const core = buildCoreContext(globals);
|
|
40265
|
+
const result = await collectEnvironment(core, Boolean(opts.offline));
|
|
40266
|
+
const v = result.verdict;
|
|
40267
|
+
const label = result.environment.wsl ? `${v.target} (WSL)` : v.target;
|
|
40268
|
+
const human = v.suitable === true ? [
|
|
40269
|
+
`\u0421\u0440\u0435\u0434\u0430: ${label} \xB7 Node ${result.environment.node} \xB7 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435: ${result.storage.recommended ?? "\u2014"}`,
|
|
40270
|
+
`\u041A\u043E\u0440\u0435\u043D\u044C \u041C\u0438\u043D\u0446\u0438\u0444\u0440\u044B: ${result.rootCa === "not-required" ? "\u043D\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F" : result.rootCa} \xB7 \u0428\u043B\u044E\u0437 \u042D\u041A: ${result.network.gateway}`,
|
|
40271
|
+
...result.existing.binding ? ["\u041F\u0440\u0438\u0432\u044F\u0437\u043A\u0430 \u0443\u0436\u0435 \u0435\u0441\u0442\u044C \u2014 \u043D\u043E\u0432\u0430\u044F \u043D\u0435 \u043D\u0430\u0447\u043D\u0451\u0442\u0441\u044F \u043F\u043E\u0432\u0435\u0440\u0445 \u043D\u0435\u0451"] : [],
|
|
40272
|
+
"\u041F\u0440\u0438\u0433\u043E\u0434\u043D\u043E\u0441\u0442\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0430 \u2014 \u043C\u043E\u0436\u043D\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0443 (sberpay-cli setup --skill-dir \u2026)"
|
|
40273
|
+
].join("\n") : [
|
|
40274
|
+
`\u0421\u0440\u0435\u0434\u0430 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u0430: ${v.reason ?? "\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E"}`,
|
|
40275
|
+
...v.next ? [`\u2192 ${v.next}`] : [],
|
|
40276
|
+
"(\u043F\u043E\u043B\u043D\u044B\u0439 \u043E\u0442\u0447\u0451\u0442: sberpay-cli setup doctor --json)"
|
|
40277
|
+
].join("\n");
|
|
40278
|
+
core.out.result(result, human);
|
|
40279
|
+
if (v.suitable === false) process.exitCode = EXIT.API;
|
|
40280
|
+
}
|
|
40281
|
+
|
|
39794
40282
|
// packages/cli/src/ca/command.ts
|
|
39795
40283
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
39796
|
-
import { existsSync as
|
|
39797
|
-
import { homedir as
|
|
40284
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
40285
|
+
import { homedir as homedir9 } from "node:os";
|
|
39798
40286
|
var INSTALL_TIMEOUT_MS = 12e4;
|
|
39799
40287
|
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)" };
|
|
39800
40288
|
function runSecurity(argv) {
|
|
@@ -39834,7 +40322,7 @@ async function caFetchCommand(globals) {
|
|
|
39834
40322
|
function caInstallCommand(globals) {
|
|
39835
40323
|
const out = createOutput(Boolean(globals.json));
|
|
39836
40324
|
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");
|
|
39837
|
-
const result = installRootCa({ paths: cliPaths(), platform: process.platform, home:
|
|
40325
|
+
const result = installRootCa({ paths: cliPaths(), platform: process.platform, home: homedir9(), exists: existsSync14, run: runSecurity });
|
|
39838
40326
|
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");
|
|
39839
40327
|
out.result(result, human);
|
|
39840
40328
|
}
|
|
@@ -39896,6 +40384,14 @@ setup.option("--no-skill", "\u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0
|
|
|
39896
40384
|
fail(globals, error62);
|
|
39897
40385
|
}
|
|
39898
40386
|
});
|
|
40387
|
+
setup.command("doctor").description("\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0441\u0440\u0435\u0434\u044B \u043F\u0435\u0440\u0435\u0434 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u043E\u0439: \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u0435\u043D\u0438\u0435, \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043C\u0435\u043D\u044F\u0435\u0442").option("--offline", "\u043D\u0435 \u0445\u043E\u0434\u0438\u0442\u044C \u0432 \u0441\u0435\u0442\u044C, \u0448\u043B\u044E\u0437 \u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C").action(async (opts) => {
|
|
40388
|
+
const globals = program2.opts();
|
|
40389
|
+
try {
|
|
40390
|
+
await doctorCommand(globals, { offline: Boolean(opts.offline) });
|
|
40391
|
+
} catch (error62) {
|
|
40392
|
+
fail(globals, error62);
|
|
40393
|
+
}
|
|
40394
|
+
});
|
|
39899
40395
|
function standalone(fn) {
|
|
39900
40396
|
return async () => {
|
|
39901
40397
|
const globals = program2.opts();
|
|
@@ -39970,6 +40466,13 @@ address.command("get").description("\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u
|
|
|
39970
40466
|
address.command("set").description("\u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C, \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u043B\u0438 \u0434\u0435\u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0430\u0434\u0440\u0435\u0441").requiredOption("--json-file <path>", "JSON-\u0444\u0430\u0439\u043B \u0430\u0434\u0440\u0435\u0441\u0430; - \u0434\u043B\u044F stdin").action(action((s, opts) => s.addressSet(opts)));
|
|
39971
40467
|
var merchants = program2.command("merchants").description("\u043C\u0430\u0433\u0430\u0437\u0438\u043D\u044B, \u0433\u0434\u0435 \u0430\u0433\u0435\u043D\u0442 \u043C\u043E\u0436\u0435\u0442 \u043F\u043B\u0430\u0442\u0438\u0442\u044C SberPay");
|
|
39972
40468
|
merchants.command("check <domain>").description("\u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u043B\u0438 \u0441\u0430\u0439\u0442 \u043E\u043F\u043B\u0430\u0442\u0443 \u0430\u0433\u0435\u043D\u0442\u043E\u043C; \u0434\u043E\u043C\u0435\u043D \u0438\u043B\u0438 URL").action(action((s, domain2) => s.merchantsCheck(domain2)));
|
|
40469
|
+
merchants.command("domains").description(
|
|
40470
|
+
"\u0433\u0434\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043E\u043F\u043B\u0430\u0442\u0430 \u0430\u0433\u0435\u043D\u0442\u043E\u043C: \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0444\u0430\u0439\u043B \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0430, \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0440\u0430\u0437 \u0432 \u0441\u0443\u0442\u043A\u0438 \u043F\u0440\u0438 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0438; \u043F\u0435\u0440\u0435\u0434 \u043E\u043F\u043B\u0430\u0442\u043E\u0439 \u2014 \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E check"
|
|
40471
|
+
).option("--match <domain...>", "\u043A\u0430\u043A\u0438\u0435 \u0438\u0437 \u044D\u0442\u0438\u0445 \u0434\u043E\u043C\u0435\u043D\u043E\u0432 \u0438\u043B\u0438 URL \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u044E\u0442 \u043E\u043F\u043B\u0430\u0442\u0443 \u0430\u0433\u0435\u043D\u0442\u043E\u043C").option("--search <text>", "\u0434\u043E\u043C\u0435\u043D\u044B, \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u0442\u0435\u043A\u0441\u0442 (\u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430 \u0438\u043B\u0438 \u043A\u0438\u0440\u0438\u043B\u043B\u0438\u0446\u0430)").option("--limit <n>", "\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u043E\u0432 --search \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50)").option("--refresh", "\u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u0437\u0430\u043D\u043E\u0432\u043E, \u043D\u0435 \u0434\u043E\u0436\u0438\u0434\u0430\u044F\u0441\u044C \u0441\u0443\u0442\u043E\u043A").option("--offline", "\u0442\u043E\u043B\u044C\u043A\u043E \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0444\u0430\u0439\u043B, \u0431\u0435\u0437 \u0441\u0435\u0442\u0438").action(
|
|
40472
|
+
action(
|
|
40473
|
+
(s, opts) => s.merchantsDomains(opts)
|
|
40474
|
+
)
|
|
40475
|
+
);
|
|
39973
40476
|
if (BUILD.profile === "diagnostic") registerReportCommands(program2);
|
|
39974
40477
|
if (BUILD.profile === "diagnostic") registerPaymentModeCommands(program2);
|
|
39975
40478
|
program2.hook("preAction", async (_root, command) => {
|