@songsid/agend 2.1.0-beta.8 → 2.1.0

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.
Files changed (119) hide show
  1. package/README.md +1 -0
  2. package/README.zh-TW.md +2 -1
  3. package/dist/access-path.js +3 -3
  4. package/dist/access-path.js.map +1 -1
  5. package/dist/agent-cli.js +1 -1
  6. package/dist/agent-cli.js.map +1 -1
  7. package/dist/agent-endpoint.d.ts +8 -0
  8. package/dist/agent-endpoint.js +36 -8
  9. package/dist/agent-endpoint.js.map +1 -1
  10. package/dist/backend/antigravity.d.ts +8 -0
  11. package/dist/backend/antigravity.js +46 -3
  12. package/dist/backend/antigravity.js.map +1 -1
  13. package/dist/backend/claude-code.d.ts +6 -0
  14. package/dist/backend/claude-code.js +20 -4
  15. package/dist/backend/claude-code.js.map +1 -1
  16. package/dist/backend/codex.d.ts +12 -1
  17. package/dist/backend/codex.js +55 -1
  18. package/dist/backend/codex.js.map +1 -1
  19. package/dist/backend/factory.js +4 -1
  20. package/dist/backend/factory.js.map +1 -1
  21. package/dist/backend/grok.d.ts +59 -0
  22. package/dist/backend/grok.js +329 -0
  23. package/dist/backend/grok.js.map +1 -0
  24. package/dist/backend/kiro.d.ts +6 -0
  25. package/dist/backend/kiro.js +38 -3
  26. package/dist/backend/kiro.js.map +1 -1
  27. package/dist/backend/opencode.d.ts +5 -0
  28. package/dist/backend/opencode.js +18 -0
  29. package/dist/backend/opencode.js.map +1 -1
  30. package/dist/backend/types.d.ts +59 -3
  31. package/dist/backend/types.js +15 -2
  32. package/dist/backend/types.js.map +1 -1
  33. package/dist/channel/adapters/discord.d.ts +20 -0
  34. package/dist/channel/adapters/discord.js +88 -11
  35. package/dist/channel/adapters/discord.js.map +1 -1
  36. package/dist/channel/adapters/telegram.js +4 -1
  37. package/dist/channel/adapters/telegram.js.map +1 -1
  38. package/dist/channel/mcp-tools.js +18 -2
  39. package/dist/channel/mcp-tools.js.map +1 -1
  40. package/dist/chat-export.js +5 -2
  41. package/dist/chat-export.js.map +1 -1
  42. package/dist/classic-channel-manager.d.ts +16 -1
  43. package/dist/classic-channel-manager.js +76 -4
  44. package/dist/classic-channel-manager.js.map +1 -1
  45. package/dist/cli.js +82 -16
  46. package/dist/cli.js.map +1 -1
  47. package/dist/config-validator.js +70 -1
  48. package/dist/config-validator.js.map +1 -1
  49. package/dist/config.d.ts +3 -1
  50. package/dist/config.js +14 -1
  51. package/dist/config.js.map +1 -1
  52. package/dist/daemon.d.ts +83 -5
  53. package/dist/daemon.js +556 -173
  54. package/dist/daemon.js.map +1 -1
  55. package/dist/daily-summary.js +7 -2
  56. package/dist/daily-summary.js.map +1 -1
  57. package/dist/fleet-context.d.ts +11 -0
  58. package/dist/fleet-manager.d.ts +129 -8
  59. package/dist/fleet-manager.js +1125 -142
  60. package/dist/fleet-manager.js.map +1 -1
  61. package/dist/fleet-system-prompt.js +1 -1
  62. package/dist/general-knowledge/skills/fleet-config/SKILL.md +19 -13
  63. package/dist/general-knowledge/skills/fleet-health/SKILL.md +30 -51
  64. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
  65. package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +19 -13
  66. package/dist/general-knowledge/skills/model-discovery/SKILL.md +1 -5
  67. package/dist/general-knowledge/skills/scheduling/SKILL.md +41 -0
  68. package/dist/general-knowledge/skills/session-management/SKILL.md +29 -116
  69. package/dist/instance-lifecycle.d.ts +14 -1
  70. package/dist/instance-lifecycle.js +59 -20
  71. package/dist/instance-lifecycle.js.map +1 -1
  72. package/dist/locale.js +28 -2
  73. package/dist/locale.js.map +1 -1
  74. package/dist/logger.d.ts +6 -0
  75. package/dist/logger.js +23 -7
  76. package/dist/logger.js.map +1 -1
  77. package/dist/outbound-handlers.js +199 -11
  78. package/dist/outbound-handlers.js.map +1 -1
  79. package/dist/outbound-schemas.d.ts +44 -2
  80. package/dist/outbound-schemas.js +50 -3
  81. package/dist/outbound-schemas.js.map +1 -1
  82. package/dist/pause-marker.d.ts +5 -0
  83. package/dist/pause-marker.js +36 -0
  84. package/dist/pause-marker.js.map +1 -0
  85. package/dist/scheduler/db.d.ts +8 -0
  86. package/dist/scheduler/db.js +74 -5
  87. package/dist/scheduler/db.js.map +1 -1
  88. package/dist/scheduler/db.test.js +50 -0
  89. package/dist/scheduler/db.test.js.map +1 -1
  90. package/dist/scheduler/scheduler.d.ts +6 -0
  91. package/dist/scheduler/scheduler.js +99 -16
  92. package/dist/scheduler/scheduler.js.map +1 -1
  93. package/dist/scheduler/scheduler.test.js +131 -1
  94. package/dist/scheduler/scheduler.test.js.map +1 -1
  95. package/dist/scheduler/types.d.ts +9 -3
  96. package/dist/scheduler/types.js.map +1 -1
  97. package/dist/settings-api.d.ts +20 -2
  98. package/dist/settings-api.js +213 -9
  99. package/dist/settings-api.js.map +1 -1
  100. package/dist/setup-wizard.js +8 -0
  101. package/dist/setup-wizard.js.map +1 -1
  102. package/dist/tmux-control.d.ts +7 -0
  103. package/dist/tmux-control.js +22 -1
  104. package/dist/tmux-control.js.map +1 -1
  105. package/dist/tmux-manager.d.ts +1 -1
  106. package/dist/tmux-manager.js.map +1 -1
  107. package/dist/topic-commands.d.ts +14 -0
  108. package/dist/topic-commands.js +107 -15
  109. package/dist/topic-commands.js.map +1 -1
  110. package/dist/types.d.ts +29 -1
  111. package/dist/tz-utils.d.ts +26 -0
  112. package/dist/tz-utils.js +46 -0
  113. package/dist/tz-utils.js.map +1 -0
  114. package/dist/ui/dashboard.html +3 -3
  115. package/dist/ui/settings.html +453 -74
  116. package/dist/web-api.js +3 -1
  117. package/dist/web-api.js.map +1 -1
  118. package/dist/workflow-templates/default.md +0 -4
  119. package/package.json +2 -1
