instar 0.28.77 → 0.28.78

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 (46) hide show
  1. package/dashboard/index.html +184 -4
  2. package/dist/commands/server.d.ts.map +1 -1
  3. package/dist/commands/server.js +46 -2
  4. package/dist/commands/server.js.map +1 -1
  5. package/dist/monitoring/TokenLedger.d.ts +39 -0
  6. package/dist/monitoring/TokenLedger.d.ts.map +1 -1
  7. package/dist/monitoring/TokenLedger.js +110 -13
  8. package/dist/monitoring/TokenLedger.js.map +1 -1
  9. package/dist/monitoring/TokenLedgerPoller.d.ts.map +1 -1
  10. package/dist/monitoring/TokenLedgerPoller.js +8 -8
  11. package/dist/monitoring/TokenLedgerPoller.js.map +1 -1
  12. package/dist/server/AgentServer.d.ts +4 -0
  13. package/dist/server/AgentServer.d.ts.map +1 -1
  14. package/dist/server/AgentServer.js +14 -1
  15. package/dist/server/AgentServer.js.map +1 -1
  16. package/dist/server/routes.d.ts +8 -1
  17. package/dist/server/routes.d.ts.map +1 -1
  18. package/dist/server/routes.js +98 -0
  19. package/dist/server/routes.js.map +1 -1
  20. package/dist/threadline/BackfillCore.d.ts +70 -0
  21. package/dist/threadline/BackfillCore.d.ts.map +1 -0
  22. package/dist/threadline/BackfillCore.js +117 -0
  23. package/dist/threadline/BackfillCore.js.map +1 -0
  24. package/dist/threadline/ListenerSessionManager.d.ts +35 -0
  25. package/dist/threadline/ListenerSessionManager.d.ts.map +1 -1
  26. package/dist/threadline/ListenerSessionManager.js +41 -0
  27. package/dist/threadline/ListenerSessionManager.js.map +1 -1
  28. package/dist/threadline/TelegramBridge.d.ts +140 -0
  29. package/dist/threadline/TelegramBridge.d.ts.map +1 -0
  30. package/dist/threadline/TelegramBridge.js +224 -0
  31. package/dist/threadline/TelegramBridge.js.map +1 -0
  32. package/dist/threadline/ThreadlineMCPServer.d.ts.map +1 -1
  33. package/dist/threadline/ThreadlineMCPServer.js +5 -0
  34. package/dist/threadline/ThreadlineMCPServer.js.map +1 -1
  35. package/dist/threadline/ThreadlineObservability.d.ts +95 -0
  36. package/dist/threadline/ThreadlineObservability.d.ts.map +1 -0
  37. package/dist/threadline/ThreadlineObservability.js +310 -0
  38. package/dist/threadline/ThreadlineObservability.js.map +1 -0
  39. package/package.json +1 -1
  40. package/scripts/threadline-bridge-backfill.mjs +379 -0
  41. package/src/data/builtin-manifest.json +47 -47
  42. package/upgrades/0.28.78.md +90 -0
  43. package/upgrades/side-effects/threadline-bridge-backfill.md +203 -0
  44. package/upgrades/side-effects/threadline-observability-tab.md +206 -0
  45. package/upgrades/side-effects/threadline-tg-bridge-module.md +196 -0
  46. package/upgrades/side-effects/token-ledger-bounded-scan.md +230 -0
@@ -2946,9 +2946,34 @@
2946
2946
  <div id="tlBridgeError" style="color:var(--err, #c44);font-size:12px;display:none"></div>
2947
2947
  </div>
2948
2948
 
