@aion0/forge 0.5.35 → 0.5.37

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/RELEASE_NOTES.md CHANGED
@@ -1,14 +1,11 @@
1
- # Forge v0.5.35
1
+ # Forge v0.5.37
2
2
 
3
3
  Released: 2026-04-11
4
4
 
5
- ## Changes since v0.5.34
5
+ ## Changes since v0.5.36
6
6
 
7
- ### Features
8
- - feat: workspace UX refresh, bell, lock, mouse, terminal layout
7
+ ### Performance
8
+ - perf: prune bus log to prevent unbounded growth
9
9
 
10
- ### Other
11
- - feat(telegram): /i inject command for direct terminal input
12
10
 
13
-
14
- **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.5.34...v0.5.35
11
+ **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.5.36...v0.5.37
@@ -3,12 +3,12 @@ import { loadSettings } from '@/lib/settings';
3
3
  import { addNotification } from '@/lib/notifications';
4
4
 
5
5
  export async function POST(req: Request) {
6
- const { tabLabel } = await req.json();
6
+ const { tabLabel, source } = await req.json();
7
7
  const label = tabLabel || 'Terminal';
8
8
 
9
- // Check settings — terminal bell notifications can be disabled
9
+ // Check settings — terminal bell can be disabled (but workspace smith bells always go through)
10
10
  const settings = loadSettings();
11
- if ((settings as any).terminalBellEnabled === false) {
11
+ if ((settings as any).terminalBellEnabled === false && source !== 'workspace') {
12
12
  return NextResponse.json({ ok: true, skipped: true });
13
13
  }
14
14
 
@@ -2025,11 +2025,11 @@ function fireSmithBell(label: string, status: 'done' | 'failed') {
2025
2025
  if (typeof Notification !== 'undefined' && Notification.permission === 'granted') {
2026
2026
  new Notification(title, { body, icon: '/icon.png' });
2027
2027
  }
2028
- // Telegram + in-app via API (reuse terminal-bell endpoint)
2028
+ // Telegram + in-app via API (reuse terminal-bell endpoint, marked as workspace source)
2029
2029
  fetch('/api/terminal-bell', {
2030
2030
  method: 'POST',
2031
2031
  headers: { 'Content-Type': 'application/json' },
2032
- body: JSON.stringify({ tabLabel: `${label} (${status})` }),
2032
+ body: JSON.stringify({ tabLabel: `${label} (${status})`, source: 'workspace' }),
2033
2033
  }).catch(() => {});
2034
2034
  }
2035
2035
 
@@ -63,6 +63,7 @@ export class AgentBus extends EventEmitter {
63
63
  };
64
64
 
65
65
  this.log.push(msg);
66
+ this.pruneIfNeeded();
66
67
  this.emit('message', msg);
67
68
 
68
69
  // ACK messages don't need delivery tracking
@@ -350,6 +351,35 @@ export class AgentBus extends EventEmitter {
350
351
  if (count > 0) console.log(`[bus] Marked ${count} pending messages as failed (restart cleanup)`);
351
352
  }
352
353
 
354
+ // ─── Log maintenance ───────────────────────────────────
355
+
356
+ private static readonly MAX_LOG_SIZE = 500;
357
+ private static readonly PRUNE_KEEP = 200;
358
+
359
+ /** Prune completed messages to prevent unbounded log growth.
360
+ * Keeps: all pending/running messages + last N completed ones.
361
+ * Called automatically after each send(). */
362
+ private pruneIfNeeded(): void {
363
+ if (this.log.length <= AgentBus.MAX_LOG_SIZE) return;
364
+
365
+ // Separate active (must keep) from completed (can prune)
366
+ const active: BusMessage[] = [];
367
+ const completed: BusMessage[] = [];
368
+ for (const m of this.log) {
369
+ if (m.status === 'pending' || m.status === 'pending_approval' || m.status === 'running') {
370
+ active.push(m);
371
+ } else {
372
+ completed.push(m);
373
+ }
374
+ }
375
+
376
+ // Keep all active + most recent N completed
377
+ const keep = completed.slice(-AgentBus.PRUNE_KEEP);
378
+ this.log = [...active, ...keep].sort((a, b) => a.timestamp - b.timestamp);
379
+ const pruned = completed.length - keep.length;
380
+ if (pruned > 0) console.log(`[bus] Pruned ${pruned} completed messages (${this.log.length} remaining)`);
381
+ }
382
+
353
383
  // ─── Query ─────────────────────────────────────────────
354
384
 
355
385
  getMessagesFor(agentId: string): BusMessage[] {
@@ -374,6 +404,11 @@ export class AgentBus extends EventEmitter {
374
404
  return this.log;
375
405
  }
376
406
 
407
+ /** Get log for persistence — excludes _system messages (transient notifications) */
408
+ getLogForPersistence(): BusMessage[] {
409
+ return this.log.filter(m => m.to !== '_system');
410
+ }
411
+
377
412
  /** Get all outbox queues (for persistence) */
378
413
  getAllOutbox(): Record<string, BusMessage[]> {
379
414
  const result: Record<string, BusMessage[]> = {};
@@ -385,6 +420,7 @@ export class AgentBus extends EventEmitter {
385
420
 
386
421
  loadLog(messages: BusMessage[]): void {
387
422
  this.log = [...messages];
423
+ this.pruneIfNeeded();
388
424
  }
389
425
 
390
426
  /** Restore outbox from persisted state */
@@ -1870,7 +1870,7 @@ export class WorkspaceOrchestrator extends EventEmitter {
1870
1870
  agents: Array.from(this.agents.values()).map(e => e.config),
1871
1871
  agentStates: this.getAllAgentStates(),
1872
1872
  nodePositions: this.nodePositions,
1873
- busLog: [...this.bus.getLog()],
1873
+ busLog: this.bus.getLogForPersistence(),
1874
1874
  busOutbox: this.bus.getAllOutbox(),
1875
1875
  createdAt: this.createdAt,
1876
1876
  updatedAt: Date.now(),
package/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/dev/types/routes.d.ts";
3
+ import "./.next/types/routes.d.ts";
4
4
 
5
5
  // NOTE: This file should not be edited
6
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aion0/forge",
3
- "version": "0.5.35",
3
+ "version": "0.5.37",
4
4
  "description": "Unified AI workflow platform — multi-model task orchestration, persistent sessions, web terminal, remote access",
5
5
  "type": "module",
6
6
  "scripts": {