blun-king-cli 9.1.60 → 9.1.62
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 +12 -3
- package/README.md +10 -1
- package/bin/core-bootstrap.js +3 -6
- package/bin/launcher-runtime.js +135 -12
- package/bin/profile-runtime.cjs +145 -9
- package/bin/running-update.cjs +389 -0
- package/bin/update-notice.js +24 -0
- package/blun.mjs +93 -23
- package/package.json +1 -1
- package/telegram-plugin/commands/access.md +10 -2
- package/telegram-plugin/dist/bridge.mjs +505 -63776
- package/telegram-plugin/dist/mcp-server.mjs +8976 -72843
- package/telegram-plugin/dist/noise.mjs +63473 -2
package/blun.mjs
CHANGED
|
@@ -503027,7 +503027,7 @@ var PersonalMemoryController = class {
|
|
|
503027
503027
|
//#endregion
|
|
503028
503028
|
//#region src/tui/constant/scrollback.ts
|
|
503029
503029
|
function shouldEnableScrollbackMouseTracking(buffer) {
|
|
503030
|
-
return buffer !== void 0 && buffer.
|
|
503030
|
+
return buffer !== void 0 && buffer.totalLines > 0;
|
|
503031
503031
|
}
|
|
503032
503032
|
const ENABLE_SCROLLBACK_MOUSE_TRACKING = "\x1B[?1000h\x1B[?1006h";
|
|
503033
503033
|
const DISABLE_SCROLLBACK_MOUSE_TRACKING = "\x1B[?1000l\x1B[?1006l";
|
|
@@ -503099,8 +503099,8 @@ registerUiCatalogFragment({
|
|
|
503099
503099
|
* 0 = most recent clipped lines visible
|
|
503100
503100
|
* N = N lines up from the bottom
|
|
503101
503101
|
*/
|
|
503102
|
-
/**
|
|
503103
|
-
const MAX_BUFFER_LINES =
|
|
503102
|
+
/** Retain the complete rendered session unless the process itself ends. */
|
|
503103
|
+
const MAX_BUFFER_LINES = Number.POSITIVE_INFINITY;
|
|
503104
503104
|
var ScrollbackBuffer = class {
|
|
503105
503105
|
lines = [];
|
|
503106
503106
|
scrollOffset = 0;
|
|
@@ -505264,6 +505264,7 @@ var SessionEventHandler = class {
|
|
|
505264
505264
|
this.goalCompletionTurnEnded = true;
|
|
505265
505265
|
this.scheduleQueuedGoalPromotion();
|
|
505266
505266
|
if (event.reason === "completed") this.host.refreshManagedQuotaWindows();
|
|
505267
|
+
requestRunningUpdateAtSafeBoundary(this.host);
|
|
505267
505268
|
}
|
|
505268
505269
|
handleStepBegin(event) {
|
|
505269
505270
|
this.host.commitQueuedSteerAtStepStart(event.turnId);
|
|
@@ -505311,12 +505312,13 @@ var SessionEventHandler = class {
|
|
|
505311
505312
|
const duration = durationMs === void 0 ? "—" : formatResponseDuration(durationMs);
|
|
505312
505313
|
const tokens = this.currentTurnTokenCount === void 0 ? "—" : formatTokenCount(this.currentTurnTokenCount);
|
|
505313
505314
|
const tokenKey = this.currentTurnTokenCount === 1 ? "thinking.tokens.one" : "thinking.tokens.other";
|
|
505315
|
+
const startedAt = formatLiveStartedAt(this.currentTurnStartedAtMs ?? Date.now());
|
|
505314
505316
|
this.host.appendTranscriptEntry({
|
|
505315
505317
|
id: nextTranscriptId(),
|
|
505316
505318
|
kind: "status",
|
|
505317
505319
|
turnId: String(event.turnId),
|
|
505318
505320
|
renderMode: "plain",
|
|
505319
|
-
content: `${duration} · ${uiText(tokenKey, { count: tokens })}`
|
|
505321
|
+
content: `${duration} · ${uiText(tokenKey, { count: tokens })} · ${startedAt}`
|
|
505320
505322
|
});
|
|
505321
505323
|
}
|
|
505322
505324
|
markActiveAgentSwarmsCancelled() {
|
|
@@ -506297,12 +506299,6 @@ function createReplayRenderContext() {
|
|
|
506297
506299
|
suppressNextPlanModeOffNotice: false
|
|
506298
506300
|
};
|
|
506299
506301
|
}
|
|
506300
|
-
function limitReplayRecordsByTurn(records, maxTurns) {
|
|
506301
|
-
if (maxTurns <= 0) return [];
|
|
506302
|
-
const turnStarts = records.flatMap((record, index) => isReplayUserTurnRecord(record) ? [index] : []);
|
|
506303
|
-
if (turnStarts.length <= maxTurns) return records;
|
|
506304
|
-
return records.slice(turnStarts[turnStarts.length - maxTurns]);
|
|
506305
|
-
}
|
|
506306
506302
|
function replayEntry(context, kind, content, renderMode, extras = {}) {
|
|
506307
506303
|
return {
|
|
506308
506304
|
id: nextTranscriptId(),
|
|
@@ -506630,7 +506626,7 @@ var SessionReplayRenderer = class {
|
|
|
506630
506626
|
}
|
|
506631
506627
|
renderRecords(agent) {
|
|
506632
506628
|
const context = createReplayRenderContext();
|
|
506633
|
-
for (const record of
|
|
506629
|
+
for (const record of agent.replay) this.renderRecord(context, record);
|
|
506634
506630
|
this.flushAssistant(context);
|
|
506635
506631
|
this.cleanupRuntime(context);
|
|
506636
506632
|
}
|
|
@@ -507717,7 +507713,7 @@ function formatLoopChatIndicator(loop, colors, nowMs = Date.now()) {
|
|
|
507717
507713
|
numeric: "always",
|
|
507718
507714
|
style: "short"
|
|
507719
507715
|
}).format(value, unit);
|
|
507720
|
-
return chalk.hex(colors.
|
|
507716
|
+
return chalk.hex(colors.textMuted)(`Loop ${relative}`);
|
|
507721
507717
|
}
|
|
507722
507718
|
function formatBadgeElapsed(ms) {
|
|
507723
507719
|
const totalSeconds = Math.round(ms / 1e3);
|
|
@@ -508032,9 +508028,9 @@ var FooterComponent = class {
|
|
|
508032
508028
|
if (model) {
|
|
508033
508029
|
const sep = chalk.hex(colors.textMuted)(" · ");
|
|
508034
508030
|
const persona = personaName();
|
|
508035
|
-
const profileLabel = process.env["BLUN_PROFILE"]
|
|
508036
|
-
const profile = chalk.hex(colors.textDim)(profileLabel) + sep;
|
|
508037
|
-
const brand = chalk.hex(colors.primary).bold("●
|
|
508031
|
+
const profileLabel = process.env["BLUN_PROFILE"]?.trim();
|
|
508032
|
+
const profile = profileLabel !== void 0 && profileLabel.length > 0 && profileLabel.toLowerCase() !== "default" ? chalk.hex(colors.textDim)(profileLabel) + sep : "";
|
|
508033
|
+
const brand = chalk.hex(colors.primary).bold("● BL") + chalk.hex(colors.text)("UN") + sep + profile + (persona !== void 0 ? chalk.hex(colors.text)(persona) + sep : "");
|
|
508038
508034
|
const modelLabel = model;
|
|
508039
508035
|
const modeLabel = uiText(state.permissionMode === "yolo" ? "footer.mode.god" : state.permissionMode === "auto" ? "footer.mode.auto" : "footer.mode.manual");
|
|
508040
508036
|
const modeSuffix = sep + chalk.hex(colors.textDim)(uiText("footer.mode", { mode: modeLabel }));
|
|
@@ -511396,12 +511392,18 @@ var CustomEditor = class extends Editor {
|
|
|
511396
511392
|
if (isKeyRelease(normalized)) return;
|
|
511397
511393
|
if (!matchesKey(normalized, Key.escape)) this.onNonEscapeInput?.();
|
|
511398
511394
|
if (this.consumingPaste) {
|
|
511399
|
-
|
|
511400
|
-
if (
|
|
511395
|
+
const cancelPaste = matchesKey(normalized, Key.ctrl("c")) || matchesKey(normalized, Key.escape);
|
|
511396
|
+
if (cancelPaste) {
|
|
511401
511397
|
this.consumingPaste = false;
|
|
511402
511398
|
this.consumeBuffer = "";
|
|
511399
|
+
} else {
|
|
511400
|
+
this.consumeBuffer += normalized;
|
|
511401
|
+
if (this.consumeBuffer.includes(BRACKET_PASTE_END)) {
|
|
511402
|
+
this.consumingPaste = false;
|
|
511403
|
+
this.consumeBuffer = "";
|
|
511404
|
+
}
|
|
511405
|
+
return;
|
|
511403
511406
|
}
|
|
511404
|
-
return;
|
|
511405
511407
|
}
|
|
511406
511408
|
if (normalized.includes(BRACKET_PASTE_START) && this.expandPasteMarkerAtCursor()) {
|
|
511407
511409
|
if (!normalized.includes(BRACKET_PASTE_END)) this.consumingPaste = true;
|
|
@@ -511456,6 +511458,7 @@ var CustomEditor = class extends Editor {
|
|
|
511456
511458
|
if (this.inputMode === "bash" && this.getText().length === 0 && (matchesKey(normalized, Key.escape) || matchesKey(normalized, Key.backspace))) {
|
|
511457
511459
|
this.inputMode = "prompt";
|
|
511458
511460
|
this.onInputModeChange?.("prompt");
|
|
511461
|
+
if (matchesKey(normalized, Key.escape)) this.onEscape?.(true);
|
|
511459
511462
|
return;
|
|
511460
511463
|
}
|
|
511461
511464
|
if (matchesKey(normalized, Key.up)) {
|
|
@@ -511742,6 +511745,7 @@ var GhostSuggestEditor = class extends CustomEditor {
|
|
|
511742
511745
|
if (matchesKey(normalized, Key.escape)) {
|
|
511743
511746
|
this.ghostSuggestion = null;
|
|
511744
511747
|
this.onGhostDismissed?.();
|
|
511748
|
+
this.onEscape?.(true);
|
|
511745
511749
|
return;
|
|
511746
511750
|
}
|
|
511747
511751
|
if (this.isCursorAtTextEnd() && !this.isShowingAutocomplete()) {
|
|
@@ -513049,13 +513053,13 @@ function readEnvInt(name, fallback) {
|
|
|
513049
513053
|
return value;
|
|
513050
513054
|
}
|
|
513051
513055
|
/** Keep the most recent N turns. `0` disables trimming. */
|
|
513052
|
-
const TRANSCRIPT_MAX_TURNS = readEnvInt("BLUN_TUI_MAX_TURNS",
|
|
513056
|
+
const TRANSCRIPT_MAX_TURNS = readEnvInt("BLUN_TUI_MAX_TURNS", 0);
|
|
513053
513057
|
/** Only the most recent E turns are allowed to expand (Ctrl+O). `0` disables expanding. */
|
|
513054
513058
|
const TRANSCRIPT_EXPAND_TURNS = readEnvInt("BLUN_TUI_EXPAND_TURNS", 3);
|
|
513055
513059
|
/** Only trim once the window exceeds maxTurns by this much (avoids churn). */
|
|
513056
513060
|
const TRANSCRIPT_HYSTERESIS = readEnvInt("BLUN_TUI_HYSTERESIS", 5);
|
|
513057
513061
|
/** Keep this many recent steps untouched inside a turn; older steps are merged into a summary. `0` disables merging. */
|
|
513058
|
-
const TRANSCRIPT_KEEP_RECENT_STEPS = readEnvInt("BLUN_TUI_KEEP_RECENT_STEPS",
|
|
513062
|
+
const TRANSCRIPT_KEEP_RECENT_STEPS = readEnvInt("BLUN_TUI_KEEP_RECENT_STEPS", 0);
|
|
513059
513063
|
/**
|
|
513060
513064
|
* Group consecutive entries into turns by `turnId`. Entries with the same
|
|
513061
513065
|
* non-undefined `turnId` that are adjacent belong to the same turn.
|
|
@@ -513112,6 +513116,60 @@ function turnsToTrim(turns, maxTurns, hysteresis) {
|
|
|
513112
513116
|
}
|
|
513113
513117
|
//#endregion
|
|
513114
513118
|
//#region src/tui/blun-tui.ts
|
|
513119
|
+
const {
|
|
513120
|
+
RUNNING_UPDATE_HANDOFF_EXIT_CODE,
|
|
513121
|
+
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
513122
|
+
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
513123
|
+
RUNTIME_READY_MESSAGE,
|
|
513124
|
+
isSafeRuntimeBoundary
|
|
513125
|
+
} = __require("./bin/running-update.cjs");
|
|
513126
|
+
function notifyRunningRuntimeReady(tui) {
|
|
513127
|
+
if (!process.connected) return;
|
|
513128
|
+
const sessionId = tui.getCurrentSessionId();
|
|
513129
|
+
if (sessionId.length === 0) return;
|
|
513130
|
+
try {
|
|
513131
|
+
process.send({
|
|
513132
|
+
type: RUNTIME_READY_MESSAGE,
|
|
513133
|
+
sessionId
|
|
513134
|
+
});
|
|
513135
|
+
} catch {}
|
|
513136
|
+
}
|
|
513137
|
+
function requestRunningUpdateAtSafeBoundary(tui) {
|
|
513138
|
+
if (tui.runningUpdatePreparedVersion === void 0 || tui.runningUpdateHandoffStarted || !process.connected) return false;
|
|
513139
|
+
if (!isSafeRuntimeBoundary({
|
|
513140
|
+
isShuttingDown: tui.isShuttingDown,
|
|
513141
|
+
streamingPhase: tui.state.appState.streamingPhase,
|
|
513142
|
+
isCompacting: tui.state.appState.isCompacting,
|
|
513143
|
+
queuedMessages: tui.state.queuedMessages.length,
|
|
513144
|
+
activeToolCalls: tui.streamingUI.hasActiveToolCalls() ? 1 : 0,
|
|
513145
|
+
shellCommands: tui.shellOutputStreams.size,
|
|
513146
|
+
queueCommandRunning: tui.queueCommandRunning
|
|
513147
|
+
})) return false;
|
|
513148
|
+
const sessionId = tui.getCurrentSessionId();
|
|
513149
|
+
if (sessionId.length === 0) return false;
|
|
513150
|
+
tui.runningUpdateHandoffStarted = true;
|
|
513151
|
+
try {
|
|
513152
|
+
process.send({
|
|
513153
|
+
type: RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
513154
|
+
sessionId,
|
|
513155
|
+
version: tui.runningUpdatePreparedVersion
|
|
513156
|
+
});
|
|
513157
|
+
} catch {
|
|
513158
|
+
tui.runningUpdateHandoffStarted = false;
|
|
513159
|
+
return false;
|
|
513160
|
+
}
|
|
513161
|
+
void tui.stop(RUNNING_UPDATE_HANDOFF_EXIT_CODE);
|
|
513162
|
+
return true;
|
|
513163
|
+
}
|
|
513164
|
+
function installRunningUpdateListener(tui) {
|
|
513165
|
+
const handler = (message) => {
|
|
513166
|
+
if (message?.type !== RUNNING_UPDATE_PREPARED_MESSAGE || typeof message.version !== "string") return;
|
|
513167
|
+
tui.runningUpdatePreparedVersion = message.version;
|
|
513168
|
+
requestRunningUpdateAtSafeBoundary(tui);
|
|
513169
|
+
};
|
|
513170
|
+
process.on("message", handler);
|
|
513171
|
+
return () => process.off("message", handler);
|
|
513172
|
+
}
|
|
513115
513173
|
function loadingTipKind(mode) {
|
|
513116
513174
|
if (mode === "waiting" || mode === "tool") return "blun";
|
|
513117
513175
|
if (mode === "composing") return "composing";
|
|
@@ -513196,6 +513254,9 @@ var BlunTUI = class {
|
|
|
513196
513254
|
startupLoginRequired = false;
|
|
513197
513255
|
startupWorkspaceSelectionPending = false;
|
|
513198
513256
|
startupGoalPromptedSessionId;
|
|
513257
|
+
runningUpdatePreparedVersion;
|
|
513258
|
+
runningUpdateHandoffStarted = false;
|
|
513259
|
+
runningUpdateMessageDispose;
|
|
513199
513260
|
startupPhaseMs = {};
|
|
513200
513261
|
lastActivityMode;
|
|
513201
513262
|
currentLoadingTip = void 0;
|
|
@@ -513309,6 +513370,7 @@ var BlunTUI = class {
|
|
|
513309
513370
|
this.editorKeyboard.install();
|
|
513310
513371
|
this.scrollbackController = new ScrollbackController(this.state);
|
|
513311
513372
|
this.scrollbackController.install();
|
|
513373
|
+
this.runningUpdateMessageDispose = installRunningUpdateListener(this);
|
|
513312
513374
|
this.buildLayout();
|
|
513313
513375
|
}
|
|
513314
513376
|
getSlashCommands() {
|
|
@@ -513739,6 +513801,8 @@ var BlunTUI = class {
|
|
|
513739
513801
|
this.managedQuotaWarningController.dispose();
|
|
513740
513802
|
this.state.loopIndicator.dispose();
|
|
513741
513803
|
this.state.footer.dispose();
|
|
513804
|
+
this.runningUpdateMessageDispose?.();
|
|
513805
|
+
this.runningUpdateMessageDispose = void 0;
|
|
513742
513806
|
for (const dispose of this.reverseRpcDisposers) dispose();
|
|
513743
513807
|
this.reverseRpcDisposers.length = 0;
|
|
513744
513808
|
this.disposeTerminalTracking();
|
|
@@ -513962,6 +514026,7 @@ var BlunTUI = class {
|
|
|
513962
514026
|
if (this.shellOutputStreams.size === 0) {
|
|
513963
514027
|
this.setAppState({ streamingPhase: "idle" });
|
|
513964
514028
|
this.drainOneQueuedMessage();
|
|
514029
|
+
requestRunningUpdateAtSafeBoundary(this);
|
|
513965
514030
|
}
|
|
513966
514031
|
}
|
|
513967
514032
|
queueDrainTimer;
|
|
@@ -516409,22 +516474,27 @@ async function runShell(opts, version, updateStartupNotice) {
|
|
|
516409
516474
|
tui.onExit = async (exitCode = 0) => {
|
|
516410
516475
|
const sessionId = tui.getCurrentSessionId();
|
|
516411
516476
|
const hasContent = tui.hasSessionContent();
|
|
516477
|
+
const runningUpdateHandoff = exitCode === RUNNING_UPDATE_HANDOFF_EXIT_CODE;
|
|
516412
516478
|
setCrashPhase("shutdown");
|
|
516413
516479
|
trackLifecycle("exit", { duration_ms: Date.now() - startedAt });
|
|
516414
516480
|
await shutdownTelemetry({ timeoutMs: CLI_SHUTDOWN_TIMEOUT_MS });
|
|
516415
516481
|
const gutter = " ".repeat(1);
|
|
516416
|
-
process.stdout.write(`${gutter}Bye!\n`);
|
|
516482
|
+
if (!runningUpdateHandoff) process.stdout.write(`${gutter}Bye!\n`);
|
|
516417
516483
|
const hints = [];
|
|
516418
|
-
if (sessionId !== "" && hasContent) hints.push(`${gutter}To resume this session: blun -r ${sessionId}`);
|
|
516419
|
-
if (tui.exitOpenUrl !== void 0) hints.push(`${gutter}open ${toTerminalHyperlink$1(tui.exitOpenUrl, tui.exitOpenUrl)}`);
|
|
516484
|
+
if (!runningUpdateHandoff && sessionId !== "" && hasContent) hints.push(`${gutter}To resume this session: blun -r ${sessionId}`);
|
|
516485
|
+
if (!runningUpdateHandoff && tui.exitOpenUrl !== void 0) hints.push(`${gutter}open ${toTerminalHyperlink$1(tui.exitOpenUrl, tui.exitOpenUrl)}`);
|
|
516420
516486
|
if (hints.length > 0) process.stderr.write(`\n${hints.join("\n")}\n`);
|
|
516421
516487
|
removeCrashHandlers();
|
|
516422
516488
|
restoreStty();
|
|
516489
|
+
if (process.connected) try {
|
|
516490
|
+
process.disconnect();
|
|
516491
|
+
} catch {}
|
|
516423
516492
|
process.exit(exitCode);
|
|
516424
516493
|
};
|
|
516425
516494
|
try {
|
|
516426
516495
|
const initStartedAt = Date.now();
|
|
516427
516496
|
await tui.start();
|
|
516497
|
+
notifyRunningRuntimeReady(tui);
|
|
516428
516498
|
const initMs = Date.now() - initStartedAt;
|
|
516429
516499
|
const startupSessionId = tui.getCurrentSessionId();
|
|
516430
516500
|
const mcpMs = await tui.getStartupMcpMs();
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: access
|
|
3
|
-
description: Manage Telegram channel access — approve pairings, edit allowlists, set DM/group policy.
|
|
3
|
+
description: Manage Telegram channel access — create connection codes, approve pairings, edit allowlists, set DM/group policy.
|
|
4
4
|
---
|
|
5
5
|
Manage access control for the BLUN Telegram channel. The state file is
|
|
6
6
|
`~/.blun/channels/telegram/access.json` (create the directory and a default
|
|
7
|
-
`{"dmPolicy":"pairing","allowFrom":[],"groups":{},"pending":{}}` if missing).
|
|
7
|
+
`{"dmPolicy":"pairing","allowFrom":[],"groups":{},"pending":{},"connect":{}}` if missing).
|
|
8
8
|
Honor `BLUN_TELEGRAM_STATE_DIR` if that environment variable is set.
|
|
9
9
|
|
|
10
10
|
ARGUMENTS: $ARGUMENTS
|
|
@@ -13,6 +13,14 @@ Supported operations (parse from the arguments above; if empty, show current
|
|
|
13
13
|
state as a short summary — dmPolicy, allowFrom entries, groups, pending codes
|
|
14
14
|
with expiry):
|
|
15
15
|
|
|
16
|
+
- `connect` — generate a cryptographically random 6-character lowercase hex
|
|
17
|
+
code in this console. Store it as `connect[code]` with `createdAt` now and
|
|
18
|
+
`expiresAt` ten minutes from now, save atomically, then print exactly these
|
|
19
|
+
two useful lines (never ask for or print a Telegram chat id):
|
|
20
|
+
`Telegram-Code: <code>`
|
|
21
|
+
`Jetzt im gewuenschten privaten Chat oder in der Gruppe senden: /connect <code>`
|
|
22
|
+
The bridge consumes the code once and records the Telegram ids internally.
|
|
23
|
+
|
|
16
24
|
- `pair <code>` — look up `pending[<code>]`. If present and not expired
|
|
17
25
|
(`expiresAt` in ms since epoch): move its `senderId` into `allowFrom`
|
|
18
26
|
(deduplicated), delete the pending entry, save the file, then write an empty
|