2949
- <!-- Future home of the conversation observability view (deliverable 4) -->
2950
- <div style="border:1px dashed var(--border);border-radius:8px;padding:16px;font-size:12px;color:var(--text-dim);line-height:1.5">
2951
- The conversation observability view — threads list, color-coded message stream, latency metrics, FTS search — lands here in a follow-up. The settings above ship now so the bridge stays quiet by default once it goes live.
2949
+ <!-- Conversation observability threads list + message stream + search -->
2950
+ <div style="border:1px solid var(--border);border-radius:8px;padding:0;display:flex;flex-direction:column;min-height:480px">
2951
+ <!-- Toolbar -->
2952
+ <div style="display:flex;gap:8px;align-items:center;padding:12px 16px;border-bottom:1px solid var(--border)">
2953
+ <div style="font-weight:600">Conversations</div>
2954
+ <div style="flex:1"></div>
2955
+ <input type="search" id="tlObsSearchInput" placeholder="search messages…" style="padding:6px 8px;font-size:12px;width:220px" oninput="tlObsSearchDebounced(this.value)" />
2956
+ <select id="tlObsHasTopicFilter" onchange="tlObsLoadThreads()" style="padding:6px 8px;font-size:12px">
2957
+ <option value="">all threads</option>
2958
+ <option value="yes">with Telegram topic</option>
2959
+ <option value="no">without Telegram topic</option>
2960
+ </select>
2961
+ <input type="text" id="tlObsRemoteFilter" placeholder="agent filter" style="padding:6px 8px;font-size:12px;width:140px" oninput="tlObsLoadThreadsDebounced()" />
2962
+ <button onclick="tlObsLoadThreads()" style="padding:6px 10px;font-size:12px">Refresh</button>
2963
+ </div>
2964
+
2965
+ <!-- Two-pane: threads list + active thread -->
2966
+ <div style="display:grid;grid-template-columns:280px 1fr;flex:1;min-height:420px">
2967
+ <ul id="tlObsThreadsList" style="list-style:none;padding:0;margin:0;border-right:1px solid var(--border);overflow-y:auto;max-height:520px">
2968
+ <li style="padding:16px;color:var(--text-dim);font-size:12px">Loading…</li>
2969
+ </ul>
2970
+ <div id="tlObsConversation" style="padding:16px;overflow-y:auto;max-height:520px;display:flex;flex-direction:column;gap:10px">
2971
+ <div style="color:var(--text-dim);font-size:12px;font-style:italic">Select a thread on the left to view the conversation.</div>
2972
+ </div>
2973
+ </div>
2974
+
2975
+ <!-- Search results -->
2976
+ <div id="tlObsSearchResults" style="display:none;border-top:1px solid var(--border);padding:12px 16px;max-height:280px;overflow-y:auto"></div>
2952
2977
  </div>
2953
2978
  </div>
2954
2979
 
@@ -4008,7 +4033,10 @@
4008
4033
  id: 'threadline',
4009
4034
  panels: ['threadlineTab'],
4010
4035
  display: ['flex'],
4011
- onActivate: () => { if (typeof loadThreadlineBridgeConfig === 'function') loadThreadlineBridgeConfig(); },
4036
+ onActivate: () => {
4037
+ if (typeof loadThreadlineBridgeConfig === 'function') loadThreadlineBridgeConfig();
4038
+ if (typeof tlObsLoadThreads === 'function') tlObsLoadThreads();
4039
+ },
4012
4040
  },
4013
4041
  {
4014
4042
  id: 'secrets',
@@ -4303,6 +4331,158 @@
4303
4331
  wire('tlBridgeMirrorExisting', 'mirrorExisting');
4304
4332
  });
4305
4333
 
