instar 1.2.81 → 1.2.83

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 (53) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +110 -11
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +23 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/PostUpdateMigrator.d.ts +7 -0
  8. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  9. package/dist/core/PostUpdateMigrator.js +59 -75
  10. package/dist/core/PostUpdateMigrator.js.map +1 -1
  11. package/dist/core/SessionManager.d.ts +43 -0
  12. package/dist/core/SessionManager.d.ts.map +1 -1
  13. package/dist/core/SessionManager.js +123 -24
  14. package/dist/core/SessionManager.js.map +1 -1
  15. package/dist/core/types.d.ts +26 -0
  16. package/dist/core/types.d.ts.map +1 -1
  17. package/dist/core/types.js.map +1 -1
  18. package/dist/monitoring/SessionReaper.d.ts +153 -0
  19. package/dist/monitoring/SessionReaper.d.ts.map +1 -0
  20. package/dist/monitoring/SessionReaper.js +376 -0
  21. package/dist/monitoring/SessionReaper.js.map +1 -0
  22. package/dist/monitoring/TokenLedger.d.ts +12 -0
  23. package/dist/monitoring/TokenLedger.d.ts.map +1 -1
  24. package/dist/monitoring/TokenLedger.js +22 -0
  25. package/dist/monitoring/TokenLedger.js.map +1 -1
  26. package/dist/monitoring/transcriptProber.d.ts +44 -0
  27. package/dist/monitoring/transcriptProber.d.ts.map +1 -0
  28. package/dist/monitoring/transcriptProber.js +57 -0
  29. package/dist/monitoring/transcriptProber.js.map +1 -0
  30. package/dist/scaffold/templates.d.ts.map +1 -1
  31. package/dist/scaffold/templates.js +21 -0
  32. package/dist/scaffold/templates.js.map +1 -1
  33. package/dist/server/AgentServer.d.ts +3 -0
  34. package/dist/server/AgentServer.d.ts.map +1 -1
  35. package/dist/server/AgentServer.js +1 -0
  36. package/dist/server/AgentServer.js.map +1 -1
  37. package/dist/server/routes.d.ts +3 -0
  38. package/dist/server/routes.d.ts.map +1 -1
  39. package/dist/server/routes.js +108 -0
  40. package/dist/server/routes.js.map +1 -1
  41. package/dist/threadline/CollaborationSurfacer.d.ts +67 -18
  42. package/dist/threadline/CollaborationSurfacer.d.ts.map +1 -1
  43. package/dist/threadline/CollaborationSurfacer.js +132 -37
  44. package/dist/threadline/CollaborationSurfacer.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/data/builtin-manifest.json +63 -63
  47. package/src/scaffold/templates.ts +21 -0
  48. package/upgrades/1.2.81.md +13 -0
  49. package/upgrades/1.2.82.md +26 -0
  50. package/upgrades/1.2.83.md +26 -0
  51. package/upgrades/side-effects/1.2.81.md +127 -0
  52. package/upgrades/side-effects/session-reaper.md +42 -0
  53. package/upgrades/side-effects/threadline-notification-routing.md +46 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0QH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiqDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgkMtE;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;AA0QH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiqDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6pMtE;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"}
