blun-king-cli 9.1.607 → 9.1.609

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # BLUN King Changelog
2
2
 
3
+ ## 9.1.609
4
+
5
+ - Open the existing effort picker with Ctrl+L while preserving the editor draft. Reuse the existing effort settings and model restrictions rather than adding a second configuration path.
6
+ - Preserve the existing busy-session rule: an effort change during active work is rejected, not queued for later. Ignore the shortcut during replay or editor takeover.
7
+ - These changes do not establish faster live model responses, lower billed token usage, or complete OpenClaw parity.
8
+
9
+ ## 9.1.608
10
+
11
+ - Apply Telegram mention admission before unaddressed group messages enter the session context; preserve the explicit opt-out.
12
+ - Preserve custom multiple-choice selections and sequential question cancellation. Keep the goal footer on one shared refresh timer.
13
+ - Reduce Windows ACL transfer overhead without weakening permission validation. Bound recovery from temporary configuration replacement failures while retaining writer ownership.
14
+ - Verify disappearance of a concurrently removed Windows writer marker before retrying acquisition; unreadable existing markers still fail closed.
15
+ - These changes do not establish faster live model responses, lower billed token usage, or complete OpenClaw parity.
16
+
3
17
  ## 9.1.607
4
18
 
5
19
  - Add opt-in last-selected-session restoration with resume_last_selected in tui.toml. Scope the selection to the verified account, runtime, agent and workspace. Keep ordinary startup unchanged and explicit session choices authoritative; unavailable selections fall back to a fresh session, not another session.
package/LIESMICH.txt CHANGED
@@ -26,7 +26,7 @@ Installation
26
26
  ------------
27
27
  Die geprüfte Version exakt global installieren:
28
28
 
29
- npm install -g blun-king-cli@9.1.607
29
+ npm install -g blun-king-cli@9.1.609
30
30
 
31
31
  Start
32
32
  -----
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.607
12
+ npm install -g blun-king-cli@9.1.609
13
13
  ```
14
14
 
15
15
  ### Windows: Node.js, npm und Git Bash
package/blun.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:9c2732198b7a858bcd8b66604ad503ed8e359fcaa2b196011f9954a3caa53dba
2
+ // BLUN_BUILD_INPUT_SHA256:5d42292f090cacd4506d9194f177756c6d8acc509f938ecc413c752522d368c2
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);
@@ -10449,7 +10449,18 @@ async function readOwner(lockDirectory) {
10449
10449
  const marker = join(lockDirectory, name);
10450
10450
  const stats = await lstat(marker);
10451
10451
  if (!stats.isFile() || stats.isSymbolicLink() || stats.size > 2048) throw unavailable();
10452
- const record = JSON.parse(await readFile(marker, "utf8"));
10452
+ let content;
10453
+ try {
10454
+ content = await readFile(marker, "utf8");
10455
+ } catch (error) {
10456
+ if (process.platform === "win32" && codeOf(error) === "EPERM") try {
10457
+ await lstat(marker);
10458
+ } catch (inspectionError) {
10459
+ if (codeOf(inspectionError) === "ENOENT") throw inspectionError;
10460
+ }
10461
+ throw error;
10462
+ }
10463
+ const record = JSON.parse(content);
10453
10464
  if (record === null || record.version !== 1 || record.ownerId !== match[1] || !Number.isSafeInteger(record.pid) || record.pid <= 0 || record.hostname !== hostname()) throw unavailable();
10454
10465
  return {
10455
10466
  name,
@@ -10641,6 +10652,22 @@ function isRecord$26(value) {
10641
10652
  var init_utils$1 = __esmMin((() => {}));
10642
10653
  //#endregion
10643
10654
  //#region ../../packages/oauth/src/windows-command-worker.ts
10655
+ function prepareWindowsCommand(executable, args, platform = process.platform) {
10656
+ const target = args[0];
10657
+ if (platform !== "win32" || win32.basename(executable).toLowerCase() !== "icacls.exe" || !target || !win32.isAbsolute(target) || !win32.basename(target)) return { args };
10658
+ const save = args.length === 4 && args[1] === "/save" && args[3] === "/Q" && !!args[2] && win32.isAbsolute(args[2]);
10659
+ const repair = [
10660
+ "/inheritance:r",
10661
+ "/grant:r",
10662
+ "/remove",
10663
+ "/remove:d"
10664
+ ].includes(args[1] ?? "") && args.at(-1) === "/Q";
10665
+ if (!save && !repair) return { args };
10666
+ return {
10667
+ args: [win32.basename(target), ...args.slice(1)],
10668
+ cwd: win32.dirname(target)
10669
+ };
10670
+ }
10644
10671
  function retireWhenIdle(state) {
10645
10672
  if (state.pending.size !== 0) return;
10646
10673
  state.worker.unref();
@@ -10694,7 +10721,7 @@ function runWindowsCommand(executable, args) {
10694
10721
  state.worker.postMessage({
10695
10722
  id,
10696
10723
  executable,
10697
- args: [...args]
10724
+ ...prepareWindowsCommand(executable, [...args])
10698
10725
  });
10699
10726
  } catch (error) {
10700
10727
  state.pending.delete(id);
@@ -10708,10 +10735,10 @@ var init_windows_command_worker = __esmMin((() => {
10708
10735
  SOURCE = `
