blun-king-cli 9.1.45 → 9.1.46
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 +1 -1
- package/README.md +1 -1
- package/blun.mjs +184 -31
- package/package.json +1 -1
package/LIESMICH.txt
CHANGED
package/README.md
CHANGED
package/blun.mjs
CHANGED
|
@@ -76582,6 +76582,24 @@ var init_jitter = __esmMin((() => {
|
|
|
76582
76582
|
}));
|
|
76583
76583
|
//#endregion
|
|
76584
76584
|
//#region ../../packages/agent-core/src/tools/cron/scheduler.ts
|
|
76585
|
+
function sessionLoopIntervalMs(task) {
|
|
76586
|
+
if (task.owner !== "session-loop" || typeof task.loopInterval !== "string") return null;
|
|
76587
|
+
if (task.loopInterval === "auto") return 15 * 6e4;
|
|
76588
|
+
const match = /^([1-9]\d*)(m|h|d)$/i.exec(task.loopInterval);
|
|
76589
|
+
if (match === null) return null;
|
|
76590
|
+
const amount = Number(match[1]);
|
|
76591
|
+
const unit = match[2]?.toLowerCase();
|
|
76592
|
+
const multiplier = unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5;
|
|
76593
|
+
const intervalMs = amount * multiplier;
|
|
76594
|
+
return Number.isSafeInteger(intervalMs) ? intervalMs : null;
|
|
76595
|
+
}
|
|
76596
|
+
function countSessionLoopCoalesced(intervalMs, firstFireMs, nowMs) {
|
|
76597
|
+
const count = Math.max(1, Math.min(MAX_COALESCE_ITERATIONS, Math.floor((nowMs - firstFireMs) / intervalMs) + 1));
|
|
76598
|
+
return {
|
|
76599
|
+
count,
|
|
76600
|
+
lastDueMs: firstFireMs + (count - 1) * intervalMs
|
|
76601
|
+
};
|
|
76602
|
+
}
|
|
76585
76603
|
function createCronScheduler(opts) {
|
|
76586
76604
|
const { clocks, source, onFire, isIdle, isKilled, removeOneShot, onAdvanceCursor, pollIntervalMs } = opts;
|
|
76587
76605
|
const parsedCache = /* @__PURE__ */ new Map();
|
|
@@ -76605,6 +76623,8 @@ function createCronScheduler(opts) {
|
|
|
76605
76623
|
* the search budget (legal-but-never-fires expression).
|
|
76606
76624
|
*/
|
|
76607
76625
|
function computeJitteredNext(task, parsed, baseMs) {
|
|
76626
|
+
const intervalMs = sessionLoopIntervalMs(task);
|
|
76627
|
+
if (intervalMs !== null) return baseMs + intervalMs;
|
|
76608
76628
|
const ideal = computeNextCronRun(parsed, baseMs);
|
|
76609
76629
|
if (ideal === null) return null;
|
|
76610
76630
|
if (task.recurring === false) return oneShotJitteredNextCronRunMs(task, ideal);
|
|
@@ -76668,11 +76688,12 @@ function createCronScheduler(opts) {
|
|
|
76668
76688
|
const nextFireAt = computeJitteredNext(task, parsed, baseFromMs);
|
|
76669
76689
|
if (nextFireAt === null) continue;
|
|
76670
76690
|
if (now < nextFireAt) continue;
|
|
76671
|
-
const
|
|
76691
|
+
const intervalMs = sessionLoopIntervalMs(task);
|
|
76692
|
+
const ideal = intervalMs === null ? computeNextCronRun(parsed, baseFromMs) : nextFireAt;
|
|
76672
76693
|
let coalescedCount = 1;
|
|
76673
76694
|
let lastDueMs = null;
|
|
76674
76695
|
if (task.recurring !== false && ideal !== null) {
|
|
76675
|
-
const result = countCoalesced(task, parsed, ideal, now);
|
|
76696
|
+
const result = intervalMs === null ? countCoalesced(task, parsed, ideal, now) : countSessionLoopCoalesced(intervalMs, ideal, now);
|
|
76676
76697
|
coalescedCount = Math.max(1, result.count);
|
|
76677
76698
|
lastDueMs = result.lastDueMs;
|
|
76678
76699
|
}
|
|
@@ -77632,6 +77653,10 @@ var init_cron_create = __esmMin((() => {
|
|
|
77632
77653
|
//#endregion
|
|
77633
77654
|
//#region ../../packages/agent-core/src/agent/session-loop.ts
|
|
77634
77655
|
function parseLoopInterval(rawInterval) {
|
|
77656
|
+
if (rawInterval.trim().toLowerCase() === "auto") return {
|
|
77657
|
+
interval: "auto",
|
|
77658
|
+
cron: "* * * * *"
|
|
77659
|
+
};
|
|
77635
77660
|
const match = LOOP_INTERVAL_PATTERN.exec(rawInterval.trim());
|
|
77636
77661
|
if (match === null) throw invalidLoopInterval(rawInterval);
|
|
77637
77662
|
const amount = Number(match[1]);
|
|
@@ -77639,25 +77664,13 @@ function parseLoopInterval(rawInterval) {
|
|
|
77639
77664
|
if (!Number.isSafeInteger(amount)) throw invalidLoopInterval(rawInterval);
|
|
77640
77665
|
const totalMinutes = unit === "m" ? amount : unit === "h" ? amount * 60 : amount * 1440;
|
|
77641
77666
|
if (!Number.isSafeInteger(totalMinutes)) throw invalidLoopInterval(rawInterval);
|
|
77642
|
-
|
|
77643
|
-
interval:
|
|
77644
|
-
cron: "
|
|
77645
|
-
};
|
|
77646
|
-
if (totalMinutes < 60 && 60 % totalMinutes === 0) return {
|
|
77647
|
-
interval: `${String(totalMinutes)}m`,
|
|
77648
|
-
cron: totalMinutes === 1 ? "* * * * *" : `*/${String(totalMinutes)} * * * *`
|
|
77667
|
+
return {
|
|
77668
|
+
interval: `${String(amount)}${unit}`,
|
|
77669
|
+
cron: "* * * * *"
|
|
77649
77670
|
};
|
|
77650
|
-
if (totalMinutes < 1440 && totalMinutes % 60 === 0) {
|
|
77651
|
-
const hours = totalMinutes / 60;
|
|
77652
|
-
if (24 % hours === 0) return {
|
|
77653
|
-
interval: `${String(hours)}h`,
|
|
77654
|
-
cron: hours === 1 ? "0 * * * *" : `0 */${String(hours)} * * *`
|
|
77655
|
-
};
|
|
77656
|
-
}
|
|
77657
|
-
throw invalidLoopInterval(rawInterval);
|
|
77658
77671
|
}
|
|
77659
77672
|
function invalidLoopInterval(rawInterval) {
|
|
77660
|
-
return new BlunError(ErrorCodes.LOOP_INTERVAL_INVALID, `Invalid loop interval ${JSON.stringify(rawInterval)}
|
|
77673
|
+
return new BlunError(ErrorCodes.LOOP_INTERVAL_INVALID, `Invalid loop interval ${JSON.stringify(rawInterval)}`);
|
|
77661
77674
|
}
|
|
77662
77675
|
var MAX_LOOP_PROMPT_BYTES, LOOP_INTERVAL_PATTERN, SessionLoopMode;
|
|
77663
77676
|
var init_session_loop = __esmMin((() => {
|
|
@@ -401109,7 +401122,8 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
|
|
|
401109
401122
|
aliases: [],
|
|
401110
401123
|
descriptionKey: "command.loop.description",
|
|
401111
401124
|
priority: 80,
|
|
401112
|
-
argumentHint: "
|
|
401125
|
+
argumentHint: "<natürlicher Auftrag>",
|
|
401126
|
+
liveArgumentHint: loopInputHint,
|
|
401113
401127
|
availability: (args) => {
|
|
401114
401128
|
const trimmed = args.trim();
|
|
401115
401129
|
if (trimmed === "") return "always";
|
|
@@ -420058,7 +420072,8 @@ function isBusy(host) {
|
|
|
420058
420072
|
}
|
|
420059
420073
|
//#endregion
|
|
420060
420074
|
//#region src/tui/commands/loop.ts
|
|
420061
|
-
const LOOP_ARGUMENT_HINT = "/loop
|
|
420075
|
+
const LOOP_ARGUMENT_HINT = "/loop <natürlicher Auftrag> · Zeitangaben dürfen überall stehen";
|
|
420076
|
+
const DEFAULT_LOOP_INTERVAL = "auto";
|
|
420062
420077
|
const LOOP_CREATE_FILLERS = new Set([
|
|
420063
420078
|
"mit",
|
|
420064
420079
|
"alle",
|
|
@@ -420068,6 +420083,77 @@ const LOOP_CREATE_FILLERS = new Set([
|
|
|
420068
420083
|
"each"
|
|
420069
420084
|
]);
|
|
420070
420085
|
const LOOP_INTERVAL_TOKEN = /^\d+(?:m|h|d)$/i;
|
|
420086
|
+
const LOOP_NATURAL_INTERVAL = /\b(?:alle|jede(?:n|r|s)?|every|each)\s+(\d+)\s*(min(?:ute)?n?|minutes?|stunden?|hours?|tage?|days?)\b/iu;
|
|
420087
|
+
const LOOP_NATURAL_HALF_HOUR = /\b(?:alle|jede(?:n|r|s)?|every|each)\s+(?:halbe|half(?:\s+an)?)\s+(?:stunde|hour)\b/iu;
|
|
420088
|
+
const LOOP_NATURAL_SINGLE_INTERVAL = /\b(?:jede(?:n|r|s)?|every|each)\s+(minute|stunde|hour|tag|day)\b/iu;
|
|
420089
|
+
const LOOP_NATURAL_ADVERB_INTERVAL = /\b(stündlich|stuendlich|hourly|täglich|taeglich|daily)\b/iu;
|
|
420090
|
+
const LOOP_SELF_CONTROLLED = /\b(?:selbst\s+entscheiden|selbstgesteuert)\b/iu;
|
|
420091
|
+
function naturalLoopIntervalMatch(args) {
|
|
420092
|
+
const numeric = LOOP_NATURAL_INTERVAL.exec(args);
|
|
420093
|
+
if (numeric !== null) {
|
|
420094
|
+
const amount = numeric[1];
|
|
420095
|
+
const unit = numeric[2]?.toLowerCase() ?? "";
|
|
420096
|
+
const suffix = unit.startsWith("stund") || unit.startsWith("hour") ? "h" : unit.startsWith("tag") || unit.startsWith("day") ? "d" : "m";
|
|
420097
|
+
return {
|
|
420098
|
+
match: numeric,
|
|
420099
|
+
interval: `${amount}${suffix}`
|
|
420100
|
+
};
|
|
420101
|
+
}
|
|
420102
|
+
const halfHour = LOOP_NATURAL_HALF_HOUR.exec(args);
|
|
420103
|
+
if (halfHour !== null) return {
|
|
420104
|
+
match: halfHour,
|
|
420105
|
+
interval: "30m"
|
|
420106
|
+
};
|
|
420107
|
+
const single = LOOP_NATURAL_SINGLE_INTERVAL.exec(args);
|
|
420108
|
+
if (single !== null) {
|
|
420109
|
+
const unit = single[1]?.toLowerCase() ?? "";
|
|
420110
|
+
return {
|
|
420111
|
+
match: single,
|
|
420112
|
+
interval: unit === "minute" ? "1m" : unit === "tag" || unit === "day" ? "1d" : "1h"
|
|
420113
|
+
};
|
|
420114
|
+
}
|
|
420115
|
+
const adverb = LOOP_NATURAL_ADVERB_INTERVAL.exec(args);
|
|
420116
|
+
if (adverb !== null) {
|
|
420117
|
+
const unit = adverb[1]?.toLowerCase() ?? "";
|
|
420118
|
+
return {
|
|
420119
|
+
match: adverb,
|
|
420120
|
+
interval: unit === "täglich" || unit === "taeglich" || unit === "daily" ? "1d" : "1h"
|
|
420121
|
+
};
|
|
420122
|
+
}
|
|
420123
|
+
return null;
|
|
420124
|
+
}
|
|
420125
|
+
function parseNaturalLoopInterval(args) {
|
|
420126
|
+
const parsed = naturalLoopIntervalMatch(args);
|
|
420127
|
+
if (parsed === null) return null;
|
|
420128
|
+
const { match, interval } = parsed;
|
|
420129
|
+
const prompt = `${args.slice(0, match.index)} ${args.slice(match.index + match[0].length)}`.replace(/\s+/gu, " ").trim();
|
|
420130
|
+
if (prompt.length === 0) return { kind: "error" };
|
|
420131
|
+
return {
|
|
420132
|
+
kind: "create",
|
|
420133
|
+
interval,
|
|
420134
|
+
prompt
|
|
420135
|
+
};
|
|
420136
|
+
}
|
|
420137
|
+
function naturalLoopIntervalText(interval) {
|
|
420138
|
+
if (interval === "auto") return "Selbstgesteuert";
|
|
420139
|
+
const match = /^([1-9]\d*)(m|h|d)$/i.exec(interval);
|
|
420140
|
+
if (match === null) return "";
|
|
420141
|
+
const amount = Number(match[1]);
|
|
420142
|
+
const unit = match[2]?.toLowerCase();
|
|
420143
|
+
if (unit === "m") return `Erkannt: alle ${String(amount)} ${amount === 1 ? "Minute" : "Minuten"}`;
|
|
420144
|
+
if (unit === "h") return `Erkannt: alle ${String(amount)} ${amount === 1 ? "Stunde" : "Stunden"}`;
|
|
420145
|
+
return `Erkannt: alle ${String(amount)} ${amount === 1 ? "Tag" : "Tage"}`;
|
|
420146
|
+
}
|
|
420147
|
+
function loopInputHint(rawArgs) {
|
|
420148
|
+
const args = rawArgs.trim();
|
|
420149
|
+
if (args.length === 0) return "Natürlichen Auftrag eingeben; Zeitangaben dürfen überall stehen";
|
|
420150
|
+
if (/^(?:status|pause|paused|resume|stop)$/i.test(args)) return "";
|
|
420151
|
+
const natural = naturalLoopIntervalMatch(args);
|
|
420152
|
+
if (natural !== null) return naturalLoopIntervalText(natural.interval);
|
|
420153
|
+
const explicit = /^(?:start\s+)?([1-9]\d*(?:m|h|d))\b/i.exec(args);
|
|
420154
|
+
if (explicit?.[1] !== void 0) return naturalLoopIntervalText(explicit[1].toLowerCase());
|
|
420155
|
+
return "Selbstgesteuert";
|
|
420156
|
+
}
|
|
420071
420157
|
function parseLoopCommand(rawArgs) {
|
|
420072
420158
|
const args = rawArgs.trim();
|
|
420073
420159
|
if (args.length === 0 || args.toLowerCase() === "status") return { kind: "status" };
|
|
@@ -420079,13 +420165,35 @@ function parseLoopCommand(rawArgs) {
|
|
|
420079
420165
|
if (action === "stop") return { kind: "stop" };
|
|
420080
420166
|
}
|
|
420081
420167
|
let startIndex = action === "start" ? 1 : 0;
|
|
420168
|
+
const createArgs = tokens.slice(startIndex).join(" ");
|
|
420169
|
+
const natural = parseNaturalLoopInterval(createArgs);
|
|
420170
|
+
if (natural !== null) return natural;
|
|
420171
|
+
const selfControlled = LOOP_SELF_CONTROLLED.exec(createArgs);
|
|
420172
|
+
if (selfControlled !== null) {
|
|
420173
|
+
const prompt = `${createArgs.slice(0, selfControlled.index)} ${createArgs.slice(selfControlled.index + selfControlled[0].length)}`.replace(/\s+/gu, " ").trim();
|
|
420174
|
+
if (prompt.length === 0) return { kind: "error" };
|
|
420175
|
+
return {
|
|
420176
|
+
kind: "create",
|
|
420177
|
+
interval: "auto",
|
|
420178
|
+
prompt
|
|
420179
|
+
};
|
|
420180
|
+
}
|
|
420082
420181
|
if (LOOP_CREATE_FILLERS.has(tokens[startIndex]?.toLowerCase() ?? "")) startIndex += 1;
|
|
420083
420182
|
const interval = tokens[startIndex];
|
|
420084
|
-
|
|
420085
|
-
|
|
420183
|
+
if (interval !== void 0 && LOOP_INTERVAL_TOKEN.test(interval)) {
|
|
420184
|
+
const prompt = tokens.slice(startIndex + 1).join(" ").trim();
|
|
420185
|
+
if (prompt.length === 0) return { kind: "error" };
|
|
420186
|
+
return {
|
|
420187
|
+
kind: "create",
|
|
420188
|
+
interval,
|
|
420189
|
+
prompt
|
|
420190
|
+
};
|
|
420191
|
+
}
|
|
420192
|
+
const prompt = tokens.slice(startIndex).join(" ").trim();
|
|
420193
|
+
if (prompt.length === 0) return { kind: "error" };
|
|
420086
420194
|
return {
|
|
420087
420195
|
kind: "create",
|
|
420088
|
-
interval,
|
|
420196
|
+
interval: DEFAULT_LOOP_INTERVAL,
|
|
420089
420197
|
prompt
|
|
420090
420198
|
};
|
|
420091
420199
|
}
|
|
@@ -501930,6 +502038,9 @@ var PersonalMemoryController = class {
|
|
|
501930
502038
|
};
|
|
501931
502039
|
//#endregion
|
|
501932
502040
|
//#region src/tui/constant/scrollback.ts
|
|
502041
|
+
function shouldEnableScrollbackMouseTracking(buffer) {
|
|
502042
|
+
return buffer !== void 0 && buffer.isActive();
|
|
502043
|
+
}
|
|
501933
502044
|
const ENABLE_SCROLLBACK_MOUSE_TRACKING = "\x1B[?1000h\x1B[?1006h";
|
|
501934
502045
|
const DISABLE_SCROLLBACK_MOUSE_TRACKING = "\x1B[?1000l\x1B[?1006l";
|
|
501935
502046
|
//#endregion
|
|
@@ -502286,7 +502397,7 @@ var BottomPinnedTUI = class extends TUI {
|
|
|
502286
502397
|
}
|
|
502287
502398
|
const buffer = this.scrollbackBuffer;
|
|
502288
502399
|
buffer?.updateSnapshot(clipped, scrollViewportRows);
|
|
502289
|
-
this.setMouseTracking(buffer
|
|
502400
|
+
this.setMouseTracking(shouldEnableScrollbackMouseTracking(buffer));
|
|
502290
502401
|
if (buffer !== void 0 && buffer.isActive() && terminalRows > 0) {
|
|
502291
502402
|
const pinnedLines = [];
|
|
502292
502403
|
for (let i = chromeAt; i < blocks.length; i++) {
|
|
@@ -510056,8 +510167,10 @@ var CustomEditor = class extends Editor {
|
|
|
510056
510167
|
consumingPaste = false;
|
|
510057
510168
|
consumeBuffer = "";
|
|
510058
510169
|
argumentHints = /* @__PURE__ */ new Map();
|
|
510059
|
-
|
|
510170
|
+
argumentHintResolvers = /* @__PURE__ */ new Map();
|
|
510171
|
+
setArgumentHints(hints, resolvers = /* @__PURE__ */ new Map()) {
|
|
510060
510172
|
this.argumentHints = hints;
|
|
510173
|
+
this.argumentHintResolvers = resolvers;
|
|
510061
510174
|
}
|
|
510062
510175
|
constructor(tui, options = {}) {
|
|
510063
510176
|
const theme = createEditorTheme();
|
|
@@ -510151,12 +510264,18 @@ var CustomEditor = class extends Editor {
|
|
|
510151
510264
|
computeArgumentHint() {
|
|
510152
510265
|
if (this.inputMode === "bash") return void 0;
|
|
510153
510266
|
const text = this.getText();
|
|
510154
|
-
const match = /^\/(\S+)(
|
|
510267
|
+
const match = /^\/(\S+)(?:\s+([\s\S]*))?$/.exec(text);
|
|
510155
510268
|
if (match === null) return void 0;
|
|
510156
510269
|
const cmd = match[1];
|
|
510157
|
-
const
|
|
510270
|
+
const args = match[2] ?? "";
|
|
510271
|
+
const trailingSpace = text.endsWith(" ") ? " " : "";
|
|
510158
510272
|
if (cmd === void 0) return void 0;
|
|
510159
510273
|
if (this.hasAutocompleteActivity() && trailingSpace.length === 0) return void 0;
|
|
510274
|
+
const resolver = this.argumentHintResolvers.get(cmd);
|
|
510275
|
+
if (resolver !== void 0) {
|
|
510276
|
+
const resolved = resolver(args);
|
|
510277
|
+
if (resolved.length > 0) return args.length > 0 ? ` · ${resolved}` : ` ${resolved}`;
|
|
510278
|
+
}
|
|
510160
510279
|
const hint = this.argumentHints.get(cmd);
|
|
510161
510280
|
if (hint === void 0) return void 0;
|
|
510162
510281
|
const { line, col } = this.getCursor();
|
|
@@ -512061,20 +512180,26 @@ var BlunTUI = class {
|
|
|
512061
512180
|
aliases: cmd.aliases,
|
|
512062
512181
|
description: cmd.description,
|
|
512063
512182
|
...cmd.argumentHint !== void 0 ? { argumentHint: cmd.argumentHint } : {},
|
|
512183
|
+
...cmd.liveArgumentHint !== void 0 ? { liveArgumentHint: cmd.liveArgumentHint } : {},
|
|
512064
512184
|
...completer !== void 0 ? { getArgumentCompletions: (prefix) => completer(prefix) } : {}
|
|
512065
512185
|
};
|
|
512066
512186
|
});
|
|
512067
512187
|
const provider = new FileMentionProvider(slashCommands, this.state.appState.workDir, this.fdPath, this.state.appState.additionalDirs, () => this.state.appState.inputMode, this.mentionFileSearch);
|
|
512068
512188
|
this.state.editor.setAutocompleteProvider(provider);
|
|
512069
512189
|
const argumentHints = /* @__PURE__ */ new Map();
|
|
512190
|
+
const argumentHintResolvers = /* @__PURE__ */ new Map();
|
|
512070
512191
|
for (const cmd of slashCommands) {
|
|
512071
512192
|
if (cmd.argumentHint === void 0) continue;
|
|
512072
512193
|
const visibleHint = cmd.description?.trim();
|
|
512073
512194
|
if (visibleHint === void 0 || visibleHint.length === 0) continue;
|
|
512074
512195
|
argumentHints.set(cmd.name, visibleHint);
|
|
512075
512196
|
for (const alias of cmd.aliases ?? []) argumentHints.set(alias, visibleHint);
|
|
512197
|
+
if (cmd.liveArgumentHint !== void 0) {
|
|
512198
|
+
argumentHintResolvers.set(cmd.name, cmd.liveArgumentHint);
|
|
512199
|
+
for (const alias of cmd.aliases ?? []) argumentHintResolvers.set(alias, cmd.liveArgumentHint);
|
|
512200
|
+
}
|
|
512076
512201
|
}
|
|
512077
|
-
this.state.editor.setArgumentHints(argumentHints);
|
|
512202
|
+
this.state.editor.setArgumentHints(argumentHints, argumentHintResolvers);
|
|
512078
512203
|
}
|
|
512079
512204
|
refreshSlashCommandAutocomplete() {
|
|
512080
512205
|
this.setupAutocomplete();
|
|
@@ -514681,16 +514806,44 @@ function readTelegramUpdateRecipients(stateDir = defaultTelegramStateDir()) {
|
|
|
514681
514806
|
return [];
|
|
514682
514807
|
}
|
|
514683
514808
|
}
|
|
514809
|
+
function claimTelegramUpdateNotice(version, chatId, receiptDir = join(homedir(), ".blun", "updates", "telegram-notices")) {
|
|
514810
|
+
const safeVersion = version.trim().replace(/[^0-9A-Za-z._-]/gu, "_").slice(0, 64);
|
|
514811
|
+
if (safeVersion.length === 0 || !TELEGRAM_DM_ID.test(chatId)) return null;
|
|
514812
|
+
const receiptPath = join(receiptDir, `${safeVersion}-${chatId}.sent`);
|
|
514813
|
+
try {
|
|
514814
|
+
mkdirSync(receiptDir, {
|
|
514815
|
+
recursive: true,
|
|
514816
|
+
mode: 448
|
|
514817
|
+
});
|
|
514818
|
+
writeFileSync(receiptPath, `${(/* @__PURE__ */ new Date()).toISOString()}\n`, {
|
|
514819
|
+
encoding: "utf8",
|
|
514820
|
+
flag: "wx",
|
|
514821
|
+
mode: 384
|
|
514822
|
+
});
|
|
514823
|
+
return receiptPath;
|
|
514824
|
+
} catch {
|
|
514825
|
+
return null;
|
|
514826
|
+
}
|
|
514827
|
+
}
|
|
514684
514828
|
async function sendTelegramUpdateNotice(text, options = {}) {
|
|
514685
514829
|
const stateDir = options.stateDir ?? defaultTelegramStateDir();
|
|
514686
514830
|
const configured = hasConfiguredToken(stateDir);
|
|
514687
514831
|
const recipients = configured ? readTelegramUpdateRecipients(stateDir) : [];
|
|
514688
514832
|
const send = options.send ?? ((chatId, message) => sendReplyFallback(chatId, message));
|
|
514689
514833
|
let sent = 0;
|
|
514690
|
-
|
|
514834
|
+
let attempted = 0;
|
|
514835
|
+
for (const chatId of recipients) {
|
|
514836
|
+
const receiptPath = options.version === void 0 ? void 0 : claimTelegramUpdateNotice(options.version, chatId, options.receiptDir);
|
|
514837
|
+
if (options.version !== void 0 && receiptPath === null) continue;
|
|
514838
|
+
attempted += 1;
|
|
514839
|
+
if (await send(chatId, text).catch(() => false)) sent += 1;
|
|
514840
|
+
else if (receiptPath !== void 0) try {
|
|
514841
|
+
unlinkSync(receiptPath);
|
|
514842
|
+
} catch {}
|
|
514843
|
+
}
|
|
514691
514844
|
return {
|
|
514692
514845
|
configured,
|
|
514693
|
-
attempted
|
|
514846
|
+
attempted,
|
|
514694
514847
|
sent
|
|
514695
514848
|
};
|
|
514696
514849
|
}
|
|
@@ -514843,7 +514996,7 @@ async function runShell(opts, version, updateStartupNotice) {
|
|
|
514843
514996
|
workDir,
|
|
514844
514997
|
startupNotice: configWarning,
|
|
514845
514998
|
onStartupNoticeShown: updateStartupNotice === void 0 || updateNoticeText === void 0 ? void 0 : async () => {
|
|
514846
|
-
const delivery = await sendTelegramUpdateNotice(updateNoticeText);
|
|
514999
|
+
const delivery = await sendTelegramUpdateNotice(updateNoticeText, { version: updateStartupNotice.details.version });
|
|
514847
515000
|
if (!delivery.configured || delivery.attempted === 0 || delivery.sent === delivery.attempted) await updateStartupNotice.acknowledge();
|
|
514848
515001
|
}
|
|
514849
515002
|
});
|