@@ -1,4 +1,4 @@
1
- import type { FleetConfig, InstanceConfig } from "./types.js";
1
+ import type { FleetConfig, RawFleetConfig, InstanceConfig } from "./types.js";
2
2
  import { type RouteTarget } from "./fleet-context.js";
3
3
  import { EventLog } from "./event-log.js";
4
4
  import { AdapterWorld } from "./adapter-world.js";
@@ -14,10 +14,34 @@ import { InstanceLifecycle, type LifecycleContext } from "./instance-lifecycle.j
14
14
  import { type ArchiverContext } from "./topic-archiver.js";
15
15
  import { type StatuslineWatcherContext } from "./statusline-watcher.js";
16
16
  import { type OutboundContext } from "./outbound-handlers.js";
17
+ import { type RawConfigPatch } from "./settings-api.js";
17
18
  import { type AgentEndpointContext } from "./agent-endpoint.js";
18
19
  import { ClassicChannelManager } from "./classic-channel-manager.js";
19
20
  import type { InstanceState } from "./backend/types.js";
20
21
  export declare function resolveReplyThreadId(argsThreadId: unknown, instanceConfig?: InstanceConfig): string | undefined;
22
+ /**
23
+ * Pure warm-cap victim selection (extracted for testability). Given the current
24
+ * warm (running) instance names and a cap, return the LRU idle instances to evict
25
+ * so the running count returns to the cap. Skips: the `exclude` instance, any
26
+ * already-evicting, general instances (never evicted), and non-idle instances
27
+ * (working/stuck can't be evicted). Oldest last-inbound is evicted first; a
28
+ * missing timestamp (0) sorts oldest. cap <= 0 (or non-integer) = unlimited → [].
29
+ */
30
+ export declare function selectLruEvictions(warm: string[], cap: number, opts: {
31
+ exclude?: string;
32
+ isEvicting: (name: string) => boolean;
33
+ isGeneral: (name: string) => boolean;
34
+ isIdle: (name: string) => boolean;
35
+ lastInboundAt: (name: string) => number;
36
+ }): string[];
37
+ export interface DeliveryOptions {
38
+ /** Explicitly identify agent-to-agent delivery when metadata is unavailable. */
39
+ isCrossInstance?: boolean;
40
+ /** Force or bypass the idle gate. Schedules set this explicitly. */
41
+ waitForIdle?: boolean;
42
+ /** Test/operational override; normal deliveries use the 60 second backstop. */
43
+ idleTimeoutMs?: number;
44
+ }
21
45
  export declare class FleetManager implements FleetContext, LifecycleContext, ArchiverContext, StatuslineWatcherContext, OutboundContext, AgentEndpointContext {
22
46
  dataDir: string;
23
47
  private children;
@@ -25,6 +49,9 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
25
49
  /** @deprecated Use lifecycle.daemons — kept for backward compat */
26
50
  get daemons(): Map<string, import("./daemon.js").Daemon>;
27
51
  fleetConfig: FleetConfig | null;
52
+ private rawFleetConfig;
53
+ private rawFleetDocument;
54
+ private savedFleetConfigSnapshot;
28
55
  adapter: ChannelAdapter | null;
29
56
  readonly worlds: Map<string, AdapterWorld>;
30
57
  readonly adapters: Map<string, ChannelAdapter>;
@@ -51,12 +78,25 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
51
78
  private lastActivity;
52
79
  /** Latest pane-derived execution snapshot reported by each daemon. */
53
80
  private instanceStateCache;
81
+ /** CLI pane status overrides; daemon.pid alone only proves FleetManager lives. */
82
+ private instanceProcessStatus;
83
+ /** Instances currently being auto-paused by warm_cap, so concurrent checks don't double-evict. */
84
+ private warmCapEvicting;
85
+ /** Per-instance tail keeps cross-instance and scheduled deliveries FIFO. */
86
+ private idleGatedDeliveryTails;
87
+ /** Non-user work must observe a fresh idle snapshot after the latest delivery. */
88
+ private lastDeliveryAt;
89
+ /** State-cache updates wake event-driven idle waiters without busy polling. */
90
+ private instanceIdleWaiters;
54
91
  private lastInboundUser;
55
92
  private cancelButtons;
56
93
  private lastInboundMsg;
57
94
  private topicArchiver;
58
95
  controlClient: TmuxControlClient | null;
59
96
  classicChannels: ClassicChannelManager | null;
97
+ private pendingClassicStarts;
98
+ /** In-flight /model selections, keyed by nonce (see handleModelSelection). */
99
+ private pendingModelSelects;
60
100
  private failoverActive;
61
101
  readonly ipcStoppingInstances: Set<string>;
62
102
  private adapterRestarting;
@@ -79,6 +119,8 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
79
119
  getSysInfo(): import("./fleet-context.js").SysInfo;
80
120
  /** Load fleet.yaml and build routing table */
81
121
  loadConfig(configPath: string): FleetConfig;
122
+ /** User-authored fleet.yaml, before defaults are merged into instances. */
123
+ getRawFleetConfig(): RawFleetConfig;
82
124
  /** Build topic routing table: { topicId -> RouteTarget } */
83
125
  buildRoutingTable(): Map<string, RouteTarget>;
84
126
  /**
@@ -100,6 +142,13 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
100
142
  * /cancel). Classic-only commands (/chat, /load) must NOT use this.
101
143
  */
102
144
  private resolveSlashTarget;
145
+ /**
146
+ * Model switching is privileged. Fleet allowlisted admins retain authority in
147
+ * ClassicBot channels, while ClassicBot's own admin_users may also switch the
148
+ * model of the channel they administer.
149
+ */
150
+ private isModelAdmin;
151
+ private handlePauseWakeSlash;
103
152
  /** Get the adapter bound to an instance, falling back to primary adapter */
104
153
  getAdapterForInstance(name: string): ChannelAdapter | null;
105
154
  /** Get the world for an instance */
@@ -118,10 +167,31 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
118
167
  bindInstanceAdapter(name: string, adapterId: string, fromInbound?: boolean): void;
119
168
  getInstanceStatus(name: string): "running" | "paused" | "stopped" | "crashed";
120
169
  getInstanceExecutionState(name: string): InstanceState | null;
170
+ isClassicInstance(name: string): boolean;
121
171
  private cacheInstanceExecutionState;
122
- /** Single delivery facade: wake an auto-paused CLI before sending to daemon IPC. */
123
- deliverToInstance(instanceName: string, payload: Record<string, unknown>): Promise<void>;
172
+ private cacheInstanceProcessStatus;
173
+ /**
174
+ * Fleet-wide warm cap: if more than `defaults.warm_cap` instances are running,
175
+ * auto-pause the least-recently-active idle instances until back at the cap.
176
+ * Never evicts general instances (must stay warm) or working/stuck instances
177
+ * (only idle). 0/unset = unlimited. wake-before-deliver re-warms any evicted
178
+ * instance when a message next arrives.
179
+ *
180
+ * @param exclude instance to spare (e.g. one just woken to receive a delivery).
181
+ */
182
+ private enforceWarmCap;
183
+ private waitForInstanceIdle;
184
+ private deliverWithIdleGate;
185
+ /** Single delivery facade: wake paused CLIs and serialize non-user work behind idle. */
186
+ deliverToInstance(instanceName: string, payload: Record<string, unknown>, options?: DeliveryOptions): Promise<void>;
187
+ /** Fleet admin is an explicit config allowlist entry, not merely an open/paired user. */
188
+ isFleetAdmin(userId: string, adapterId?: string): boolean;
189
+ changeInstancePauseState(name: string, action: "pause" | "wake"): Promise<"paused" | "awake" | "not_idle">;
190
+ /** Apply a Settings edit to a ClassicBot channel without waiting for the poller. */
191
+ restartClassicInstanceFromSettings(instanceName: string): Promise<void>;
124
192
  startInstance(name: string, config: InstanceConfig, topicMode: boolean): Promise<void>;
193
+ /** Recreate a daemon for a marker-only paused instance after an explicit wake/delivery. */
194
+ startPersistedPausedInstance(name: string): Promise<void>;
125
195
  /**
126
196
  * Start instances with configurable concurrency and stagger delay.
127
197
  * Instances sharing the same working_directory are serialized within a group
@@ -131,7 +201,16 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
131
201
  private startInstancesWithConcurrency;
132
202
  stopInstance(name: string): Promise<void>;
133
203
  /** Restart a single instance, reloading fleet.yaml first to pick up config changes. */
134
- restartSingleInstance(name: string): Promise<void>;
204
+ restartSingleInstance(name: string, opts?: {
205
+ freshStart?: boolean;
206
+ }): Promise<void>;
207
+ /**
208
+ * Mark an instance so its next daemon start skips session resume. Written AFTER
209
+ * stop (survives the old daemon's cleanup) and BEFORE start so the respawn reads
210
+ * it — reuses the crash-state → resumeDisabled path from crash-loop recovery.
211
+ * One-shot: the daemon deletes it on startup.
212
+ */
213
+ private writeFreshStartMarker;
135
214
  /** Load .env file from data dir into process.env */
136
215
  private loadEnvFile;
137
216
  /** Start all instances from fleet config */
@@ -203,8 +282,12 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
203
282
  private botUserId;
204
283
  /** Periodically check if bound topics still exist */
205
284
  private startTopicCleanupPoller;
206
- /** Save fleet config back to fleet.yaml */
207
- saveFleetConfig(): void;
285
+ /**
286
+ * Patch only values changed in the effective config into the original YAML
287
+ * document. Unknown keys, explicit overrides and comments remain untouched.
288
+ */
289
+ saveFleetConfig(explicitPatches?: RawConfigPatch[]): void;
290
+ private patchFleetDocument;
208
291
  removeInstance(name: string): Promise<void>;
209
292
  startStatuslineWatcher(name: string): void;
210
293
  stopStatuslineWatcher(name: string): void;
@@ -266,7 +349,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
266
349
  id: string;
267
350
  title: string;
268
351
  }>;