@@ -4874,6 +4874,12 @@ export async function startServer(options) {
4874
4874
  // is OFF for Telegram by default and, when enabled, coalesces into ONE
4875
4875
  // consolidated message to the existing system topic. No new-topic-per-event.
4876
4876
  // Spec: docs/specs/silently-stopped-trio.md.
4877
+ //
4878
+ // Captured out of the trio block so the SessionReaper's recovery veto can
4879
+ // compose socket + silence in too (SESSION-REAPER-SPEC §4 "compose, don't
4880
+ // replace"). undefined when the corresponding sentinel is disabled.
4881
+ let socketRecoveryActive;
4882
+ let silenceRecoveryActive;
4877
4883
  {
4878
4884
  const { SocketDisconnectSentinel } = await import('../monitoring/SocketDisconnectSentinel.js');
4879
4885
  const { ActiveWorkSilenceSentinel } = await import('../monitoring/ActiveWorkSilenceSentinel.js');
@@ -4926,6 +4932,7 @@ export async function startServer(options) {
4926
4932
  socketSentinel.on('recovered', (n) => notifier.record('recovered', 'socket-disconnect', n));
4927
4933
  socketSentinel.on('recovery-error', (e) => notifier.record('recovery-error', 'socket-disconnect', e.sessionName, e.err instanceof Error ? e.err.message : String(e.err)));
4928
4934
  socketSentinel.start();
4935
+ socketRecoveryActive = (s) => socketSentinel.isRecoveryActive(s);
4929
4936
  console.log(pc.green(' SocketDisconnectSentinel enabled (connection-drop recovery)'));
4930
4937
  }
4931
4938
  const silenceCfg = config.monitoring?.activeWorkSilenceSentinel ?? { enabled: true };
@@ -4939,11 +4946,23 @@ export async function startServer(options) {
4939
4946
  silenceSentinel.on('recovered', (n) => notifier.record('recovered', 'active-silence', n));
4940
4947
  silenceSentinel.on('nudge-error', (e) => notifier.record('nudge-error', 'active-silence', e.sessionName, e.err instanceof Error ? e.err.message : String(e.err)));
4941
4948
  silenceSentinel.start();
4949
+ silenceRecoveryActive = (s) => silenceSentinel.isRecoveryActive(s);
4942
4950
  console.log(pc.green(telegramEscalation
4943
4951
  ? ' ActiveWorkSilenceSentinel enabled (silent-freeze watchdog — Telegram escalation ON, consolidated)'
4944
4952
  : ' ActiveWorkSilenceSentinel enabled (silent-freeze watchdog — logs only, Telegram escalation OFF)'));
4945
4953
  }
4946
4954
  }
4955
+ // Recompose the zombie-kill veto to include ALL four recovery sentinels now
4956
+ // that socket + silence exist (the interim set above covered only compaction
4957
+ // + rate-limit, before those two were constructed). This single composed
4958
+ // predicate is the superset — it drops none — and is reused as the
4959
+ // SessionReaper's recovery gate (G) so the reaper never kills a session any
4960
+ // sentinel is reviving. SESSION-REAPER-SPEC §4 "compose, don't replace".
4961
+ const composedRecoveryActive = (session) => compactionSentinel.isRecoveryActive(session.tmuxSession) ||
4962
+ rateLimitSentinel.isRecoveryActive(session.tmuxSession) ||
4963
+ (socketRecoveryActive?.(session.tmuxSession) ?? false) ||
4964
+ (silenceRecoveryActive?.(session.tmuxSession) ?? false);
4965
+ sessionManager.setActiveRecoveryChecker(composedRecoveryActive);
4947
4966
  // Trigger 1: PreCompact hook event — report to sentinel.
4948
4967
  hookEventReceiver.on('PreCompact', () => {
4949
4968
  // Delay to let compaction + recovery hooks finish
@@ -6632,16 +6651,17 @@ export async function startServer(options) {
6632
6651
  });
6633
6652
  if (decision.suppress) {
6634
6653
  console.log(`[relay] warrants-reply gate suppressed reply (${decision.verdict.signal}) for ${senderName} thread ${gateThreadId.slice(0, 8)}`);
6635
- // On budget exhaustion, escalate ONE attention item — never silently drop.
6636
- if (decision.verdict.budgetExhausted && telegram) {
6637
- telegram.createAttentionItem({
6638
- id: `threadline-loop-${gateThreadId.slice(0, 12)}`,
6639
- title: `Threadline conversation loop wound down (${senderName})`,
6640
- summary: `Stopped auto-replying to an agent-to-agent thread that kept going with no new content.`,
6641
- description: `An agent-to-agent thread with ${senderName} kept exchanging messages with no new content, so I stopped auto-replying to keep it from looping. Thread ${gateThreadId.slice(0, 8)}. Let me know if you want me to re-engage.`,
6642
- category: 'threadline-loop-gate',
6643
- priority: 'LOW',
6644
- }).catch(escErr => console.warn(`[relay] loop-gate attention escalation failed: ${escErr instanceof Error ? escErr.message : escErr}`));
6654
+ // On budget exhaustion, surface ONE status notice — never silently
6655
+ // drop. CMT-519: route it to the SILENT Threadline hub (not a
6656
+ // per-event attention topic, not the parent topic the operator is
6657
+ // working in). This is housekeeping, not a user task.
6658
+ if (decision.verdict.budgetExhausted && collaborationSurfacer) {
6659
+ void collaborationSurfacer.notify({
6660
+ threadId: gateThreadId,
6661
+ title: 'Conversation loop paused',
6662
+ body: `Stopped auto-replying to a thread with ${senderName} that kept going with no new content (thread ${gateThreadId.slice(0, 8)}). Say "re-engage" in this topic if you want me to pick it back up.`,
6663
+ peerName: senderName,
6664
+ }).catch(escErr => console.warn(`[relay] loop-gate hub notice failed: ${escErr instanceof Error ? escErr.message : escErr}`));
6645
6665
  }
6646
6666
  return; // short-circuit ALL three routing branches
6647
6667
  }
@@ -7192,7 +7212,86 @@ export async function startServer(options) {
7192
7212
  },
7193
7213
  });
7194
7214
  }
