instar 0.28.61 → 0.28.62

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 (65) hide show
  1. package/dist/cli.js +0 -0
  2. package/dist/commands/server.d.ts.map +1 -1
  3. package/dist/commands/server.js +97 -21
  4. package/dist/commands/server.js.map +1 -1
  5. package/dist/core/types.d.ts +26 -0
  6. package/dist/core/types.d.ts.map +1 -1
  7. package/dist/messaging/DeliveryRetryManager.d.ts.map +1 -1
  8. package/dist/messaging/DeliveryRetryManager.js +6 -4
  9. package/dist/messaging/DeliveryRetryManager.js.map +1 -1
  10. package/dist/messaging/MessageStore.d.ts +10 -0
  11. package/dist/messaging/MessageStore.d.ts.map +1 -1
  12. package/dist/messaging/MessageStore.js +52 -0
  13. package/dist/messaging/MessageStore.js.map +1 -1
  14. package/dist/messaging/SpawnRequestManager.d.ts +224 -19
  15. package/dist/messaging/SpawnRequestManager.d.ts.map +1 -1
  16. package/dist/messaging/SpawnRequestManager.js +600 -70
  17. package/dist/messaging/SpawnRequestManager.js.map +1 -1
  18. package/dist/messaging/types.d.ts +11 -1
  19. package/dist/messaging/types.d.ts.map +1 -1
  20. package/dist/messaging/types.js +7 -0
  21. package/dist/messaging/types.js.map +1 -1
  22. package/dist/monitoring/SessionWatchdog.d.ts.map +1 -1
  23. package/dist/monitoring/SessionWatchdog.js +23 -7
  24. package/dist/monitoring/SessionWatchdog.js.map +1 -1
  25. package/dist/monitoring/watchdog-notifications.d.ts +15 -0
  26. package/dist/monitoring/watchdog-notifications.d.ts.map +1 -0
  27. package/dist/monitoring/watchdog-notifications.js +24 -0
  28. package/dist/monitoring/watchdog-notifications.js.map +1 -0
  29. package/dist/server/routes.d.ts.map +1 -1
  30. package/dist/server/routes.js +56 -0
  31. package/dist/server/routes.js.map +1 -1
  32. package/dist/threadline/ThreadlineRouter.d.ts +64 -2
  33. package/dist/threadline/ThreadlineRouter.d.ts.map +1 -1
  34. package/dist/threadline/ThreadlineRouter.js +117 -9
  35. package/dist/threadline/ThreadlineRouter.js.map +1 -1
  36. package/dist/threadline/client/ThreadlineClient.d.ts +25 -1
  37. package/dist/threadline/client/ThreadlineClient.d.ts.map +1 -1
  38. package/dist/threadline/client/ThreadlineClient.js +79 -2
  39. package/dist/threadline/client/ThreadlineClient.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/data/builtin-manifest.json +50 -50
  42. package/upgrades/side-effects/threadline-cooldown-prereq-1-undelivered-phase.md +73 -0
  43. package/upgrades/side-effects/threadline-cooldown-sec4.1-branded-trust-union.md +68 -0
  44. package/upgrades/side-effects/threadline-cooldown-sec4.1-client-affinity.md +71 -0
  45. package/upgrades/side-effects/threadline-cooldown-sec4.1-receiver-affinity.md +67 -0
  46. package/upgrades/side-effects/threadline-cooldown-sec4.2-drain-loop.md +92 -0
  47. package/upgrades/side-effects/threadline-cooldown-sec4.2-infra-soft-limiter.md +75 -0
  48. package/upgrades/side-effects/threadline-cooldown-sec4.2-state-refactor.md +78 -0
  49. package/upgrades/side-effects/threadline-cooldown-sec4.3-envelope-byte-cap.md +66 -0
  50. package/upgrades/side-effects/threadline-cooldown-sec4.3-envelope-hash.md +71 -0
  51. package/upgrades/side-effects/threadline-cooldown-sec4.3-truncation-and-global-cap.md +69 -0
  52. package/upgrades/side-effects/threadline-cooldown-sec4.4-config-plumbing.md +77 -0
  53. package/upgrades/side-effects/threadline-cooldown-sec4.4-drain-consumer-wiring.md +72 -0
  54. package/upgrades/side-effects/threadline-cooldown-sec4.4-patch-endpoint.md +72 -0
  55. package/upgrades/side-effects/threadline-cooldown-sec4.5-degradation-reporter.md +83 -0
  56. package/upgrades/side-effects/threadline-cooldown-sec4.5-triggeredby-plumbing.md +76 -0
  57. package/upgrades/side-effects/threadline-cooldown-spec-landing.md +48 -0
  58. package/upgrades/side-effects/watchdog-user-comfort.md +136 -0
  59. package/dist/core/InitiativeDigestJob.d.ts +0 -54
  60. package/dist/core/InitiativeDigestJob.d.ts.map +0 -1
  61. package/dist/core/InitiativeDigestJob.js +0 -128
  62. package/dist/core/InitiativeDigestJob.js.map +0 -1
  63. package/upgrades/NEXT.md +0 -53
  64. /package/upgrades/{0.28.61.md → 0.28.62.md} +0 -0
  65. /package/upgrades/side-effects/{scheduler-gate-exit-code.md → 0.28.61.md} +0 -0