269
- sendHangNotification(instanceName: string): Promise<void>;
352
+ sendHangNotification(instanceName: string, unchangedForMs?: number): Promise<void>;
270
353
  private static INSTRUCTIONS_FILENAME;
271
354
  private static GENERAL_INSTRUCTIONS;
272
355
  /** Ensure the general instance has its project instructions file + knowledge */
@@ -289,12 +372,50 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
289
372
  private forwardToClassicInstance;
290
373
  /** Paste raw text directly to a classic instance's CLI (no [user:] wrapping) */
291
374
  private pasteRawToClassicInstance;
375
+ /** Resolve the backend name configured for an instance (fleet or classic). */
376
+ private backendNameForInstance;
377
+ private cliEnvPath;
378
+ /** Read the cached CLI env for a backend, or null if missing/stale/unparseable. */
379
+ private readCliEnv;
380
+ /** Resolve the model currently configured for a fleet or ClassicBot instance. */
381
+ private currentModelForInstance;
382
+ private modelChoiceLabel;
383
+ /** Probe one backend's CLI env and cache it. Best-effort; never throws. */
384
+ private probeBackend;
385
+ /** Background-probe every distinct backend in use at startup (non-blocking). */
386
+ private probeCliEnvs;
387
+ /** Best-effort model list for `/model`: cached CLI env first, else live probe. Never throws. */
388
+ private getModelOptions;
389
+ /** `/model` slash handler (admin only). No arg → DC menu; `/model <name>` → apply directly. */
390
+ private handleModelSlash;
391
+ /**
392
+ * Show a TG inline-keyboard model-selection menu. Reuses the same
393
+ * pendingModelSelects coordinator as the DC Select Menu path.
394
+ * Returns null on success (menu shown), or a fallback string to send.
395
+ */
396
+ promptModelMenu(instanceName: string, userId: string, channelId: string, adapter: ChannelAdapter, chatId: string, threadId?: string): Promise<string | null>;
397
+ /** Consume a `/model` selection callback. Returns true for all model-select ids (incl. stale). */
398
+ private handleModelSelection;
399
+ /** Apply a model to an instance: runtime paste (claude-code) or persist + restart (others). */
400
+ applyModel(instanceName: string, model: string): Promise<string>;
292
401
  /** Read recent chat log for agent context */
