@songsid/agend 2.3.3-beta.8 → 2.3.3-beta.9
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 +17 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +15 -0
- package/dist/backend/codex.js +67 -18
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.js +60 -17
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/daemon.d.ts +17 -0
- package/dist/daemon.js +85 -9
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +15 -0
- package/dist/fleet-manager.js +77 -11
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +13 -0
- package/dist/instance-lifecycle.js +30 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +2 -0
- package/dist/locale.js.map +1 -1
- package/dist/parked-notices.d.ts +87 -0
- package/dist/parked-notices.js +194 -0
- package/dist/parked-notices.js.map +1 -0
- package/package.json +1 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -2849,6 +2849,21 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
2849
2849
|
* would have to make this async and change every caller.
|
|
2850
2850
|
*/
|
|
2851
2851
|
notifyInstanceTopic(instanceName: string, text: string, extraOpts?: import("./channel/types.js").SendOpts): boolean;
|
|
2852
|
+
/**
|
|
2853
|
+
* notifyInstanceTopic's routing, handing back the send itself — and which world sent it — for a caller that must
|
|
2854
|
+
* edit or delete the message later (#2897). Null when there is no adapter or no postable target (already logged).
|
|
2855
|
+
*/
|
|
2856
|
+
private sendToInstanceTopic;
|
|
2857
|
+
private parkedNoticesStore;
|
|
2858
|
+
private get parkedNotices();
|
|
2859
|
+
/**
|
|
2860
|
+
* A held CLI dialog's notices: the instance-topic one and the General one, each edited in place while the
|
|
2861
|
+
* dialog stays (one live message per place, never a pile), and taken back by resolveParkedNotice.
|
|
2862
|
+
*/
|
|
2863
|
+
showParkedNotice(instanceName: string, topicText: string | null, generalText: string | null): void;
|
|
2864
|
+
/** The held dialog is resolved, or the instance stopped or restarted: delete its notices (no-op when none). */
|
|
2865
|
+
resolveParkedNotice(instanceName: string): void;
|
|
2866
|
+
private postParkedNotice;
|
|
2852
2867
|
/**
|
|
2853
2868
|
* Post decision buttons whose callback ids are `<prefix><nonce>:<action>`.
|
|
2854
2869
|
* The entry is registered before the send and rolled back if the send
|
package/dist/fleet-manager.js
CHANGED
|
@@ -80,6 +80,7 @@ import { TmuxManager } from "./tmux-manager.js";
|
|
|
80
80
|
import { AccessManager } from "./channel/access-manager.js";
|
|
81
81
|
import { IpcClient } from "./channel/ipc-bridge.js";
|
|
82
82
|
import { usesChannelAddress } from "./channel/mcp-tools.js";
|
|
83
|
+
import { ParkedNotices, PARKED_NOTICE_LEDGER_FILE } from "./parked-notices.js";
|
|
83
84
|
import { formatFleetTime } from "./tz-utils.js";
|
|
84
85
|
import { createAdapter } from "./channel/factory.js";
|
|
85
86
|
import { isWebChannelEcho, WEB_ECHO_PREFIX } from "./web-channel-echo.js";
|
|
@@ -3079,6 +3080,7 @@ export class FleetManager {
|
|
|
3079
3080
|
if (this.reloadPending)
|
|
3080
3081
|
this.scheduleReconcile();
|
|
3081
3082
|
void this.sweepOrphanedCancelButtons();
|
|
3083
|
+
void this.parkedNotices.sweep();
|
|
3082
3084
|
}
|
|
3083
3085
|
/**
|
|
3084
3086
|
* We are the post-update fleet: the update is over by definition. Clearing it here (rather than in the update
|
|
@@ -14278,11 +14280,22 @@ export class FleetManager {
|
|
|
14278
14280
|
* would have to make this async and change every caller.
|
|
14279
14281
|
*/
|
|
14280
14282
|
notifyInstanceTopic(instanceName, text, extraOpts) {
|
|
14283
|
+
const send = this.sendToInstanceTopic(instanceName, text, extraOpts);
|
|
14284
|
+
if (!send)
|
|
14285
|
+
return false;
|
|
14286
|
+
send.sent.catch(e => this.logger.warn({ err: e, instanceName }, send.failure));
|
|
14287
|
+
return true;
|
|
14288
|
+
}
|
|
14289
|
+
/**
|
|
14290
|
+
* notifyInstanceTopic's routing, handing back the send itself — and which world sent it — for a caller that must
|
|
14291
|
+
* edit or delete the message later (#2897). Null when there is no adapter or no postable target (already logged).
|
|
14292
|
+
*/
|
|
14293
|
+
sendToInstanceTopic(instanceName, text, extraOpts) {
|
|
14281
14294
|
const adapter = this.getAdapterForInstance(instanceName) ?? this.adapter;
|
|
14282
14295
|
if (!adapter) {
|
|
14283
14296
|
// Early startup: adapters are created well after the fleet object exists.
|
|
14284
14297
|
this.logger.warn({ instanceName }, "No adapter yet — instance topic notification not sent");
|
|
14285
|
-
return
|
|
14298
|
+
return null;
|
|
14286
14299
|
}
|
|
14287
14300
|
const channelCfg = this.getChannelConfig(this.getInstanceAdapterId(instanceName));
|
|
14288
14301
|
const groupId = channelCfg?.group_id;
|
|
@@ -14291,17 +14304,13 @@ export class FleetManager {
|
|
|
14291
14304
|
const worldId = this.getInstanceAdapterId(instanceName);
|
|
14292
14305
|
if (threadId != null && groupId) {
|
|
14293
14306
|
const out = this.renderPlaces(worldId, text, { threadId: String(threadId), ...extraOpts });
|
|
14294
|
-
adapter.sendText(String(groupId), out.text, out.opts)
|
|
14295
|
-
.catch(e => this.logger.warn({ err: e, instanceName }, "Failed to send instance topic notification"));
|
|
14296
|
-
return true;
|
|
14307
|
+
return { adapterId: worldId, sent: adapter.sendText(String(groupId), out.text, out.opts), failure: "Failed to send instance topic notification" };
|
|
14297
14308
|
}
|
|
14298
14309
|
// Classic instance: find its channelId from the classic manager
|
|
14299
14310
|
const classicChatId = this.classicChannels?.getChannelIdByInstance(instanceName);
|
|
14300
14311
|
if (classicChatId) {
|
|
14301
14312
|
// #1990: a ClassicBot room's readers need not be in the fleet's group, so its notices name places as plain text.
|
|
14302
|
-
adapter.sendText(classicChatId, stripPlaceRefs(text), extraOpts)
|
|
14303
|
-
.catch(e => this.logger.warn({ err: e, instanceName }, "Failed to send classic notification"));
|
|
14304
|
-
return true;
|
|
14313
|
+
return { adapterId: worldId, sent: adapter.sendText(classicChatId, stripPlaceRefs(text), extraOpts), failure: "Failed to send classic notification" };
|
|
14305
14314
|
}
|
|
14306
14315
|
// Fallback: the instance has neither a topic nor a classic channel, so post
|
|
14307
14316
|
// where fleet-wide notices go. Not the bare group id: on Discord that is a
|
|
@@ -14309,12 +14318,67 @@ export class FleetManager {
|
|
|
14309
14318
|
const target = this.fleetNoticeTarget(worldId);
|
|
14310
14319
|
if (target) {
|
|
14311
14320
|
const out = this.renderPlaces(worldId, text, { ...target.opts, ...extraOpts });
|
|
14312
|
-
adapter.sendText(target.chatId, out.text, out.opts)
|
|
14313
|
-
.catch(e => this.logger.warn({ err: e, instanceName }, "Failed to send notification (no topic)"));
|
|
14314
|
-
return true;
|
|
14321
|
+
return { adapterId: worldId, sent: adapter.sendText(target.chatId, out.text, out.opts), failure: "Failed to send notification (no topic)" };
|
|
14315
14322
|
}
|
|
14316
14323
|
this.logger.warn({ instanceName }, "No postable target — instance topic notification not sent");
|
|
14317
|
-
return
|
|
14324
|
+
return null;
|
|
14325
|
+
}
|
|
14326
|
+
// ── Parked-dialog notices (#2897) ──
|
|
14327
|
+
parkedNoticesStore = null;
|
|
14328
|
+
get parkedNotices() {
|
|
14329
|
+
this.parkedNoticesStore ??= new ParkedNotices({
|
|
14330
|
+
file: join(this.dataDir, PARKED_NOTICE_LEDGER_FILE),
|
|
14331
|
+
logger: this.logger,
|
|
14332
|
+
post: (instanceName, place, text) => this.postParkedNotice(instanceName, place, text),
|
|
14333
|
+
adapterFor: adapterId => this.worlds.get(adapterId)?.adapter
|
|
14334
|
+
?? (adapterId === this.getPrimaryAdapterId() ? this.adapter ?? undefined : undefined),
|
|
14335
|
+
resolvedText: () => t("fleet.dialog_parked_resolved"),
|
|
14336
|
+
// A ClassicBot room names places as plain text (#1990), as its post did.
|
|
14337
|
+
render: (row, text) => row.place === "topic" && this.classicChannels?.getChannelIdByInstance(row.instanceName) === row.chatId
|
|
14338
|
+
? stripPlaceRefs(text) : this.renderPlaces(row.adapterId, text).text,
|
|
14339
|
+
});
|
|
14340
|
+
return this.parkedNoticesStore;
|
|
14341
|
+
}
|
|
14342
|
+
/**
|
|
14343
|
+
* A held CLI dialog's notices: the instance-topic one and the General one, each edited in place while the
|
|
14344
|
+
* dialog stays (one live message per place, never a pile), and taken back by resolveParkedNotice.
|
|
14345
|
+
*/
|
|
14346
|
+
showParkedNotice(instanceName, topicText, generalText) {
|
|
14347
|
+
if (topicText !== null)
|
|
14348
|
+
void this.parkedNotices.show(instanceName, "topic", topicText);
|
|
14349
|
+
if (generalText !== null)
|
|
14350
|
+
void this.parkedNotices.show(instanceName, "general", generalText);
|
|
14351
|
+
}
|
|
14352
|
+
/** The held dialog is resolved, or the instance stopped or restarted: delete its notices (no-op when none). */
|
|
14353
|
+
resolveParkedNotice(instanceName) {
|
|
14354
|
+
void this.parkedNotices.resolve(instanceName);
|
|
14355
|
+
}
|
|
14356
|
+
async postParkedNotice(instanceName, place, text) {
|
|
14357
|
+
let send;
|
|
14358
|
+
if (place === "topic") {
|
|
14359
|
+
send = this.sendToInstanceTopic(instanceName, text);
|
|
14360
|
+
}
|
|
14361
|
+
else {
|
|
14362
|
+
// Where notifyFleetError posts, without its text throttle: the ledger is what keeps this to one message.
|
|
14363
|
+
const general = Object.entries(this.fleetConfig?.instances ?? {})
|
|
14364
|
+
.find(([, config]) => config.general_topic === true)?.[0];
|
|
14365
|
+
const target = general ? null : this.fleetNoticeTarget();
|
|
14366
|
+
if (general)
|
|
14367
|
+
send = this.sendToInstanceTopic(general, text);
|
|
14368
|
+
else if (this.adapter && target) {
|
|
14369
|
+
const out = this.renderPlaces(this.getPrimaryAdapterId(), text, target.opts);
|
|
14370
|
+
send = { adapterId: this.getPrimaryAdapterId(), sent: this.adapter.sendText(target.chatId, out.text, out.opts) };
|
|
14371
|
+
}
|
|
14372
|
+
else
|
|
14373
|
+
send = null;
|
|
14374
|
+
}
|
|
14375
|
+
if (!send)
|
|
14376
|
+
return null;
|
|
14377
|
+
const sent = await send.sent;
|
|
14378
|
+
const adapterId = send.adapterId ?? this.getPrimaryAdapterId();
|
|
14379
|
+
if (!adapterId)
|
|
14380
|
+
return null;
|
|
14381
|
+
return { adapterId, chatId: sent.chatId, ...(sent.threadId !== undefined ? { threadId: sent.threadId } : {}), messageId: sent.messageId };
|
|
14318
14382
|
}
|
|
14319
14383
|
// ── Nonce-armed button prompts (hang / assist / exit / clear) ──
|
|
14320
14384
|
//
|
|
@@ -21215,6 +21279,8 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21215
21279
|
for (const timer of this.cancelButtonIdleRetireTimers.values())
|
|
21216
21280
|
clearTimeout(timer);
|
|
21217
21281
|
this.cancelButtonIdleRetireTimers.clear();
|
|
21282
|
+
// #2897: notices still being retired stay in the ledger; the next fleet's sweep finishes them.
|
|
21283
|
+
this.parkedNoticesStore?.dispose();
|
|
21218
21284
|
if (this.topicCleanupTimer) {
|
|
21219
21285
|
clearInterval(this.topicCleanupTimer);
|
|
21220
21286
|
this.topicCleanupTimer = null;
|