4334
+ // ── Threadline observability — threads list + conversation view ──
4335
+ let tlObsActiveThreadId = null;
4336
+ let tlObsLoadThreadsTimer = null;
4337
+ let tlObsSearchTimer = null;
4338
+
4339
+ function tlObsLoadThreadsDebounced() {
4340
+ if (tlObsLoadThreadsTimer) clearTimeout(tlObsLoadThreadsTimer);
4341
+ tlObsLoadThreadsTimer = setTimeout(tlObsLoadThreads, 300);
4342
+ }
4343
+
4344
+ function tlObsSearchDebounced(value) {
4345
+ if (tlObsSearchTimer) clearTimeout(tlObsSearchTimer);
4346
+ tlObsSearchTimer = setTimeout(() => tlObsRunSearch(value), 300);
4347
+ }
4348
+
4349
+ async function tlObsLoadThreads() {
4350
+ const list = document.getElementById('tlObsThreadsList');
4351
+ if (!list) return;
4352
+ const remoteAgent = document.getElementById('tlObsRemoteFilter')?.value?.trim() || '';
4353
+ const hasTopic = document.getElementById('tlObsHasTopicFilter')?.value || '';
4354
+ const params = new URLSearchParams();
4355
+ if (remoteAgent) params.set('remoteAgent', remoteAgent);
4356
+ if (hasTopic) params.set('hasTopic', hasTopic);
4357
+ try {
4358
+ const resp = await apiFetch('/threadline/observability/threads?' + params.toString());
4359
+ const threads = resp.threads || [];
4360
+ if (threads.length === 0) {
4361
+ list.innerHTML = '<li style="padding:16px;color:var(--text-dim);font-size:12px;font-style:italic">No threads yet.</li>';
4362
+ return;
4363
+ }
4364
+ list.innerHTML = threads.map(t => tlObsRenderThreadRow(t)).join('');
4365
+ } catch (err) {
4366
+ list.innerHTML = `<li style="padding:16px;color:var(--red)">Error: ${escapeHtml(err.message || String(err))}</li>`;
4367
+ }
4368
+ }
4369
+
4370
+ function tlObsRenderThreadRow(t) {
4371
+ const lastSeen = t.lastSeen ? fmtRelTime(t.lastSeen) : '—';
4372
+ const bridgeBadge = t.bridge
4373
+ ? '<span style="display:inline-block;padding:1px 6px;border-radius:8px;background:#3b82f6;color:#fff;font-size:10px;margin-left:6px">TG</span>'
4374
+ : '';
4375
+ const spawnBadge = t.hasSpawnedSession
4376
+ ? '<span style="display:inline-block;padding:1px 6px;border-radius:8px;background:#16a34a;color:#fff;font-size:10px;margin-left:4px">S</span>'
4377
+ : '';
4378
+ const isActive = tlObsActiveThreadId === t.threadId ? 'background:rgba(59,130,246,0.08);' : '';
4379
+ return `
4380
+ <li onclick="tlObsLoadThread('${t.threadId.replace(/'/g, "\\'")}')"
4381
+ style="padding:10px 12px;border-bottom:1px solid var(--border);cursor:pointer;${isActive}">
4382
+ <div style="display:flex;justify-content:space-between;align-items:center">
4383
+ <div style="font-weight:600;font-size:13px">${escapeHtml(t.remoteAgentName)}${bridgeBadge}${spawnBadge}</div>
4384
+ <div style="font-size:11px;color:var(--text-dim)">${escapeHtml(lastSeen)}</div>
4385
+ </div>
4386
+ <div style="font-size:11px;color:var(--text-dim);margin-top:2px;font-family:monospace">
4387
+ ${escapeHtml(t.threadId.slice(0, 16))}…
4388
+ </div>
4389
+ <div style="font-size:11px;color:var(--text-dim);margin-top:2px">
4390
+ ${t.messageCount} msgs · ${t.inboundCount} in / ${t.outboundCount} out
4391
+ ${typeof t.avgResponseLatencyMs === 'number' ? ' · ~' + Math.round(t.avgResponseLatencyMs / 1000) + 's reply' : ''}
4392
+ </div>
4393
+ </li>
4394
+ `;
4395
+ }
4396
+
4397
+ async function tlObsLoadThread(threadId) {
4398
+ tlObsActiveThreadId = threadId;
4399
+ tlObsLoadThreads(); // Re-render threads list to highlight active row
4400
+ const conv = document.getElementById('tlObsConversation');
4401
+ if (!conv) return;
4402
+ conv.innerHTML = '<div style="color:var(--text-dim);font-size:12px">Loading…</div>';
4403
+ try {
4404
+ const detail = await apiFetch(`/threadline/observability/threads/${encodeURIComponent(threadId)}`);
4405
+ conv.innerHTML = tlObsRenderConversation(detail);
4406
+ } catch (err) {
4407
+ conv.innerHTML = `<div style="color:var(--red);font-size:12px">Error: ${escapeHtml(err.message || String(err))}</div>`;
4408
+ }
4409
+ }
4410
+
4411
+ function tlObsRenderConversation(detail) {
4412
+ const header = `
4413
+ <div style="border-bottom:1px solid var(--border);padding-bottom:10px;margin-bottom:10px">
4414
+ <div style="font-weight:600;font-size:14px">${escapeHtml(detail.remoteAgentName)}</div>
4415
+ <div style="font-family:monospace;font-size:11px;color:var(--text-dim)">${escapeHtml(detail.threadId)}</div>
4416
+ <div style="display:flex;gap:14px;font-size:11px;color:var(--text-dim);margin-top:6px;flex-wrap:wrap">
4417
+ <span>${detail.messageCount} messages</span>
4418
+ <span>${detail.inboundCount} in / ${detail.outboundCount} out</span>
4419
+ <span>first: ${escapeHtml(fmtRelTime(detail.firstSeen))}</span>
4420
+ <span>last: ${escapeHtml(fmtRelTime(detail.lastSeen))}</span>
4421
+ ${typeof detail.avgResponseLatencyMs === 'number' ? '<span>avg reply: ' + Math.round(detail.avgResponseLatencyMs/1000) + 's</span>' : ''}
4422
+ ${detail.bridge ? '<span>📨 topic ' + detail.bridge.topicId + '</span>' : '<span style="color:var(--text-dim);font-style:italic">no Telegram topic</span>'}
4423
+ ${detail.hasSpawnedSession ? '<span>🧵 spawn-session</span>' : ''}
4424
+ </div>
4425
+ </div>
4426
+ `;
4427
+ const messages = (detail.messages || []).map(m => tlObsRenderMessage(m)).join('');
4428
+ return header + messages;
4429
+ }
4430
+
4431
+ function tlObsRenderMessage(m) {
4432
+ const isIn = m.direction === 'in';
4433
+ const bg = isIn ? 'rgba(99,102,241,0.10)' : 'rgba(34,197,94,0.10)';
4434
+ const border = isIn ? '#6366f1' : '#22c55e';
4435
+ const arrow = isIn ? '←' : '→';
4436
+ const meta = `${escapeHtml(m.timestamp)} · ${escapeHtml(m.id.slice(0, 8))}${m.outcome ? ' · ' + escapeHtml(m.outcome) : ''} · trust:${escapeHtml(m.trustLevel)}`;
4437
+ return `
4438
+ <div style="border-left:3px solid ${border};background:${bg};padding:8px 10px;border-radius:4px">
4439
+ <div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:4px">
4440
+ <div style="font-weight:600;font-size:12px">
4441
+ ${arrow} ${escapeHtml(m.remoteAgentName)}
4442
+ </div>
4443
+ <div style="font-size:11px;color:var(--text-dim)">${escapeHtml(fmtRelTime(m.timestamp))}</div>
4444
+ </div>
4445
+ <div style="font-size:13px;white-space:pre-wrap;word-break:break-word;line-height:1.4">${escapeHtml(m.text)}</div>
4446
+ <div style="font-family:monospace;font-size:10px;color:var(--text-dim);margin-top:4px">${meta}</div>
4447
+ </div>
4448
+ `;
4449
+ }
4450
+
4451
+ async function tlObsRunSearch(query) {
4452
+ const panel = document.getElementById('tlObsSearchResults');
4453
+ if (!panel) return;
4454
+ const q = (query || '').trim();
4455
+ if (!q) { panel.style.display = 'none'; return; }
4456
+ panel.style.display = 'block';
4457
+ panel.innerHTML = '<div style="color:var(--text-dim);font-size:12px">Searching…</div>';
4458
+ try {
4459
+ const resp = await apiFetch('/threadline/observability/search?q=' + encodeURIComponent(q) + '&limit=30');
4460
+ const hits = resp.hits || [];
4461
+ if (hits.length === 0) {
4462
+ panel.innerHTML = '<div style="color:var(--text-dim);font-size:12px">No matches.</div>';
4463
+ return;
4464
+ }
4465
+ panel.innerHTML = `<div style="font-size:12px;color:var(--text-dim);margin-bottom:8px">${hits.length} match${hits.length === 1 ? '' : 'es'} (click to open thread)</div>` +
4466
+ hits.map(h => `
4467
+ <div onclick="tlObsLoadThread('${h.message.threadId.replace(/'/g, "\\'")}')"
4468
+ style="padding:6px 8px;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
4469
+ <div style="display:flex;justify-content:space-between">
4470
+ <span style="font-weight:600">${h.message.direction === 'in' ? '←' : '→'} ${escapeHtml(h.message.remoteAgentName)}</span>
4471
+ <span style="font-size:11px;color:var(--text-dim)">${escapeHtml(fmtRelTime(h.message.timestamp))}</span>
4472
+ </div>
4473
+ <div style="margin-top:2px;line-height:1.4">${tlObsRenderSnippet(h.snippet)}</div>
4474
+ </div>
4475
+ `).join('');
4476
+ } catch (err) {
4477
+ panel.innerHTML = `<div style="color:var(--red);font-size:12px">Error: ${escapeHtml(err.message || String(err))}</div>`;
4478
+ }
4479
+ }
4480
+
4481
+ function tlObsRenderSnippet(s) {
4482
+ // Server returns matches wrapped in «...» — render as <mark>
4483
+ return escapeHtml(s).replace(/«/g, '<mark style="background:#fef08a;color:#000">').replace(/»/g, '</mark>');
4484
+ }
4485
+
4306
4486
  async function loadFileTree() {
4307
4487
  fileTreeLoaded = true;
4308
4488
  const list = document.getElementById('fileTreeList');
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAg4CD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8qJtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAg4CD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6tJtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
@@ -1476,10 +1476,21 @@ export async function startServer(options) {
1476
1476
  });