293
402
  private getRecentChatLog;
403
+ /** Return a user-facing blocker without mutating ClassicBot state. */
404
+ private validateClassicStart;
405
+ private isBackendInstalled;
406
+ private getMissingBackendWarning;
407
+ /** Handle Discord's required static slash choice, warning before a likely startup failure. */
408
+ private handleClassicStartSlash;
409
+ /** Present platform-native backend choices, then start on selection or timeout. */
410
+ private beginClassicBackendSelection;
411
+ /** Consume a selection callback. Returns true for all ClassicBot callback IDs, including stale ones. */
412
+ private handleClassicBackendSelection;
413
+ /** Atomically claim one pending request so timeout/click races create at most one instance. */
414
+ private finishClassicBackendSelection;
294
415
  /** Start a classic channel instance with lightweight config */
295
416
  private startClassicInstance;
296
417
  /** Handle /start slash command — register classic channel */
297
- handleClassicStart(channelId: string, channelName: string, userId: string, guildId?: string, adapterId?: string): Promise<string>;
418
+ handleClassicStart(channelId: string, channelName: string, userId: string, guildId?: string, adapterId?: string, backend?: string): Promise<string>;
298
419
  /** Handle /stop slash command — unregister classic channel */
299
420
  handleClassicStop(channelId: string, adapterId?: string): Promise<string>;
300
421
  stopAll(): Promise<void>;