7195
- 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, rateLimitSentinel, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? 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, conversationStore, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, proxyCoordinator, topicIntentStore, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, workingMemory, taskFlowRegistry, threadlineFlowBridge });
7215
+ // ── SessionReaper (SESSION-REAPER-SPEC) ──────────────────────────────
7216
+ // Pressure-aware reaper of idle-but-alive sessions. Ships OFF + dry-run by
7217
+ // default; the classifier's positive-evidence + confidence-contract is what
7218
+ // guarantees it never reaps a working session. Reuses composedRecoveryActive
7219
+ // (gate G) so it defers to every recovery sentinel. Pressure is freemem-tiered
7220
+ // for v1 (advisory; spawn-denial-primary is a tracked follow-up) — and note
7221
+ // an over-eager tier can only reap a GENUINELY-idle session sooner, never a
7222
+ // working one (the classifier protects working sessions regardless of tier).
7223
+ const { SessionReaper, fileAuditSink } = await import('../monitoring/SessionReaper.js');
7224
+ const _os = await import('node:os');
7225
+ const _resolveTopic = (tmuxSession) => {
7226
+ const t = telegram?.getTopicForSession(tmuxSession);
7227
+ if (t == null)
7228
+ return null;
7229
+ const n = typeof t === 'number' ? t : Number(t);
7230
+ return Number.isFinite(n) ? n : null;
7231
+ };
7232
+ const sessionReaper = new SessionReaper({
7233
+ listRunningSessions: () => sessionManager.listRunningSessions(),
7234
+ captureOutput: (s, n) => sessionManager.captureOutput(s, n) ?? '',
7235
+ hasActiveProcesses: (s) => sessionManager.hasActiveProcesses(s),
7236
+ frameworkForSession: (s) => sessionManager.frameworkForSession(s),
7237
+ isRecoveryActive: (session) => composedRecoveryActive(session),
7238
+ isRelayLeaseActive: (id) => sessionManager.isRelayLeaseActive(id),
7239
+ hasPendingInjection: (s) => sessionManager.getPendingInjection(s) != null,
7240
+ topicBinding: _resolveTopic,
7241
+ // Gate I is a v1 stub (returns false): active conversation is already
7242
+ // covered by the relay-lease + pending-injection gates and by render
7243
+ // stasis (a session being talked to is not render-static for the full
7244
+ // hysteresis+threshold window). Promoting to a real message-recency
7245
+ // query is a tracked tuning follow-up.
7246
+ recentUserMessage: () => false,
7247
+ activeCommitmentForTopic: (topicId) => {
7248
+ try {
7249
+ return commitmentTracker.getActive().some(c => c.topicId === topicId);
7250
+ }
7251
+ catch {
7252
+ return true;
7253
+ } // cannot tell → protect
7254
+ },
7255
+ activeSubagentCount: (csid) => {
7256
+ try {
7257
+ return csid ? subagentTracker.getActiveSubagents(csid).length : 0;
7258
+ }
7259
+ catch {
7260
+ return 1;
7261
+ } // cannot tell → protect
7262
+ },
7263
+ buildOrAutonomousActive: (topicId) => {
7264
+ const fresh = (p) => {
7265
+ try {
7266
+ return fs.existsSync(p) && (Date.now() - fs.statSync(p).mtimeMs) < 30 * 60_000;
7267
+ }
7268
+ catch {
7269
+ return false;
7270
+ }
7271
+ };
7272
+ if (topicId != null && fresh(path.join(config.stateDir, 'autonomous', `${topicId}.local.md`)))
7273
+ return true;
7274
+ return fresh(path.join(config.stateDir, 'state', 'build', 'build-state.json'));
7275
+ },
7276
+ protectedSessions: () => sessionManager.getProtectedSessions(),
7277
+ pressure: () => {
7278
+ const total = _os.totalmem();
7279
+ const freePct = total > 0 ? (_os.freemem() / total) * 100 : 100;
7280
+ const tier = freePct < 5 ? 'critical' : freePct < 12 ? 'moderate' : 'normal';
7281
+ return { tier, inputs: { freePct: Math.round(freePct * 10) / 10 } };
7282
+ },
7283
+ terminate: (id, reason) => sessionManager.terminateSession(id, reason),
7284
+ markReaping: (id) => sessionManager.markReaping(id),
7285
+ clearReaping: (id) => sessionManager.clearReaping(id),
7286
+ audit: fileAuditSink(config.stateDir),
7287
+ }, config.monitoring?.sessionReaper);
7288
+ sessionReaper.start();
7289
+ if (config.monitoring?.sessionReaper?.enabled) {
7290
+ console.log(pc.green(config.monitoring.sessionReaper.dryRun === false
7291
+ ? ' SessionReaper enabled (idle-session reaper — LIVE)'
7292
+ : ' SessionReaper enabled (idle-session reaper — dry-run, logs only)'));
7293
+ }
7294
+ 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, rateLimitSentinel, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? 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, conversationStore, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, proxyCoordinator, topicIntentStore, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper });
7196
7295
  // Boot-recovery (tunnel-failure-resilience spec Part 6): if the agent
7197
7296
  // died mid-relay-episode, the persisted tunnel.json carries
7198
7297
  // rotationPending=true. Rotate the dashboard PIN + authToken BEFORE