package/dist/cli.js CHANGED
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA81CD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8+ItE;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;AA4PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA81CD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsjJtE;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"}
@@ -45,6 +45,7 @@ import { QuotaNotifier } from '../monitoring/QuotaNotifier.js';
45
45
  import { QuotaManager } from '../monitoring/QuotaManager.js';
46
46
  import { classifySessionDeath } from '../monitoring/QuotaExhaustionDetector.js';
47
47
  import { SessionWatchdog } from '../monitoring/SessionWatchdog.js';
48
+ import { formatWatchdogUserMessage } from '../monitoring/watchdog-notifications.js';
48
49
  import { StallTriageNurse } from '../monitoring/StallTriageNurse.js';
49
50
  import { TriageOrchestrator } from '../monitoring/TriageOrchestrator.js';
50
51
  import { SessionMonitor } from '../monitoring/SessionMonitor.js';
@@ -3156,33 +3157,26 @@ export async function startServer(options) {
3156
3157
  watchdog = new SessionWatchdog(config, sessionManager, state);
3157
3158
  watchdog.intelligence = sharedIntelligence ?? null;
3158
3159
  watchdog.on('intervention', (event) => {
3159
- const levelNames = ['Monitoring', 'Ctrl+C', 'SIGTERM', 'SIGKILL', 'Kill Session'];
3160
- const levelName = levelNames[event.level] || `Level ${event.level}`;
3161
- const msg = `🔧 Watchdog [${levelName}]: ${event.action}\nStuck: \`${event.stuckCommand.slice(0, 60)}\``;
3160
+ // Routine recovery (Ctrl+C, SIGTERM) stays as console diagnostics only.
3161
+ // The user only hears when we had to force-kill (SIGKILL / session-kill) —
3162
+ // that's the "actual issue" threshold. See watchdog-notifications.ts.
3163
+ const userMsg = formatWatchdogUserMessage(event);
3164
+ if (!userMsg)
3165
+ return;
3162
3166
  if (telegram) {
3163
3167
  const topicId = telegram.getTopicForSession(event.sessionName);
3164
3168
  if (topicId)
3165
- telegram.sendToTopic(topicId, msg).catch(() => { });
3169
+ telegram.sendToTopic(topicId, userMsg).catch(() => { });
3166
3170
  }
3167
3171
  if (_slackAdapter) {
3168
3172
  const channelId = _slackAdapter.getChannelForSession(event.sessionName);
3169
3173
  if (channelId)
3170
- _slackAdapter.sendToChannel(channelId, msg).catch(() => { });
3171
- }
3172
- });
3173
- watchdog.on('recovery', (sessionName, fromLevel) => {
3174
- const msg = `✅ Watchdog: session recovered (was at escalation level ${fromLevel})`;
3175
- if (telegram) {
3176
- const topicId = telegram.getTopicForSession(sessionName);
3177
- if (topicId)
3178
- telegram.sendToTopic(topicId, msg).catch(() => { });
3179
- }
3180
- if (_slackAdapter) {
3181
- const channelId = _slackAdapter.getChannelForSession(sessionName);
3182
- if (channelId)
3183
- _slackAdapter.sendToChannel(channelId, msg).catch(() => { });
3174
+ _slackAdapter.sendToChannel(channelId, userMsg).catch(() => { });
3184
3175
  }
3185
3176
  });
3177
+ // Recovery events stay silent to the user. If we didn't announce the
3178
+ // problem (Ctrl+C / SIGTERM are now silent), announcing recovery is
3179
+ // noise. Intervention log still records it for diagnostics.
3186
3180
  watchdog.start();
3187
3181
  console.log(pc.green(' Session Watchdog enabled'));
3188
3182
  }
