@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 CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "profile": "diagnostic",
3
- "version": "0.4.0-dev.7",
4
- "sourceCommit": "9a9b74aaa8ed8a80225fe2dd94e6205b2c99352e",
5
- "sourceTreeDigest": "82283fdc56d662da1a915e7bf851b0ff37905e04c4b703bddb76216cbffdb784",
3
+ "version": "0.4.0-dev.9",
4
+ "sourceCommit": "db0ec0c6594c1d28d55158cde8f6e5d564251e46",
5
+ "sourceTreeDigest": "5f12d63abb08dee373fbdd3ffd173836b8efbaa8d84886af05d5e85c3401db46",
6
6
  "snapshot": false,
7
- "buildId": "34d73db3ce021d421ea07a062aff2d25deb6b14bf7f5051235840964f70d646c",
7
+ "buildId": "81921baa6ca1b7998a4feb445c67515af5251419e7bd514bc95dd70384c32abd",
8
8
  "stateFormat": 2
9
9
  }
@@ -106,7 +106,7 @@ var require_polyfills = __commonJS({
106
106
  }
107
107
  if (platform === "win32") {
108
108
  fs.rename = typeof fs.rename !== "function" ? fs.rename : (function(fs$rename) {
109
- function rename7(from, to, cb) {
109
+ function rename8(from, to, cb) {
110
110
  var start = Date.now();
111
111
  var backoff = 0;
112
112
  fs$rename(from, to, function CB(er) {
@@ -126,8 +126,8 @@ var require_polyfills = __commonJS({
126
126
  if (cb) cb(er);
127
127
  });
128
128
  }
129
- if (Object.setPrototypeOf) Object.setPrototypeOf(rename7, fs$rename);
130
- return rename7;
129
+ if (Object.setPrototypeOf) Object.setPrototypeOf(rename8, fs$rename);
130
+ return rename8;
131
131
  })(fs.rename);
132
132
  }
133
133
  fs.read = typeof fs.read !== "function" ? fs.read : (function(fs$read) {
@@ -531,8 +531,8 @@ var require_graceful_fs = __commonJS({
531
531
  fs2.createReadStream = createReadStream;
532
532
  fs2.createWriteStream = createWriteStream;
533
533
  var fs$readFile = fs2.readFile;
534
- fs2.readFile = readFile4;
535
- function readFile4(path, options, cb) {
534
+ fs2.readFile = readFile5;
535
+ function readFile5(path, options, cb) {
536
536
  if (typeof options === "function")
537
537
  cb = options, options = null;
538
538
  return go$readFile(path, options, cb);
@@ -548,8 +548,8 @@ var require_graceful_fs = __commonJS({
548
548
  }
549
549
  }
550
550
  var fs$writeFile = fs2.writeFile;
551
- fs2.writeFile = writeFile4;
552
- function writeFile4(path, data, options, cb) {
551
+ fs2.writeFile = writeFile5;
552
+ function writeFile5(path, data, options, cb) {
553
553
  if (typeof options === "function")
554
554
  cb = options, options = null;
555
555
  return go$writeFile(path, data, options, cb);
@@ -708,7 +708,7 @@ var require_graceful_fs = __commonJS({
708
708
  }
709
709
  function ReadStream$open() {
710
710
  var that = this;
711
- open8(that.path, that.flags, that.mode, function(err, fd) {
711
+ open9(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
- open8(that.path, that.flags, that.mode, function(err, fd) {
731
+ open9(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 = open8;
749
- function open8(path, flags, mode, cb) {
748
+ fs2.open = open9;
749
+ function open9(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);
@@ -1617,8 +1617,8 @@ var require_proper_lockfile = __commonJS({
1617
1617
  });
1618
1618
 
1619
1619
  // scripts/diagnostics/npm-entry.mts
1620
- import { readFile as readFile3 } from "node:fs/promises";
1621
- import { dirname as dirname7, join as join11 } from "node:path";
1620
+ import { readFile as readFile4 } from "node:fs/promises";
1621
+ import { dirname as dirname7, join as join12 } 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
 
@@ -2348,9 +2348,9 @@ function floatSafeRemainder(val, step) {
2348
2348
  return ratio - roundedRatio;
2349
2349
  }
2350
2350
  var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
2351
- function defineLazy(object2, key, getter) {
2351
+ function defineLazy(object3, key, getter) {
2352
2352
  let value = void 0;
2353
- Object.defineProperty(object2, key, {
2353
+ Object.defineProperty(object3, key, {
2354
2354
  get() {
2355
2355
  if (value === EVALUATING) {
2356
2356
  return void 0;
@@ -2362,7 +2362,7 @@ function defineLazy(object2, key, getter) {
2362
2362
  return value;
2363
2363
  },
2364
2364
  set(v) {
2365
- Object.defineProperty(object2, key, {
2365
+ Object.defineProperty(object3, key, {
2366
2366
  value: v
2367
2367
  // configurable: true,
2368
2368
  });
@@ -17429,8 +17429,8 @@ function foldObjects(members2) {
17429
17429
  }
17430
17430
  const properties = {};
17431
17431
  const required2 = /* @__PURE__ */ new Set();
17432
- for (const object2 of objects) {
17433
- for (const key in object2.properties) {
17432
+ for (const object3 of objects) {
17433
+ for (const key in object3.properties) {
17434
17434
  if (Object.prototype.hasOwnProperty.call(properties, key))
17435
17435
  continue;
17436
17436
  const parts = [];
@@ -17444,18 +17444,18 @@ function foldObjects(members2) {
17444
17444
  const merged = parts.length === 1 ? parts[0] : foldObjects(parts) ?? { allOf: parts };
17445
17445
  assignProp(properties, key, merged);
17446
17446
  }
17447
- for (const key of object2.required ?? [])
17447
+ for (const key of object3.required ?? [])
17448
17448
  required2.add(key);
17449
17449
  }
17450
17450
  const folded = { type: "object", properties };
17451
17451
  if (required2.size)
17452
17452
  folded.required = [...required2];
17453
- if (objects.every((object2) => object2.additionalProperties === false)) {
17453
+ if (objects.every((object3) => object3.additionalProperties === false)) {
17454
17454
  folded.additionalProperties = false;
17455
17455
  } else {
17456
17456
  const constraints = [];
17457
- for (const object2 of objects) {
17458
- const constraint = undeclaredConstraint(object2);
17457
+ for (const object3 of objects) {
17458
+ const constraint = undeclaredConstraint(object3);
17459
17459
  if (constraint && !constraints.some((seen) => JSON.stringify(seen) === JSON.stringify(constraint)))
17460
17460
  constraints.push(constraint);
17461
17461
  }
@@ -21374,7 +21374,7 @@ function skillFileHashes(skill, files, platform = process.platform) {
21374
21374
  }
21375
21375
  function renderDiagnosticSkill(source2, platform, launcher, node2) {
21376
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" : "");
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. \u041F\u0440\u0438\u0432\u044F\u0437\u043A\u0435 \u043A \u0447\u0430\u0442\u0443 Claude Code \u0445\u0443\u043A SessionStart \u0438 Git Bash \u043D\u0435 \u043D\u0443\u0436\u043D\u044B.\n" : "");
21378
21378
  }
21379
21379
 
21380
21380
  // packages/cli/src/core/paths.ts
@@ -21418,7 +21418,7 @@ import { join as join2 } from "node:path";
21418
21418
  import { mkdirSync, existsSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, rmSync } from "node:fs";
21419
21419
  import { dirname as dirname2 } from "node:path";
21420
21420
  import { randomUUID } from "node:crypto";
21421
- function atomicJson(path, value) {
21421
+ function atomicJson(path, value, options = {}) {
21422
21422
  if (process.platform === "win32") {
21423
21423
  ensureWindowsPrivateDirectory(dirname2(path));
21424
21424
  if (existsSync(path)) assertWindowsPrivatePath(path);
@@ -21427,7 +21427,7 @@ function atomicJson(path, value) {
21427
21427
  try {
21428
21428
  const fd = openSync(temp, "wx", 384);
21429
21429
  try {
21430
- writeFileSync(fd, JSON.stringify(value, null, 2) + "\n");
21430
+ writeFileSync(fd, (options.compact ? JSON.stringify(value) : JSON.stringify(value, null, 2)) + "\n");
21431
21431
  fsyncSync(fd);
21432
21432
  } finally {
21433
21433
  closeSync(fd);
@@ -21876,7 +21876,7 @@ async function exclusive(paths, recover, fn, installing2 = false) {
21876
21876
  JSON.stringify({ pid: process.pid }),
21877
21877
  { mode: 384, flag: "wx" }
21878
21878
  );
21879
- const fd = openSync4(join5(lock, "owner.json"), "r");
21879
+ const fd = openSync4(join5(lock, "owner.json"), "r+");
21880
21880
  try {
21881
21881
  fsyncSync3(fd);
21882
21882
  } finally {
@@ -22220,13 +22220,23 @@ import { createHash as createHash4 } from "node:crypto";
22220
22220
  var windowsArgument = (s) => '"' + s.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
22221
22221
  function windowsSenderConfig(home, launcher, node2) {
22222
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" }) };
22223
+ return { path: win323.join(home, ".local", "share", "sberpay-diagnostic", "sender-task.json"), text: JSON.stringify({
22224
+ name: "SberPay.Diagnostic." + createHash4("sha256").update(launcher.toLowerCase()).digest("hex").slice(0, 24),
22225
+ node: node2,
22226
+ launcher,
22227
+ arguments: windowsArgument(launcher) + " report flush --json",
22228
+ // node.exe is a console program: started by Task Scheduler in the user's session it opens a console window every
22229
+ // 5 minutes. conhost.exe --headless hosts the same process without a window; same user, token and arguments.
22230
+ headlessArguments: "--headless " + windowsArgument(node2) + " " + windowsArgument(launcher) + " report flush --json"
22231
+ }) };
22224
22232
  }
22225
22233
  var SCRIPT2 = String.raw`
22226
22234
  $ErrorActionPreference='Stop'
22227
22235
  [Console]::OutputEncoding=New-Object System.Text.UTF8Encoding($false)
22228
22236
  $c=Get-Content -LiteralPath $env:SBERPAY_SENDER_CONFIG -Raw -Encoding UTF8|ConvertFrom-Json
22229
22237
  $sid=[Security.Principal.WindowsIdentity]::GetCurrent().User.Value
22238
+ # Task Scheduler reads Principal.UserId back as an account name ("julia"), not the SID it was registered with.
22239
+ function SidOf($u){if(!$u){return $null};if($u -match '^S-1-'){return $u};try{return (New-Object Security.Principal.NTAccount($u)).Translate([Security.Principal.SecurityIdentifier]).Value}catch{return $null}}
22230
22240
  $service=New-Object -ComObject 'Schedule.Service'
22231
22241
  $service.Connect()
22232
22242
  $folder=$service.GetFolder('\')
@@ -22234,7 +22244,7 @@ $source='sberpay-diagnostic:'+ $c.launcher
22234
22244
  $existing=$null
22235
22245
  try{$existing=$folder.GetTask($c.name)}catch{$e=$_.Exception;while($e.InnerException){$e=$e.InnerException};if($e.HResult -ne -2147024894){throw}}
22236
22246
  if($existing){
22237
- if($existing.Definition.RegistrationInfo.Source -cne $source -or $existing.Definition.Principal.UserId -ne $sid){throw 'SENDER_TASK_CONFLICT'}
22247
+ if($existing.Definition.RegistrationInfo.Source -cne $source -or (SidOf $existing.Definition.Principal.UserId) -ne $sid){throw 'SENDER_TASK_CONFLICT'}
22238
22248
  }
22239
22249
  $task=$service.NewTask(0)
22240
22250
  $task.RegistrationInfo.Source=$source
@@ -22256,15 +22266,18 @@ $timer.Enabled=$true
22256
22266
  $logon=$task.Triggers.Create(9)
22257
22267
  $logon.UserId=$sid
22258
22268
  $logon.Enabled=$true
22269
+ # Hidden console: the system conhost.exe hosts node without a window. Without it, fall back to node itself.
22270
+ $conhost=[IO.Path]::Combine($env:SystemRoot,'System32','conhost.exe')
22271
+ if($c.headlessArguments -and (Test-Path -LiteralPath $conhost -PathType Leaf)){$program=$conhost;$programArguments=$c.headlessArguments}else{$program=$c.node;$programArguments=$c.arguments}
22259
22272
  $action=$task.Actions.Create(0)
22260
- $action.Path=$c.node
22261
- $action.Arguments=$c.arguments
22273
+ $action.Path=$program
22274
+ $action.Arguments=$programArguments
22262
22275
  $action.WorkingDirectory=[IO.Path]::GetDirectoryName($c.launcher)
22263
22276
  $registered=$folder.RegisterTaskDefinition($c.name,$task,6,$sid,$null,3,$null)
22264
22277
  $read=$folder.GetTask($c.name)
22265
22278
  $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
22279
+ if($d.Settings.ExecutionTimeLimit -ne 'PT0S' -or $d.Settings.MultipleInstances -ne 2 -or !$read.Enabled -or (SidOf $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 $program -or $d.Actions.Item(1).Arguments -cne $programArguments -or $d.Triggers.Count -ne 2 -or $d.Triggers.Item(1).Repetition.Interval -ne 'PT5M'){throw 'SENDER_TASK_NOT_ACTIVE'}
22280
+ @{status='active';taskName=$c.name;hidden=($program -ceq $conhost)}|ConvertTo-Json -Compress
22268
22281
  `;
22269
22282
  function windowsSenderCommand(path, env = process.env) {
22270
22283
  if (!env.SystemRoot || !win323.isAbsolute(env.SystemRoot)) throw Error("WINDOWS_SYSTEM_ROOT_MISSING");
@@ -22345,6 +22358,81 @@ async function installSender(home, launcher) {
22345
22358
  }
22346
22359
  }
22347
22360
 
22361
+ // packages/cli/src/report/claudeHook.ts
22362
+ import { open as open7, chmod, lstat as lstat5, mkdir as mkdir4, readFile as readFile2, realpath, rename as rename6, writeFile as writeFile3 } from "node:fs/promises";
22363
+ import { join as join10 } from "node:path";
22364
+ import { randomUUID as randomUUID7 } from "node:crypto";
22365
+
22366
+ // packages/cli/src/report/adapters/types.ts
22367
+ function object2(value) {
22368
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
22369
+ }
22370
+
22371
+ // packages/cli/src/report/claudeHook.ts
22372
+ var shellQuote = (text) => `'${text.replace(/'/g, "'\\''")}'`;
22373
+ var claudeHookCommandFor = (args) => [...args, "report", "claude-hook"].map((s) => shellQuote(process.platform === "win32" ? s.replaceAll("\\", "/") : s)).join(" ");
22374
+ var HOOK_SUFFIX = " 'report' 'claude-hook'";
22375
+ async function readSettings(configDir, create) {
22376
+ if (create) {
22377
+ if (process.platform === "win32") ensureWindowsPrivateDirectory(configDir);
22378
+ else await mkdir4(configDir, { recursive: true, mode: 448 });
22379
+ }
22380
+ const path = join10(configDir, "settings.json");
22381
+ let original;
22382
+ try {
22383
+ const info = await lstat5(path);
22384
+ if (!info.isFile() || info.isSymbolicLink()) throw new BindingError("UNSAFE_SETTINGS");
22385
+ if (process.platform === "win32") assertWindowsPrivatePath(path);
22386
+ original = await readFile2(path, "utf8");
22387
+ } catch (error62) {
22388
+ if (error62.code !== "ENOENT") throw error62;
22389
+ }
22390
+ const settings = original === void 0 ? {} : object2(JSON.parse(original));
22391
+ if (!settings) throw new BindingError("INVALID_SETTINGS");
22392
+ const hooks = settings.hooks === void 0 ? {} : object2(settings.hooks);
22393
+ if (!hooks) throw new BindingError("INVALID_HOOK_SETTINGS");
22394
+ const start = hooks.SessionStart === void 0 ? [] : hooks.SessionStart;
22395
+ if (!Array.isArray(start)) throw new BindingError("INVALID_HOOK_SETTINGS");
22396
+ return { path, original, settings, hooks, start };
22397
+ }
22398
+ async function writeSettings(path, original, settings) {
22399
+ const suffix = randomUUID7();
22400
+ if (original !== void 0) await writeFile3(`${path}.sberpay-${suffix}.bak`, original, { flag: "wx", mode: 384 });
22401
+ const temp = `${path}.sberpay-${suffix}.tmp`;
22402
+ await writeFile3(temp, JSON.stringify(settings, null, 2) + "\n", { flag: "wx", mode: 384 });
22403
+ await rename6(temp, path);
22404
+ await chmod(path, 384);
22405
+ }
22406
+ async function updateClaudeHook(configDir, command) {
22407
+ let read;
22408
+ try {
22409
+ read = await readSettings(configDir, false);
22410
+ } catch (error62) {
22411
+ if (error62.code === "ENOENT") return "absent";
22412
+ throw error62;
22413
+ }
22414
+ const { path, original, settings, start } = read;
22415
+ if (original === void 0) return "absent";
22416
+ let found = false, changed = false;
22417
+ for (const entry of start) {
22418
+ const group = object2(entry);
22419
+ if (!group || !Array.isArray(group.hooks)) continue;
22420
+ for (const value of group.hooks) {
22421
+ const hook = object2(value);
22422
+ if (hook?.type !== "command" || typeof hook.command !== "string" || !hook.command.endsWith(HOOK_SUFFIX) || !hook.command.includes("sberpay-diagnostic")) continue;
22423
+ found = true;
22424
+ if (hook.command !== command) {
22425
+ hook.command = command;
22426
+ changed = true;
22427
+ }
22428
+ }
22429
+ }
22430
+ if (!found) return "absent";
22431
+ if (!changed) return "current";
22432
+ await writeSettings(path, original, settings);
22433
+ return "updated";
22434
+ }
22435
+
22348
22436
  // packages/cli/src/setup/steps.ts
22349
22437
  var MIN_NODE_MINOR = { 22: 19, 24: 5 };
22350
22438
  var LAST_LISTED_MAJOR = 24;
@@ -22353,27 +22441,27 @@ var LAST_LISTED_MAJOR = 24;
22353
22441
  import { constants as constants4 } from "node:fs";
22354
22442
  import { pathToFileURL } from "node:url";
22355
22443
  import { homedir as homedir3 } from "node:os";
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";
22444
+ import { join as join11, resolve, dirname as dirname6 } from "node:path";
22445
+ import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4, lstat as lstat6, rename as rename7, rm as rm6, cp, open as open8, chmod as chmod2 } from "node:fs/promises";
22446
+ import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
22359
22447
  var hash3 = (text) => createHash5("sha256").update(text).digest("hex");
22360
22448
  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();
22361
22449
  async function regular(path) {
22362
- const s = await lstat5(path);
22450
+ const s = await lstat6(path);
22363
22451
  if (!s.isFile() || s.isSymbolicLink()) throw Error("UNSAFE_PACKAGE");
22364
22452
  }
22365
22453
  async function atomic(path, text, mode = 384) {
22366
- const temp = path + "." + randomUUID7() + ".tmp";
22454
+ const temp = path + "." + randomUUID8() + ".tmp";
22367
22455
  try {
22368
- await writeFile3(temp, text, { flag: "wx", mode });
22369
- await rename6(temp, path);
22456
+ await writeFile4(temp, text, { flag: "wx", mode });
22457
+ await rename7(temp, path);
22370
22458
  } finally {
22371
22459
  await rm6(temp, { force: true });
22372
22460
  }
22373
22461
  }
22374
22462
  async function installDiagnostic(source2, home = homedir3(), options = {}) {
22375
- const root2 = privateDir2(join10(home, ".local", "share", "sberpay-diagnostic"));
22376
- return withInstallLock(root2, () => withPaymentLock(cliPaths({ SBERPAY_CLI_HOME: join10(root2, "profile") }), () => installLocked(source2, home, options), true));
22463
+ const root2 = privateDir2(join11(home, ".local", "share", "sberpay-diagnostic"));
22464
+ return withInstallLock(root2, () => withPaymentLock(cliPaths({ SBERPAY_CLI_HOME: join11(root2, "profile") }), () => installLocked(source2, home, options), true));
22377
22465
  }
22378
22466
  async function installLocked(source2, home, options) {
22379
22467
  const enroll = typeof options === "function" ? options : options.enrollInvitation ?? enrollInvitation;
@@ -22381,15 +22469,15 @@ async function installLocked(source2, home, options) {
22381
22469
  if (!(major > LAST_LISTED_MAJOR || MIN_NODE_MINOR[major] !== void 0 && minor >= MIN_NODE_MINOR[major])) throw Error("UNSUPPORTED_RUNTIME");
22382
22470
  source2 = resolve(source2);
22383
22471
  try {
22384
- const info = JSON.parse(await readFile2(join10(source2, "build-info.json"), "utf8"));
22472
+ const info = JSON.parse(await readFile3(join11(source2, "build-info.json"), "utf8"));
22385
22473
  if (info.profile !== "diagnostic" || info.stateFormat !== 2) throw Error();
22386
22474
  } catch {
22387
22475
  throw Error("INCOMPATIBLE_STATE_FORMAT");
22388
22476
  }
22389
- const packageRoot = join10(source2, "package");
22390
- await regular(join10(source2, "manifest.json"));
22391
- const manifest = Manifest2.parse(JSON.parse(await readFile2(join10(source2, "manifest.json"), "utf8")));
22392
- if (manifest.setupHash && hash3(await readFile2(join10(source2, "dist/npm-entry.mjs"))) !== manifest.setupHash) throw Error("PACKAGE_HASH_MISMATCH");
22477
+ const packageRoot = join11(source2, "package");
22478
+ await regular(join11(source2, "manifest.json"));
22479
+ const manifest = Manifest2.parse(JSON.parse(await readFile3(join11(source2, "manifest.json"), "utf8")));
22480
+ if (manifest.setupHash && hash3(await readFile3(join11(source2, "dist/npm-entry.mjs"))) !== manifest.setupHash) throw Error("PACKAGE_HASH_MISMATCH");
22393
22481
  const entries = Object.entries(manifest.files);
22394
22482
  if (entries.length < 2 || entries.length > 1e3 || !manifest.files["dist/cli.mjs"] || !manifest.files["bin/sberpay-cli.mjs"] || !manifest.files["skill/sberpay/SKILL.md"]) throw Error("INVALID_MANIFEST");
22395
22483
  for (const [path, digest] of entries) {
@@ -22397,17 +22485,17 @@ async function installLocked(source2, home, options) {
22397
22485
  let cursor = packageRoot;
22398
22486
  const parts = path.split("/");
22399
22487
  for (const part of parts.slice(0, -1)) {
22400
- cursor = join10(cursor, part);
22401
- const s = await lstat5(cursor);
22488
+ cursor = join11(cursor, part);
22489
+ const s = await lstat6(cursor);
22402
22490
  if (!s.isDirectory() || s.isSymbolicLink()) throw Error("UNSAFE_PACKAGE");
22403
22491
  }
22404
- await regular(join10(packageRoot, path));
22405
- if (hash3(await readFile2(join10(packageRoot, path))) !== digest) throw Error("PACKAGE_HASH_MISMATCH");
22492
+ await regular(join11(packageRoot, path));
22493
+ if (hash3(await readFile3(join11(packageRoot, path))) !== digest) throw Error("PACKAGE_HASH_MISMATCH");
22406
22494
  }
22407
22495
  if (process.platform === "win32" && !manifest.files[`helpers/win32-${process.arch}/sberpay-tpm.exe`]) throw Error("WINDOWS_HELPER_NOT_PACKAGED");
22408
- const root2 = privateDir2(join10(home, ".local", "share", "sberpay-diagnostic"));
22409
- const skill = join10(home, ".agents", "skills", "sberpay-diagnostic");
22410
- const markerPath = join10(root2, "installed.json");
22496
+ const root2 = privateDir2(join11(home, ".local", "share", "sberpay-diagnostic"));
22497
+ const skill = join11(home, ".agents", "skills", "sberpay-diagnostic");
22498
+ const markerPath = join11(root2, "installed.json");
22411
22499
  let prior;
22412
22500
  try {
22413
22501
  prior = JSON.parse((await privateRead(markerPath, 8192)).toString());
@@ -22416,20 +22504,20 @@ async function installLocked(source2, home, options) {
22416
22504
  }
22417
22505
  let pending;
22418
22506
  try {
22419
- pending = JSON.parse((await privateRead(join10(root2, "install-pending.json"), 1024 * 1024)).toString());
22507
+ pending = JSON.parse((await privateRead(join11(root2, "install-pending.json"), 1024 * 1024)).toString());
22420
22508
  } catch (e) {
22421
22509
  if (e.code !== "ENOENT") throw Error("INSTALLATION_STATE_INVALID");
22422
22510
  }
22423
22511
  if (pending && pending.buildId !== manifest.buildId) throw Error("INSTALLATION_CONFLICT");
22424
22512
  if (prior?.stateFormat !== void 0 && ![1, 2].includes(prior.stateFormat)) throw Error("INCOMPATIBLE_STATE_FORMAT");
22425
- const paymentPaths = cliPaths({ SBERPAY_CLI_HOME: join10(root2, "profile") });
22513
+ const paymentPaths = cliPaths({ SBERPAY_CLI_HOME: join11(root2, "profile") });
22426
22514
  const paymentModeFile = modeFile(paymentPaths);
22427
22515
  let modeState;
22428
22516
  if (prior?.stateFormat === 2) modeState = readPaymentMode(paymentPaths);
22429
22517
  else {
22430
22518
  let modeExists = false;
22431
22519
  try {
22432
- await lstat5(paymentModeFile);
22520
+ await lstat6(paymentModeFile);
22433
22521
  modeExists = true;
22434
22522
  } catch (e) {
22435
22523
  if (e.code !== "ENOENT") throw e;
@@ -22441,18 +22529,18 @@ async function installLocked(source2, home, options) {
22441
22529
  }
22442
22530
  const acceptedPending = (path, digest) => pending?.files.some((f) => f.path === path && (f.before === digest || f.after === digest));
22443
22531
  try {
22444
- const info = await lstat5(skill);
22532
+ const info = await lstat6(skill);
22445
22533
  if (!info.isDirectory() || info.isSymbolicLink()) throw Error("SKILL_MODIFIED");
22446
- const text2 = await readFile2(join10(skill, "SKILL.md"), "utf8");
22447
- if (!acceptedPending(join10(skill, "SKILL.md"), hash3(text2)) && (!prior || hash3(text2) !== prior.skillHash && hash3(text2) !== prior.previousSkillHash)) throw Error("SKILL_MODIFIED");
22534
+ const text2 = await readFile3(join11(skill, "SKILL.md"), "utf8");
22535
+ if (!acceptedPending(join11(skill, "SKILL.md"), hash3(text2)) && (!prior || hash3(text2) !== prior.skillHash && hash3(text2) !== prior.previousSkillHash)) throw Error("SKILL_MODIFIED");
22448
22536
  } catch (error62) {
22449
22537
  if (error62.code !== "ENOENT") throw error62;
22450
22538
  }
22451
- const releases = privateDir2(join10(root2, "releases"));
22452
- const release = join10(releases, manifest.buildId);
22539
+ const releases = privateDir2(join11(root2, "releases"));
22540
+ const release = join11(releases, manifest.buildId);
22453
22541
  let exists = false;
22454
22542
  try {
22455
- const info = await lstat5(release);
22543
+ const info = await lstat6(release);
22456
22544
  if (!info.isDirectory() || info.isSymbolicLink()) throw Error("UNSAFE_RELEASE");
22457
22545
  exists = true;
22458
22546
  } catch (error62) {
@@ -22462,64 +22550,64 @@ async function installLocked(source2, home, options) {
22462
22550
  for (const [path, digest] of entries) {
22463
22551
  let cursor = release;
22464
22552
  for (const part of path.split("/").slice(0, -1)) {
22465
- cursor = join10(cursor, part);
22466
- const info = await lstat5(cursor);
22553
+ cursor = join11(cursor, part);
22554
+ const info = await lstat6(cursor);
22467
22555
  if (!info.isDirectory() || info.isSymbolicLink()) throw Error("UNSAFE_RELEASE");
22468
22556
  }
22469
- await regular(join10(release, path));
22470
- if (hash3(await readFile2(join10(release, path))) !== digest) throw Error("RELEASE_MODIFIED");
22557
+ await regular(join11(release, path));
22558
+ if (hash3(await readFile3(join11(release, path))) !== digest) throw Error("RELEASE_MODIFIED");
22471
22559
  }
22472
22560
  } else {
22473
- const staged = join10(releases, ".staging-" + randomUUID7());
22474
- await mkdir4(staged, { mode: 448 });
22561
+ const staged = join11(releases, ".staging-" + randomUUID8());
22562
+ await mkdir5(staged, { mode: 448 });
22475
22563
  try {
22476
22564
  for (const [path] of entries) {
22477
- const target = join10(staged, path);
22478
- await mkdir4(dirname6(target), { recursive: true, mode: 448 });
22479
- await cp(join10(packageRoot, path), target, { force: false, errorOnExist: true });
22480
- await chmod(target, /^helpers\/[^/]+\/sberpay-(se|tpm)(\.exe)?$/.test(path) ? 448 : 384);
22565
+ const target = join11(staged, path);
22566
+ await mkdir5(dirname6(target), { recursive: true, mode: 448 });
22567
+ await cp(join11(packageRoot, path), target, { force: false, errorOnExist: true });
22568
+ await chmod2(target, /^helpers\/[^/]+\/sberpay-(se|tpm)(\.exe)?$/.test(path) ? 448 : 384);
22481
22569
  }
22482
- await rename6(staged, release);
22570
+ await rename7(staged, release);
22483
22571
  } finally {
22484
22572
  await rm6(staged, { recursive: true, force: true });
22485
22573
  }
22486
22574
  }
22487
- const profile = privateDir2(join10(root2, "profile"));
22575
+ const profile = privateDir2(join11(root2, "profile"));
22488
22576
  let hasInvitation = false;
22489
22577
  try {
22490
- await regular(join10(source2, "invitation.json"));
22578
+ await regular(join11(source2, "invitation.json"));
22491
22579
  hasInvitation = true;
22492
22580
  } catch (error62) {
22493
22581
  if (error62.code !== "ENOENT") throw error62;
22494
22582
  }
22495
22583
  if (hasInvitation) {
22496
- const invitationFile = await open7(join10(source2, "invitation.json"), constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
22584
+ const invitationFile = await open8(join11(source2, "invitation.json"), constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
22497
22585
  try {
22498
22586
  const info = await invitationFile.stat();
22499
22587
  if (!info.isFile() || process.getuid && info.uid !== process.getuid()) throw Error("UNSAFE_INVITATION");
22500
- if (process.platform === "win32") assertWindowsPrivatePath(join10(source2, "invitation.json"));
22588
+ if (process.platform === "win32") assertWindowsPrivatePath(join11(source2, "invitation.json"));
22501
22589
  else await invitationFile.chmod(384);
22502
22590
  } finally {
22503
22591
  await invitationFile.close();
22504
22592
  }
22505
- await enroll(join10(source2, "invitation.json"), { ...process.env, SBERPAY_CLI_HOME: profile });
22593
+ await enroll(join11(source2, "invitation.json"), { ...process.env, SBERPAY_CLI_HOME: profile });
22506
22594
  } else {
22507
22595
  let hasCredential = false;
22508
22596
  try {
22509
- await regular(join10(profile, "config", "report-upload.json"));
22597
+ await regular(join11(profile, "config", "report-upload.json"));
22510
22598
  hasCredential = true;
22511
22599
  } catch (e) {
22512
22600
  if (e.code !== "ENOENT") throw e;
22513
22601
  }
22514
22602
  if (hasCredential) {
22515
22603
  try {
22516
- external_exports.object({ endpoint: external_exports.literal(DIAGNOSTIC_ENDPOINT), token: external_exports.string().min(32).max(512).regex(/^[A-Za-z0-9_-]+$/) }).strict().parse(JSON.parse((await privateRead(join10(profile, "config", "report-upload.json"), 16384)).toString()));
22604
+ external_exports.object({ endpoint: external_exports.literal(DIAGNOSTIC_ENDPOINT), token: external_exports.string().min(32).max(512).regex(/^[A-Za-z0-9_-]+$/) }).strict().parse(JSON.parse((await privateRead(join11(profile, "config", "report-upload.json"), 16384)).toString()));
22517
22605
  } catch {
22518
22606
  throw Error("ENROLLMENT_REQUIRED");
22519
22607
  }
22520
22608
  } else await (typeof options === "function" ? enrollOpen : options.enrollOpen ?? enrollOpen)({ ...process.env, SBERPAY_CLI_HOME: profile });
22521
22609
  }
22522
- const configFile = join10(privateDir2(join10(profile, "config")), "config.json");
22610
+ const configFile = join11(privateDir2(join11(profile, "config")), "config.json");
22523
22611
  let config2 = { stand: "prod", stands: {} };
22524
22612
  try {
22525
22613
  config2 = JSON.parse((await privateRead(configFile, 65536)).toString());
@@ -22532,45 +22620,46 @@ async function installLocked(source2, home, options) {
22532
22620
  config2.stands[stand].merchantsUrl ??= "https://aiplatilka.ru/aim/aipay/gw/agent/api/v1";
22533
22621
  }
22534
22622
  await atomic(configFile, JSON.stringify(config2));
22535
- const launcher = join10(privateDir2(join10(root2, "bin")), "sberpay-cli-diagnostic.mjs");
22623
+ const launcher = join11(privateDir2(join11(root2, "bin")), "sberpay-cli-diagnostic.mjs");
22536
22624
  const launcherText = `#!/usr/bin/env node
22537
22625
  import {existsSync,readFileSync} from "node:fs";
22538
- if(existsSync(${JSON.stringify(join10(root2, "install-pending.json"))})){console.log(JSON.stringify({status:"not_ready",code:"INSTALL_IN_PROGRESS"}));process.exit(4);}
22626
+ if(existsSync(${JSON.stringify(join11(root2, "install-pending.json"))})){console.log(JSON.stringify({status:"not_ready",code:"INSTALL_IN_PROGRESS"}));process.exit(4);}
22539
22627
  try{const marker=JSON.parse(readFileSync(${JSON.stringify(markerPath)},"utf8"));if(marker.stateFormat!==2||marker.buildId!==${JSON.stringify(manifest.buildId)})throw Error();}catch{console.log(JSON.stringify({status:"not_ready",code:"SETUP_REQUIRED"}));process.exit(4);}
22540
22628
  process.env.SBERPAY_CLI_HOME=${JSON.stringify(profile)};
22541
22629
  process.env.SBERPAY_DIAGNOSTIC_CAPTURE="1";
22542
- await import(${JSON.stringify(pathToFileURL(join10(release, "bin", "sberpay-cli.mjs")).href)});
22630
+ process.env.SBERPAY_DIAGNOSTIC_LAUNCHER=${JSON.stringify(launcher)};
22631
+ await import(${JSON.stringify(pathToFileURL(join11(release, "bin", "sberpay-cli.mjs")).href)});
22543
22632
  `;
22544
- const original = await readFile2(join10(release, "skill", "sberpay", "SKILL.md"), "utf8");
22633
+ const original = await readFile3(join11(release, "skill", "sberpay", "SKILL.md"), "utf8");
22545
22634
  const text = renderDiagnosticSkill(original, process.platform, launcher, process.execPath);
22546
22635
  if (process.platform === "win32") privateDir2(skill);
22547
22636
  else {
22548
- await mkdir4(dirname6(skill), { recursive: true, mode: 448 });
22549
- await mkdir4(skill, { mode: 448 }).catch((e) => {
22637
+ await mkdir5(dirname6(skill), { recursive: true, mode: 448 });
22638
+ await mkdir5(skill, { mode: 448 }).catch((e) => {
22550
22639
  if (e.code !== "EEXIST") throw e;
22551
22640
  });
22552
22641
  }
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 }];
22642
+ const managed = [{ path: paymentModeFile, text: JSON.stringify(modeState), mode: 384 }, { path: launcher, text: launcherText, mode: 448 }, { path: join11(skill, "SKILL.md"), text, mode: 384 }];
22554
22643
  for (const [path] of entries) {
22555
22644
  if (!path.startsWith("skill/sberpay/") || path === "skill/sberpay/SKILL.md") continue;
22556
22645
  const rel = path.slice("skill/sberpay/".length);
22557
22646
  let cursor = skill;
22558
22647
  for (const part of rel.split("/").slice(0, -1)) {
22559
- cursor = join10(cursor, part);
22560
- await mkdir4(cursor, { mode: 448 }).catch((e) => {
22648
+ cursor = join11(cursor, part);
22649
+ await mkdir5(cursor, { mode: 448 }).catch((e) => {
22561
22650
  if (e.code !== "EEXIST") throw e;
22562
22651
  });
22563
- const info = await lstat5(cursor);
22652
+ const info = await lstat6(cursor);
22564
22653
  if (!info.isDirectory() || info.isSymbolicLink()) throw Error("UNSAFE_SKILL_PATH");
22565
22654
  }
22566
- const target = join10(skill, rel);
22655
+ const target = join11(skill, rel);
22567
22656
  try {
22568
22657
  await regular(target);
22569
- const current = hash3(await readFile2(target, "utf8"));
22658
+ const current = hash3(await readFile3(target, "utf8"));
22570
22659
  let expected = prior?.skillFiles?.[rel];
22571
22660
  if (!expected && prior?.buildId) {
22572
22661
  try {
22573
- expected = hash3(await readFile2(join10(releases, prior.buildId, "skill/sberpay", rel), "utf8"));
22662
+ expected = hash3(await readFile3(join11(releases, prior.buildId, "skill/sberpay", rel), "utf8"));
22574
22663
  } catch {
22575
22664
  }
22576
22665
  }
@@ -22578,7 +22667,7 @@ await import(${JSON.stringify(pathToFileURL(join10(release, "bin", "sberpay-cli.
22578
22667
  } catch (e) {
22579
22668
  if (e.code !== "ENOENT") throw e;
22580
22669
  }
22581
- managed.push({ path: target, text: await readFile2(join10(release, path), "utf8"), mode: 384 });
22670
+ managed.push({ path: target, text: await readFile3(join11(release, path), "utf8"), mode: 384 });
22582
22671
  }
22583
22672
  const skillFiles = skillFileHashes(skill, managed);
22584
22673
  const marker = { buildId: manifest.buildId, stateFormat: 2, skillHash: hash3(text), skillFiles, launcher, profile };
@@ -22588,27 +22677,29 @@ await import(${JSON.stringify(pathToFileURL(join10(release, "bin", "sberpay-cli.
22588
22677
  if (sender.status === "needs_activation") throw Error("SENDER_ACTIVATION_REQUIRED");
22589
22678
  await durableWrite(markerPath, JSON.stringify(marker));
22590
22679
  });
22591
- return { status: "ready", profile: "diagnostic", buildId: manifest.buildId, launcher, skill, sender };
22680
+ const claudeConfig = home === homedir3() && process.env.CLAUDE_CONFIG_DIR ? process.env.CLAUDE_CONFIG_DIR : join11(home, ".claude");
22681
+ const claudeHook = await updateClaudeHook(claudeConfig, claudeHookCommandFor([process.execPath, launcher])).catch(() => "skipped");
22682
+ return { status: "ready", profile: "diagnostic", buildId: manifest.buildId, launcher, skill, sender, claudeHook };
22592
22683
  }
22593
22684
 
22594
22685
  // scripts/diagnostics/npm-entry.mts
22595
22686
  var source = dirname7(dirname7(fileURLToPath2(import.meta.url)));
22596
- var root = join11(homedir4(), ".local/share/sberpay-diagnostic");
22687
+ var root = join12(homedir4(), ".local/share/sberpay-diagnostic");
22597
22688
  try {
22598
22689
  if (process.argv[2] === "setup") {
22599
22690
  if (process.argv.slice(3).some((x) => x !== "--json")) throw Error("INVALID_SETUP_ARGUMENT");
22600
22691
  const result = await installDiagnostic(source);
22601
22692
  console.log(JSON.stringify(result));
22602
22693
  } else {
22603
- const manifest = JSON.parse(await readFile3(join11(source, "manifest.json"), "utf8"));
22694
+ const manifest = JSON.parse(await readFile4(join12(source, "manifest.json"), "utf8"));
22604
22695
  let marker;
22605
22696
  try {
22606
- marker = JSON.parse(await readFile3(join11(root, "installed.json"), "utf8"));
22697
+ marker = JSON.parse(await readFile4(join12(root, "installed.json"), "utf8"));
22607
22698
  } catch {
22608
22699
  throw Error("SETUP_REQUIRED");
22609
22700
  }
22610
22701
  if (marker.stateFormat !== 2 || marker.buildId !== manifest.buildId) throw Error("SETUP_REQUIRED");
22611
- await import(pathToFileURL2(join11(root, "bin/sberpay-cli-diagnostic.mjs")).href);
22702
+ await import(pathToFileURL2(join12(root, "bin/sberpay-cli-diagnostic.mjs")).href);
22612
22703
  }
22613
22704
  } catch (e) {
22614
22705
  console.log(JSON.stringify({ status: "not_ready", code: e.message, hint: "\u0412\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 sberpay-cli-diagnostic setup --json; \u043F\u0440\u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u043C \u043E\u0442\u043A\u0430\u0437\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u0435 \u043A\u043E\u0434 \u043E\u0448\u0438\u0431\u043A\u0438." }));