@songsid/agend 2.1.6-beta.4 → 2.1.6-beta.5
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 +24 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/factory.js +4 -1
- package/dist/backend/factory.js.map +1 -1
- package/dist/backend/muse.d.ts +90 -0
- package/dist/backend/muse.js +428 -0
- package/dist/backend/muse.js.map +1 -0
- package/dist/backend/types.d.ts +2 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/access-manager.d.ts +20 -0
- package/dist/channel/access-manager.js +25 -0
- package/dist/channel/access-manager.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +3 -0
- package/dist/channel/adapters/discord.js +13 -10
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/markdown-chunk.d.ts +8 -3
- package/dist/channel/markdown-chunk.js +12 -3
- package/dist/channel/markdown-chunk.js.map +1 -1
- package/dist/channel/tool-router.js +12 -2
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/config-validator.js +14 -3
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.js +7 -2
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +23 -0
- package/dist/fleet-manager.js +83 -8
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.js +8 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/logger.js +42 -25
- package/dist/logger.js.map +1 -1
- package/dist/outbound-schemas.d.ts +1 -0
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/quickstart-api.d.ts +3 -0
- package/dist/quickstart-api.js +1 -0
- package/dist/quickstart-api.js.map +1 -1
- package/dist/scheduler/db.js +17 -5
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/db.test.js +34 -1
- package/dist/scheduler/db.test.js.map +1 -1
- package/dist/scheduler/types.d.ts +4 -0
- package/dist/scheduler/types.js.map +1 -1
- package/dist/setup-wizard.js +4 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/steer-capability.js +4 -1
- package/dist/steer-capability.js.map +1 -1
- package/dist/tmux-manager.js +29 -4
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.js +1 -0
- package/dist/topic-commands.js.map +1 -1
- package/dist/web-api.js +2 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-terminal.d.ts +30 -1
- package/dist/web-terminal.js +86 -3
- package/dist/web-terminal.js.map +1 -1
- package/package.json +2 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -757,6 +757,14 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
757
757
|
* Pure: callers rely on being able to ask before claiming the dedup key.
|
|
758
758
|
*/
|
|
759
759
|
private botMessageDropReason;
|
|
760
|
+
/**
|
|
761
|
+
* Say so when an adapter's access mode is coming from its state file rather
|
|
762
|
+
* than from fleet.yaml. The state file wins by design — a pairing done at
|
|
763
|
+
* runtime has to survive a restart — but that also means an edit to
|
|
764
|
+
* `access.mode` silently does nothing, which is indistinguishable from the
|
|
765
|
+
* fleet not having reloaded. Naming the file is what makes it fixable.
|
|
766
|
+
*/
|
|
767
|
+
private warnIfAccessModeOverridden;
|
|
760
768
|
private handleInboundMessage;
|
|
761
769
|
/** Handle outbound tool calls from a daemon instance */
|
|
762
770
|
/** Warn (but don't block) when rate limits are high. 30-min debounce per instance. */
|
|
@@ -1084,6 +1092,21 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1084
1092
|
* (or an assist for one they stopped) must not stay clickable for the rest
|
|
1085
1093
|
* of its 15 minutes.
|
|
1086
1094
|
*/
|
|
1095
|
+
/**
|
|
1096
|
+
* Collapse every still-armed button prompt, for a fleet that is going away.
|
|
1097
|
+
*
|
|
1098
|
+
* The map is in memory; the buttons are in the chat for up to 24 hours. A
|
|
1099
|
+
* restart therefore leaves them looking live — pressing one takes the stale
|
|
1100
|
+
* branch, which acknowledges the click and drops the dismissal without
|
|
1101
|
+
* saying so. Retiring them here means the user meets a spent prompt instead
|
|
1102
|
+
* of a live-looking dead one.
|
|
1103
|
+
*
|
|
1104
|
+
* Best effort and bounded. Each collapse is a platform call, a day of tips
|
|
1105
|
+
* can be many of them, and shutdown still has instances to stop. Whatever
|
|
1106
|
+
* has not finished by the deadline is abandoned — that is exactly today's
|
|
1107
|
+
* behaviour, so the budget can only leave things no worse than before.
|
|
1108
|
+
*/
|
|
1109
|
+
private retirePendingNoncePrompts;
|
|
1087
1110
|
clearNoncePromptsForInstance(instanceName: string): void;
|
|
1088
1111
|
/** A clean exit is intentional from the CLI's perspective, but often not from
|
|
1089
1112
|
* the operator's. Keep the instance notice passive and put the action in the
|
package/dist/fleet-manager.js
CHANGED
|
@@ -217,6 +217,8 @@ const CLEAR_CONFIRM_TIMEOUT_MS = 15_000;
|
|
|
217
217
|
/** Default lifetime for long-lived nonce prompts (clear overrides this to 15s). */
|
|
218
218
|
const NONCE_BUTTON_TIMEOUT_MS = 15 * 60_000;
|
|
219
219
|
const TIP_BUTTON_TIMEOUT_MS = 24 * 60 * 60_000;
|
|
220
|
+
/** How long shutdown will spend retiring still-armed button prompts. */
|
|
221
|
+
const NONCE_RETIRE_BUDGET_MS = 5_000;
|
|
220
222
|
const CLI_ENV_TTL_MS = 24 * 60 * 60 * 1000; // hard validity bound for the cached CLI env
|
|
221
223
|
/**
|
|
222
224
|
* How old the cached CLI env may be before `/model` re-probes it live.
|
|
@@ -3167,7 +3169,9 @@ export class FleetManager {
|
|
|
3167
3169
|
}
|
|
3168
3170
|
const accessDir = join(this.dataDir, "access");
|
|
3169
3171
|
mkdirSync(accessDir, { recursive: true });
|
|
3170
|
-
const
|
|
3172
|
+
const accessStatePath = join(accessDir, "access.json");
|
|
3173
|
+
const accessManager = new AccessManager(channelConfig.access ?? DEFAULT_OPEN_ACCESS, accessStatePath);
|
|
3174
|
+
this.warnIfAccessModeOverridden(accessManager, accessStatePath);
|
|
3171
3175
|
this.accessManager = accessManager;
|
|
3172
3176
|
const inboxDir = join(this.dataDir, "inbox");
|
|
3173
3177
|
mkdirSync(inboxDir, { recursive: true });
|
|
@@ -3559,7 +3563,9 @@ export class FleetManager {
|
|
|
3559
3563
|
}
|
|
3560
3564
|
const accessDir = join(this.dataDir, "access");
|
|
3561
3565
|
mkdirSync(accessDir, { recursive: true });
|
|
3562
|
-
const
|
|
3566
|
+
const accessStatePath = join(accessDir, `access-${adapterId}.json`);
|
|
3567
|
+
const accessManager = new AccessManager(channelConfig.access ?? DEFAULT_OPEN_ACCESS, accessStatePath);
|
|
3568
|
+
this.warnIfAccessModeOverridden(accessManager, accessStatePath);
|
|
3563
3569
|
const inboxDir = join(this.dataDir, "inbox");
|
|
3564
3570
|
mkdirSync(inboxDir, { recursive: true });
|
|
3565
3571
|
const adapter = await createAdapter(channelConfig, {
|
|
@@ -4314,13 +4320,36 @@ export class FleetManager {
|
|
|
4314
4320
|
const target = this.routing.resolve(threadId);
|
|
4315
4321
|
if (!target)
|
|
4316
4322
|
return "fleet topic: no instance routed for this thread";
|
|
4317
|
-
// Fleet topic:
|
|
4323
|
+
// Fleet topic: this gate lets the copy through when the adapter is open OR
|
|
4324
|
+
// collab is on for the instance. "Through" is not "delivered" — access
|
|
4325
|
+
// control runs next, and the two arms are not symmetric there:
|
|
4326
|
+
//
|
|
4327
|
+
// open adapter → isAllowed() returns true outright: really admitted.
|
|
4328
|
+
// locked + collab → the bot's user id still has to be on the allowlist,
|
|
4329
|
+
// so the message is normally refused a few lines later
|
|
4330
|
+
// under "Access DENIED for non-allowed user".
|
|
4331
|
+
//
|
|
4332
|
+
// Collab alone therefore does not admit a bot on a locked adapter; it only
|
|
4333
|
+
// declines to drop the copy here and leaves the decision to access control.
|
|
4318
4334
|
const isOpen = this.getChannelConfig(msg.adapterId)?.access?.mode === "open";
|
|
4319
4335
|
if (!isOpen && !this.collabInstances.has(target.name)) {
|
|
4320
4336
|
return `fleet topic: adapter not open and collab off for ${target.name}`;
|
|
4321
4337
|
}
|
|
4322
4338
|
return null;
|
|
4323
4339
|
}
|
|
4340
|
+
/**
|
|
4341
|
+
* Say so when an adapter's access mode is coming from its state file rather
|
|
4342
|
+
* than from fleet.yaml. The state file wins by design — a pairing done at
|
|
4343
|
+
* runtime has to survive a restart — but that also means an edit to
|
|
4344
|
+
* `access.mode` silently does nothing, which is indistinguishable from the
|
|
4345
|
+
* fleet not having reloaded. Naming the file is what makes it fixable.
|
|
4346
|
+
*/
|
|
4347
|
+
warnIfAccessModeOverridden(accessManager, statePath) {
|
|
4348
|
+
const configured = accessManager.overriddenConfigMode();
|
|
4349
|
+
if (!configured)
|
|
4350
|
+
return;
|
|
4351
|
+
this.logger.warn({ statePath, configured, inEffect: accessManager.getMode() }, `access mode "${accessManager.getMode()}" comes from the state file and overrides "${configured}" in fleet.yaml; delete ${statePath} to go back to the configured value`);
|
|
4352
|
+
}
|
|
4324
4353
|
async handleInboundMessage(msg) {
|
|
4325
4354
|
const threadId = msg.threadId || undefined;
|
|
4326
4355
|
this.logger.debug({ source: msg.source, chatId: msg.chatId, threadId, userId: msg.userId, isBotMessage: msg.isBotMessage, textLen: (msg.text ?? "").length, text: (msg.text ?? "").slice(0, 80) }, "handleInboundMessage entry");
|
|
@@ -5227,6 +5256,15 @@ export class FleetManager {
|
|
|
5227
5256
|
*/
|
|
5228
5257
|
scheduleSourceAdapter(schedule) {
|
|
5229
5258
|
const chatId = String(schedule.reply_chat_id);
|
|
5259
|
+
// New schedules carry the adapter that owned the source chat at creation.
|
|
5260
|
+
// Keep that persona across source-instance rebinding, but never trust a
|
|
5261
|
+
// stale adapter after the chat has moved to another world.
|
|
5262
|
+
const persistedWorld = schedule.reply_adapter_id
|
|
5263
|
+
? this.worlds.get(schedule.reply_adapter_id)
|
|
5264
|
+
: undefined;
|
|
5265
|
+
if (persistedWorld && String(persistedWorld.groupId) === chatId) {
|
|
5266
|
+
return persistedWorld.adapter;
|
|
5267
|
+
}
|
|
5230
5268
|
const sourceAdapterId = schedule.source ? this.getInstanceAdapterId(schedule.source) : undefined;
|
|
5231
5269
|
const sourceWorld = sourceAdapterId ? this.worlds.get(sourceAdapterId) : undefined;
|
|
5232
5270
|
if (sourceWorld && String(sourceWorld.groupId) === chatId)
|
|
@@ -5337,6 +5375,7 @@ export class FleetManager {
|
|
|
5337
5375
|
target: payload.target || instanceName,
|
|
5338
5376
|
reply_chat_id: meta.chat_id,
|
|
5339
5377
|
reply_thread_id: meta.thread_id || null,
|
|
5378
|
+
reply_adapter_id: meta.adapter_id || null,
|
|
5340
5379
|
label: payload.label,
|
|
5341
5380
|
timezone: payload.timezone,
|
|
5342
5381
|
silent: !!(payload.silent),
|
|
@@ -7004,6 +7043,39 @@ export class FleetManager {
|
|
|
7004
7043
|
* (or an assist for one they stopped) must not stay clickable for the rest
|
|
7005
7044
|
* of its 15 minutes.
|
|
7006
7045
|
*/
|
|
7046
|
+
/**
|
|
7047
|
+
* Collapse every still-armed button prompt, for a fleet that is going away.
|
|
7048
|
+
*
|
|
7049
|
+
* The map is in memory; the buttons are in the chat for up to 24 hours. A
|
|
7050
|
+
* restart therefore leaves them looking live — pressing one takes the stale
|
|
7051
|
+
* branch, which acknowledges the click and drops the dismissal without
|
|
7052
|
+
* saying so. Retiring them here means the user meets a spent prompt instead
|
|
7053
|
+
* of a live-looking dead one.
|
|
7054
|
+
*
|
|
7055
|
+
* Best effort and bounded. Each collapse is a platform call, a day of tips
|
|
7056
|
+
* can be many of them, and shutdown still has instances to stop. Whatever
|
|
7057
|
+
* has not finished by the deadline is abandoned — that is exactly today's
|
|
7058
|
+
* behaviour, so the budget can only leave things no worse than before.
|
|
7059
|
+
*/
|
|
7060
|
+
async retirePendingNoncePrompts(budgetMs = NONCE_RETIRE_BUDGET_MS) {
|
|
7061
|
+
const entries = [...this.pendingNonceButtons.values()];
|
|
7062
|
+
this.pendingNonceButtons.clear();
|
|
7063
|
+
for (const entry of entries)
|
|
7064
|
+
if (entry.timer)
|
|
7065
|
+
clearTimeout(entry.timer);
|
|
7066
|
+
const collapses = entries
|
|
7067
|
+
.filter(entry => entry.messageId && entry.adapter.editMessageRemoveButtons)
|
|
7068
|
+
.map(entry => entry.adapter.editMessageRemoveButtons(entry.chatId, entry.messageId, entry.expiredText, entry.threadId).catch(err => this.logger.debug({ err, instanceName: entry.instanceName, prefix: entry.prefix }, "Failed to retire button prompt during shutdown")));
|
|
7069
|
+
if (!collapses.length)
|
|
7070
|
+
return;
|
|
7071
|
+
await Promise.race([
|
|
7072
|
+
Promise.allSettled(collapses),
|
|
7073
|
+
new Promise(resolve => {
|
|
7074
|
+
const timer = setTimeout(resolve, budgetMs);
|
|
7075
|
+
timer.unref?.();
|
|
7076
|
+
}),
|
|
7077
|
+
]);
|
|
7078
|
+
}
|
|
7007
7079
|
clearNoncePromptsForInstance(instanceName) {
|
|
7008
7080
|
for (const [nonce, entry] of this.pendingNonceButtons) {
|
|
7009
7081
|
if (entry.instanceName !== instanceName)
|
|
@@ -8788,6 +8860,8 @@ export class FleetManager {
|
|
|
8788
8860
|
// Grok reads AGENTS.md project docs; agy reads .agents/agents.md — the
|
|
8789
8861
|
// same files their writeConfig() appends fleet instructions to.
|
|
8790
8862
|
"grok": "AGENTS.md",
|
|
8863
|
+
// muse init scaffolds AGENTS.md and the binary reads it as project rules.
|
|
8864
|
+
"muse": "AGENTS.md",
|
|
8791
8865
|
"antigravity": ".agents/agents.md",
|
|
8792
8866
|
"mock": "CLAUDE.md",
|
|
8793
8867
|
};
|
|
@@ -8863,6 +8937,9 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
8863
8937
|
// vendor-canonical location is .grok/skills.
|
|
8864
8938
|
"opencode": [".agents", "skills"],
|
|
8865
8939
|
"grok": [".grok", "skills"],
|
|
8940
|
+
// Live-verified on muse 1.3.0: `muse skills list --source project` sees
|
|
8941
|
+
// .agents/skills and ignores .muse/skills.
|
|
8942
|
+
"muse": [".agents", "skills"],
|
|
8866
8943
|
"antigravity": [".agents", "skills"],
|
|
8867
8944
|
};
|
|
8868
8945
|
/** Copy general-knowledge steering + all role-eligible skills to General. */
|
|
@@ -10602,11 +10679,9 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
10602
10679
|
for (const pending of this.pendingClassicStarts.values())
|
|
10603
10680
|
clearTimeout(pending.timer);
|
|
10604
10681
|
this.pendingClassicStarts.clear();
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
}
|
|
10609
|
-
this.pendingNonceButtons.clear();
|
|
10682
|
+
// Adapters are still connected here — they are stopped further down — so
|
|
10683
|
+
// this is the last moment the prompts can be collapsed.
|
|
10684
|
+
await this.retirePendingNoncePrompts();
|
|
10610
10685
|
this.topicArchiver.stop();
|
|
10611
10686
|
this.scheduler?.shutdown();
|
|
10612
10687
|
// Stop instances in parallel batches to avoid long sequential waits.
|