1477
1477
  liveConfig.start();
1478
1478
  // Threadline → Telegram bridge config — settings surface for the bridge
1479
- // module (deliverable b). Default-OFF auto-create ships from day one;
1479
+ // module. Default-OFF auto-create ships from day one;
1480
1480
  // see TelegramBridgeConfig for the policy.
1481
1481
  const { TelegramBridgeConfig } = await import('../threadline/TelegramBridgeConfig.js');
1482
1482
  const telegramBridgeConfig = new TelegramBridgeConfig(liveConfig);
1483
+ // The actual bridge module is instantiated AFTER the Telegram adapter is
1484
+ // wired (further down in this file). Held as a let so closures formed
1485
+ // here can reference whatever instance ends up assigned. Bridge is
1486
+ // RELAY-ONLY (signal-vs-authority compliant): emits no routing decisions,
1487
+ // blocks nothing. Authority lives in TelegramBridgeConfig.
1488
+ let telegramBridge = null;
1489
+ // Read-only observability layer over canonical inbox/outbox/bindings.
1490
+ // Stateless — reads files at every query. Powers the dashboard
1491
+ // Threadline tab via /threadline/observability/* endpoints.
1492
+ const { ThreadlineObservability } = await import('../threadline/ThreadlineObservability.js');
1493
+ const threadlineObservability = new ThreadlineObservability({ stateDir: config.stateDir });
1483
1494
  // NotificationBatcher: consolidate all Telegram notifications into tiered delivery.
