blun-king-cli 9.1.16 → 9.1.18
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/README.md +1 -1
- package/bin/blun.js +0 -0
- package/bin/core-bootstrap.js +0 -0
- package/bin/king.js +0 -0
- package/bin/launcher-mode.js +0 -0
- package/bin/launcher-runtime.js +0 -0
- package/bin/plugin-bootstrap.js +0 -0
- package/bin/private-paths.js +0 -0
- package/bin/standard-tools-bootstrap.js +0 -0
- package/bin/update-lease.js +0 -0
- package/bin/update-notice.js +0 -0
- package/blun.mjs +104 -32
- package/package.json +3 -2
- package/telegram-plugin/dist/bridge.mjs +24 -5
- package/telegram-plugin/dist/mcp-server.mjs +24 -5
- package/telegram-plugin/dist/noise.mjs +1 -1
package/README.md
CHANGED
package/bin/blun.js
CHANGED
|
File without changes
|
package/bin/core-bootstrap.js
CHANGED
|
File without changes
|
package/bin/king.js
CHANGED
|
File without changes
|
package/bin/launcher-mode.js
CHANGED
|
File without changes
|
package/bin/launcher-runtime.js
CHANGED
|
File without changes
|
package/bin/plugin-bootstrap.js
CHANGED
|
File without changes
|
package/bin/private-paths.js
CHANGED
|
File without changes
|
|
File without changes
|
package/bin/update-lease.js
CHANGED
|
File without changes
|
package/bin/update-notice.js
CHANGED
|
File without changes
|
package/blun.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// BLUN_BUILD_INPUT_SHA256:
|
|
2
|
+
// BLUN_BUILD_INPUT_SHA256:e2258991ea4b7ce19aa0b6147dfc25e8b2f1945acc329856a2a2d00ad594a825
|
|
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);
|
|
@@ -74394,8 +74394,8 @@ var init_kosong_llm = __esmMin((() => {
|
|
|
74394
74394
|
//#endregion
|
|
74395
74395
|
//#region ../../packages/agent-core/src/agent/compaction/typical-duration.ts
|
|
74396
74396
|
/**
|
|
74397
|
-
* Experience-based expectation for compaction duration
|
|
74398
|
-
*
|
|
74397
|
+
* Experience-based expectation for compaction duration: instead of a
|
|
74398
|
+
* fabricated percentage, the compaction indicator
|
|
74399
74399
|
* may show the median duration of past completed runs for the same
|
|
74400
74400
|
* provider+model — but only when the data actually supports it.
|
|
74401
74401
|
*
|
|
@@ -232242,9 +232242,14 @@ var WINDOWS_MCP_TOOL_PREFIX, DesktopControlAlwaysAskPermissionPolicy;
|
|
|
232242
232242
|
var init_desktop_control_always_ask = __esmMin((() => {
|
|
232243
232243
|
WINDOWS_MCP_TOOL_PREFIX = "mcp__windows-mcp__";
|
|
232244
232244
|
DesktopControlAlwaysAskPermissionPolicy = class {
|
|
232245
|
+
agent;
|
|
232245
232246
|
name = "desktop-control-always-ask";
|
|
232247
|
+
constructor(agent) {
|
|
232248
|
+
this.agent = agent;
|
|
232249
|
+
}
|
|
232246
232250
|
evaluate(context) {
|
|
232247
232251
|
if (!context.toolCall.name.toLowerCase().startsWith(WINDOWS_MCP_TOOL_PREFIX)) return;
|
|
232252
|
+
if (this.agent.permission.mode === "yolo") return;
|
|
232248
232253
|
return { kind: "ask" };
|
|
232249
232254
|
}
|
|
232250
232255
|
};
|
|
@@ -232873,7 +232878,7 @@ function createPermissionDecisionPolicies(agent) {
|
|
|
232873
232878
|
new PlanModeGuardDenyPermissionPolicy(agent),
|
|
232874
232879
|
new UserConfiguredDenyPermissionPolicy(agent),
|
|
232875
232880
|
new PersonalMemoryMutationAlwaysAskPermissionPolicy(),
|
|
232876
|
-
new DesktopControlAlwaysAskPermissionPolicy(),
|
|
232881
|
+
new DesktopControlAlwaysAskPermissionPolicy(agent),
|
|
232877
232882
|
new AutoModeApprovePermissionPolicy(agent),
|
|
232878
232883
|
new SessionApprovalHistoryPermissionPolicy(agent),
|
|
232879
232884
|
new UserConfiguredAskPermissionPolicy(agent),
|
|
@@ -336447,6 +336452,7 @@ function buildSkillSlashCommands(skills) {
|
|
|
336447
336452
|
//#region src/constant/account-memory.ts
|
|
336448
336453
|
const ACCOUNT_MEMORY_READ_URL = "https://chat.blun.ai/api/blun-memory?persona_id=king&surface=global";
|
|
336449
336454
|
const ACCOUNT_MEMORY_EXTRACT_URL = "https://chat.blun.ai/api/blun-memory/extract?persona_id=king&surface=global";
|
|
336455
|
+
const ACCOUNT_MEMORY_PREFERENCES_URL = "https://account.blun.ai/api/me/preferences";
|
|
336450
336456
|
const ACCOUNT_MEMORY_MAX_FACT_CHARS = 1e3;
|
|
336451
336457
|
//#endregion
|
|
336452
336458
|
//#region src/utils/account-memory.ts
|
|
@@ -336464,6 +336470,19 @@ function createAccountMemoryClient(auth, options = {}) {
|
|
|
336464
336470
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
336465
336471
|
const timeoutMs = options.timeoutMs ?? 4e3;
|
|
336466
336472
|
return {
|
|
336473
|
+
async getConsentStatus() {
|
|
336474
|
+
return readAccountMemoryConsentStatus(await requestWithOAuth(auth, fetchImpl, ACCOUNT_MEMORY_PREFERENCES_URL, { method: "GET" }, timeoutMs, readBoundedJson));
|
|
336475
|
+
},
|
|
336476
|
+
async setConsent(enabled) {
|
|
336477
|
+
if (readAccountMemoryConsentStatus(await requestWithOAuth(auth, fetchImpl, "https://account.blun.ai/api/account/settings", {
|
|
336478
|
+
method: "PATCH",
|
|
336479
|
+
headers: { "Content-Type": "application/json" },
|
|
336480
|
+
body: JSON.stringify({ data_controls: {
|
|
336481
|
+
allow_memory: enabled,
|
|
336482
|
+
memory_consent_asked: true
|
|
336483
|
+
} })
|
|
336484
|
+
}, timeoutMs, readBoundedJson)) !== (enabled ? "enabled" : "disabled")) throw new Error("Account memory returned an invalid response.");
|
|
336485
|
+
},
|
|
336467
336486
|
async loadSystemContext() {
|
|
336468
336487
|
return renderAccountMemoryContext(await requestWithOAuth(auth, fetchImpl, ACCOUNT_MEMORY_READ_URL, { method: "GET" }, timeoutMs, readBoundedJson));
|
|
336469
336488
|
},
|
|
@@ -336476,6 +336495,15 @@ function createAccountMemoryClient(auth, options = {}) {
|
|
|
336476
336495
|
}
|
|
336477
336496
|
};
|
|
336478
336497
|
}
|
|
336498
|
+
function readAccountMemoryConsentStatus(payload) {
|
|
336499
|
+
const settings = unwrapPayload(payload)?.["settings"];
|
|
336500
|
+
const dataControls = isRecord$13(settings) ? settings["data_controls"] : void 0;
|
|
336501
|
+
if (!isRecord$13(dataControls)) throw new Error("Account memory returned an invalid response.");
|
|
336502
|
+
if (dataControls["memory_consent_asked"] !== true) return "never_asked";
|
|
336503
|
+
if (dataControls["allow_memory"] === true) return "enabled";
|
|
336504
|
+
if (dataControls["allow_memory"] === false) return "disabled";
|
|
336505
|
+
throw new Error("Account memory returned an invalid response.");
|
|
336506
|
+
}
|
|
336479
336507
|
async function requestWithOAuth(auth, fetchImpl, url, init, timeoutMs, consume) {
|
|
336480
336508
|
const controller = new AbortController();
|
|
336481
336509
|
let timeout;
|
|
@@ -407807,12 +407835,20 @@ function installRainbowDance(requestRender) {
|
|
|
407807
407835
|
if (currentDanceController === dance) setRainbowDance(void 0);
|
|
407808
407836
|
};
|
|
407809
407837
|
}
|
|
407838
|
+
function getRainbowDanceView() {
|
|
407839
|
+
return currentDanceView;
|
|
407840
|
+
}
|
|
407810
407841
|
function isRainbowDancing() {
|
|
407811
407842
|
return currentDanceView?.colored === true;
|
|
407812
407843
|
}
|
|
407813
407844
|
function renderDanceFooterModel(modelLabel) {
|
|
407814
407845
|
return rainbowText(modelLabel, getDanceRainbowPalette(), currentDanceView?.phase ?? 0);
|
|
407815
407846
|
}
|
|
407847
|
+
function renderDanceWelcomeWordmark(rows) {
|
|
407848
|
+
const phase = currentDanceView?.phase ?? 0;
|
|
407849
|
+
const palette = getDanceRainbowPalette();
|
|
407850
|
+
return rows.map((row, index) => rainbowText(row, palette, phase + index * 3, true));
|
|
407851
|
+
}
|
|
407816
407852
|
/**
|
|
407817
407853
|
* Drives the rainbow: a single timer advances a shared `phase` and asks the UI
|
|
407818
407854
|
* to repaint. Lives independently of any component, so the welcome banner
|
|
@@ -412627,12 +412663,12 @@ registerUiCatalogFragment({
|
|
|
412627
412663
|
//#region src/tui/utils/channel-injection.ts
|
|
412628
412664
|
/**
|
|
412629
412665
|
* Channel inbound injection into the VISIBLE interactive TUI session
|
|
412630
|
-
*
|
|
412666
|
+
* for channel delivery.
|
|
412631
412667
|
*
|
|
412632
412668
|
* A remote message (Telegram) must NEVER travel through handleUserInput():
|
|
412633
412669
|
* no slash-command dispatch (a Telegram "/new" must not open a session), no
|
|
412634
412670
|
* bash mode, no local editor history — and the transcript shows a clean user
|
|
412635
|
-
* line ("Telegram ·
|
|
412671
|
+
* line ("Telegram · User <text>") while the MODEL receives the full
|
|
412636
412672
|
* <channel …> payload (plus the channel preamble once per TUI process).
|
|
412637
412673
|
*
|
|
412638
412674
|
* This module is dependency-free on purpose: verify-telegram.ts drives the
|
|
@@ -412669,7 +412705,7 @@ function bufferContext(state, chatId, tag) {
|
|
|
412669
412705
|
while (messages.length > MAX_BUFFERED_CONTEXT_MESSAGES || chars > MAX_BUFFERED_CONTEXT_CHARS) chars -= messages.shift()?.length ?? 0;
|
|
412670
412706
|
buffers.set(chatId, messages);
|
|
412671
412707
|
}
|
|
412672
|
-
/** Muted origin prefix for the transcript line, e.g. "Telegram ·
|
|
412708
|
+
/** Muted origin prefix for the transcript line, e.g. "Telegram · User". */
|
|
412673
412709
|
function channelOrigin(envelope) {
|
|
412674
412710
|
return `Telegram · ${envelope.meta.user ?? envelope.meta.chat_id}`;
|
|
412675
412711
|
}
|
|
@@ -412768,7 +412804,7 @@ registerUiCatalogFragment({
|
|
|
412768
412804
|
/**
|
|
412769
412805
|
* Telegram channel attach mode — the visible TUI session takes over delivery.
|
|
412770
412806
|
*
|
|
412771
|
-
* Design
|
|
412807
|
+
* Design: one poller with lease routing.
|
|
412772
412808
|
* - The bridge (plugins/telegram dist/bridge.mjs) stays the ONLY getUpdates
|
|
412773
412809
|
* poller at all times. The TUI never talks to Telegram itself.
|
|
412774
412810
|
* - While this controller runs, it holds a lease: tui.pid in the channel
|
|
@@ -413228,7 +413264,7 @@ var TelegramChannelController = class {
|
|
|
413228
413264
|
for (const candidate of candidates) if (candidate !== void 0 && existsSync(candidate)) return candidate;
|
|
413229
413265
|
}
|
|
413230
413266
|
/**
|
|
413231
|
-
* The reply path must live in THIS session
|
|
413267
|
+
* The reply path must live in THIS session: without the
|
|
413232
413268
|
* telegram MCP the model can read channel messages but its answers never
|
|
413233
413269
|
* reach the chat — warn loudly instead of failing silently.
|
|
413234
413270
|
*/
|
|
@@ -422061,17 +422097,23 @@ const BLUN_GLYPHS = {
|
|
|
422061
422097
|
"█ █"
|
|
422062
422098
|
]
|
|
422063
422099
|
};
|
|
422064
|
-
function
|
|
422065
|
-
const white = chalk.bold.hex("#ffffff");
|
|
422066
|
-
const blue = chalk.bold.hex(blueHex);
|
|
422100
|
+
function blunWordmarkParts() {
|
|
422067
422101
|
const rows = [];
|
|
422068
422102
|
for (let i = 0; i < 5; i++) {
|
|
422069
422103
|
const bl = `${BLUN_GLYPHS["B"][i]} ${BLUN_GLYPHS["L"][i]}`;
|
|
422070
422104
|
const un = `${BLUN_GLYPHS["U"][i]} ${BLUN_GLYPHS["N"][i]}`;
|
|
422071
|
-
rows.push(
|
|
422105
|
+
rows.push({
|
|
422106
|
+
bl,
|
|
422107
|
+
un
|
|
422108
|
+
});
|
|
422072
422109
|
}
|
|
422073
422110
|
return rows;
|
|
422074
422111
|
}
|
|
422112
|
+
function renderBlunWordmark(blueHex) {
|
|
422113
|
+
const white = chalk.bold.hex("#ffffff");
|
|
422114
|
+
const blue = chalk.bold.hex(blueHex);
|
|
422115
|
+
return blunWordmarkParts().map(({ bl, un }) => white(bl) + " " + blue(un));
|
|
422116
|
+
}
|
|
422075
422117
|
function renderHelpLine(text, dim, command) {
|
|
422076
422118
|
const token = "/help";
|
|
422077
422119
|
const tokenIndex = text.indexOf(token);
|
|
@@ -422102,7 +422144,7 @@ var WelcomeComponent = class {
|
|
|
422102
422144
|
const pad = " ";
|
|
422103
422145
|
const dim = chalk.hex(currentTheme.palette.textDim);
|
|
422104
422146
|
const labelStyle = chalk.hex(currentTheme.palette.textDim);
|
|
422105
|
-
const wordmarkRows = renderBlunWordmark(primaryHex);
|
|
422147
|
+
const wordmarkRows = getRainbowDanceView()?.colored === true ? renderDanceWelcomeWordmark(blunWordmarkParts().map(({ bl, un }) => `${bl} ${un}`)) : renderBlunWordmark(primaryHex);
|
|
422106
422148
|
const tagline = chalk.bold.hex(currentTheme.palette.textStrong)(uiText("welcome.tagline"));
|
|
422107
422149
|
const helpLine = isLoggedOut ? chalk.hex(currentTheme.palette.warning)(uiText("welcome.start")) : renderHelpLine(uiText("welcome.help"), dim, chalk.bold.hex(primaryHex));
|
|
422108
422150
|
const directoryLabel = uiText("welcome.label.directory");
|
|
@@ -422122,7 +422164,7 @@ var WelcomeComponent = class {
|
|
|
422122
422164
|
renderLabel(directoryLabel) + chalk.hex(currentTheme.palette.text)(this.state.workDir),
|
|
422123
422165
|
renderLabel(sessionLabel) + chalk.hex(currentTheme.palette.text)(this.state.sessionId),
|
|
422124
422166
|
renderLabel(modelLabel) + chalk.bold.hex(primaryHex)(modelValue),
|
|
422125
|
-
renderLabel(versionLabel) + chalk.hex(currentTheme.palette.text)(`${PRODUCT_NAME}
|
|
422167
|
+
renderLabel(versionLabel) + chalk.hex(currentTheme.palette.text)(`${PRODUCT_NAME} ${this.state.version}`)
|
|
422126
422168
|
];
|
|
422127
422169
|
if (this.state.mcpServersSummary) infoLines.push(renderLabel(mcpLabel) + chalk.hex(currentTheme.palette.text)(this.state.mcpServersSummary));
|
|
422128
422170
|
const contentLines = [
|
|
@@ -486823,8 +486865,8 @@ var PrefixedWrappedLine = class {
|
|
|
486823
486865
|
};
|
|
486824
486866
|
/** BLUN code surface — the same colored full-width band the ActivityPane uses
|
|
486825
486867
|
* (WORK_BG #16233a), wrapped around a Write preview so code King writes sits on
|
|
486826
|
-
* a coloured background over the FULL width
|
|
486827
|
-
*
|
|
486868
|
+
* a coloured background over the FULL width. applyBackgroundToLine pads to
|
|
486869
|
+
* width and survives the inner
|
|
486828
486870
|
* syntax-highlight ANSI resets; the line count is unchanged so the pinned
|
|
486829
486871
|
* editor below never moves. */
|
|
486830
486872
|
const CODE_SURFACE_BG = "#16233a";
|
|
@@ -486832,7 +486874,7 @@ var CodeSurfaceComponent = class extends Container {
|
|
|
486832
486874
|
fixedLines;
|
|
486833
486875
|
fixedRows;
|
|
486834
486876
|
/**
|
|
486835
|
-
* Fixed mode
|
|
486877
|
+
* Fixed mode prevents the chat area from moving while tools run:
|
|
486836
486878
|
* while Write args STREAM, the preview must have a CONSTANT physical height —
|
|
486837
486879
|
* wrapped long lines and collapsing blank lines made the band grow/shrink
|
|
486838
486880
|
* every delta, which bounced the whole frame once the transcript filled the
|
|
@@ -486865,7 +486907,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
486865
486907
|
* True once the STREAMING preview rendered the fixed-height code band.
|
|
486866
486908
|
* The collapsed FINAL preview then keeps exactly that height (padded band),
|
|
486867
486909
|
* so the result landing never changes the block height — no short transcript
|
|
486868
|
-
* jump per tool call
|
|
486910
|
+
* jump per tool call.
|
|
486869
486911
|
*/
|
|
486870
486912
|
streamedFixedBand = false;
|
|
486871
486913
|
toolCall;
|
|
@@ -487041,7 +487083,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
487041
487083
|
* rief SOFORT rebuildBody+requestRender. Weil die Body-Hoehe sich dabei um
|
|
487042
487084
|
* eine Zeile aendert, verschob der BottomPinnedTUI-Filler die Eingabe fuer
|
|
487043
487085
|
* einen Frame — das sporadische 1-Zeilen-Zucken NUR waehrend Tool-Aktivitaet
|
|
487044
|
-
*
|
|
487086
|
+
* appendLiveOutput previously had the debounce
|
|
487045
487087
|
* schon; hier fehlte er. Daten sofort, Neu-Render coalesced (50ms).
|
|
487046
487088
|
*/
|
|
487047
487089
|
progressRenderTimer;
|
|
@@ -496055,7 +496097,7 @@ function isRateLimitError(error) {
|
|
|
496055
496097
|
/**
|
|
496056
496098
|
* F2 Tippen-mit-Vorschlag — Completion-Client.
|
|
496057
496099
|
*
|
|
496058
|
-
*
|
|
496100
|
+
* Provider-neutral since 2026-08-04.
|
|
496059
496101
|
* Vorher stand hier eine fest verdrahtete Route zu einem Fremdanbieter:
|
|
496060
496102
|
* Bei jedem Tippen ging ein Datei-Ausschnitt dorthin, ohne dass der Nutzer
|
|
496061
496103
|
* etwas abgeschickt hat. Das widersprach der Zusage, dass nichts den Rechner
|
|
@@ -497334,7 +497376,11 @@ var BottomPinnedTUI = class extends TUI {
|
|
|
497334
497376
|
}
|
|
497335
497377
|
paintSurface(lines, width) {
|
|
497336
497378
|
if (!this.surfaceEnabled) return lines;
|
|
497337
|
-
|
|
497379
|
+
try {
|
|
497380
|
+
return lines.map((line) => applyBackgroundToLine(line, width, (text) => currentTheme.bg("surface", text)));
|
|
497381
|
+
} catch {
|
|
497382
|
+
return lines;
|
|
497383
|
+
}
|
|
497338
497384
|
}
|
|
497339
497385
|
/**
|
|
497340
497386
|
* Children from this index on (editor, footer) are pinned to the bottom.
|
|
@@ -497354,7 +497400,7 @@ var BottomPinnedTUI = class extends TUI {
|
|
|
497354
497400
|
chromeFromIndex = Number.POSITIVE_INFINITY;
|
|
497355
497401
|
/**
|
|
497356
497402
|
* Rows of the pinned block that are an OVERLAY (the editor's autocomplete
|
|
497357
|
-
* menu). The menu must not shift the transcript (
|
|
497403
|
+
* menu). The menu must not shift the transcript (the
|
|
497358
497404
|
* ändert es trotzdem noch") — instead it covers the bottommost transcript
|
|
497359
497405
|
* rows: we drop that many content rows so every remaining row keeps its
|
|
497360
497406
|
* exact position while the menu is open.
|
|
@@ -497437,7 +497483,7 @@ var BottomPinnedTUI = class extends TUI {
|
|
|
497437
497483
|
const pinAt = this.pinFromIndex;
|
|
497438
497484
|
if (!Number.isFinite(pinAt) || pinAt < 0 || pinAt >= this.children.length) {
|
|
497439
497485
|
this.setMouseTracking(false);
|
|
497440
|
-
return
|
|
497486
|
+
return super.render(width);
|
|
497441
497487
|
}
|
|
497442
497488
|
try {
|
|
497443
497489
|
const blocks = this.children.map((child) => child.render(width));
|
|
@@ -507184,6 +507230,7 @@ var BlunTUI = class {
|
|
|
507184
507230
|
scrollbackController;
|
|
507185
507231
|
personalMemoryController;
|
|
507186
507232
|
accountMemory;
|
|
507233
|
+
accountMemoryEnabledForSession = false;
|
|
507187
507234
|
pendingAccountMemoryExtractions = /* @__PURE__ */ new Set();
|
|
507188
507235
|
managedQuotaWarningController;
|
|
507189
507236
|
managedQuotaWarningPersistence = Promise.resolve();
|
|
@@ -507489,7 +507536,10 @@ var BlunTUI = class {
|
|
|
507489
507536
|
}
|
|
507490
507537
|
if (this.aborted) return;
|
|
507491
507538
|
if (this.session === void 0 && this.state.startupState !== "picker") return;
|
|
507492
|
-
if (this.session !== void 0)
|
|
507539
|
+
if (this.session !== void 0) {
|
|
507540
|
+
await this.refreshPersonalMemory(true);
|
|
507541
|
+
await this.authFlow.refreshManagedQuotaWindows();
|
|
507542
|
+
}
|
|
507493
507543
|
this.showTmuxKeyboardWarningIfNeeded();
|
|
507494
507544
|
this.startTelegramChannel();
|
|
507495
507545
|
if (this.state.startupState === "picker") {
|
|
@@ -508093,10 +508143,10 @@ var BlunTUI = class {
|
|
|
508093
508143
|
this.state.ui.requestRender();
|
|
508094
508144
|
}
|
|
508095
508145
|
/**
|
|
508096
|
-
* Remote channel inbound (Telegram) into THIS visible session
|
|
508146
|
+
* Remote channel inbound (Telegram) into THIS visible session.
|
|
508097
508147
|
* Never routes through handleUserInput: no slash/bash dispatch (a Telegram
|
|
508098
508148
|
* "/new" is just text for the model), no local editor history. The transcript
|
|
508099
|
-
* shows a clean user line with a muted origin prefix
|
|
508149
|
+
* shows a clean user line with a muted origin prefix; the
|
|
508100
508150
|
* model receives the full <channel …> payload. Busy turns queue via the same
|
|
508101
508151
|
* queuedMessages mechanic as typed input; a completed tool/step boundary
|
|
508102
508152
|
* steers one FIFO head into the active turn without interrupting it.
|
|
@@ -508522,12 +508572,34 @@ var BlunTUI = class {
|
|
|
508522
508572
|
refreshManagedQuotaWindows() {
|
|
508523
508573
|
this.authFlow.refreshManagedQuotaWindows();
|
|
508524
508574
|
}
|
|
508525
|
-
async refreshPersonalMemory(
|
|
508526
|
-
|
|
508575
|
+
async refreshPersonalMemory(promptIfNeverAsked = false) {
|
|
508576
|
+
const session = this.session;
|
|
508577
|
+
if (session === void 0) return;
|
|
508578
|
+
this.accountMemoryEnabledForSession = false;
|
|
508579
|
+
try {
|
|
508580
|
+
let consentStatus = await this.accountMemory.getConsentStatus();
|
|
508581
|
+
if (consentStatus === "never_asked" && promptIfNeverAsked) {
|
|
508582
|
+
const consent = await ensureStartupPersonalMemoryConsent({
|
|
508583
|
+
host: this,
|
|
508584
|
+
consentStatus,
|
|
508585
|
+
copy: startupPersonalMemoryConsentCopy(),
|
|
508586
|
+
updateSettings: async (patch) => {
|
|
508587
|
+
await this.accountMemory.setConsent(patch.memory_enabled === true);
|
|
508588
|
+
}
|
|
508589
|
+
});
|
|
508590
|
+
if (consent === "persistence-failed") this.showStatus(startupPersonalMemoryConsentCopy().persistenceFailed, "warning");
|
|
508591
|
+
consentStatus = consent === "enabled" || consent === "disabled" ? consent : "never_asked";
|
|
508592
|
+
}
|
|
508593
|
+
this.accountMemoryEnabledForSession = consentStatus === "enabled";
|
|
508594
|
+
} catch (error) {
|
|
508595
|
+
this.reportAccountMemoryIssue("Account memory consent unavailable", error);
|
|
508596
|
+
}
|
|
508597
|
+
await this.applyAccountMemoryContext(session);
|
|
508527
508598
|
}
|
|
508528
508599
|
async applyAccountMemoryContext(session) {
|
|
508529
508600
|
try {
|
|
508530
|
-
|
|
508601
|
+
const context = this.accountMemoryEnabledForSession ? await this.accountMemory.loadSystemContext() : void 0;
|
|
508602
|
+
await session.setAccountMemoryContext(context);
|
|
508531
508603
|
} catch (error) {
|
|
508532
508604
|
try {
|
|
508533
508605
|
await session.setAccountMemoryContext(void 0);
|
|
@@ -508536,7 +508608,7 @@ var BlunTUI = class {
|
|
|
508536
508608
|
}
|
|
508537
508609
|
}
|
|
508538
508610
|
extractAccountMemory(text) {
|
|
508539
|
-
if (text.trim().length === 0) return;
|
|
508611
|
+
if (!this.accountMemoryEnabledForSession || text.trim().length === 0) return;
|
|
508540
508612
|
let pending;
|
|
508541
508613
|
pending = this.accountMemory.extract(text).catch((error) => {
|
|
508542
508614
|
this.reportAccountMemoryIssue("Account memory update failed", error);
|
|
@@ -509464,7 +509536,7 @@ var BlunTUI = class {
|
|
|
509464
509536
|
/**
|
|
509465
509537
|
* Presence label next to the thinking spinner — uses the persona name the
|
|
509466
509538
|
* user gave the agent, falling back to the model name "King". E.g. "Sven
|
|
509467
|
-
* denkt…" / "King arbeitet…"
|
|
509539
|
+
* denkt…" / "King arbeitet…" persona status line.
|
|
509468
509540
|
*/
|
|
509469
509541
|
personaVerbLabel(mode) {
|
|
509470
509542
|
return uiText(mode === "thinking" ? "blunTui.activity.thinking" : "blunTui.activity.working", { name: personaName() ?? "King" });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blun-king-cli",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.18",
|
|
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": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"x64",
|
|
23
23
|
"arm64"
|
|
24
24
|
],
|
|
25
|
+
"dependencies": {},
|
|
25
26
|
"optionalDependencies": {
|
|
26
27
|
"@mariozechner/clipboard": "^0.3.9",
|
|
27
28
|
"node-pty": "^1.1.0"
|
|
@@ -44,5 +45,5 @@
|
|
|
44
45
|
"cli",
|
|
45
46
|
"assistant"
|
|
46
47
|
],
|
|
47
|
-
"author": "BLUN
|
|
48
|
+
"author": "BLUN"
|
|
48
49
|
}
|
|
@@ -59318,13 +59318,32 @@ function defaultAccess() {
|
|
|
59318
59318
|
pending: {}
|
|
59319
59319
|
};
|
|
59320
59320
|
}
|
|
59321
|
+
function normalizeIdList(value) {
|
|
59322
|
+
if (!Array.isArray(value)) return [];
|
|
59323
|
+
return [...new Set(value.filter((entry) => typeof entry === "string" || typeof entry === "number").map((entry) => String(entry).trim()).filter((entry) => entry.length > 0))];
|
|
59324
|
+
}
|
|
59325
|
+
function normalizeGroups(value) {
|
|
59326
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
|
|
59327
|
+
const groups = {};
|
|
59328
|
+
for (const [chatId, rawPolicy] of Object.entries(value)) {
|
|
59329
|
+
if (rawPolicy === null || typeof rawPolicy !== "object" || Array.isArray(rawPolicy)) continue;
|
|
59330
|
+
const policy = rawPolicy;
|
|
59331
|
+
const alwaysAllowFrom = normalizeIdList(policy.alwaysAllowFrom);
|
|
59332
|
+
groups[chatId] = {
|
|
59333
|
+
requireMention: policy.requireMention !== false,
|
|
59334
|
+
allowFrom: normalizeIdList(policy.allowFrom),
|
|
59335
|
+
...alwaysAllowFrom.length > 0 ? { alwaysAllowFrom } : {}
|
|
59336
|
+
};
|
|
59337
|
+
}
|
|
59338
|
+
return groups;
|
|
59339
|
+
}
|
|
59321
59340
|
function readAccess() {
|
|
59322
59341
|
try {
|
|
59323
59342
|
const parsed = JSON.parse(readFileSync(accessFile(), "utf8"));
|
|
59324
59343
|
return {
|
|
59325
59344
|
dmPolicy: parsed.dmPolicy ?? "pairing",
|
|
59326
|
-
allowFrom: parsed.allowFrom
|
|
59327
|
-
groups: parsed.groups
|
|
59345
|
+
allowFrom: normalizeIdList(parsed.allowFrom),
|
|
59346
|
+
groups: normalizeGroups(parsed.groups),
|
|
59328
59347
|
pending: parsed.pending ?? {},
|
|
59329
59348
|
mentionPatterns: parsed.mentionPatterns,
|
|
59330
59349
|
ignorePatterns: parsed.ignorePatterns,
|
|
@@ -59333,8 +59352,8 @@ function readAccess() {
|
|
|
59333
59352
|
textChunkLimit: parsed.textChunkLimit,
|
|
59334
59353
|
chunkMode: parsed.chunkMode
|
|
59335
59354
|
};
|
|
59336
|
-
} catch (
|
|
59337
|
-
if (
|
|
59355
|
+
} catch (error) {
|
|
59356
|
+
if (error.code === "ENOENT") return defaultAccess();
|
|
59338
59357
|
try {
|
|
59339
59358
|
renameSync(accessFile(), `${accessFile()}.corrupt-${Date.now()}`);
|
|
59340
59359
|
} catch {}
|
|
@@ -67292,7 +67311,7 @@ function normalize(s) {
|
|
|
67292
67311
|
}
|
|
67293
67312
|
const STRONG_META = /\b(keine (gruppen ?)?antwort|gar keine antwort|halte (mich|die klappe)|(bin|bleibe) (jetzt )?still|ich schweige|schweige|stille|nichts (zu tun|zu melden|fur mich|fuer mich)|nicht (direkt )?an mich( gerichtet)?|nicht meine lane|keine reaktion|no ?action|kein wort|silence|staying (silent|out|quiet)|keeping (quiet|out)|no (response|reply|answer|comment)|nothing (to (add|do|report)|for me)|not (for me|my lane|addressed to me|directed at me)|holding back|standing by|no need to (respond|reply))\b/;
|
|
67294
67313
|
const SHORT_CONFIRM = /^(verstanden|kapiert|ok|okay|alles klar|geht klar|angekommen|seh sie|ich seh sie|gemerkt|passt|erledigt notiert|notiert|no ?action|understood|got it|noted|acknowledged|roger|received|silence|still)\b[\s\S]{0,48}$/;
|
|
67295
|
-
const PRESENCE_ONLY = /^(
|
|
67314
|
+
const PRESENCE_ONLY = /^(bin +da|bin +hier|hier +bin +ich|ich +bin +da|was +brauchst +du|was +gibt +es|was +liegt +an|wie +kann +ich +helfen|bereit|ich +warte|warte +auf|melde +mich|freut +mich|here|standing +by|ready|awaiting|what +do +you +need)\b[\s\S]{0,40}$/;
|
|
67296
67315
|
/**
|
|
67297
67316
|
* True when this reply text, sent into a GROUP, is pure meta/acknowledgement
|
|
67298
67317
|
* noise that must not be delivered. Length-guarded so genuine longer answers
|
|
@@ -73135,13 +73135,32 @@ function defaultAccess() {
|
|
|
73135
73135
|
pending: {}
|
|
73136
73136
|
};
|
|
73137
73137
|
}
|
|
73138
|
+
function normalizeIdList(value) {
|
|
73139
|
+
if (!Array.isArray(value)) return [];
|
|
73140
|
+
return [...new Set(value.filter((entry) => typeof entry === "string" || typeof entry === "number").map((entry) => String(entry).trim()).filter((entry) => entry.length > 0))];
|
|
73141
|
+
}
|
|
73142
|
+
function normalizeGroups(value) {
|
|
73143
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
|
|
73144
|
+
const groups = {};
|
|
73145
|
+
for (const [chatId, rawPolicy] of Object.entries(value)) {
|
|
73146
|
+
if (rawPolicy === null || typeof rawPolicy !== "object" || Array.isArray(rawPolicy)) continue;
|
|
73147
|
+
const policy = rawPolicy;
|
|
73148
|
+
const alwaysAllowFrom = normalizeIdList(policy.alwaysAllowFrom);
|
|
73149
|
+
groups[chatId] = {
|
|
73150
|
+
requireMention: policy.requireMention !== false,
|
|
73151
|
+
allowFrom: normalizeIdList(policy.allowFrom),
|
|
73152
|
+
...alwaysAllowFrom.length > 0 ? { alwaysAllowFrom } : {}
|
|
73153
|
+
};
|
|
73154
|
+
}
|
|
73155
|
+
return groups;
|
|
73156
|
+
}
|
|
73138
73157
|
function readAccess() {
|
|
73139
73158
|
try {
|
|
73140
73159
|
const parsed = JSON.parse(readFileSync(accessFile(), "utf8"));
|
|
73141
73160
|
return {
|
|
73142
73161
|
dmPolicy: parsed.dmPolicy ?? "pairing",
|
|
73143
|
-
allowFrom: parsed.allowFrom
|
|
73144
|
-
groups: parsed.groups
|
|
73162
|
+
allowFrom: normalizeIdList(parsed.allowFrom),
|
|
73163
|
+
groups: normalizeGroups(parsed.groups),
|
|
73145
73164
|
pending: parsed.pending ?? {},
|
|
73146
73165
|
mentionPatterns: parsed.mentionPatterns,
|
|
73147
73166
|
ignorePatterns: parsed.ignorePatterns,
|
|
@@ -73150,8 +73169,8 @@ function readAccess() {
|
|
|
73150
73169
|
textChunkLimit: parsed.textChunkLimit,
|
|
73151
73170
|
chunkMode: parsed.chunkMode
|
|
73152
73171
|
};
|
|
73153
|
-
} catch (
|
|
73154
|
-
if (
|
|
73172
|
+
} catch (error) {
|
|
73173
|
+
if (error.code === "ENOENT") return defaultAccess();
|
|
73155
73174
|
try {
|
|
73156
73175
|
renameSync(accessFile(), `${accessFile()}.corrupt-${Date.now()}`);
|
|
73157
73176
|
} catch {}
|
|
@@ -73448,7 +73467,7 @@ function normalize(s) {
|
|
|
73448
73467
|
}
|
|
73449
73468
|
const STRONG_META = /\b(keine (gruppen ?)?antwort|gar keine antwort|halte (mich|die klappe)|(bin|bleibe) (jetzt )?still|ich schweige|schweige|stille|nichts (zu tun|zu melden|fur mich|fuer mich)|nicht (direkt )?an mich( gerichtet)?|nicht meine lane|keine reaktion|no ?action|kein wort|silence|staying (silent|out|quiet)|keeping (quiet|out)|no (response|reply|answer|comment)|nothing (to (add|do|report)|for me)|not (for me|my lane|addressed to me|directed at me)|holding back|standing by|no need to (respond|reply))\b/;
|
|
73450
73469
|
const SHORT_CONFIRM = /^(verstanden|kapiert|ok|okay|alles klar|geht klar|angekommen|seh sie|ich seh sie|gemerkt|passt|erledigt notiert|notiert|no ?action|understood|got it|noted|acknowledged|roger|received|silence|still)\b[\s\S]{0,48}$/;
|
|
73451
|
-
const PRESENCE_ONLY = /^(
|
|
73470
|
+
const PRESENCE_ONLY = /^(bin +da|bin +hier|hier +bin +ich|ich +bin +da|was +brauchst +du|was +gibt +es|was +liegt +an|wie +kann +ich +helfen|bereit|ich +warte|warte +auf|melde +mich|freut +mich|here|standing +by|ready|awaiting|what +do +you +need)\b[\s\S]{0,40}$/;
|
|
73452
73471
|
/**
|
|
73453
73472
|
* True when this reply text, sent into a GROUP, is pure meta/acknowledgement
|
|
73454
73473
|
* noise that must not be delivered. Length-guarded so genuine longer answers
|
|
@@ -22,7 +22,7 @@ function normalize(s) {
|
|
|
22
22
|
}
|
|
23
23
|
const STRONG_META = /\b(keine (gruppen ?)?antwort|gar keine antwort|halte (mich|die klappe)|(bin|bleibe) (jetzt )?still|ich schweige|schweige|stille|nichts (zu tun|zu melden|fur mich|fuer mich)|nicht (direkt )?an mich( gerichtet)?|nicht meine lane|keine reaktion|no ?action|kein wort|silence|staying (silent|out|quiet)|keeping (quiet|out)|no (response|reply|answer|comment)|nothing (to (add|do|report)|for me)|not (for me|my lane|addressed to me|directed at me)|holding back|standing by|no need to (respond|reply))\b/;
|
|
24
24
|
const SHORT_CONFIRM = /^(verstanden|kapiert|ok|okay|alles klar|geht klar|angekommen|seh sie|ich seh sie|gemerkt|passt|erledigt notiert|notiert|no ?action|understood|got it|noted|acknowledged|roger|received|silence|still)\b[\s\S]{0,48}$/;
|
|
25
|
-
const PRESENCE_ONLY = /^(
|
|
25
|
+
const PRESENCE_ONLY = /^(bin +da|bin +hier|hier +bin +ich|ich +bin +da|was +brauchst +du|was +gibt +es|was +liegt +an|wie +kann +ich +helfen|bereit|ich +warte|warte +auf|melde +mich|freut +mich|here|standing +by|ready|awaiting|what +do +you +need)\b[\s\S]{0,40}$/;
|
|
26
26
|
/**
|
|
27
27
|
* True when this reply text, sent into a GROUP, is pure meta/acknowledgement
|
|
28
28
|
* noise that must not be delivered. Length-guarded so genuine longer answers
|