@songsid/agend 2.3.3-beta.2 → 2.3.3-beta.4
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/backend/claude-code.js +3 -25
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/claude-transcript-errors.d.ts +18 -0
- package/dist/backend/claude-transcript-errors.js +19 -0
- package/dist/backend/claude-transcript-errors.js.map +1 -0
- package/dist/classic-channel-manager.d.ts +4 -1
- package/dist/classic-channel-manager.js +21 -7
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-history.d.ts +50 -0
- package/dist/config-history.js +263 -0
- package/dist/config-history.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +7 -2
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +6 -0
- package/dist/daemon.js +22 -3
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +8 -1
- package/dist/fleet-manager.js +47 -16
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +5 -0
- package/dist/fleet-process-handlers.js +21 -0
- package/dist/fleet-process-handlers.js.map +1 -1
- package/dist/locale.js +20 -0
- package/dist/locale.js.map +1 -1
- package/dist/needs-you-hub.d.ts +1 -0
- package/dist/needs-you-hub.js +2 -2
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +8 -2
- package/dist/needs-you.js +7 -1
- package/dist/needs-you.js.map +1 -1
- package/dist/task-board-waker.d.ts +4 -1
- package/dist/task-board-waker.js +13 -2
- package/dist/task-board-waker.js.map +1 -1
- package/dist/transcript-monitor.d.ts +7 -0
- package/dist/transcript-monitor.js +32 -4
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/ui/panel-needs.js +11 -9
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-needs.js +5 -1
- package/dist/web-api.js +2 -0
- package/dist/web-api.js.map +1 -1
- package/launcher/fleet-service-owner.cjs +4 -1
- package/package.json +1 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -466,6 +466,10 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
466
466
|
private kiroMigrationRuns;
|
|
467
467
|
/** #1386 "Needs you": the list, its live chat messages and Acknowledge. Started with the fleet (finishStartup). */
|
|
468
468
|
private needsYou;
|
|
469
|
+
private configHistory;
|
|
470
|
+
private configHistoryTimer;
|
|
471
|
+
private loadedFleetSource;
|
|
472
|
+
private getConfigHistory;
|
|
469
473
|
/** When the fleet first saw an instance crashed, for its "Needs you" age; cleared when it is not. */
|
|
470
474
|
private readonly needsCrashedAt;
|
|
471
475
|
/** Pause reason/time read from the marker, per paused instance; dropped on any attention change of it, and at most
|
|
@@ -1065,7 +1069,10 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1065
1069
|
webhookEmit(event: string, name: string, data?: Record<string, unknown>): void;
|
|
1066
1070
|
getSysInfo(): import("./fleet-context.js").SysInfo;
|
|
1067
1071
|
/** Load fleet.yaml and build routing table */
|
|
1068
|
-
loadConfig(configPath: string
|
|
1072
|
+
loadConfig(configPath: string, options?: {
|
|
1073
|
+
startup?: boolean;
|
|
1074
|
+
remember?: boolean;
|
|
1075
|
+
}): FleetConfig;
|
|
1069
1076
|
private relayLoginModeWarned;
|
|
1070
1077
|
/** `login.mode: relay` was removed (#1139). Still accepted so an upgrade cannot stop a fleet from starting. */
|
|
1071
1078
|
private warnAboutRemovedLoginMode;
|
package/dist/fleet-manager.js
CHANGED
|
@@ -67,7 +67,7 @@ const __dirname = dirname(__filename);
|
|
|
67
67
|
const DEFAULT_OPEN_ACCESS = { mode: "open", allowed_users: [], max_pending_codes: 0, code_expiry_minutes: 0 };
|
|
68
68
|
import { STATUS_EMOJI_CONFIG_KEYS, STATUS_EMOJI_KEYS, STATUS_EMOJI_SUGGESTIONS, TELEGRAM_REACTION_EMOJIS, builtinStatusEmojis, customEmojiValue, emojiImageUrl, normalizeEmoji, previewStatusEmojis, reactionForm, reactionMatchKey, resolveStatusEmojis, statusAvoidList, statusEmojiProblem, statusMatchKey, statusMatchKeys, textForm, } from "./status-emojis.js";
|
|
69
69
|
import { isProbeableRouteTarget } from "./fleet-context.js";
|
|
70
|
-
import { getEffectiveInstanceDefaults, loadFleetConfig, loadRawFleetConfig, DEFAULT_COST_GUARD, DEFAULT_DAILY_SUMMARY, DEFAULT_INSTANCE_CONFIG, autoGeneralInstanceConfig } from "./config.js";
|
|
70
|
+
import { getEffectiveInstanceDefaults, loadFleetConfig, loadRawFleetConfig, loadFleetConfigSource, loadRawFleetConfigSource, DEFAULT_COST_GUARD, DEFAULT_DAILY_SUMMARY, DEFAULT_INSTANCE_CONFIG, autoGeneralInstanceConfig } from "./config.js";
|
|
71
71
|
import { EventLog } from "./event-log.js";
|
|
72
72
|
import { binaryProbe } from "./binary-probe.js";
|
|
73
73
|
import { AVAILABILITY_STALE_MS, BackendAvailabilityStore, hostAvailabilityProbes } from "./backend-availability.js";
|
|
@@ -234,6 +234,7 @@ import { remoteCardAction, remoteCardChoiceLabel, remoteCardOutcomeText, remoteC
|
|
|
234
234
|
import { recentChatContext } from "./log-tail.js";
|
|
235
235
|
import { describeSignalSource, recordInternalRequest, withOrigin } from "./fleet-control-audit.js";
|
|
236
236
|
import { handleAgentRequest, ToolNotPermittedError } from "./agent-endpoint.js";
|
|
237
|
+
import { ConfigHistory, ConfigSyntaxError, configIssueText } from "./config-history.js";
|
|
237
238
|
import { ClassicChannelManager, classicWebEchoOn, getClassicBackendChoices, inferClassicChannelType, isSelectableClassicBackend, readClassicLastActivityAt, readClassicRoomNames } from "./classic-channel-manager.js";
|
|
238
239
|
import { assertExplicitInstanceRemoval } from "./instance-removal.js";
|
|
239
240
|
import { KNOWN_BACKENDS, validateFleetConfig } from "./config-validator.js";
|
|
@@ -906,6 +907,12 @@ export class FleetManager {
|
|
|
906
907
|
kiroMigrationRuns = new Map();
|
|
907
908
|
/** #1386 "Needs you": the list, its live chat messages and Acknowledge. Started with the fleet (finishStartup). */
|
|
908
909
|
needsYou = null;
|
|
910
|
+
configHistory = null;
|
|
911
|
+
configHistoryTimer = null;
|
|
912
|
+
loadedFleetSource = null;
|
|
913
|
+
getConfigHistory() {
|
|
914
|
+
return this.configHistory ??= new ConfigHistory(this.dataDir, () => this.needsYou?.poke(), message => this.logger.warn(message));
|
|
915
|
+
}
|
|
909
916
|
/** When the fleet first saw an instance crashed, for its "Needs you" age; cleared when it is not. */
|
|
910
917
|
needsCrashedAt = new Map();
|
|
911
918
|
/** Pause reason/time read from the marker, per paused instance; dropped on any attention change of it, and at most
|
|
@@ -3101,7 +3108,8 @@ export class FleetManager {
|
|
|
3101
3108
|
// fleet.yaml, sent SIGHUP, and got no reaction and no explanation.
|
|
3102
3109
|
this.logger.error({ err }, "SIGHUP config reload failed");
|
|
3103
3110
|
const message = err instanceof Error ? err.message : String(err);
|
|
3104
|
-
|
|
3111
|
+
if (!(err instanceof ConfigSyntaxError))
|
|
3112
|
+
this.notifyFleetError(t("fleet.reload_failed", message));
|
|
3105
3113
|
});
|
|
3106
3114
|
}
|
|
3107
3115
|
/**
|
|
@@ -3337,19 +3345,19 @@ export class FleetManager {
|
|
|
3337
3345
|
};
|
|
3338
3346
|
}
|
|
3339
3347
|
/** Load fleet.yaml and build routing table */
|
|
3340
|
-
loadConfig(configPath) {
|
|
3348
|
+
loadConfig(configPath, options = {}) {
|
|
3341
3349
|
this.configPath = configPath;
|
|
3342
|
-
const
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
const
|
|
3348
|
-
const loaded = loadFleetConfig(configPath);
|
|
3350
|
+
const history = this.getConfigHistory();
|
|
3351
|
+
history.track("fleet.yaml", configPath);
|
|
3352
|
+
const selected = existsSync(configPath) ? history.read("fleet.yaml", configPath, options.startup) : { source: "{}\n", fallback: false };
|
|
3353
|
+
this.rawFleetDocument = parseDocument(selected.source, { keepSourceTokens: true });
|
|
3354
|
+
const raw = loadRawFleetConfigSource(selected.source);
|
|
3355
|
+
const loaded = loadFleetConfigSource(selected.source);
|
|
3349
3356
|
this.assertProviderSecretEnvKeys(loaded);
|
|
3350
3357
|
this.rawFleetConfig = raw;
|
|
3351
3358
|
this.settingsRuntimeRevision++;
|
|
3352
3359
|
this.fleetConfig = loaded;
|
|
3360
|
+
this.loadedFleetSource = selected;
|
|
3353
3361
|
this.savedFleetConfigSnapshot = structuredClone(this.fleetConfig);
|
|
3354
3362
|
this.warnAboutRemovedLoginMode(loaded);
|
|
3355
3363
|
this.enforceGuestSwitch();
|
|
@@ -3358,6 +3366,8 @@ export class FleetManager {
|
|
|
3358
3366
|
// Scope the path to its owning data directory so another inherited home's override cannot enable CW.
|
|
3359
3367
|
process.env.AGEND_FLEET_DATA_DIR = resolvePath(this.dataDir);
|
|
3360
3368
|
process.env.AGEND_FLEET_CONFIG_PATH = resolvePath(configPath);
|
|
3369
|
+
if (options.remember !== false && existsSync(configPath))
|
|
3370
|
+
history.accepted("fleet.yaml", configPath, selected);
|
|
3361
3371
|
return this.fleetConfig;
|
|
3362
3372
|
}
|
|
3363
3373
|
relayLoginModeWarned = false;
|
|
@@ -8167,7 +8177,7 @@ export class FleetManager {
|
|
|
8167
8177
|
this.tmuxExecHelperTimer ??= setInterval(() => tmuxExecHelper.maintain(), 5_000);
|
|
8168
8178
|
this.tmuxExecHelperTimer.unref?.();
|
|
8169
8179
|
this.rotateFleetLogs();
|
|
8170
|
-
const fleet = this.loadConfig(configPath);
|
|
8180
|
+
const fleet = this.loadConfig(configPath, { startup: true });
|
|
8171
8181
|
this.slimFleetConfigAtStartup();
|
|
8172
8182
|
this.logConfigWarningsAtStartup();
|
|
8173
8183
|
setLocale(detectLocale(fleet)); // user-facing text language (fleet.yaml defaults.locale / timezone)
|
|
@@ -8245,7 +8255,7 @@ export class FleetManager {
|
|
|
8245
8255
|
// migrates legacy single-bot entries and names without a suffix. Classic
|
|
8246
8256
|
// routing does NOT go through the routing engine (single-key, can't hold two
|
|
8247
8257
|
// bots in one channel) — it resolves per-bot via getInstanceByChannel.
|
|
8248
|
-
this.classicChannels = new ClassicChannelManager(this.dataDir, this.logger);
|
|
8258
|
+
this.classicChannels = new ClassicChannelManager(this.dataDir, this.logger, this.getConfigHistory());
|
|
8249
8259
|
const classicAdapters = fleet.channels?.length ? fleet.channels : (fleet.channel ? [fleet.channel] : []);
|
|
8250
8260
|
this.classicChannels.configureAdapters(classicAdapters);
|
|
8251
8261
|
// The unrecoverable-id report is deliberately NOT sent here: no adapter
|
|
@@ -8263,6 +8273,9 @@ export class FleetManager {
|
|
|
8263
8273
|
// rooms), before the dashboard serves anything; from now on every change is written back (off the loop).
|
|
8264
8274
|
this.restoreWebChat(fleet);
|
|
8265
8275
|
this.startSearchIndex(fleet);
|
|
8276
|
+
// Parse-only source monitoring; it does not apply hand-edited Fleet settings.
|
|
8277
|
+
this.configHistoryTimer = setInterval(() => this.configHistory?.check(), 1_000);
|
|
8278
|
+
this.configHistoryTimer.unref?.();
|
|
8266
8279
|
// Poll classicBot.yaml for external changes every 30s
|
|
8267
8280
|
this.classicReloadTimer = setInterval(() => {
|
|
8268
8281
|
// Attributes the synchronous part, up to the reload's first await (#1235).
|
|
@@ -8401,7 +8414,7 @@ export class FleetManager {
|
|
|
8401
8414
|
fleet.instances[name] = autoGeneralInstanceConfig(fleet.defaults, generalDir, need.adapterId); // #2598: its kiro_ui is the fleet's
|
|
8402
8415
|
generalsCreated = true;
|
|
8403
8416
|
}
|
|
8404
|
-
if (generalsCreated)
|
|
8417
|
+
if (generalsCreated && !this.configHistory?.isFallback(this.configPath))
|
|
8405
8418
|
this.saveFleetConfig();
|
|
8406
8419
|
if (topicMode && (fleet.channel || fleet.channels?.length)) {
|
|
8407
8420
|
const schedulerConfig = {
|
|
@@ -8577,7 +8590,7 @@ export class FleetManager {
|
|
|
8577
8590
|
fixedGeneral = true;
|
|
8578
8591
|
}
|
|
8579
8592
|
}
|
|
8580
|
-
if (fixedGeneral)
|
|
8593
|
+
if (fixedGeneral && !this.configHistory?.isFallback(this.configPath))
|
|
8581
8594
|
this.saveFleetConfig();
|
|
8582
8595
|
// Auto-create topics AFTER adapter is ready (needs adapter.createTopic)
|
|
8583
8596
|
await this.topicCommands.autoCreateTopics();
|
|
@@ -12604,6 +12617,7 @@ export class FleetManager {
|
|
|
12604
12617
|
},
|
|
12605
12618
|
});
|
|
12606
12619
|
this.rawFleetConfig = loadRawFleetConfig(this.configPath);
|
|
12620
|
+
this.configHistory?.accepted("fleet.yaml", this.configPath, { source: output, fallback: false });
|
|
12607
12621
|
// The instance map is defaults-expanded. A defaults edit changes that view even when it writes no instance
|
|
12608
12622
|
// leaves. Re-resolve from the committed YAML so inherited values cannot become stale overrides on the next save.
|
|
12609
12623
|
// Keep the FleetConfig object itself: Settings and other request contexts hold it.
|
|
@@ -12682,6 +12696,8 @@ export class FleetManager {
|
|
|
12682
12696
|
}
|
|
12683
12697
|
/** One-time upgrade migration; invalid YAML is never rewritten. */
|
|
12684
12698
|
migrateNoticeDeliveryStorage() {
|
|
12699
|
+
if (this.configHistory?.isFallback(this.configPath))
|
|
12700
|
+
return;
|
|
12685
12701
|
if (this.fleetConfig && this.configPath && (this.fleetConfig.web?.notify_login === "dm" || this.fleetConfig.defaults.tips === "dm"
|
|
12686
12702
|
|| this.fleetConfig.web?.notice_delivery !== undefined)
|
|
12687
12703
|
&& validateFleetConfig(this.rawFleetConfig).valid) {
|
|
@@ -12696,6 +12712,8 @@ export class FleetManager {
|
|
|
12696
12712
|
}
|
|
12697
12713
|
}
|
|
12698
12714
|
migrateOfficeStorage() {
|
|
12715
|
+
if (this.configHistory?.isFallback(this.configPath))
|
|
12716
|
+
return;
|
|
12699
12717
|
if (!this.fleetConfig || !this.configPath || !hasLegacyOffice(this.rawFleetConfig) || !validateFleetConfig(this.rawFleetConfig).valid)
|
|
12700
12718
|
return;
|
|
12701
12719
|
try {
|
|
@@ -12719,6 +12737,8 @@ export class FleetManager {
|
|
|
12719
12737
|
}
|
|
12720
12738
|
}
|
|
12721
12739
|
slimFleetConfigAtStartup() {
|
|
12740
|
+
if (this.configHistory?.isFallback(this.configPath))
|
|
12741
|
+
return;
|
|
12722
12742
|
this.migrateOfficeStorage();
|
|
12723
12743
|
this.migrateNoticeDeliveryStorage();
|
|
12724
12744
|
const redundantPaths = collectRedundantInstanceDefaultPaths(this.rawFleetConfig);
|
|
@@ -15083,6 +15103,9 @@ export class FleetManager {
|
|
|
15083
15103
|
},
|
|
15084
15104
|
tasks: () => this.needsYouTaskItems(),
|
|
15085
15105
|
backendSignIns: () => this.needsYouBackendSignIns(),
|
|
15106
|
+
configIssues: () => (this.configHistory?.currentIssues() ?? []).map(issue => ({
|
|
15107
|
+
...issue, detail: configIssueText(issue, t), owner: this.worlds.keys().next().value,
|
|
15108
|
+
})),
|
|
15086
15109
|
taskAction: action => this.taskActionFromChat(action),
|
|
15087
15110
|
settings: () => ({
|
|
15088
15111
|
liveMessage: this.fleetConfig?.needs_you?.live_message !== false,
|
|
@@ -21222,6 +21245,9 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21222
21245
|
const sharesStopped = this.officeSharesInstance?.close(); // #2636: every Office share ends, and its tunnel
|
|
21223
21246
|
// #1386: every live "Needs you" message says the fleet stopped (capabilities revoked first) — while the
|
|
21224
21247
|
// adapters can still edit. Bounded: a platform that does not answer must not hold the shutdown.
|
|
21248
|
+
if (this.configHistoryTimer)
|
|
21249
|
+
clearInterval(this.configHistoryTimer);
|
|
21250
|
+
this.configHistoryTimer = null;
|
|
21225
21251
|
const needsStopped = this.stopNeedsYou();
|
|
21226
21252
|
// #1490 P3: stop() now returns a Promise; await it so the final
|
|
21227
21253
|
// ledger flush completes before process.exit(0) in doStopAll's caller.
|
|
@@ -21567,14 +21593,16 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21567
21593
|
const previousRawConfig = this.rawFleetConfig;
|
|
21568
21594
|
const previousRawDocument = this.rawFleetDocument;
|
|
21569
21595
|
const previousSavedSnapshot = this.savedFleetConfigSnapshot;
|
|
21596
|
+
const previousSource = this.loadedFleetSource;
|
|
21570
21597
|
try {
|
|
21571
|
-
this.loadConfig(this.configPath);
|
|
21598
|
+
this.loadConfig(this.configPath, { remember: false });
|
|
21572
21599
|
}
|
|
21573
21600
|
catch (err) {
|
|
21574
21601
|
this.fleetConfig = oldConfig;
|
|
21575
21602
|
this.rawFleetConfig = previousRawConfig;
|
|
21576
21603
|
this.rawFleetDocument = previousRawDocument;
|
|
21577
21604
|
this.savedFleetConfigSnapshot = previousSavedSnapshot;
|
|
21605
|
+
this.loadedFleetSource = previousSource;
|
|
21578
21606
|
throw err;
|
|
21579
21607
|
}
|
|
21580
21608
|
const validation = validateFleetConfig(this.rawFleetConfig);
|
|
@@ -21590,6 +21618,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21590
21618
|
this.rawFleetConfig = previousRawConfig;
|
|
21591
21619
|
this.rawFleetDocument = previousRawDocument;
|
|
21592
21620
|
this.savedFleetConfigSnapshot = previousSavedSnapshot;
|
|
21621
|
+
this.loadedFleetSource = previousSource;
|
|
21593
21622
|
this.observeWebAuthority(); // #2453 review: the configuration back in force is the one seen
|
|
21594
21623
|
this.logger.error({
|
|
21595
21624
|
oldCount,
|
|
@@ -21610,6 +21639,8 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21610
21639
|
// mark every row done and tell the user "changes applied".
|
|
21611
21640
|
return { rejected: why };
|
|
21612
21641
|
}
|
|
21642
|
+
if (this.loadedFleetSource)
|
|
21643
|
+
this.getConfigHistory().accepted("fleet.yaml", this.configPath, this.loadedFleetSource);
|
|
21613
21644
|
this.migrateOfficeStorage();
|
|
21614
21645
|
this.migrateNoticeDeliveryStorage();
|
|
21615
21646
|
if (canvasWorkerEnabled(oldConfig?.web) !== this.canvasWorkerEnabled()) {
|
|
@@ -21824,7 +21855,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21824
21855
|
* the panel shows the mismatch instead of a button.
|
|
21825
21856
|
*/
|
|
21826
21857
|
checkStartupSignatureConsistency() {
|
|
21827
|
-
if (!this.configPath) {
|
|
21858
|
+
if (!this.configPath || this.configHistory?.isFallback(this.configPath)) {
|
|
21828
21859
|
this.fleetSignatureMismatch = null;
|
|
21829
21860
|
return;
|
|
21830
21861
|
}
|