blun-king-cli 9.1.0 → 9.1.2

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/LIESMICH.txt CHANGED
@@ -9,7 +9,7 @@ Installation
9
9
  ------------
10
10
  Die geprüfte Version exakt global installieren:
11
11
 
12
- npm install -g blun-king-cli@9.1.0
12
+ npm install -g blun-king-cli@9.1.1
13
13
 
14
14
  Start
15
15
  -----
package/README.md CHANGED
@@ -9,7 +9,7 @@ Voraussetzung ist Node.js 24.15 oder neuer. Die geprüfte Version wird exakt
9
9
  installiert:
10
10
 
11
11
  ```powershell
12
- npm install -g blun-king-cli@9.1.0
12
+ npm install -g blun-king-cli@9.1.1
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
package/bin/blun.js CHANGED
@@ -254,10 +254,24 @@ async function installLeaseIsClear() {
254
254
  }
255
255
 
256
256
  async function main() {
257
+ const explicitUpdateRequest = process.argv.length === 3
258
+ && /^(?:update|upgrade)$/iu.test(process.argv[2] || '');
257
259
  const result = await acquireNoticeLease();
258
- if (!result.acquired) return;
260
+ if (!result.acquired) {
261
+ process.stderr.write(explicitUpdateRequest
262
+ ? 'BLUN laeuft noch. Beende die laufende Konsole und starte das Update erneut.\n'
263
+ : 'BLUN laeuft bereits in einer anderen Konsole.\n');
264
+ process.exitCode = 1;
265
+ return;
266
+ }
259
267
  try {
260
- if (!await installLeaseIsClear()) return;
268
+ if (!await installLeaseIsClear()) {
269
+ process.stderr.write(explicitUpdateRequest
270
+ ? 'BLUN laeuft noch. Beende die laufende Konsole und starte das Update erneut.\n'
271
+ : 'BLUN laeuft bereits in einer anderen Konsole.\n');
272
+ process.exitCode = 1;
273
+ return;
274
+ }
261
275
  result.lease.assertOwned();
262
276
  const { runLauncher } = require('./launcher-runtime');
263
277
  result.lease.assertOwned();
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const fs = require('node:fs');
3
4
  const path = require('node:path');
4
5
  const { pathToFileURL } = require('node:url');
5
6
 
@@ -41,7 +42,11 @@ async function runCoreBootstrap() {
41
42
 
42
43
  if (require.main === module) {
43
44
  // oxlint-disable-next-line unicorn/prefer-top-level-await -- Worker entry is CommonJS.
44
- void runCoreBootstrap().catch(() => process.exit(1));
45
+ void runCoreBootstrap().catch((error) => {
46
+ const message = error && error.message ? error.message : String(error);
47
+ fs.writeSync(process.stderr.fd, `BLUN Start fehlgeschlagen: ${message}\n`);
48
+ process.exit(1);
49
+ });
45
50
  }
46
51
 
47
52
  module.exports = { CORE_LOADED_MESSAGE, runCoreBootstrap };
package/bin/king.js CHANGED
@@ -254,10 +254,24 @@ async function installLeaseIsClear() {
254
254
  }
255
255
 
256
256
  async function main() {
257
+ const explicitUpdateRequest = process.argv.length === 3
258
+ && /^(?:update|upgrade)$/iu.test(process.argv[2] || '');
257
259
  const result = await acquireNoticeLease();
258
- if (!result.acquired) return;
260
+ if (!result.acquired) {
261
+ process.stderr.write(explicitUpdateRequest
262
+ ? 'BLUN laeuft noch. Beende die laufende Konsole und starte das Update erneut.\n'
263
+ : 'BLUN laeuft bereits in einer anderen Konsole.\n');
264
+ process.exitCode = 1;
265
+ return;
266
+ }
259
267
  try {
260
- if (!await installLeaseIsClear()) return;
268
+ if (!await installLeaseIsClear()) {
269
+ process.stderr.write(explicitUpdateRequest
270
+ ? 'BLUN laeuft noch. Beende die laufende Konsole und starte das Update erneut.\n'
271
+ : 'BLUN laeuft bereits in einer anderen Konsole.\n');
272
+ process.exitCode = 1;
273
+ return;
274
+ }
261
275
  result.lease.assertOwned();
262
276
  const { runLauncher } = require('./launcher-runtime');
263
277
  result.lease.assertOwned();
File without changes
@@ -280,7 +280,7 @@ async function runLauncher(options = {}) {
280
280
  env.BLUN_HOME = blunDir;
281
281
  env.BLUN_MODEL_MAX_COMPLETION_TOKENS = env.BLUN_MODEL_MAX_COMPLETION_TOKENS || '32768';
282
282
  process.exitCode = await superviseProtectedCore(
283
- ['--yolo', ...ARGS],
283
+ ARGS,
284
284
  env,
285
285
  callerCwd,
286
286
  releaseNotice,
File without changes
File without changes
File without changes
File without changes
package/blun.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:77e08de6896f890d2ece095b27978ef8a0c41671818fd4968df22b6237ffaf2b
2
+ // BLUN_BUILD_INPUT_SHA256:6d54e04788e3c465f647fe659f1ddd461d4e661c33aefaaea5550319c0d52dc1
3
3
  import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
4
4
  import { dirname as __cjsShimDirname } from 'node:path';
5
5
  const __filename = __cjsShimFileURLToPath(import.meta.url);
@@ -10433,6 +10433,38 @@ function parseAclFlags(flags) {
10433
10433
  if (parsed.join("") !== flags) throw new Error("Malformed Windows ACL inheritance flags.");
10434
10434
  return parsed.toSorted();
10435
10435
  }
10436
+ function errorDetailAcl(error) {
10437
+ if (error !== null && typeof error === "object" && "stderr" in error) {
10438
+ const stderr = String(error.stderr ?? "").trim();
10439
+ if (stderr.length > 0) return stderr;
10440
+ }
10441
+ if (error instanceof Error && error.message.trim().length > 0) return error.message.trim();
10442
+ return String(error);
10443
+ }
10444
+ function unexpectedExplicitTrusteesAcl(savedAcl, userSid) {
10445
+ if (savedAcl.length === 0 || savedAcl.length % 2 !== 0) throw new Error("Windows ACL dump has an invalid UTF-16LE byte length.");
10446
+ const hasByteOrderMark = savedAcl[0] === 255 && savedAcl[1] === 254;
10447
+ const daclLines = savedAcl.subarray(hasByteOrderMark ? 2 : 0).toString("utf16le").split(/\r?\n/).filter((line) => line.startsWith("D:"));
10448
+ if (daclLines.length !== 1) throw new Error("Windows ACL dump does not contain exactly one DACL.");
10449
+ const dacl = daclLines[0];
10450
+ const firstAce = dacl.indexOf("(");
10451
+ if (firstAce === -1) return [];
10452
+ const aceText = dacl.slice(firstAce);
10453
+ const aceMatches = [...aceText.matchAll(/\(([^()]*)\)/g)];
10454
+ if (aceMatches.map((match) => match[0]).join("") !== aceText) throw new Error("Windows ACL dump contains malformed access rules.");
10455
+ const expectedTrustees = new Set([userSid.toUpperCase(), WINDOWS_SYSTEM_SID, WINDOWS_ADMINISTRATORS_SID]);
10456
+ const unexpected = new Set();
10457
+ for (const match of aceMatches) {
10458
+ const fields = match[1].split(";");
10459
+ if (fields.length < 6 || !fields[5]) throw new Error("Windows ACL dump contains a malformed access rule.");
10460
+ const flags = parseAclFlags(fields[1]);
10461
+ if (flags.includes("ID")) continue;
10462
+ const rawTrustee = fields[5].toUpperCase();
10463
+ const normalized = normalizeTrustee(rawTrustee);
10464
+ if (!expectedTrustees.has(normalized)) unexpected.add(rawTrustee);
10465
+ }
10466
+ return [...unexpected].toSorted();
10467
+ }
10436
10468
  function assertExpectedDacl(savedAcl, userSid, kind) {
10437
10469
  if (savedAcl.length === 0 || savedAcl.length % 2 !== 0) throw new Error("Windows ACL dump has an invalid UTF-16LE byte length.");
10438
10470
  const hasByteOrderMark = savedAcl[0] === 255 && savedAcl[1] === 254;
@@ -10478,7 +10510,7 @@ var init_windows_private_acl = __esmMin((() => {
10478
10510
  try {
10479
10511
  this.apply(target, kind, userSid);
10480
10512
  } catch (error) {
10481
- throw new Error("Windows credential ACL hardening failed.", { cause: error });
10513
+ throw new Error(`Windows credential ACL hardening failed: ${errorDetailAcl(error)}`, { cause: error });
10482
10514
  }
10483
10515
  this.verifyWithUserSid(target, kind, userSid);
10484
10516
  }
@@ -10518,43 +10550,28 @@ var init_windows_private_acl = __esmMin((() => {
10518
10550
  }
10519
10551
  apply(target, kind, userSid) {
10520
10552
  const absoluteTarget = resolve(target);
10521
- const targetName = basename(absoluteTarget);
10522
- if (targetName.length === 0 || /[\r\n]/.test(targetName)) throw new Error("Windows credential ACL cannot target a volume root or newline path.");
10553
+ if (basename(absoluteTarget).length === 0 || /[\r\n]/.test(absoluteTarget)) throw new Error("Windows credential ACL cannot target a volume root or newline path.");
10554
+ const unexpectedTrustees = unexpectedExplicitTrusteesAcl(this.save(absoluteTarget), userSid);
10555
+ const grant = kind === "directory" ? "(OI)(CI)F" : "F";
10556
+ this.runCommand(this.executable("icacls.exe"), [absoluteTarget, "/inheritance:r", "/Q"]);
10557
+ if (unexpectedTrustees.length > 0) this.runCommand(this.executable("icacls.exe"), [absoluteTarget, "/remove", ...unexpectedTrustees.map((trustee) => `*${trustee}`), "/Q"]);
10558
+ this.runCommand(this.executable("icacls.exe"), [absoluteTarget, "/remove:d", `*${userSid}`, `*${WINDOWS_SYSTEM_SID}`, `*${WINDOWS_ADMINISTRATORS_SID}`, "/Q"]);
10559
+ this.runCommand(this.executable("icacls.exe"), [absoluteTarget, "/grant:r", `*${userSid}:${grant}`, `*${WINDOWS_SYSTEM_SID}:${grant}`, `*${WINDOWS_ADMINISTRATORS_SID}:${grant}`, "/Q"]);
10560
+ }
10561
+ save(target) {
10523
10562
  const aclFile = this.transferPath();
10524
- const acl = `\uFEFF${targetName}\r\n${expectedDacl(userSid, kind)}\r\n`;
10525
- let created = false;
10526
10563
  try {
10527
- writeFileSync(aclFile, acl, {
10528
- encoding: "utf16le",
10529
- flag: "wx",
10530
- mode: 384
10531
- });
10532
- created = true;
10533
- this.runCommand(this.executable("icacls.exe"), [
10534
- dirname(absoluteTarget),
10535
- "/restore",
10536
- aclFile,
10537
- "/Q"
10538
- ]);
10564
+ this.runCommand(this.executable("icacls.exe"), [target, "/save", aclFile, "/Q"]);
10565
+ return readFileSync(aclFile);
10539
10566
  } finally {
10540
- if (created) this.removeTransferFile(aclFile);
10567
+ this.removeTransferFile(aclFile);
10541
10568
  }
10542
10569
  }
10543
10570
  verifyWithUserSid(target, kind, userSid) {
10544
- const absoluteTarget = resolve(target);
10545
- const aclFile = this.transferPath();
10546
10571
  try {
10547
- this.runCommand(this.executable("icacls.exe"), [
10548
- absoluteTarget,
10549
- "/save",
10550
- aclFile,
10551
- "/Q"
10552
- ]);
10553
- assertExpectedDacl(readFileSync(aclFile), userSid, kind);
10572
+ assertExpectedDacl(this.save(resolve(target)), userSid, kind);
10554
10573
  } catch (error) {
10555
- throw new Error("Windows credential ACL verification failed.", { cause: error });
10556
- } finally {
10557
- this.removeTransferFile(aclFile);
10574
+ throw new Error(`Windows credential ACL verification failed: ${errorDetailAcl(error)}`, { cause: error });
10558
10575
  }
10559
10576
  }
10560
10577
  };
@@ -499190,29 +499207,9 @@ function renderQuotaSegment(window, colors, options) {
499190
499207
  const reset = options.includeReset ? formatQuotaReset(window.resetAt, options.locale, options.timeZone) : "";
499191
499208
  return `${label} ${bar} ${percentage}${chalk.hex(colors.textDim)(reset)}`;
499192
499209
  }
499193
- function packQuotaSegments(segments, width) {
499194
- const lines = [];
499195
- let current = "";
499196
- for (const segment of segments) {
499197
- if (current.length === 0) {
499198
- current = segment;
499199
- continue;
499200
- }
499201
- const joined = `${current}${QUOTA_SEGMENT_GAP}${segment}`;
499202
- if (visibleWidth(joined) <= width) current = joined;
499203
- else {
499204
- lines.push(current);
499205
- current = segment;
499206
- }
499207
- }
499208
- if (current.length > 0) lines.push(current);
499209
- return lines;
499210
- }
499211
- function centerQuotaLines(lines, width) {
499212
- return lines.map((line) => {
499213
- const leftPadding = Math.max(0, Math.floor((width - visibleWidth(line)) / 2));
499214
- return `${" ".repeat(leftPadding)}${line}`;
499215
- });
499210
+ function centerQuotaLine(line, width) {
499211
+ const leftPadding = Math.max(0, Math.floor((width - visibleWidth(line)) / 2));
499212
+ return `${" ".repeat(leftPadding)}${line}`;
499216
499213
  }
499217
499214
  function formatManagedQuotaFooterLines(windows, colors, width, options = {}) {
499218
499215
  if (windows.length === 0 || width <= 0) return [];
@@ -499236,14 +499233,17 @@ function formatManagedQuotaFooterLines(windows, colors, width, options = {}) {
499236
499233
  }
499237
499234
  ];
499238
499235
  for (const variant of variants) {
499239
- const segments = windows.map((window) => renderQuotaSegment(window, colors, {
499236
+ const line = windows.map((window) => renderQuotaSegment(window, colors, {
499240
499237
  ...variant,
499241
499238
  locale,
499242
499239
  timeZone: options.timeZone
499243
- }));
499244
- if (segments.every((segment) => visibleWidth(segment) <= width)) return centerQuotaLines(packQuotaSegments(segments, width), width);
499240
+ })).join(QUOTA_SEGMENT_GAP);
499241
+ if (visibleWidth(line) <= width) return [centerQuotaLine(line, width)];
499245
499242
  }
499246
- return centerQuotaLines(windows.map((window) => truncateToWidth(quotaWindowLabel(window.id), width, "…")), width);
499243
+ return [centerQuotaLine(truncateToWidth(windows.map((window) => {
499244
+ const percentage = window.unlimited === true ? "∞" : `${String(Math.round(window.fraction * 100))}%`;
499245
+ return `${quotaWindowLabel(window.id)} ${percentage}`;
499246
+ }).join(" · "), width, "…"), width)];
499247
499247
  }
499248
499248
  function renderContextBar(ratio, colors) {
499249
499249
  const clamped = Math.max(0, Math.min(1, ratio));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.0",
3
+ "version": "9.1.2",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {