blun-king-cli 9.1.168 → 9.1.170
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/bin/assistant-message-offload-policy.cjs +25 -3
- package/bin/launcher-runtime.js +53 -8
- package/bin/recurring-cron-history-policy.cjs +33 -1
- package/bin/running-update-preference.cjs +68 -0
- package/bin/running-update.cjs +9 -1
- package/bin/turn-tool-performance-policy.cjs +75 -2
- package/blun.mjs +199 -3
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@ const SYNTHETIC_TOOL_ARGUMENT_MARKER = JSON.stringify({
|
|
|
12
12
|
_blun_compacted: '[Old tool call arguments cleared]',
|
|
13
13
|
});
|
|
14
14
|
const TELEGRAM_REPLY_TOOL_RE = /^mcp__[^\s]*telegram[^\s]*__reply$/iu;
|
|
15
|
+
const SYNTHETIC_TOOL_ARGUMENT_SUMMARY_MARKER = '[Historical tool arguments unavailable]';
|
|
15
16
|
|
|
16
17
|
function shouldOffloadHistoricalAssistantMessage(options = {}) {
|
|
17
18
|
const historyIndex = Number(options.historyIndex);
|
|
@@ -109,16 +110,37 @@ function compactHistoricalPostTelegramReplyNarration(messages) {
|
|
|
109
110
|
function removeSyntheticToolArgumentFailures(messages) {
|
|
110
111
|
if (!Array.isArray(messages) || messages.length === 0) return messages;
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
let summaryChanged = false;
|
|
114
|
+
const scrubbedMessages = messages.map((message) => {
|
|
115
|
+
if (message?.origin?.kind !== 'compaction_summary' || !Array.isArray(message.content)) {
|
|
116
|
+
return message;
|
|
117
|
+
}
|
|
118
|
+
let contentChanged = false;
|
|
119
|
+
const content = message.content.map((part) => {
|
|
120
|
+
if (part?.type !== 'text' || typeof part.text !== 'string' || !part.text.includes('_blun_compacted')) {
|
|
121
|
+
return part;
|
|
122
|
+
}
|
|
123
|
+
const text = part.text.split(/\r?\n/u).map((line) => (
|
|
124
|
+
line.includes('_blun_compacted') ? SYNTHETIC_TOOL_ARGUMENT_SUMMARY_MARKER : line
|
|
125
|
+
)).join('\n');
|
|
126
|
+
contentChanged = true;
|
|
127
|
+
return { ...part, text };
|
|
128
|
+
});
|
|
129
|
+
if (!contentChanged) return message;
|
|
130
|
+
summaryChanged = true;
|
|
131
|
+
return { ...message, content };
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const syntheticCallIds = new Set(scrubbedMessages.flatMap((message) => (
|
|
113
135
|
message?.role === 'assistant' && Array.isArray(message.toolCalls)
|
|
114
136
|
? message.toolCalls
|
|
115
137
|
.filter((call) => call?.arguments === SYNTHETIC_TOOL_ARGUMENT_MARKER)
|
|
116
138
|
.map((call) => call?.id)
|
|
117
139
|
: []
|
|
118
140
|
)).filter((id) => typeof id === 'string' && id.length > 0));
|
|
119
|
-
if (syntheticCallIds.size === 0) return messages;
|
|
141
|
+
if (syntheticCallIds.size === 0) return summaryChanged ? scrubbedMessages : messages;
|
|
120
142
|
|
|
121
|
-
return
|
|
143
|
+
return scrubbedMessages.flatMap((message) => {
|
|
122
144
|
if (message?.role === 'tool' && syntheticCallIds.has(message.toolCallId)) return [];
|
|
123
145
|
if (message?.role !== 'assistant' || !Array.isArray(message.toolCalls)) return [message];
|
|
124
146
|
|
package/bin/launcher-runtime.js
CHANGED
|
@@ -29,13 +29,18 @@ const { compareSemver, runExplicitUpdate, runUpdateNotice } = require('./update-
|
|
|
29
29
|
const {
|
|
30
30
|
RUNNING_UPDATE_HANDOFF_EXIT_CODE,
|
|
31
31
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
32
|
+
RUNNING_UPDATE_MODE_MESSAGE,
|
|
32
33
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
33
34
|
activateRuntime,
|
|
34
35
|
handoffRuntime,
|
|
35
36
|
prepareRunningUpdate,
|
|
36
37
|
readActiveRuntime,
|
|
37
|
-
resumeArgsForHandoff,
|
|
38
38
|
} = require('./running-update.cjs');
|
|
39
|
+
const {
|
|
40
|
+
RUNNING_UPDATE_MODES,
|
|
41
|
+
normalizeRunningUpdateMode,
|
|
42
|
+
readRunningUpdateMode,
|
|
43
|
+
} = require('./running-update-preference.cjs');
|
|
39
44
|
const {
|
|
40
45
|
ensurePrivateDirectory,
|
|
41
46
|
securePrivateFile,
|
|
@@ -224,32 +229,70 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
224
229
|
const packageRoot = path.resolve(options.packageRoot || PKG);
|
|
225
230
|
let preparedTarget;
|
|
226
231
|
let handoffSessionId;
|
|
232
|
+
let handoffMode;
|
|
227
233
|
let updateStarted = false;
|
|
234
|
+
let runtimeReady = false;
|
|
235
|
+
let runningUpdateMode = readRunningUpdateMode(env.BLUN_HOME);
|
|
236
|
+
const automaticMode = () => runningUpdateMode === RUNNING_UPDATE_MODES.RESUME
|
|
237
|
+
|| runningUpdateMode === RUNNING_UPDATE_MODES.NEW;
|
|
238
|
+
const announcePrepared = (child) => {
|
|
239
|
+
if (preparedTarget === undefined || !automaticMode() || child.connected !== true) return;
|
|
240
|
+
child.send({
|
|
241
|
+
type: RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
242
|
+
version: preparedTarget.version,
|
|
243
|
+
mode: runningUpdateMode,
|
|
244
|
+
});
|
|
245
|
+
};
|
|
228
246
|
const startPreparation = (child) => {
|
|
229
|
-
if (updateStarted || options.runningUpdate === false) return;
|
|
247
|
+
if (updateStarted || options.runningUpdate === false || !automaticMode()) return;
|
|
230
248
|
updateStarted = true;
|
|
231
249
|
const sharedHome = env.BLUN_SHARED_HOME;
|
|
232
|
-
if (typeof sharedHome !== 'string' || sharedHome.length === 0)
|
|
250
|
+
if (typeof sharedHome !== 'string' || sharedHome.length === 0) {
|
|
251
|
+
updateStarted = false;
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
233
254
|
Promise.resolve((options.prepareRunningUpdate || prepareRunningUpdate)({
|
|
234
255
|
currentVersion: JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8')).version,
|
|
235
256
|
sharedHome,
|
|
236
257
|
env,
|
|
237
258
|
})).then((target) => {
|
|
238
|
-
if (target === null
|
|
259
|
+
if (target === null) {
|
|
260
|
+
updateStarted = false;
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
239
263
|
preparedTarget = target;
|
|
240
|
-
child
|
|
264
|
+
announcePrepared(child);
|
|
241
265
|
}).catch((error) => {
|
|
266
|
+
updateStarted = false;
|
|
242
267
|
options.onRunningUpdateError?.(error);
|
|
243
268
|
});
|
|
244
269
|
};
|
|
245
270
|
const core = spawnProtectedCore(args, env, cwd, {
|
|
246
271
|
packageRoot,
|
|
247
272
|
onMessage(message, child) {
|
|
248
|
-
if (message?.type === RUNTIME_READY_MESSAGE)
|
|
273
|
+
if (message?.type === RUNTIME_READY_MESSAGE) {
|
|
274
|
+
runtimeReady = true;
|
|
275
|
+
startPreparation(child);
|
|
276
|
+
}
|
|
277
|
+
if (message?.type === RUNNING_UPDATE_MODE_MESSAGE && typeof message.mode === 'string') {
|
|
278
|
+
runningUpdateMode = normalizeRunningUpdateMode(message.mode);
|
|
279
|
+
handoffSessionId = undefined;
|
|
280
|
+
handoffMode = undefined;
|
|
281
|
+
if (automaticMode()) {
|
|
282
|
+
if (preparedTarget !== undefined) announcePrepared(child);
|
|
283
|
+
else if (runtimeReady) {
|
|
284
|
+
updateStarted = false;
|
|
285
|
+
startPreparation(child);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
249
289
|
if (message?.type === RUNNING_UPDATE_HANDOFF_MESSAGE
|
|
250
290
|
&& typeof message.sessionId === 'string'
|
|
251
|
-
&& message.sessionId.length > 0
|
|
291
|
+
&& message.sessionId.length > 0
|
|
292
|
+
&& message.mode === runningUpdateMode
|
|
293
|
+
&& automaticMode()) {
|
|
252
294
|
handoffSessionId = message.sessionId;
|
|
295
|
+
handoffMode = runningUpdateMode;
|
|
253
296
|
}
|
|
254
297
|
},
|
|
255
298
|
});
|
|
@@ -259,11 +302,13 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
259
302
|
if (result.error) throw result.error;
|
|
260
303
|
if (result.code === RUNNING_UPDATE_HANDOFF_EXIT_CODE
|
|
261
304
|
&& preparedTarget !== undefined
|
|
262
|
-
&& handoffSessionId !== undefined
|
|
305
|
+
&& handoffSessionId !== undefined
|
|
306
|
+
&& handoffMode !== undefined) {
|
|
263
307
|
const handoff = await handoffRuntime({
|
|
264
308
|
target: preparedTarget,
|
|
265
309
|
previous: { packageRoot, version: readPackageVersion() },
|
|
266
310
|
sessionId: handoffSessionId,
|
|
311
|
+
mode: handoffMode,
|
|
267
312
|
args,
|
|
268
313
|
probeTarget: options.probeRunningUpdate || (() => true),
|
|
269
314
|
stopOld: async () => {},
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const RECURRING_CRON_CONTEXT_MAX_MESSAGES = 24;
|
|
4
4
|
const RECURRING_CRON_CONTEXT_MAX_CHARS = 48_000;
|
|
5
|
+
const TRUNCATED_CONTEXT_MARKER = '\n[...context truncated...]';
|
|
5
6
|
|
|
6
7
|
function recurringCronJobId(message) {
|
|
7
8
|
if (message?.role !== 'user') return null;
|
|
@@ -43,6 +44,28 @@ function isRecurringCronSegment(segment) {
|
|
|
43
44
|
return recurringCronJobId(segment[0]) !== null;
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
function projectSegmentInstruction(segment, maxChars) {
|
|
48
|
+
const message = segment[0];
|
|
49
|
+
if (message?.role !== 'user' || !Array.isArray(message.content) || maxChars <= 0) return null;
|
|
50
|
+
let remaining = maxChars;
|
|
51
|
+
const content = [];
|
|
52
|
+
for (const part of message.content) {
|
|
53
|
+
if (part?.type !== 'text' || typeof part.text !== 'string' || remaining <= 0) continue;
|
|
54
|
+
if (part.text.length <= remaining) {
|
|
55
|
+
content.push(part);
|
|
56
|
+
remaining -= part.text.length;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const marker = remaining > TRUNCATED_CONTEXT_MARKER.length
|
|
60
|
+
? TRUNCATED_CONTEXT_MARKER
|
|
61
|
+
: '';
|
|
62
|
+
const text = `${part.text.slice(0, remaining - marker.length)}${marker}`;
|
|
63
|
+
if (text.length > 0) content.push({ ...part, text });
|
|
64
|
+
remaining = 0;
|
|
65
|
+
}
|
|
66
|
+
return content.length === 0 ? null : { ...message, content };
|
|
67
|
+
}
|
|
68
|
+
|
|
46
69
|
function projectRecurringCronHistory(history, jobId) {
|
|
47
70
|
if (!Array.isArray(history) || history.length === 0) return history;
|
|
48
71
|
const normalizedJobId = String(jobId || '').trim();
|
|
@@ -75,7 +98,16 @@ function projectRecurringCronHistory(history, jobId) {
|
|
|
75
98
|
if (
|
|
76
99
|
nextMessages > RECURRING_CRON_CONTEXT_MAX_MESSAGES
|
|
77
100
|
|| nextChars > RECURRING_CRON_CONTEXT_MAX_CHARS
|
|
78
|
-
)
|
|
101
|
+
) {
|
|
102
|
+
if (selected.length === 0 && selectedMessages < RECURRING_CRON_CONTEXT_MAX_MESSAGES) {
|
|
103
|
+
const instruction = projectSegmentInstruction(
|
|
104
|
+
segment,
|
|
105
|
+
RECURRING_CRON_CONTEXT_MAX_CHARS - selectedChars,
|
|
106
|
+
);
|
|
107
|
+
if (instruction !== null) selected.unshift([instruction]);
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
79
111
|
selected.unshift(segment);
|
|
80
112
|
selectedMessages = nextMessages;
|
|
81
113
|
selectedChars = nextChars;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { randomUUID } = require('node:crypto');
|
|
6
|
+
|
|
7
|
+
const { ensurePrivateDirectory, securePrivateFile, writePrivateFile } = require('./private-paths');
|
|
8
|
+
|
|
9
|
+
const RUNNING_UPDATE_PREFERENCE_FILE = 'running-update.json';
|
|
10
|
+
const RUNNING_UPDATE_MODES = Object.freeze({
|
|
11
|
+
MANUAL: 'manual',
|
|
12
|
+
RESUME: 'resume',
|
|
13
|
+
NEW: 'new',
|
|
14
|
+
OFF: 'off',
|
|
15
|
+
});
|
|
16
|
+
const DEFAULT_RUNNING_UPDATE_MODE = RUNNING_UPDATE_MODES.RESUME;
|
|
17
|
+
const VALID_MODES = new Set(Object.values(RUNNING_UPDATE_MODES));
|
|
18
|
+
|
|
19
|
+
function preferencePath(profileHome) {
|
|
20
|
+
return path.join(path.resolve(profileHome), RUNNING_UPDATE_PREFERENCE_FILE);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalizeRunningUpdateMode(value) {
|
|
24
|
+
return typeof value === 'string' && VALID_MODES.has(value)
|
|
25
|
+
? value
|
|
26
|
+
: DEFAULT_RUNNING_UPDATE_MODE;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function readRunningUpdateMode(profileHome) {
|
|
30
|
+
try {
|
|
31
|
+
const filePath = preferencePath(profileHome);
|
|
32
|
+
const stat = fs.lstatSync(filePath);
|
|
33
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 16 * 1024) {
|
|
34
|
+
return DEFAULT_RUNNING_UPDATE_MODE;
|
|
35
|
+
}
|
|
36
|
+
const record = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
37
|
+
return normalizeRunningUpdateMode(record?.mode);
|
|
38
|
+
} catch {
|
|
39
|
+
return DEFAULT_RUNNING_UPDATE_MODE;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function writeRunningUpdateMode(profileHome, mode) {
|
|
44
|
+
if (!VALID_MODES.has(mode)) throw new Error('RUNNING_UPDATE_MODE_INVALID');
|
|
45
|
+
const home = path.resolve(profileHome);
|
|
46
|
+
const filePath = preferencePath(home);
|
|
47
|
+
const temporaryPath = path.join(home, `.${RUNNING_UPDATE_PREFERENCE_FILE}.${process.pid}.${randomUUID()}.tmp`);
|
|
48
|
+
ensurePrivateDirectory(home);
|
|
49
|
+
try {
|
|
50
|
+
writePrivateFile(temporaryPath, `${JSON.stringify({ mode })}\n`);
|
|
51
|
+
fs.renameSync(temporaryPath, filePath);
|
|
52
|
+
securePrivateFile(filePath);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
fs.rmSync(temporaryPath, { force: true });
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
return mode;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
DEFAULT_RUNNING_UPDATE_MODE,
|
|
62
|
+
RUNNING_UPDATE_MODES,
|
|
63
|
+
RUNNING_UPDATE_PREFERENCE_FILE,
|
|
64
|
+
normalizeRunningUpdateMode,
|
|
65
|
+
preferencePath,
|
|
66
|
+
readRunningUpdateMode,
|
|
67
|
+
writeRunningUpdateMode,
|
|
68
|
+
};
|
package/bin/running-update.cjs
CHANGED
|
@@ -16,6 +16,7 @@ const ACTIVE_RUNTIME_FILE = 'active-runtime.json';
|
|
|
16
16
|
const RUNNING_UPDATE_HANDOFF_EXIT_CODE = 76;
|
|
17
17
|
const RUNNING_UPDATE_PREPARED_MESSAGE = 'blun-running-update-prepared';
|
|
18
18
|
const RUNNING_UPDATE_HANDOFF_MESSAGE = 'blun-running-update-handoff';
|
|
19
|
+
const RUNNING_UPDATE_MODE_MESSAGE = 'blun-running-update-mode';
|
|
19
20
|
const RUNTIME_READY_MESSAGE = 'blun-runtime-session-ready';
|
|
20
21
|
const MAX_TARBALL_BYTES = 128 * 1024 * 1024;
|
|
21
22
|
|
|
@@ -77,8 +78,13 @@ function resumeArgsForHandoff(args, sessionId) {
|
|
|
77
78
|
return [...filtered, '--resume', sessionId];
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
function handoffArgsForMode(args, mode, sessionId) {
|
|
82
|
+
const withoutSession = resumeArgsForHandoff(args, sessionId).slice(0, -2);
|
|
83
|
+
return mode === 'new' ? withoutSession : [...withoutSession, '--resume', sessionId];
|
|
84
|
+
}
|
|
85
|
+
|
|
80
86
|
async function handoffRuntime(options) {
|
|
81
|
-
const handoffArgs =
|
|
87
|
+
const handoffArgs = handoffArgsForMode(options.args, options.mode || 'resume', options.sessionId);
|
|
82
88
|
if (!await options.probeTarget(options.target)) {
|
|
83
89
|
return { kind: 'probe-failed', runtime: options.previous };
|
|
84
90
|
}
|
|
@@ -374,11 +380,13 @@ module.exports = {
|
|
|
374
380
|
ACTIVE_RUNTIME_FILE,
|
|
375
381
|
RUNNING_UPDATE_HANDOFF_EXIT_CODE,
|
|
376
382
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
383
|
+
RUNNING_UPDATE_MODE_MESSAGE,
|
|
377
384
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
378
385
|
RUNTIME_READY_MESSAGE,
|
|
379
386
|
activateRuntime,
|
|
380
387
|
activeRuntimePath,
|
|
381
388
|
defaultProbeRuntime,
|
|
389
|
+
handoffArgsForMode,
|
|
382
390
|
handoffRuntime,
|
|
383
391
|
isSafeRuntimeBoundary,
|
|
384
392
|
prepareRunningUpdate,
|
|
@@ -4,6 +4,24 @@ const TOOL_SCHEMA_BUDGET_RATIO = 0.25;
|
|
|
4
4
|
const TOOL_SCHEMA_MAX_TOKENS = 32_000;
|
|
5
5
|
const DEFERRED_TOOL_LOADER_NAME = 'ToolSearch';
|
|
6
6
|
const MAX_PERSISTENT_DEFERRED_TOOLS = 12;
|
|
7
|
+
const TOOL_SEARCH_INTENT_WORDS = new Set([
|
|
8
|
+
'find', 'fetch', 'get', 'holen', 'list', 'read', 'search', 'show', 'anzeigen', 'lesen', 'suchen',
|
|
9
|
+
]);
|
|
10
|
+
const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
|
|
11
|
+
Object.freeze([
|
|
12
|
+
'current', 'inbox', 'latest', 'message', 'messages', 'nachricht', 'nachrichten', 'queue', 'queued',
|
|
13
|
+
'recent', 'update', 'updates',
|
|
14
|
+
]),
|
|
15
|
+
Object.freeze(['history', 'log', 'logs', 'protokoll', 'transcript', 'verlauf']),
|
|
16
|
+
Object.freeze([
|
|
17
|
+
'fact', 'facts', 'fakt', 'fakten', 'memory', 'memories', 'merk', 'merken', 'note', 'notes',
|
|
18
|
+
'persist', 'persistent', 'profile', 'remember', 'save', 'speichern', 'store',
|
|
19
|
+
]),
|
|
20
|
+
]);
|
|
21
|
+
const TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS = new Set([
|
|
22
|
+
'fact', 'facts', 'fakt', 'fakten', 'memory', 'memories', 'merk', 'merken', 'note', 'notes',
|
|
23
|
+
'persist', 'persistent', 'profile', 'remember', 'save', 'speichern', 'store',
|
|
24
|
+
]);
|
|
7
25
|
const CORE_TOOL_NAMES = Object.freeze([
|
|
8
26
|
'Bash',
|
|
9
27
|
'Read',
|
|
@@ -66,6 +84,56 @@ function searchDeferredTools(tools, query) {
|
|
|
66
84
|
}).filter(Boolean).sort((left, right) => right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name))).slice(0, 5).map((entry) => entry.tool);
|
|
67
85
|
}
|
|
68
86
|
|
|
87
|
+
function relatedSearchTerms(token) {
|
|
88
|
+
const group = TOOL_SEARCH_RELATED_TERM_GROUPS.find((terms) => terms.includes(token));
|
|
89
|
+
return group || [token];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function searchRelatedDeferredTools(tools, query) {
|
|
93
|
+
const normalized = String(query || '').trim().toLowerCase();
|
|
94
|
+
if (!normalized || normalized.startsWith('select:')) return [];
|
|
95
|
+
const tokens = normalized.split(/\s+/).filter(Boolean);
|
|
96
|
+
const requiredNameTokens = tokens.filter((token) => token.startsWith('+')).map((token) => token.slice(1)).filter(Boolean);
|
|
97
|
+
const searchTokens = tokens
|
|
98
|
+
.filter((token) => !token.startsWith('+'))
|
|
99
|
+
.filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
|
|
100
|
+
if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
|
|
101
|
+
const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * 0.75));
|
|
102
|
+
|
|
103
|
+
return tools.map((tool) => {
|
|
104
|
+
const name = String(tool?.name || '').toLowerCase();
|
|
105
|
+
const description = String(tool?.description || '').toLowerCase();
|
|
106
|
+
if (!requiredNameTokens.every((token) => name.includes(token))) return null;
|
|
107
|
+
let matchedTokens = 0;
|
|
108
|
+
let score = requiredNameTokens.length * 8;
|
|
109
|
+
for (const token of searchTokens) {
|
|
110
|
+
if (name.includes(token)) {
|
|
111
|
+
matchedTokens += 1;
|
|
112
|
+
score += 8;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (description.includes(token)) {
|
|
116
|
+
matchedTokens += 1;
|
|
117
|
+
score += 4;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const related = relatedSearchTerms(token).filter((term) => term !== token);
|
|
121
|
+
if (related.some((term) => name.includes(term))) {
|
|
122
|
+
matchedTokens += 1;
|
|
123
|
+
score += 3;
|
|
124
|
+
} else if (related.some((term) => description.includes(term))) {
|
|
125
|
+
matchedTokens += 1;
|
|
126
|
+
score += 2;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return matchedTokens >= minimumMatchedTokens ? { tool, score, matchedTokens } : null;
|
|
130
|
+
}).filter(Boolean).sort((left, right) => (
|
|
131
|
+
right.matchedTokens - left.matchedTokens
|
|
132
|
+
|| right.score - left.score
|
|
133
|
+
|| String(left.tool.name).localeCompare(String(right.tool.name))
|
|
134
|
+
)).slice(0, 5).map((entry) => entry.tool);
|
|
135
|
+
}
|
|
136
|
+
|
|
69
137
|
function rememberLoadedTool(loadedToolNames, name) {
|
|
70
138
|
loadedToolNames.delete(name);
|
|
71
139
|
loadedToolNames.add(name);
|
|
@@ -109,7 +177,12 @@ function createDeferredToolLoader(selectedTools, deferredTools, loadedToolNames
|
|
|
109
177
|
description: query ? `Searching tool schemas for ${query}` : 'Searching tool schemas',
|
|
110
178
|
approvalRule: DEFERRED_TOOL_LOADER_NAME,
|
|
111
179
|
execute: async () => {
|
|
112
|
-
|
|
180
|
+
let matches = searchDeferredTools([...available.values()], query);
|
|
181
|
+
let relatedFallback = false;
|
|
182
|
+
if (matches.length === 0) {
|
|
183
|
+
matches = searchRelatedDeferredTools([...available.values()], query);
|
|
184
|
+
relatedFallback = matches.length > 0;
|
|
185
|
+
}
|
|
113
186
|
if (matches.length === 0) {
|
|
114
187
|
const alreadyLoaded = query.toLowerCase().startsWith('select:')
|
|
115
188
|
? searchDeferredTools(
|
|
@@ -143,7 +216,7 @@ function createDeferredToolLoader(selectedTools, deferredTools, loadedToolNames
|
|
|
143
216
|
}
|
|
144
217
|
return {
|
|
145
218
|
isError: false,
|
|
146
|
-
output:
|
|
219
|
+
output: `${relatedFallback ? 'Loaded related tool schemas' : 'Loaded tool schemas'}: ${loaded.join(', ')}. Invoke them in the next step.`,
|
|
147
220
|
};
|
|
148
221
|
},
|
|
149
222
|
};
|
package/blun.mjs
CHANGED
|
@@ -340604,6 +340604,110 @@ registerUiCatalogFragment({
|
|
|
340604
340604
|
"auth.warning.oauthCleanupFailed": "Klíč API je aktivní, ale předchozí přihlašovací údaje OAuth nebyly zcela odstraněny."
|
|
340605
340605
|
}
|
|
340606
340606
|
});
|
|
340607
|
+
registerUiCatalogFragment({
|
|
340608
|
+
en: {
|
|
340609
|
+
"command.update.description": "Configure updates",
|
|
340610
|
+
"command.premortem.description": "Stress-test a plan before execution",
|
|
340611
|
+
"premortem.usage": "Usage: /premortem <plan or decision>",
|
|
340612
|
+
"update.title": "Update behavior",
|
|
340613
|
+
"update.hint": "↑↓ navigate · Enter select · Esc cancel",
|
|
340614
|
+
"update.manual.label": "Manual updates",
|
|
340615
|
+
"update.manual.description": "Only update when you run the update command.",
|
|
340616
|
+
"update.resume.label": "Automatic: resume session",
|
|
340617
|
+
"update.resume.description": "When idle, install the update and resume the current session.",
|
|
340618
|
+
"update.new.label": "Automatic: new session",
|
|
340619
|
+
"update.new.description": "When idle, install the update and start a new session.",
|
|
340620
|
+
"update.off.label": "Automatic updates off",
|
|
340621
|
+
"update.off.description": "Do not check for or install updates automatically.",
|
|
340622
|
+
"update.saved": "Update behavior saved: {mode}",
|
|
340623
|
+
"update.saveFailed": "Could not save update behavior: {error}"
|
|
340624
|
+
},
|
|
340625
|
+
de: {
|
|
340626
|
+
"command.update.description": "Updates konfigurieren",
|
|
340627
|
+
"command.premortem.description": "Einen Plan vor der Umsetzung auf Schwachstellen prüfen",
|
|
340628
|
+
"premortem.usage": "Verwendung: /premortem <Plan oder Entscheidung>",
|
|
340629
|
+
"update.title": "Update-Verhalten",
|
|
340630
|
+
"update.hint": "↑↓ navigieren · Enter auswählen · Esc abbrechen",
|
|
340631
|
+
"update.manual.label": "Updates von Hand",
|
|
340632
|
+
"update.manual.description": "Nur aktualisieren, wenn du den Update-Befehl startest.",
|
|
340633
|
+
"update.resume.label": "Automatisch: Sitzung fortsetzen",
|
|
340634
|
+
"update.resume.description": "Im Leerlauf das Update installieren und die laufende Sitzung fortsetzen.",
|
|
340635
|
+
"update.new.label": "Automatisch: neue Sitzung",
|
|
340636
|
+
"update.new.description": "Im Leerlauf das Update installieren und eine neue Sitzung starten.",
|
|
340637
|
+
"update.off.label": "Automatische Updates aus",
|
|
340638
|
+
"update.off.description": "Nicht automatisch nach Updates suchen oder sie installieren.",
|
|
340639
|
+
"update.saved": "Update-Verhalten gespeichert: {mode}",
|
|
340640
|
+
"update.saveFailed": "Update-Verhalten konnte nicht gespeichert werden: {error}"
|
|
340641
|
+
},
|
|
340642
|
+
es: {
|
|
340643
|
+
"command.update.description": "Configurar actualizaciones",
|
|
340644
|
+
"command.premortem.description": "Someter un plan a una prueba de estrés antes de ejecutarlo",
|
|
340645
|
+
"premortem.usage": "Uso: /premortem <plan o decisión>",
|
|
340646
|
+
"update.title": "Comportamiento de las actualizaciones",
|
|
340647
|
+
"update.hint": "↑↓ navegar · Enter seleccionar · Esc cancelar",
|
|
340648
|
+
"update.manual.label": "Actualizaciones manuales",
|
|
340649
|
+
"update.manual.description": "Actualizar solo cuando ejecutes el comando de actualización.",
|
|
340650
|
+
"update.resume.label": "Automático: reanudar sesión",
|
|
340651
|
+
"update.resume.description": "Cuando esté inactivo, instalar la actualización y reanudar la sesión actual.",
|
|
340652
|
+
"update.new.label": "Automático: nueva sesión",
|
|
340653
|
+
"update.new.description": "Cuando esté inactivo, instalar la actualización e iniciar una sesión nueva.",
|
|
340654
|
+
"update.off.label": "Actualizaciones automáticas desactivadas",
|
|
340655
|
+
"update.off.description": "No buscar ni instalar actualizaciones automáticamente.",
|
|
340656
|
+
"update.saved": "Comportamiento de las actualizaciones guardado: {mode}",
|
|
340657
|
+
"update.saveFailed": "No se pudo guardar el comportamiento de las actualizaciones: {error}"
|
|
340658
|
+
},
|
|
340659
|
+
fr: {
|
|
340660
|
+
"command.update.description": "Configurer les mises à jour",
|
|
340661
|
+
"command.premortem.description": "Mettre un plan à l’épreuve avant son exécution",
|
|
340662
|
+
"premortem.usage": "Utilisation : /premortem <plan ou décision>",
|
|
340663
|
+
"update.title": "Comportement des mises à jour",
|
|
340664
|
+
"update.hint": "↑↓ naviguer · Entrée sélectionner · Échap annuler",
|
|
340665
|
+
"update.manual.label": "Mises à jour manuelles",
|
|
340666
|
+
"update.manual.description": "Mettre à jour uniquement lorsque vous exécutez la commande de mise à jour.",
|
|
340667
|
+
"update.resume.label": "Automatique : reprendre la session",
|
|
340668
|
+
"update.resume.description": "En cas d’inactivité, installer la mise à jour et reprendre la session en cours.",
|
|
340669
|
+
"update.new.label": "Automatique : nouvelle session",
|
|
340670
|
+
"update.new.description": "En cas d’inactivité, installer la mise à jour et démarrer une nouvelle session.",
|
|
340671
|
+
"update.off.label": "Mises à jour automatiques désactivées",
|
|
340672
|
+
"update.off.description": "Ne pas rechercher ni installer automatiquement les mises à jour.",
|
|
340673
|
+
"update.saved": "Comportement des mises à jour enregistré : {mode}",
|
|
340674
|
+
"update.saveFailed": "Impossible d’enregistrer le comportement des mises à jour : {error}"
|
|
340675
|
+
},
|
|
340676
|
+
sv: {
|
|
340677
|
+
"command.update.description": "Konfigurera uppdateringar",
|
|
340678
|
+
"command.premortem.description": "Stresstesta en plan före genomförandet",
|
|
340679
|
+
"premortem.usage": "Användning: /premortem <plan eller beslut>",
|
|
340680
|
+
"update.title": "Uppdateringsbeteende",
|
|
340681
|
+
"update.hint": "↑↓ navigera · Enter välj · Esc avbryt",
|
|
340682
|
+
"update.manual.label": "Manuella uppdateringar",
|
|
340683
|
+
"update.manual.description": "Uppdatera endast när du kör uppdateringskommandot.",
|
|
340684
|
+
"update.resume.label": "Automatiskt: återuppta sessionen",
|
|
340685
|
+
"update.resume.description": "Installera uppdateringen vid inaktivitet och återuppta den aktuella sessionen.",
|
|
340686
|
+
"update.new.label": "Automatiskt: ny session",
|
|
340687
|
+
"update.new.description": "Installera uppdateringen vid inaktivitet och starta en ny session.",
|
|
340688
|
+
"update.off.label": "Automatiska uppdateringar av",
|
|
340689
|
+
"update.off.description": "Sök inte efter och installera inte uppdateringar automatiskt.",
|
|
340690
|
+
"update.saved": "Uppdateringsbeteende sparat: {mode}",
|
|
340691
|
+
"update.saveFailed": "Det gick inte att spara uppdateringsbeteendet: {error}"
|
|
340692
|
+
},
|
|
340693
|
+
cs: {
|
|
340694
|
+
"command.update.description": "Nastavit aktualizace",
|
|
340695
|
+
"command.premortem.description": "Prověřit plán před provedením zátěžovým testem",
|
|
340696
|
+
"premortem.usage": "Použití: /premortem <plán nebo rozhodnutí>",
|
|
340697
|
+
"update.title": "Chování aktualizací",
|
|
340698
|
+
"update.hint": "↑↓ navigace · Enter vybrat · Esc zrušit",
|
|
340699
|
+
"update.manual.label": "Ruční aktualizace",
|
|
340700
|
+
"update.manual.description": "Aktualizovat pouze po spuštění příkazu pro aktualizaci.",
|
|
340701
|
+
"update.resume.label": "Automaticky: pokračovat v relaci",
|
|
340702
|
+
"update.resume.description": "Při nečinnosti nainstalovat aktualizaci a pokračovat v aktuální relaci.",
|
|
340703
|
+
"update.new.label": "Automaticky: nová relace",
|
|
340704
|
+
"update.new.description": "Při nečinnosti nainstalovat aktualizaci a spustit novou relaci.",
|
|
340705
|
+
"update.off.label": "Automatické aktualizace vypnuty",
|
|
340706
|
+
"update.off.description": "Nevyhledávat ani neinstalovat aktualizace automaticky.",
|
|
340707
|
+
"update.saved": "Chování aktualizací uloženo: {mode}",
|
|
340708
|
+
"update.saveFailed": "Chování aktualizací se nepodařilo uložit: {error}"
|
|
340709
|
+
}
|
|
340710
|
+
});
|
|
340607
340711
|
//#endregion
|
|
340608
340712
|
//#region src/tui/i18n/catalogs/common.ts
|
|
340609
340713
|
registerUiCatalogFragment({
|
|
@@ -402579,6 +402683,20 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
|
|
|
402579
402683
|
priority: 100,
|
|
402580
402684
|
availability: "always"
|
|
402581
402685
|
},
|
|
402686
|
+
{
|
|
402687
|
+
name: "update",
|
|
402688
|
+
aliases: [],
|
|
402689
|
+
descriptionKey: "command.update.description",
|
|
402690
|
+
priority: 100,
|
|
402691
|
+
availability: "always"
|
|
402692
|
+
},
|
|
402693
|
+
{
|
|
402694
|
+
name: "premortem",
|
|
402695
|
+
aliases: [],
|
|
402696
|
+
descriptionKey: "command.premortem.description",
|
|
402697
|
+
priority: 95,
|
|
402698
|
+
availability: "idle-only"
|
|
402699
|
+
},
|
|
402582
402700
|
{
|
|
402583
402701
|
name: "output-style",
|
|
402584
402702
|
aliases: ["style"],
|
|
@@ -494677,6 +494795,63 @@ async function executeSlashCommand(host, input) {
|
|
|
494677
494795
|
return;
|
|
494678
494796
|
}
|
|
494679
494797
|
}
|
|
494798
|
+
async function handleUpdateCommand(host) {
|
|
494799
|
+
const profileHome = process.env["BLUN_HOME"];
|
|
494800
|
+
if (typeof profileHome !== "string" || profileHome.length === 0) {
|
|
494801
|
+
host.showError(uiText("update.saveFailed", { error: "BLUN_HOME" }));
|
|
494802
|
+
return;
|
|
494803
|
+
}
|
|
494804
|
+
const currentMode = readRunningUpdateMode(profileHome);
|
|
494805
|
+
const selectedMode = await new Promise((resolve) => {
|
|
494806
|
+
host.mountEditorReplacement(new ChoicePickerComponent({
|
|
494807
|
+
title: uiText("update.title"),
|
|
494808
|
+
hint: uiText("update.hint"),
|
|
494809
|
+
currentValue: currentMode,
|
|
494810
|
+
options: Object.values(RUNNING_UPDATE_MODES).map((mode) => ({
|
|
494811
|
+
value: mode,
|
|
494812
|
+
label: uiText(`update.${mode}.label`),
|
|
494813
|
+
description: uiText(`update.${mode}.description`)
|
|
494814
|
+
})),
|
|
494815
|
+
onSelect: resolve,
|
|
494816
|
+
onCancel: () => resolve(void 0)
|
|
494817
|
+
}));
|
|
494818
|
+
});
|
|
494819
|
+
host.restoreEditor();
|
|
494820
|
+
if (selectedMode === void 0) return;
|
|
494821
|
+
try {
|
|
494822
|
+
writeRunningUpdateMode(profileHome, selectedMode);
|
|
494823
|
+
} catch (error) {
|
|
494824
|
+
host.showError(uiText("update.saveFailed", { error: formatErrorMessage$2(error) }));
|
|
494825
|
+
return;
|
|
494826
|
+
}
|
|
494827
|
+
host.runningUpdatePreparedVersion = void 0;
|
|
494828
|
+
host.runningUpdatePreparedMode = void 0;
|
|
494829
|
+
host.runningUpdateHandoffStarted = false;
|
|
494830
|
+
if (process.connected) try {
|
|
494831
|
+
process.send({ type: RUNNING_UPDATE_MODE_MESSAGE, mode: selectedMode });
|
|
494832
|
+
} catch {}
|
|
494833
|
+
host.showStatus(uiText("update.saved", { mode: uiText(`update.${selectedMode}.label`) }), "success");
|
|
494834
|
+
}
|
|
494835
|
+
function buildPremortemPrompt(plan) {
|
|
494836
|
+
return `<premortem-mode>
|
|
494837
|
+
Assume this plan failed six months from now. Identify the most plausible failure modes, their early warning signs, concrete preventive measures, and explicit stop or decision points. Rank findings by impact and likelihood. Separate evidence from assumptions. End with the three actions that reduce the most risk.
|
|
494838
|
+
|
|
494839
|
+
Plan or decision:
|
|
494840
|
+
${plan}
|
|
494841
|
+
</premortem-mode>`;
|
|
494842
|
+
}
|
|
494843
|
+
async function handlePremortemCommand(host, args) {
|
|
494844
|
+
const plan = args.trim();
|
|
494845
|
+
if (plan.length === 0) {
|
|
494846
|
+
host.showError(uiText("premortem.usage"));
|
|
494847
|
+
return;
|
|
494848
|
+
}
|
|
494849
|
+
if (host.state.appState.model.trim().length === 0 || host.session === void 0) {
|
|
494850
|
+
host.showError(uiText("goal.error.modelNotSet"));
|
|
494851
|
+
return;
|
|
494852
|
+
}
|
|
494853
|
+
host.sendMessage(host.requireSession(), plan, { parts: buildPremortemPrompt(plan) });
|
|
494854
|
+
}
|
|
494680
494855
|
async function handleBuiltInSlashCommand(host, name, args) {
|
|
494681
494856
|
switch (name) {
|
|
494682
494857
|
case "exit":
|
|
@@ -494740,6 +494915,12 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
494740
494915
|
case "settings":
|
|
494741
494916
|
showSettingsSelector(host);
|
|
494742
494917
|
return;
|
|
494918
|
+
case "update":
|
|
494919
|
+
await handleUpdateCommand(host);
|
|
494920
|
+
return;
|
|
494921
|
+
case "premortem":
|
|
494922
|
+
await handlePremortemCommand(host, args);
|
|
494923
|
+
return;
|
|
494743
494924
|
case "usage":
|
|
494744
494925
|
await showUsage(host);
|
|
494745
494926
|
return;
|
|
@@ -509383,6 +509564,9 @@ var LoopChatIndicatorComponent = class {
|
|
|
509383
509564
|
this.state = state;
|
|
509384
509565
|
this.syncTimer(state.loop);
|
|
509385
509566
|
}
|
|
509567
|
+
setRefreshHandler(onRefresh) {
|
|
509568
|
+
this.onRefresh = onRefresh;
|
|
509569
|
+
}
|
|
509386
509570
|
render(width) {
|
|
509387
509571
|
const indicator = formatLoopChatIndicator(this.state.loop, currentTheme.palette);
|
|
509388
509572
|
return indicator === null ? [] : [truncateToWidth(indicator, width, "…")];
|
|
@@ -514605,10 +514789,16 @@ function turnsToTrim(turns, maxTurns, hysteresis) {
|
|
|
514605
514789
|
const {
|
|
514606
514790
|
RUNNING_UPDATE_HANDOFF_EXIT_CODE,
|
|
514607
514791
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
514792
|
+
RUNNING_UPDATE_MODE_MESSAGE,
|
|
514608
514793
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
514609
514794
|
RUNTIME_READY_MESSAGE,
|
|
514610
514795
|
isSafeRuntimeBoundary
|
|
514611
514796
|
} = __require("./bin/running-update.cjs");
|
|
514797
|
+
const {
|
|
514798
|
+
RUNNING_UPDATE_MODES,
|
|
514799
|
+
readRunningUpdateMode,
|
|
514800
|
+
writeRunningUpdateMode
|
|
514801
|
+
} = __require("./bin/running-update-preference.cjs");
|
|
514612
514802
|
function notifyRunningRuntimeReady(tui) {
|
|
514613
514803
|
if (!process.connected) return;
|
|
514614
514804
|
const sessionId = tui.getCurrentSessionId();
|
|
@@ -514621,7 +514811,7 @@ function notifyRunningRuntimeReady(tui) {
|
|
|
514621
514811
|
} catch {}
|
|
514622
514812
|
}
|
|
514623
514813
|
function requestRunningUpdateAtSafeBoundary(tui) {
|
|
514624
|
-
if (tui.runningUpdatePreparedVersion === void 0 || tui.runningUpdateHandoffStarted || !process.connected) return false;
|
|
514814
|
+
if (tui.runningUpdatePreparedVersion === void 0 || tui.runningUpdatePreparedMode === void 0 || tui.runningUpdateHandoffStarted || !process.connected) return false;
|
|
514625
514815
|
if (!isSafeRuntimeBoundary({
|
|
514626
514816
|
isShuttingDown: tui.isShuttingDown,
|
|
514627
514817
|
streamingPhase: tui.state.appState.streamingPhase,
|
|
@@ -514638,7 +514828,8 @@ function requestRunningUpdateAtSafeBoundary(tui) {
|
|
|
514638
514828
|
process.send({
|
|
514639
514829
|
type: RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
514640
514830
|
sessionId,
|
|
514641
|
-
version: tui.runningUpdatePreparedVersion
|
|
514831
|
+
version: tui.runningUpdatePreparedVersion,
|
|
514832
|
+
mode: tui.runningUpdatePreparedMode
|
|
514642
514833
|
});
|
|
514643
514834
|
} catch {
|
|
514644
514835
|
tui.runningUpdateHandoffStarted = false;
|
|
@@ -514649,8 +514840,9 @@ function requestRunningUpdateAtSafeBoundary(tui) {
|
|
|
514649
514840
|
}
|
|
514650
514841
|
function installRunningUpdateListener(tui) {
|
|
514651
514842
|
const handler = (message) => {
|
|
514652
|
-
if (message?.type !== RUNNING_UPDATE_PREPARED_MESSAGE || typeof message.version !== "string") return;
|
|
514843
|
+
if (message?.type !== RUNNING_UPDATE_PREPARED_MESSAGE || typeof message.version !== "string" || message.mode !== RUNNING_UPDATE_MODES.RESUME && message.mode !== RUNNING_UPDATE_MODES.NEW) return;
|
|
514653
514844
|
tui.runningUpdatePreparedVersion = message.version;
|
|
514845
|
+
tui.runningUpdatePreparedMode = message.mode;
|
|
514654
514846
|
requestRunningUpdateAtSafeBoundary(tui);
|
|
514655
514847
|
};
|
|
514656
514848
|
process.on("message", handler);
|
|
@@ -514741,6 +514933,7 @@ var BlunTUI = class {
|
|
|
514741
514933
|
startupWorkspaceSelectionPending = false;
|
|
514742
514934
|
startupGoalPromptedSessionId;
|
|
514743
514935
|
runningUpdatePreparedVersion;
|
|
514936
|
+
runningUpdatePreparedMode;
|
|
514744
514937
|
runningUpdateHandoffStarted = false;
|
|
514745
514938
|
runningUpdateMessageDispose;
|
|
514746
514939
|
startupPhaseMs = {};
|
|
@@ -514810,6 +515003,9 @@ var BlunTUI = class {
|
|
|
514810
515003
|
this.startupNotice = invalidAppearance ? combineStartupNotice(startupInput.startupNotice, new TuiConfigParseError(DEFAULT_TUI_CONFIG).message) : startupInput.startupNotice;
|
|
514811
515004
|
this.onStartupNoticeShown = startupInput.onStartupNoticeShown;
|
|
514812
515005
|
this.state = createTUIState(tuiOptions);
|
|
515006
|
+
this.state.loopIndicator.setRefreshHandler(() => {
|
|
515007
|
+
void this.refreshLoopState();
|
|
515008
|
+
});
|
|
514813
515009
|
this.appearanceBasePalette = currentTheme.palette;
|
|
514814
515010
|
this.resolvedAutoTheme = currentTheme.palette === lightColors ? "light" : "dark";
|
|
514815
515011
|
currentTheme.setPalette(applyAppearanceToPalette(currentTheme.palette, initialAppState.appearance));
|