10709
10736
  const { parentPort } = require('node:worker_threads');
10710
10737
  const { execFileSync } = require('node:child_process');
10711
- parentPort.on('message', ({ id, executable, args }) => {
10738
+ parentPort.on('message', ({ id, executable, args, cwd }) => {
10712
10739
  try {
10713
10740
  const stdout = execFileSync(executable, args, {
10714
- encoding: 'utf8', shell: false, windowsHide: true,
10741
+ encoding: 'utf8', shell: false, windowsHide: true, cwd,
10715
10742
  stdio: ['ignore', 'pipe', 'pipe'],
10716
10743
  });
10717
10744
  parentPort.postMessage({ id, stdout });
@@ -10950,7 +10977,7 @@ var init_windows_private_acl = __esmMin((() => {
10950
10977
  return this.userSid;
10951
10978
  }
10952
10979
  async save(target) {
10953
- const file = join(tmpdir(), `blun-private-acl-${process.pid}-${randomBytes(16).toString("hex")}.txt`);
10980
+ const file = join(tmpdir(), `${randomBytes(16).toString("hex")}.txt`);
10954
10981
  try {
10955
10982
  await this.run("icacls.exe", [
10956
10983
  target,
@@ -11081,7 +11108,7 @@ var init_windows_private_acl = __esmMin((() => {
11081
11108
  return this.userSid;
11082
11109
  }
11083
11110
  transferPath() {
11084
- return join(tmpdir(), `blun-private-acl-${process.pid}-${randomBytes(16).toString("hex")}.txt`);
11111
+ return join(tmpdir(), `${randomBytes(16).toString("hex")}.txt`);
11085
11112
  }
11086
11113
  removeTransferFile(file) {
11087
11114
  try {
@@ -16827,8 +16854,19 @@ async function mutateConfigFile(filePath, transform) {
16827
16854
  try {
16828
16855
  await writer.assertOwned();
16829
16856
  const { config, result } = transform(readConfigFileForUpdate(canonical));
16830
- await writer.assertOwned();
16831
- await writeConfigFile(canonical, config);
16857
+ for (let attempt = 0;; attempt += 1) {
16858
+ await writer.assertOwned();
16859
+ try {
16860
+ await writeConfigFile(canonical, config);
16861
+ break;
16862
+ } catch (error) {
16863
+ const failure = error;
16864
+ if (process.platform !== "win32" || attempt >= 9 || failure?.code !== "EPERM" || failure.syscall !== "rename" || typeof failure.dest !== "string" || resolve(failure.dest) !== canonical) throw error;
16865
+ await new Promise((resolve) => {
16866
+ setTimeout(resolve, 25);
16867
+ });
16868
+ }
16869
+ }
16832
16870
  return result;
16833
16871
  } finally {
16834
16872
  await writer.release();
@@ -499423,6 +499461,7 @@ var CustomEditor = class extends Editor {
499423
499461
  onToggleToolExpand;
499424
499462
  onOpenExternalEditor;
499425
499463
  onOpenSessionPicker;
499464
+ onOpenEffortPicker;
499426
499465
  onCtrlS;
499427
499466
  /** Return `true` to consume Ctrl+B; return `false`/`undefined` to fall through to the editor default (cursor-left). */
499428
499467
  onCtrlB;
@@ -499611,6 +499650,10 @@ var CustomEditor = class extends Editor {
499611
499650
  this.onOpenSessionPicker?.();
499612
499651
  return;
499613
499652
  }
499653
+ if (matchesKey(normalized, Key.ctrl("l"))) {
499654
+ this.onOpenEffortPicker?.();
499655
+ return;
499656
+ }
499614
499657
  if (matchesKey(normalized, Key.ctrl("g"))) {
499615
499658
  this.onOpenExternalEditor?.();
499616
499659
  return;
@@ -525792,7 +525835,8 @@ var QuestionDialogComponent = class extends Container {
525792
525835
  this.cursors[questionIdx] = optionIdx;
525793
525836
  this.editingOther = false;
525794
525837
  this.reviewMessage = void 0;
525795
- if (this.isOtherOption(questionIdx, optionIdx)) {
525838
+ const togglingCommittedOther = question.multi_select && method === "space" && this.committedOtherValues[questionIdx] !== void 0;
525839
+ if (this.isOtherOption(questionIdx, optionIdx) && !togglingCommittedOther) {
525796
525840
  this.enterOtherInput(questionIdx);
525797
525841
  return;
525798
525842
  }
@@ -531405,6 +531449,10 @@ var EditorKeyboardController = class {
531405
531449
  this.clearPendingExit();
531406
531450
  host.openSessionPickerShortcut();
531407
531451
  };
531452
+ editor.onOpenEffortPicker = () => {
531453
+ this.clearPendingExit();
531454
+ host.openEffortPickerShortcut();
531455
+ };
531408
531456
  editor.onOpenExternalEditor = () => {
531409
531457
  host.track("shortcut_editor");
531410
531458
  this.openExternalEditor();
@@ -545239,6 +545287,15 @@ var BlunTUI = class {
545239
545287
  if (this.state.queuedMessages.some((item) => item.mode === "command" && item.text === "/sessions" && item.agentId === this.harness.interactiveAgentId && item.channelCommandEnvelope === void 0)) return;
545240
545288
  this.runSlashCommand("/sessions");
545241
545289
  }
545290
+ openEffortPickerShortcut() {
545291
+ if (this.editorReplacementActive || this.queueCommandRunning) return;
545292
+ if (this.state.appState.isReplaying) {
545293
+ this.showError(uiText("blunTui.input.replayBlocked"));
545294
+ return;
545295
+ }
545296
+ if (this.state.queuedMessages.some((item) => item.mode === "command" && item.text === "/effort" && item.agentId === this.harness.interactiveAgentId && item.channelCommandEnvelope === void 0)) return;
545297
+ this.runSlashCommand("/effort");
545298
+ }
545242
545299
  async showSessionPicker(target) {
545243
545300
  await this.openSessionPicker({
545244
545301
  target,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.607",
3
+ "version": "9.1.609",
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": {
package/worker-host.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:9c2732198b7a858bcd8b66604ad503ed8e359fcaa2b196011f9954a3caa53dba
2
+ // BLUN_BUILD_INPUT_SHA256:5d42292f090cacd4506d9194f177756c6d8acc509f938ecc413c752522d368c2
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);
@@ -10129,7 +10129,18 @@ async function readOwner(lockDirectory) {
10129
10129
  const marker = join(lockDirectory, name);
10130
10130
  const stats = await lstat(marker);
10131
10131
  if (!stats.isFile() || stats.isSymbolicLink() || stats.size > 2048) throw unavailable();
10132
- const record = JSON.parse(await readFile(marker, "utf8"));
10132
+ let content;
10133
+ try {
10134
+ content = await readFile(marker, "utf8");
10135
+ } catch (error) {
10136
+ if (process.platform === "win32" && codeOf(error) === "EPERM") try {
10137
+ await lstat(marker);
10138
+ } catch (inspectionError) {
10139
+ if (codeOf(inspectionError) === "ENOENT") throw inspectionError;
10140
+ }
10141
+ throw error;
10142
+ }
10143
+ const record = JSON.parse(content);
10133
10144
  if (record === null || record.version !== 1 || record.ownerId !== match[1] || !Number.isSafeInteger(record.pid) || record.pid <= 0 || record.hostname !== hostname()) throw unavailable();
10134
10145
  return {
10135
10146
  name,
@@ -10327,13 +10338,29 @@ function isRecord$9(value) {
10327
10338
  }
10328
10339
  //#endregion
10329
10340
  //#region ../../packages/oauth/src/windows-command-worker.ts
10341
+ function prepareWindowsCommand(executable, args, platform = process.platform) {
10342
+ const target = args[0];
10343
+ if (platform !== "win32" || win32.basename(executable).toLowerCase() !== "icacls.exe" || !target || !win32.isAbsolute(target) || !win32.basename(target)) return { args };
10344
+ const save = args.length === 4 && args[1] === "/save" && args[3] === "/Q" && !!args[2] && win32.isAbsolute(args[2]);
10345
+ const repair = [
10346
+ "/inheritance:r",
10347
+ "/grant:r",
10348
+ "/remove",
10349
+ "/remove:d"
10350
+ ].includes(args[1] ?? "") && args.at(-1) === "/Q";
10351
+ if (!save && !repair) return { args };
10352
+ return {
10353
+ args: [win32.basename(target), ...args.slice(1)],
10354
+ cwd: win32.dirname(target)
10355
+ };
10356
+ }
10330
10357
  const SOURCE = `
10331
10358
  const { parentPort } = require('node:worker_threads');
10332
10359
  const { execFileSync } = require('node:child_process');
10333
- parentPort.on('message', ({ id, executable, args }) => {
10360
+ parentPort.on('message', ({ id, executable, args, cwd }) => {
10334
10361
  try {
10335
10362
  const stdout = execFileSync(executable, args, {
10336
- encoding: 'utf8', shell: false, windowsHide: true,
10363
+ encoding: 'utf8', shell: false, windowsHide: true, cwd,
10337
10364
  stdio: ['ignore', 'pipe', 'pipe'],
10338
10365
  });
10339
10366
  parentPort.postMessage({ id, stdout });
@@ -10399,7 +10426,7 @@ function runWindowsCommand(executable, args) {
10399
10426
  state.worker.postMessage({
10400
10427
  id,
10401
10428
  executable,
10402
- args: [...args]
10429
+ ...prepareWindowsCommand(executable, [...args])
10403
10430
  });
10404
10431
  } catch (error) {
10405
10432
  state.pending.delete(id);
@@ -10632,7 +10659,7 @@ var AsyncWindowsPrivateAcl = class {
10632
10659
  return this.userSid;
10633
10660
  }
10634
10661
  async save(target) {
10635
- const file = join(tmpdir(), `blun-private-acl-${process.pid}-${randomBytes(16).toString("hex")}.txt`);
10662
+ const file = join(tmpdir(), `${randomBytes(16).toString("hex")}.txt`);
10636
10663
  try {
10637
10664
  await this.run("icacls.exe", [
10638
10665
  target,
@@ -10763,7 +10790,7 @@ var WindowsPrivateAcl = class {
10763
10790
  return this.userSid;
10764
10791
  }
10765
10792
  transferPath() {
10766
- return join(tmpdir(), `blun-private-acl-${process.pid}-${randomBytes(16).toString("hex")}.txt`);
10793
+ return join(tmpdir(), `${randomBytes(16).toString("hex")}.txt`);
10767
10794
  }
10768
10795
  removeTransferFile(file) {
10769
10796
  try {
@@ -16368,8 +16395,19 @@ async function mutateConfigFile(filePath, transform) {
16368
16395
  try {
16369
16396
  await writer.assertOwned();
16370
16397
  const { config, result } = transform(readConfigFileForUpdate(canonical));
16371
- await writer.assertOwned();
16372
- await writeConfigFile(canonical, config);
16398
+ for (let attempt = 0;; attempt += 1) {
16399
+ await writer.assertOwned();
16400
+ try {
16401
+ await writeConfigFile(canonical, config);
16402
+ break;
16403
+ } catch (error) {
16404
+ const failure = error;
16405
+ if (process.platform !== "win32" || attempt >= 9 || failure?.code !== "EPERM" || failure.syscall !== "rename" || typeof failure.dest !== "string" || resolve(failure.dest) !== canonical) throw error;
16406
+ await new Promise((resolve) => {
16407
+ setTimeout(resolve, 25);
16408
+ });
16409
+ }
16410
+ }
16373
16411
  return result;
16374
16412
  } finally {
16375
16413
  await writer.release();