1484
1495
  // IMMEDIATE = user needs to act NOW (quota exhausted, critical stall)
1485
1496
  // SUMMARY = batched every 30 min (degradations, coherence, orphan reports)
@@ -2213,6 +2224,23 @@ export async function startServer(options) {
2213
2224
  telegram.intelligence = sharedIntelligence ?? null;
2214
2225
  await telegram.start();
2215
2226
  console.log(pc.green(` Telegram connected (stall alerts: ${sharedIntelligence ? 'LLM-gated' : 'timer-only'})`));
2227
+ // Threadline → Telegram bridge — mirrors inbound/outbound threadline
2228
+ // messages into per-thread Telegram topics. Default-OFF; the relay
2229
+ // handler below and the threadline_send tool consult bridge.mirror*
2230
+ // unconditionally — TelegramBridgeConfig owns the gate.
2231
+ try {
2232
+ const { TelegramBridge } = await import('../threadline/TelegramBridge.js');
2233
+ telegramBridge = new TelegramBridge({
2234
+ stateDir: config.stateDir,
2235
+ localAgentName: config.projectName,
2236
+ config: telegramBridgeConfig,
2237
+ telegram,
2238
+ });
2239
+ console.log(pc.dim(` Threadline → Telegram bridge: armed (default ${telegramBridgeConfig.getSettings().enabled ? 'ENABLED' : 'OFF'})`));
2240
+ }
2241
+ catch (err) {
2242
+ console.warn(pc.yellow(` Threadline → Telegram bridge init failed (non-fatal): ${err instanceof Error ? err.message : err}`));
2243
+ }
2216
2244
  // Wire Prompt Gate callbacks — connect Telegram relay responses to sessions
2217
2245
  if (promptGateConfig?.enabled) {
2218
2246
  telegram.onPromptResponse = (sessionName, key) => {
@@ -5301,6 +5329,22 @@ export async function startServer(options) {
5301
5329
  console.warn(`[relay] Canonical inbox append failed (non-fatal): ${err instanceof Error ? err.message : err}`);
5302
5330
  }
5303
5331
  }
5332
+ // Threadline → Telegram bridge: mirror inbound message into a per-thread
5333
+ // Telegram topic so the user has visibility into agent-to-agent
5334
+ // conversations. Relay-only — TelegramBridgeConfig owns the gate
5335
+ // (default-OFF; allow/deny list determines auto-create). Async,
5336
+ // non-awaited, and never blocks routing or throws to this handler.
5337
+ if (telegramBridge) {
5338
+ telegramBridge
5339
+ .mirrorInbound({
5340
+ threadId: msg.threadId ?? getSyntheticThreadId(senderFingerprint),
5341
+ remoteAgent: senderFingerprint,
5342
+ remoteAgentName: senderName,
5343
+ text: textContent,
5344
+ messageId: msg.messageId,
5345
+ })
5346
+ .catch(err => console.warn(`[tg-bridge] mirrorInbound: ${err instanceof Error ? err.message : err}`));
5347
+ }
5304
5348
  // Phase 2a: Pipe-mode session for simple queries (lightweight, auto-exit)
5305
5349
  // Rapid-fire same-thread guard: if an active pipe session already exists for this
5306
5350
  // thread, fall through to the listener/cold-spawn path so messages queue serially
@@ -5591,7 +5635,7 @@ export async function startServer(options) {
5591
5635
  }
5592
5636
  const { InitiativeTracker } = await import('../core/InitiativeTracker.js');
5593
5637
  const initiativeTracker = new InitiativeTracker(config.stateDir);
5594
- const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, proxyCoordinator, telegramBridgeConfig });
5638
+ const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, proxyCoordinator, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability });
5595
5639
  await server.start();
5596
5640
  // Connect DegradationReporter downstream systems now that everything is initialized.
5597
5641
  // Any degradation events queued during startup will drain to feedback + telegram.