instar 1.3.310 → 1.3.312
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/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +32 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +8 -5
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +17 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/AgentWorktreeDetector.d.ts +27 -3
- package/dist/core/AgentWorktreeDetector.d.ts.map +1 -1
- package/dist/core/AgentWorktreeDetector.js +77 -19
- package/dist/core/AgentWorktreeDetector.js.map +1 -1
- package/dist/core/BootSelfKnowledge.d.ts +121 -0
- package/dist/core/BootSelfKnowledge.d.ts.map +1 -0
- package/dist/core/BootSelfKnowledge.js +285 -0
- package/dist/core/BootSelfKnowledge.js.map +1 -0
- package/dist/core/InstarWorktreeManager.d.ts +7 -0
- package/dist/core/InstarWorktreeManager.d.ts.map +1 -1
- package/dist/core/InstarWorktreeManager.js +47 -1
- package/dist/core/InstarWorktreeManager.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +10 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +161 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/messaging/AttentionTopicGuard.d.ts +14 -0
- package/dist/messaging/AttentionTopicGuard.d.ts.map +1 -1
- package/dist/messaging/AttentionTopicGuard.js +21 -0
- package/dist/messaging/AttentionTopicGuard.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts +40 -3
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +61 -11
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +8 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +3 -3
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +137 -2
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/CollaborationSurfacer.d.ts +4 -1
- package/dist/threadline/CollaborationSurfacer.d.ts.map +1 -1
- package/dist/threadline/CollaborationSurfacer.js +1 -1
- package/dist/threadline/CollaborationSurfacer.js.map +1 -1
- package/dist/threadline/TelegramBridge.d.ts +4 -1
- package/dist/threadline/TelegramBridge.d.ts.map +1 -1
- package/dist/threadline/TelegramBridge.js +1 -1
- package/dist/threadline/TelegramBridge.js.map +1 -1
- package/dist/threadline/hubCommands.d.ts +4 -1
- package/dist/threadline/hubCommands.d.ts.map +1 -1
- package/dist/threadline/hubCommands.js +3 -3
- package/dist/threadline/hubCommands.js.map +1 -1
- package/package.json +2 -2
- package/scripts/lint-no-direct-destructive.js +4 -0
- package/scripts/lint-no-unfunneled-topic-creation.js +129 -0
- package/src/data/builtin-manifest.json +73 -65
- package/src/scaffold/templates.ts +8 -0
- package/src/templates/scripts/secret-get.mjs +143 -0
- package/upgrades/1.3.311.md +20 -0
- package/upgrades/1.3.312.md +31 -0
- package/upgrades/side-effects/bounded-notification-surface.md +34 -0
- package/upgrades/side-effects/session-boot-self-knowledge.md +78 -0
|
@@ -25,7 +25,7 @@ import { formatForTelegram } from './TelegramMarkdownFormatter.js';
|
|
|
25
25
|
import { recordFormatApplied, recordFormatLintIssue, recordFormatFallbackPlainRetry, } from './telegramFormatMetrics.js';
|
|
26
26
|
import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
|
|
27
27
|
import { stopAutonomousTopic } from '../core/AutonomousSessions.js';
|
|
28
|
-
import { AttentionTopicGuard } from './AttentionTopicGuard.js';
|
|
28
|
+
import { AttentionTopicGuard, TopicFloodBudgetError } from './AttentionTopicGuard.js';
|
|
29
29
|
/**
|
|
30
30
|
* Telegram General topic convention:
|
|
31
31
|
* - Incoming: messages in General have message_thread_id=1 (or undefined in older API)
|
|
@@ -161,6 +161,9 @@ export class TelegramAdapter {
|
|
|
161
161
|
attentionFilePath;
|
|
162
162
|
// Per-source forum-topic circuit breaker (2026-05-28 topic-flood lockdown).
|
|
163
163
|
attentionTopicGuard;
|
|
164
|
+
// LAST-RESORT auto-topic ceiling enforced inside createForumTopic itself
|
|
165
|
+
// (2026-06-05 flood lesson — covers every caller, not just attention items).
|
|
166
|
+
topicCreationGuard;
|
|
164
167
|
// bucket -> the single reused "notices coalesced" topic for that bucket.
|
|
165
168
|
floodNoticeTopicByBucket = new Map();
|
|
166
169
|
// bucket -> in-flight createForumTopic promise, so concurrent coalesced items
|
|
@@ -399,6 +402,15 @@ export class TelegramAdapter {
|
|
|
399
402
|
this.attentionFilePath = path.join(this.botStateDir, 'state', 'attention-items.json');
|
|
400
403
|
this.attentionSuppressedLogPath = path.join(this.botStateDir, 'state', 'attention-suppressed.jsonl');
|
|
401
404
|
this.attentionTopicGuard = new AttentionTopicGuard(config.attentionTopicGuard ?? {});
|
|
405
|
+
// Backstop ceiling: looser than the attention guard by design (the
|
|
406
|
+
// attention guard SHAPES politely per-source; this is the absolute bound
|
|
407
|
+
// a mis-wired or future caller cannot dodge). Config can tighten/loosen.
|
|
408
|
+
this.topicCreationGuard = new AttentionTopicGuard({
|
|
409
|
+
windowMs: 10 * 60 * 1000,
|
|
410
|
+
maxTopicsPerSource: 8,
|
|
411
|
+
maxTopicsGlobal: 12,
|
|
412
|
+
...(config.topicCreationBudget ?? {}),
|
|
413
|
+
});
|
|
402
414
|
const alc = config.agentHealthLane ?? {};
|
|
403
415
|
this.agentHealthLaneCfg = {
|
|
404
416
|
enabled: alc.enabled !== false,
|
|
@@ -930,11 +942,40 @@ export class TelegramAdapter {
|
|
|
930
942
|
}
|
|
931
943
|
/**
|
|
932
944
|
* Create a forum topic in the supergroup.
|
|
945
|
+
*
|
|
946
|
+
* THE TOPIC-CREATION CHOKEPOINT. Every topic this process creates is born
|
|
947
|
+
* here, so the last-resort flood ceiling lives here (see
|
|
948
|
+
* `topicCreationBudget` on the config). `opts.origin` declares who is
|
|
949
|
+
* asking:
|
|
950
|
+
* - 'user' — a human asked for this topic (operator command, inbound
|
|
951
|
+
* conversation). Exempt: humans are self-rate-limiting.
|
|
952
|
+
* - 'system' — a bounded, create-once-then-reuse infrastructure topic
|
|
953
|
+
* (Lifeline, Dashboard, Updates, the flood-notice topic
|
|
954
|
+
* itself). Exempt: cardinality is fixed by design.
|
|
955
|
+
* - 'auto' — anything a feature decided to create on its own. Counted.
|
|
956
|
+
* THIS IS THE DEFAULT — a caller that doesn't declare an
|
|
957
|
+
* origin is budgeted, so a future mis-wired feature is
|
|
958
|
+
* bounded without having to know this mechanism exists.
|
|
959
|
+
* Past the budget this throws TopicFloodBudgetError — the same failure
|
|
960
|
+
* shape as a Telegram 429, which every caller already survives.
|
|
933
961
|
*/
|
|
934
|
-
async createForumTopic(name, iconColor) {
|
|
962
|
+
async createForumTopic(name, iconColor, opts) {
|
|
935
963
|
if (this.notAForum) {
|
|
936
964
|
throw new Error('Chat is not a forum — topic creation skipped');
|
|
937
965
|
}
|
|
966
|
+
const origin = opts?.origin ?? 'auto';
|
|
967
|
+
if (origin === 'auto') {
|
|
968
|
+
const label = opts?.label ?? 'unlabeled-auto';
|
|
969
|
+
const decision = this.topicCreationGuard.decide(label, undefined);
|
|
970
|
+
if (decision.action === 'coalesce') {
|
|
971
|
+
console.warn(`[telegram] topic-creation budget: REFUSED auto topic "${name}" ` +
|
|
972
|
+
`(label=${label}, bucket=${decision.bucket}, #${decision.suppressedCount} in episode) — ` +
|
|
973
|
+
`the last-resort flood ceiling. If this label is legitimate at this volume, ` +
|
|
974
|
+
`raise messaging[].config.topicCreationBudget; if it is operator/system-driven, ` +
|
|
975
|
+
`pass an explicit origin.`);
|
|
976
|
+
throw new TopicFloodBudgetError(name, label, decision.bucket);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
938
979
|
const params = {
|
|
939
980
|
chat_id: this.config.chatId,
|
|
940
981
|
name,
|
|
@@ -992,7 +1033,7 @@ export class TelegramAdapter {
|
|
|
992
1033
|
* Find an existing topic by name, or create a new one if none exists.
|
|
993
1034
|
* Prevents duplicate topics when sessions respawn or the server restarts.
|
|
994
1035
|
*/
|
|
995
|
-
async findOrCreateForumTopic(name, iconColor) {
|
|
1036
|
+
async findOrCreateForumTopic(name, iconColor, opts) {
|
|
996
1037
|
const normalizedName = name.toLowerCase().trim();
|
|
997
1038
|
for (const [topicId, existingName] of this.topicToName) {
|
|
998
1039
|
if (existingName.toLowerCase().trim() === normalizedName) {
|
|
@@ -1000,7 +1041,7 @@ export class TelegramAdapter {
|
|
|
1000
1041
|
return { topicId, name: existingName, reused: true };
|
|
1001
1042
|
}
|
|
1002
1043
|
}
|
|
1003
|
-
const result = await this.createForumTopic(name, iconColor);
|
|
1044
|
+
const result = await this.createForumTopic(name, iconColor, opts);
|
|
1004
1045
|
return { ...result, reused: false };
|
|
1005
1046
|
}
|
|
1006
1047
|
/**
|
|
@@ -1072,7 +1113,7 @@ export class TelegramAdapter {
|
|
|
1072
1113
|
if (!this.config.lifelineTopicId) {
|
|
1073
1114
|
// No lifeline topic configured — create one
|
|
1074
1115
|
try {
|
|
1075
|
-
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.SYSTEM.color);
|
|
1116
|
+
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.SYSTEM.color, { origin: 'system' });
|
|
1076
1117
|
this.config.lifelineTopicId = topic.topicId;
|
|
1077
1118
|
this.persistLifelineTopicId(topic.topicId);
|
|
1078
1119
|
console.log(`[telegram] Created Lifeline topic: ${topic.topicId}`);
|
|
@@ -1107,7 +1148,7 @@ export class TelegramAdapter {
|
|
|
1107
1148
|
errStr.includes('TOPIC_CLOSED') || errStr.includes('not found')) {
|
|
1108
1149
|
console.log(`[telegram] Lifeline topic ${this.config.lifelineTopicId} was deleted — recreating`);
|
|
1109
1150
|
try {
|
|
1110
|
-
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.SYSTEM.color);
|
|
1151
|
+
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.SYSTEM.color, { origin: 'system' });
|
|
1111
1152
|
this.config.lifelineTopicId = topic.topicId;
|
|
1112
1153
|
this.persistLifelineTopicId(topic.topicId);
|
|
1113
1154
|
console.log(`[telegram] Recreated Lifeline topic: ${topic.topicId}`);
|
|
@@ -1210,7 +1251,7 @@ export class TelegramAdapter {
|
|
|
1210
1251
|
const styledName = `${TOPIC_STYLE.INFO.emoji} Dashboard`;
|
|
1211
1252
|
if (!this.config.dashboardTopicId) {
|
|
1212
1253
|
try {
|
|
1213
|
-
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.INFO.color);
|
|
1254
|
+
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.INFO.color, { origin: 'system' });
|
|
1214
1255
|
this.config.dashboardTopicId = topic.topicId;
|
|
1215
1256
|
this.persistDashboardTopicId(topic.topicId);
|
|
1216
1257
|
console.log(`[telegram] Created Dashboard topic: ${topic.topicId}`);
|
|
@@ -1262,7 +1303,7 @@ export class TelegramAdapter {
|
|
|
1262
1303
|
errStr.includes('TOPIC_CLOSED') || errStr.includes('not found')) {
|
|
1263
1304
|
console.log(`[telegram] Dashboard topic ${this.config.dashboardTopicId} was deleted — recreating`);
|
|
1264
1305
|
try {
|
|
1265
|
-
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.INFO.color);
|
|
1306
|
+
const topic = await this.createForumTopic(styledName, TOPIC_STYLE.INFO.color, { origin: 'system' });
|
|
1266
1307
|
this.config.dashboardTopicId = topic.topicId;
|
|
1267
1308
|
this.persistDashboardTopicId(topic.topicId);
|
|
1268
1309
|
return topic.topicId;
|
|
@@ -2999,7 +3040,13 @@ export class TelegramAdapter {
|
|
|
2999
3040
|
const emoji = PRIORITY_EMOJI[item.priority] || PRIORITY_EMOJI.NORMAL;
|
|
3000
3041
|
const color = PRIORITY_COLOR[item.priority] || PRIORITY_COLOR.NORMAL;
|
|
3001
3042
|
const topicTitle = `${emoji} ${item.title}`.slice(0, 128);
|
|
3002
|
-
|
|
3043
|
+
// HIGH/URGENT are 'system' (the guard's critical-never-coalesced
|
|
3044
|
+
// invariant holds at both layers); everything else is budgeted 'auto'.
|
|
3045
|
+
const critical = item.priority === 'HIGH' || item.priority === 'URGENT';
|
|
3046
|
+
const topic = await this.createForumTopic(topicTitle, color, {
|
|
3047
|
+
origin: critical ? 'system' : 'auto',
|
|
3048
|
+
label: 'attention-item',
|
|
3049
|
+
});
|
|
3003
3050
|
const topicId = topic.topicId;
|
|
3004
3051
|
attention.topicId = topicId;
|
|
3005
3052
|
// Register mappings
|
|
@@ -3129,7 +3176,8 @@ export class TelegramAdapter {
|
|
|
3129
3176
|
return this.agentHealthPending;
|
|
3130
3177
|
this.agentHealthPending = (async () => {
|
|
3131
3178
|
const name = this.agentHealthLaneCfg.topicName;
|
|
3132
|
-
|
|
3179
|
+
// 'system': single named lane topic, create-once-then-reuse by design.
|
|
3180
|
+
const topic = await this.findOrCreateForumTopic(name, TOPIC_STYLE.SYSTEM.color, { origin: 'system' });
|
|
3133
3181
|
this.agentHealthTopicId = topic.topicId;
|
|
3134
3182
|
if (!topic.reused) {
|
|
3135
3183
|
const intro = [
|
|
@@ -3231,7 +3279,9 @@ export class TelegramAdapter {
|
|
|
3231
3279
|
const creation = (async () => {
|
|
3232
3280
|
const label = bucket === '*' ? 'multiple sources' : bucket;
|
|
3233
3281
|
const title = `🔁 ${label}: notices coalesced (flood guard)`.slice(0, 128);
|
|
3234
|
-
|
|
3282
|
+
// 'system': the coalesce surface itself must never be refused by the
|
|
3283
|
+
// budget it exists to absorb (one topic per bucket, create-once-reuse).
|
|
3284
|
+
const topic = await this.createForumTopic(title, PRIORITY_COLOR.LOW ?? PRIORITY_COLOR.NORMAL, { origin: 'system' });
|
|
3235
3285
|
const topicId = topic.topicId;
|
|
3236
3286
|
this.floodNoticeTopicByBucket.set(bucket, topicId);
|
|
3237
3287
|
this.topicToName.set(topicId, title);
|