@@ -4850,7 +4844,14 @@ export async function startServer(options) {
4850
4844
  summarySentinel.start();
4851
4845
  messageRouter.setSummarySentinel(summarySentinel);
4852
4846
  // On-demand session spawning for message delivery (Phase 5)
4853
- const spawnManager = new SpawnRequestManager({
4847
+ // §4.4: spawn knobs are read from config.threadline.spawn — see
4848
+ // ThreadlineSpawnConfig in core/types.ts. All fields are optional and
4849
+ // fall through to manager-level defaults if absent.
4850
+ const spawnConfig = config.threadline?.spawn;
4851
+ // Forward-declared `let` so the onDrainReady callback can reference the
4852
+ // manager it belongs to (for re-entrant evaluate() calls during drain).
4853
+ let spawnManager;
4854
+ spawnManager = new SpawnRequestManager({
4854
4855
  maxSessions: config.sessions.maxSessions ?? 5,
4855
4856
  getActiveSessions: () => sessionManager.listRunningSessions(),
4856
4857
  spawnSession: async (prompt, opts) => {
@@ -4859,7 +4860,9 @@ export async function startServer(options) {
4859
4860
  prompt,
4860
4861
  model: opts?.model,
4861
4862
  maxDurationMinutes: opts?.maxDurationMinutes,
4862
- triggeredBy: 'spawn-request',
4863
+ // §4.5: honor SpawnRequestManager's provenance tag so drain-spawned
4864
+ // sessions are distinguishable from inline-spawned ones in logs/stream.
4865
+ triggeredBy: opts?.triggeredBy ?? 'spawn-request',
4863
4866
  });
4864
4867
  return session.id;
4865
4868
  },
@@ -4872,7 +4875,74 @@ export async function startServer(options) {
4872
4875
  onEscalate: (request, reason) => {
4873
4876
  notify('IMMEDIATE', 'messaging', `Spawn escalation: ${reason}\n Requester: ${request.requester.agent}\n Target: ${request.target.agent}`);
4874
4877
  },
4878
+ // §4.5: emit degradation breadcrumbs on edge transitions.
4879
+ onDegradation: (event) => {
4880
+ try {
4881
+ const reporter = DegradationReporter.getInstance();
4882
+ if (event.kind === 'spawn-penalty-tripped') {
4883
+ reporter.report({
4884
+ feature: 'Threadline.SpawnPenalty',
4885
+ primary: `Open spawn slot for peer "${event.agent}"`,
4886
+ fallback: `Spawn blocked for ${Math.round(event.penaltyMs / 1000)}s after ${event.consecutiveFailures} consecutive agent-attributable failures`,
4887
+ reason: `Peer "${event.agent}" tripped the consecutive-failure penalty (3 strikes)`,
4888
+ impact: 'Peer cannot spawn sessions until penalty clears. Successful inbound spawn from a different peer is unaffected.',
4889
+ });
4890
+ }
4891
+ else if (event.kind === 'spawn-infra-degraded') {
4892
+ reporter.report({
4893
+ feature: 'Threadline.SpawnInfraDegraded',
4894
+ primary: `Full queue admission (cap 10) for peer "${event.agent}"`,
4895
+ fallback: `Degraded admission (cap ${spawnConfig?.degradedMaxQueuedPerAgent ?? 1}) for ${Math.round(event.degradationMs / 60_000)}min`,
4896
+ reason: `Peer "${event.agent}" tripped the infra-failure soft limiter (${event.failureCount} non-attributable failures in 10min)`,
4897
+ impact: 'Peer\'s queue depth is capped; older messages are dropped. No blame attribution.',
4898
+ });
4899
+ }
4900
+ }
4901
+ catch (err) {
4902
+ console.warn(`[spawn-manager] degradation reporter failed: ${err instanceof Error ? err.message : String(err)}`);
4903
+ }
4904
+ },
4905
+ // §4.4: optional knobs from config.
4906
+ cooldownMs: spawnConfig?.cooldownMs,
4907
+ maxDrainsPerTick: spawnConfig?.maxDrainsPerTick,
4908
+ maxEnvelopeBytes: spawnConfig?.maxEnvelopeBytes,
4909
+ maxGlobalQueued: spawnConfig?.maxGlobalQueued,
4910
+ degradedMaxQueuedPerAgent: spawnConfig?.degradedMaxQueuedPerAgent,
4911
+ // §4.4 commit 2 + §4.5: drain-loop consumer wiring.
4912
+ // When the drain loop finds an agent ready (cooldown cleared + queued
4913
+ // messages present), this callback re-invokes evaluate() with a
4914
+ // synthetic SpawnRequest tagged `triggeredBy: 'spawn-request-drain'`.
4915
+ // The real queued context is reattached by SpawnRequestManager.evaluate
4916
+ // via its internal drainQueue() call. Stub session/machine values:
4917
+ // requester.session/machine isn't preserved per-message — those fields
4918
+ // are only used in the spawn prompt template for display.
4919
+ onDrainReady: async (agent) => {
4920
+ try {
4921
+ const result = await spawnManager.evaluate({
4922
+ requester: { agent, session: 'drain', machine: 'drain' },
4923
+ target: { agent: config.projectName, machine: os.hostname() },
4924
+ reason: `Drain re-attempt for queued messages from ${agent}`,
4925
+ priority: 'medium',
4926
+ triggeredBy: 'spawn-request-drain',
4927
+ });
4928
+ if (!result.approved) {
4929
+ console.log(`[spawn-manager] drain re-attempt for ${agent} not approved: ${result.reason}`);
4930
+ }
4931
+ }
4932
+ catch (err) {
4933
+ console.warn(`[spawn-manager] drain re-attempt for ${agent} threw: ${err instanceof Error ? err.message : String(err)}`);
4934
+ }
4935
+ },
4875
4936
  });
4937
+ // §4.4 kill switch: drain loop runs unless explicitly disabled in config.
4938
+ // Wired here so emergency rollback is a config flip, not a code change.
4939
+ if (spawnConfig?.drainEnabled !== false) {
4940
+ spawnManager.start();
4941
+ console.log(`[spawn-manager] drain loop started (tick=${spawnManager.getDrainTickMs()}ms)`);
4942
+ }
4943
+ else {
4944
+ console.log('[spawn-manager] drain loop disabled by config.threadline.spawn.drainEnabled=false');
4945
+ }
4876
4946
  // Threadline Router — handles threaded cross-agent conversations via relay
4877
4947
  const threadlineRouter = new ThreadlineRouter(messageRouter, spawnManager, threadResumeMap, messageStore, { localAgent: config.projectName, localMachine: os.hostname() }, null, // autonomyGate
4878
4948
  messageDelivery);
@@ -5178,7 +5248,12 @@ export async function startServer(options) {
5178
5248
  transport: { protocol: 'relay', origin: { agent: senderFingerprint, machine: 'relay' }, nonce: `${crypto.randomUUID()}:${new Date().toISOString()}`, timestamp: new Date().toISOString() },
5179
5249
  delivery: { status: 'delivered', attempts: 1, lastAttempt: new Date().toISOString() },
5180
5250
  };
5181
- const relayContext = { senderFingerprint, senderName, trustLevel };
5251
+ const relayContext = {
5252
+ trust: { kind: 'plaintext-tofu', senderFingerprint },
5253
+ senderFingerprint,
5254
+ senderName,
5255
+ trustLevel,
5256
+ };
5182
5257
  let result = await threadlineRouter.handleInboundMessage(envelope, relayContext);
5183
5258
  // Fallback for threadId-less messages
5184
5259
  if (!result.handled && !msg.threadId) {
@@ -5687,6 +5762,7 @@ export async function startServer(options) {
5687
5762
  await notificationBatcher.flushAll(); // Drain pending notifications before exit
5688
5763
  notificationBatcher.stop();
5689
5764
  retryManager.stop();
5765
+ spawnManager.dispose(); // §4.4: stop drain loop + clear DRR state
5690
5766
  summarySentinel.stop();
5691
5767
  memoryMonitor.stop();
5692
5768
  caffeinateManager.stop();