@wrongstack/core 0.250.0 → 0.255.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 (37) hide show
  1. package/dist/{agent-bridge-4gc0vfW2.d.ts → agent-bridge-l_DsFEbr.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-Dz-9kiE6.d.ts → agent-subagent-runner-DhYLgAJo.d.ts} +3 -3
  3. package/dist/{brain-sCZ3lCjq.d.ts → brain-BaQsRNka.d.ts} +17 -0
  4. package/dist/coordination/index.d.ts +10 -10
  5. package/dist/coordination/index.js +132 -0
  6. package/dist/coordination/index.js.map +1 -1
  7. package/dist/defaults/index.d.ts +11 -11
  8. package/dist/execution/index.d.ts +7 -7
  9. package/dist/extension/index.d.ts +3 -3
  10. package/dist/{goal-preamble-BjJpnLW4.d.ts → goal-preamble-BgoPmZ8l.d.ts} +4 -4
  11. package/dist/{index-Dy8OwfBD.d.ts → index-BilZMsOK.d.ts} +3 -3
  12. package/dist/{index-IehiNryU.d.ts → index-Csoc_bKs.d.ts} +2 -2
  13. package/dist/index.d.ts +21 -21
  14. package/dist/index.js +150 -3
  15. package/dist/index.js.map +1 -1
  16. package/dist/infrastructure/index.d.ts +2 -2
  17. package/dist/infrastructure/index.js +12 -0
  18. package/dist/infrastructure/index.js.map +1 -1
  19. package/dist/kernel/index.d.ts +4 -4
  20. package/dist/kernel/index.js.map +1 -1
  21. package/dist/{multi-agent-coordinator-CnbEqpv0.d.ts → multi-agent-coordinator-Bs-M0Mo6.d.ts} +1 -1
  22. package/dist/{null-fleet-bus-Do1OLYpj.d.ts → null-fleet-bus-CWdU1_cO.d.ts} +4 -4
  23. package/dist/observability/index.d.ts +1 -1
  24. package/dist/{package-outdated-watcher-CA5GGB4C.d.ts → package-outdated-watcher-Dz-eNZlQ.d.ts} +23 -2
  25. package/dist/{parallel-eternal-engine-UZg1xOzE.d.ts → parallel-eternal-engine-CAMabk-X.d.ts} +4 -4
  26. package/dist/{path-resolver-BaP06Owy.d.ts → path-resolver-B7VjhUHq.d.ts} +1 -1
  27. package/dist/{pipeline-D1n-gQI-.d.ts → pipeline-Bxa3wDcy.d.ts} +41 -1
  28. package/dist/{plan-templates-BUVRY0pU.d.ts → plan-templates-D3guWwTi.d.ts} +1 -1
  29. package/dist/{provider-runner-D0HgUqwV.d.ts → provider-runner-C8_e4Lo1.d.ts} +1 -1
  30. package/dist/sdd/index.d.ts +4 -4
  31. package/dist/storage/index.d.ts +5 -5
  32. package/dist/types/index.d.ts +10 -10
  33. package/dist/types/index.js +12 -0
  34. package/dist/types/index.js.map +1 -1
  35. package/dist/utils/index.js +2 -0
  36. package/dist/utils/index.js.map +1 -1
  37. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { B as BridgeTransport, a as BridgeMessage, A as AgentBridge, b as AgentBridgeConfig } from './agent-subagent-runner-Dz-9kiE6.js';
1
+ import { B as BridgeTransport, a as BridgeMessage, A as AgentBridge, b as AgentBridgeConfig } from './agent-subagent-runner-DhYLgAJo.js';
2
2
 
3
3
  /**
4
4
  * In-memory pub/sub transport for agent-to-agent messaging.
@@ -1,6 +1,6 @@
1
- import { c as ToolCallPipelinePayload, d as ToolWrapper, E as ExtensionRegistry, S as SystemPromptContributor, e as ToolRegistry, P as ProviderRegistry, A as AgentPipelines, f as ToolExecutorLike, g as AgentInit, h as AgentInput, R as RunResult } from './index-IehiNryU.js';
2
- import { C as Container, R as ReadonlyPipeline, a as Renderer } from './pipeline-D1n-gQI-.js';
3
- import { E as EventBus, a as EventName, L as Listener } from './brain-sCZ3lCjq.js';
1
+ import { c as ToolCallPipelinePayload, d as ToolWrapper, E as ExtensionRegistry, S as SystemPromptContributor, e as ToolRegistry, P as ProviderRegistry, A as AgentPipelines, f as ToolExecutorLike, g as AgentInit, h as AgentInput, R as RunResult } from './index-Csoc_bKs.js';
2
+ import { C as Container, R as ReadonlyPipeline, a as Renderer } from './pipeline-Bxa3wDcy.js';
3
+ import { E as EventBus, a as EventName, L as Listener } from './brain-BaQsRNka.js';
4
4
  import { R as RetryPolicy, E as ErrorHandler } from './retry-policy-BVnkbMET.js';
5
5
  import { L as Logger } from './logger-B63L5bTg.js';
6
6
  import { T as Tracer } from './observability-D-HZN_mF.js';
@@ -374,6 +374,23 @@ interface EventMap {
374
374
  used: number;
375
375
  limit: number;
376
376
  };
377
+ /**
378
+ * Fired by `DefaultTokenCounter` after each call to `account()` /
379
+ * `accountWithModel()` updates its internal state. The payload carries
380
+ * the live snapshot so subscribers (notably the TUI's `StatusBar`) can
381
+ * re-render fresh token/cost/cache data immediately instead of waiting
382
+ * for a slow polling interval. Cost fields may be zero when the model
383
+ * is unknown to the ModelsRegistry — that is already signalled separately
384
+ * by `token.cost_estimate_unavailable`.
385
+ */
386
+ 'token.accounted': {
387
+ usage: Usage;
388
+ cost: {
389
+ input: number;
390
+ output: number;
391
+ total: number;
392
+ };
393
+ };
377
394
  /**
378
395
  * Fired when the subagent budget hits a soft limit and the coordinator
379
396
  * is being asked for an extension. The coordinator should call `extend()`
@@ -1,17 +1,17 @@
1
- export { B as BrainArbiter, b as BrainDecision, c as BrainDecisionOption, d as BrainDecisionQueue, e as BrainDecisionRequest, f as BrainDecisionSource, g as BrainFallback, h as BrainRisk, D as DefaultBrainArbiter, i as DefaultBrainArbiterOptions, H as HumanEscalatingBrainArbiter, O as ObservableBrainArbiter, j as formatHumanPrompt } from '../brain-sCZ3lCjq.js';
2
- export { A as ACP_AGENTS, a as AGENTS_BY_PHASE, b as AGENT_CATALOG, c as ALL_AGENT_DEFINITIONS, d as ALL_FLEET_AGENTS, e as AUDIT_LOG_AGENT, f as AutoExtendCeiling, g as AutoExtendPolicy, B as BUG_HUNTER_AGENT, h as BugFinding, C as CollabBudgetConfig, i as CollabBudgetOverrides, j as CollabBudgetWarningPayload, k as CollabDebugReport, l as CollabSession, m as CollabSessionOptions, n as CreateDelegateToolOptions, o as CriticConcern, p as CriticEvaluation, D as DEFAULT_DIRECTOR_PREAMBLE, q as DEFAULT_SUBAGENT_BASELINE, r as DelegateHost, s as Director, t as DirectorAlert, u as DirectorAlertLevel, v as DirectorCancelCollabPayload, w as DirectorPromptParts, x as DirectorSessionFactory, y as DirectorSessionFactoryOptions, F as FLEET_ROSTER, z as FLEET_ROSTER_BUDGETS, E as FLEET_ROSTER_WITHACP, G as FleetCostCapError, H as FleetManager, I as FleetManagerOptions, J as FleetRosterBudget, K as FleetSpawnBudgetError, L as ICoordinator, M as IFleetManager, N as LargeAnswerStore, O as NULL_FLEET_BUS, R as REFACTOR_PLANNER_AGENT, P as RefactorPhase, Q as RefactorPlan, S as SECURITY_SCANNER_AGENT, T as SharedFileEntry, U as SharedFileSnapshot, V as SubagentPromptParts, W as applyRosterBudget, X as attachAutoExtend, Y as composeDirectorPrompt, Z as composeSubagentPrompt, _ as createDelegateTool, $ as getAgentDefinition, a0 as makeAskResultTool, a1 as makeAskTool, a2 as makeAssignTool, a3 as makeAwaitTasksTool, a4 as makeCollabDebugTool, a5 as makeDirectorSessionFactory, a6 as makeFleetEmitTool, a7 as makeFleetHealthTool, a8 as makeFleetSessionTool, a9 as makeFleetStatusTool, aa as makeFleetUsageTool, ab as makeRollUpTool, ac as makeSpawnTool, ad as makeTerminateTool, ae as makeWorkCompleteTool, af as rosterSummaryFromConfigs } from '../null-fleet-bus-Do1OLYpj.js';
3
- import { A as AgentDefinition } from '../multi-agent-coordinator-CnbEqpv0.js';
4
- export { T as AGENT_TOOL_PRESETS, b as AgentBudgetTier, c as AgentCapability, d as AgentPhase, e as DEFAULT_DISPATCH_ROLE, a as DefaultMultiAgentCoordinator, f as DispatchCandidate, D as DispatchClassifier, g as DispatchMethod, h as DispatchOptions, i as DispatchResult, H as HEAVY_BUDGET, L as LIGHT_BUDGET, M as MEDIUM_BUDGET, j as MultiAgentCoordinatorOptions, k as dispatchAgent, m as makeLLMClassifier, s as scoreAgents } from '../multi-agent-coordinator-CnbEqpv0.js';
5
- export { h as AgentFactory, i as AgentFactoryResult, j as AgentRunnerOptions, k as BudgetExceededError, l as BudgetKind, m as BudgetLimits, n as BudgetNegotiationMode, o as BudgetThresholdDecision, p as BudgetThresholdHandler, q as BudgetThresholdSignal, r as BudgetUsage, F as FleetBus, s as FleetEvent, t as FleetHandler, u as FleetUsage, v as FleetUsageAggregator, w as SubagentBudget, x as SubagentUsageSnapshot, y as makeAgentSubagentRunner } from '../agent-subagent-runner-Dz-9kiE6.js';
6
- export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-4gc0vfW2.js';
7
- export { B as BrainInterventionInput, a as BrainMonitor, b as BrainMonitorOptions, D as DEPENDENCY_FILE_PATTERNS, c as DefaultMailbox, d as DepWatchEntry, e as DepWatcherBridgeOptions, f as DependencyWatcherConfig, G as GlobalMailbox, M as MailToolsOptions, g as MailboxResolver, h as MailboxToolOptions, O as OutdatedNotifyMessage, P as PackageAuthorEntry, i as PackageAuthorLog, j as PackageAuthorTrackerOptions, k as PackageOutdatedEntry, l as PackageOutdatedResult, m as PackageOutdatedWatcherOptions, n as attachDepWatcherBridge, o as detectEcosystem, p as getFullPackageLog, q as getManifestPackages, r as getPackageAuthor, s as getPackagesByAgent, t as mailboxSessionTag, u as makeDependencyWatcherConfig, v as makeMailInboxTool, w as makeMailSendTool, x as makeMailboxTool, y as recordPackageAction, z as resolveMailboxIdentity, A as resolveProjectDir, C as startPackageOutdatedWatcher, E as updatePackageOutdatedStatus } from '../package-outdated-watcher-CA5GGB4C.js';
8
- import { b as Mailbox } from '../pipeline-D1n-gQI-.js';
9
- export { h as AgentHeartbeatInput, A as AgentRegistrationInput, f as MailboxAckInput, g as MailboxAgentStatus, d as MailboxMessage, i as MailboxMessageType, e as MailboxQuery, c as MailboxSendInput, j as MailboxTaskContext, k as ReadReceipts, l as RegisteredAgent, n as normalizeRecipient } from '../pipeline-D1n-gQI-.js';
1
+ export { B as BrainArbiter, b as BrainDecision, c as BrainDecisionOption, d as BrainDecisionQueue, e as BrainDecisionRequest, f as BrainDecisionSource, g as BrainFallback, h as BrainRisk, D as DefaultBrainArbiter, i as DefaultBrainArbiterOptions, H as HumanEscalatingBrainArbiter, O as ObservableBrainArbiter, j as formatHumanPrompt } from '../brain-BaQsRNka.js';
2
+ export { A as ACP_AGENTS, a as AGENTS_BY_PHASE, b as AGENT_CATALOG, c as ALL_AGENT_DEFINITIONS, d as ALL_FLEET_AGENTS, e as AUDIT_LOG_AGENT, f as AutoExtendCeiling, g as AutoExtendPolicy, B as BUG_HUNTER_AGENT, h as BugFinding, C as CollabBudgetConfig, i as CollabBudgetOverrides, j as CollabBudgetWarningPayload, k as CollabDebugReport, l as CollabSession, m as CollabSessionOptions, n as CreateDelegateToolOptions, o as CriticConcern, p as CriticEvaluation, D as DEFAULT_DIRECTOR_PREAMBLE, q as DEFAULT_SUBAGENT_BASELINE, r as DelegateHost, s as Director, t as DirectorAlert, u as DirectorAlertLevel, v as DirectorCancelCollabPayload, w as DirectorPromptParts, x as DirectorSessionFactory, y as DirectorSessionFactoryOptions, F as FLEET_ROSTER, z as FLEET_ROSTER_BUDGETS, E as FLEET_ROSTER_WITHACP, G as FleetCostCapError, H as FleetManager, I as FleetManagerOptions, J as FleetRosterBudget, K as FleetSpawnBudgetError, L as ICoordinator, M as IFleetManager, N as LargeAnswerStore, O as NULL_FLEET_BUS, R as REFACTOR_PLANNER_AGENT, P as RefactorPhase, Q as RefactorPlan, S as SECURITY_SCANNER_AGENT, T as SharedFileEntry, U as SharedFileSnapshot, V as SubagentPromptParts, W as applyRosterBudget, X as attachAutoExtend, Y as composeDirectorPrompt, Z as composeSubagentPrompt, _ as createDelegateTool, $ as getAgentDefinition, a0 as makeAskResultTool, a1 as makeAskTool, a2 as makeAssignTool, a3 as makeAwaitTasksTool, a4 as makeCollabDebugTool, a5 as makeDirectorSessionFactory, a6 as makeFleetEmitTool, a7 as makeFleetHealthTool, a8 as makeFleetSessionTool, a9 as makeFleetStatusTool, aa as makeFleetUsageTool, ab as makeRollUpTool, ac as makeSpawnTool, ad as makeTerminateTool, ae as makeWorkCompleteTool, af as rosterSummaryFromConfigs } from '../null-fleet-bus-CWdU1_cO.js';
3
+ import { A as AgentDefinition } from '../multi-agent-coordinator-Bs-M0Mo6.js';
4
+ export { T as AGENT_TOOL_PRESETS, b as AgentBudgetTier, c as AgentCapability, d as AgentPhase, e as DEFAULT_DISPATCH_ROLE, a as DefaultMultiAgentCoordinator, f as DispatchCandidate, D as DispatchClassifier, g as DispatchMethod, h as DispatchOptions, i as DispatchResult, H as HEAVY_BUDGET, L as LIGHT_BUDGET, M as MEDIUM_BUDGET, j as MultiAgentCoordinatorOptions, k as dispatchAgent, m as makeLLMClassifier, s as scoreAgents } from '../multi-agent-coordinator-Bs-M0Mo6.js';
5
+ export { h as AgentFactory, i as AgentFactoryResult, j as AgentRunnerOptions, k as BudgetExceededError, l as BudgetKind, m as BudgetLimits, n as BudgetNegotiationMode, o as BudgetThresholdDecision, p as BudgetThresholdHandler, q as BudgetThresholdSignal, r as BudgetUsage, F as FleetBus, s as FleetEvent, t as FleetHandler, u as FleetUsage, v as FleetUsageAggregator, w as SubagentBudget, x as SubagentUsageSnapshot, y as makeAgentSubagentRunner } from '../agent-subagent-runner-DhYLgAJo.js';
6
+ export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-l_DsFEbr.js';
7
+ export { B as BrainInterventionInput, a as BrainMonitor, b as BrainMonitorOptions, D as DEPENDENCY_FILE_PATTERNS, c as DefaultMailbox, d as DepWatchEntry, e as DepWatcherBridgeOptions, f as DependencyWatcherConfig, G as GlobalMailbox, M as MailToolsOptions, g as MailboxResolver, h as MailboxToolOptions, O as OutdatedNotifyMessage, P as PackageAuthorEntry, i as PackageAuthorLog, j as PackageAuthorTrackerOptions, k as PackageOutdatedEntry, l as PackageOutdatedResult, m as PackageOutdatedWatcherOptions, n as attachDepWatcherBridge, o as detectEcosystem, p as getFullPackageLog, q as getManifestPackages, r as getPackageAuthor, s as getPackagesByAgent, t as mailboxSessionTag, u as makeDependencyWatcherConfig, v as makeMailInboxTool, w as makeMailSendTool, x as makeMailboxTool, y as recordPackageAction, z as resolveMailboxIdentity, A as resolveProjectDir, C as startPackageOutdatedWatcher, E as updatePackageOutdatedStatus } from '../package-outdated-watcher-Dz-eNZlQ.js';
8
+ import { b as Mailbox } from '../pipeline-Bxa3wDcy.js';
9
+ export { h as AgentHeartbeatInput, A as AgentRegistrationInput, f as MailboxAckInput, g as MailboxAgentStatus, d as MailboxMessage, l as MailboxMessageType, e as MailboxQuery, c as MailboxSendInput, m as MailboxTaskContext, n as ReadReceipts, o as RegisteredAgent, p as normalizeRecipient } from '../pipeline-Bxa3wDcy.js';
10
10
  import '../context-CLz3z_E8.js';
11
11
  import 'node:events';
12
12
  import '../director-state-BfeCUbmk.js';
13
13
  import '../config-eSsrto5d.js';
14
- import '../index-IehiNryU.js';
14
+ import '../index-Csoc_bKs.js';
15
15
  import '../logger-B63L5bTg.js';
16
16
  import '../observability-D-HZN_mF.js';
17
17
  import '../permission-DbWPbuoA.js';
@@ -10041,6 +10041,14 @@ var DefaultMailbox = class {
10041
10041
  await fsp6.writeFile(this.filePath, "", "utf8");
10042
10042
  });
10043
10043
  }
10044
+ // ── Client registry stubs (not applicable per-session) ─────────────────
10045
+ async registerClient(_input) {
10046
+ }
10047
+ async clientHeartbeat(_input) {
10048
+ }
10049
+ async getClientStatuses() {
10050
+ return [];
10051
+ }
10044
10052
  // ── Internal ──────────────────────────────────────────────────────────
10045
10053
  async _readAll() {
10046
10054
  try {
@@ -10217,7 +10225,9 @@ function wstackGlobalRoot() {
10217
10225
 
10218
10226
  // src/coordination/global-mailbox.ts
10219
10227
  var MAILBOX_FILE2 = "_mailbox.jsonl";
10228
+ var CLIENT_REGISTRY_FILE = "_mailbox.clients.json";
10220
10229
  var AGENT_STALE_MS = 6e4;
10230
+ var CLIENT_STALE_MS = 6e4;
10221
10231
  var HEARTBEAT_THROTTLE_MS = 5e3;
10222
10232
  var REGISTRY_CACHE_TTL_MS = 2e3;
10223
10233
  var LINE_SEPARATOR2 = "\n";
@@ -10229,6 +10239,8 @@ var GlobalMailbox = class {
10229
10239
  messagePath;
10230
10240
  /** Path to the JSON agent registry file. */
10231
10241
  registryPath;
10242
+ /** Path to the JSON client registry file. */
10243
+ clientRegistryPath;
10232
10244
  /** Optional event bus for emitting agent registration/heartbeat events. */
10233
10245
  _events;
10234
10246
  /**
@@ -10240,8 +10252,17 @@ var GlobalMailbox = class {
10240
10252
  _registryCache = null;
10241
10253
  /** When the registry cache was last refreshed from disk (epoch ms). */
10242
10254
  _registryCacheAt = 0;
10255
+ /**
10256
+ * Local cache of the client registry to avoid re-reading on every call.
10257
+ * Same reasoning as agent registry cache.
10258
+ */
10259
+ _clientRegistryCache = null;
10260
+ /** When the client registry cache was last refreshed from disk (epoch ms). */
10261
+ _clientRegistryCacheAt = 0;
10243
10262
  /** Last time each local agent sent a heartbeat (throttle). */
10244
10263
  _lastHeartbeat = /* @__PURE__ */ new Map();
10264
+ /** Last time each local client sent a heartbeat (throttle). */
10265
+ _lastClientHeartbeat = /* @__PURE__ */ new Map();
10245
10266
  /**
10246
10267
  * @param projectDir — `~/.wrongstack/projects/<slug>/`
10247
10268
  * @param events — optional EventBus for real-time TUI/WebUI notifications
@@ -10249,6 +10270,7 @@ var GlobalMailbox = class {
10249
10270
  constructor(projectDir, events) {
10250
10271
  this.messagePath = path4.join(projectDir, MAILBOX_FILE2);
10251
10272
  this.registryPath = path4.join(projectDir, "_mailbox.registry.json");
10273
+ this.clientRegistryPath = path4.join(projectDir, CLIENT_REGISTRY_FILE);
10252
10274
  this._events = events;
10253
10275
  }
10254
10276
  // ── Messages ────────────────────────────────────────────────────────────
@@ -10430,9 +10452,74 @@ var GlobalMailbox = class {
10430
10452
  const all = await this.getAgentStatuses();
10431
10453
  return all.filter((a) => a.online);
10432
10454
  }
10455
+ // ── Client registry ─────────────────────────────────────────────────────
10456
+ async registerClient(input) {
10457
+ await this._ensureClientRegistry();
10458
+ const now = (/* @__PURE__ */ new Date()).toISOString();
10459
+ const client = {
10460
+ clientId: input.clientId,
10461
+ sessionId: input.sessionId,
10462
+ name: input.name,
10463
+ source: input.source,
10464
+ registeredAt: now,
10465
+ lastSeenAt: now,
10466
+ pid: input.pid
10467
+ };
10468
+ await withFileLock(this.clientRegistryPath, async () => {
10469
+ const registry = await this._readClientRegistry({ fresh: true });
10470
+ this._pruneStaleClientsInPlace(registry);
10471
+ registry.set(input.clientId, client);
10472
+ this._clientRegistryCache = registry;
10473
+ this._clientRegistryCacheAt = Date.now();
10474
+ await this._writeClientRegistry(registry);
10475
+ });
10476
+ this._events?.emitCustom("mailbox.client_registered", {
10477
+ clientId: input.clientId,
10478
+ sessionId: input.sessionId,
10479
+ name: input.name,
10480
+ source: input.source
10481
+ });
10482
+ }
10483
+ async clientHeartbeat(input) {
10484
+ const last = this._lastClientHeartbeat.get(input.clientId) ?? 0;
10485
+ const now = Date.now();
10486
+ if (now - last < HEARTBEAT_THROTTLE_MS) return;
10487
+ this._lastClientHeartbeat.set(input.clientId, now);
10488
+ await this._ensureClientRegistry();
10489
+ await withFileLock(this.clientRegistryPath, async () => {
10490
+ const registry = await this._readClientRegistry({ fresh: true });
10491
+ this._pruneStaleClientsInPlace(registry);
10492
+ const client = registry.get(input.clientId);
10493
+ if (client) {
10494
+ client.lastSeenAt = (/* @__PURE__ */ new Date()).toISOString();
10495
+ }
10496
+ this._clientRegistryCache = registry;
10497
+ this._clientRegistryCacheAt = Date.now();
10498
+ await this._writeClientRegistry(registry);
10499
+ });
10500
+ this._events?.emitCustom("mailbox.client_heartbeat", {
10501
+ clientId: input.clientId
10502
+ });
10503
+ }
10504
+ async getClientStatuses() {
10505
+ await this._ensureClientRegistry();
10506
+ const registry = await this._readClientRegistry();
10507
+ this._pruneStaleClientsInPlace(registry);
10508
+ const now = Date.now();
10509
+ return Array.from(registry.values()).map((c) => ({
10510
+ clientId: c.clientId,
10511
+ name: c.name,
10512
+ source: c.source,
10513
+ sessionId: c.sessionId,
10514
+ lastSeenAt: c.lastSeenAt,
10515
+ online: now - new Date(c.lastSeenAt).getTime() < CLIENT_STALE_MS,
10516
+ pid: c.pid
10517
+ })).sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));
10518
+ }
10433
10519
  // ── Lifecycle ───────────────────────────────────────────────────────────
10434
10520
  async close() {
10435
10521
  this._registryCache = null;
10522
+ this._clientRegistryCache = null;
10436
10523
  }
10437
10524
  async clearAll() {
10438
10525
  await withFileLock(this.messagePath, async () => {
@@ -10511,6 +10598,51 @@ var GlobalMailbox = class {
10511
10598
  await fsp6.writeFile(tmp, JSON.stringify(obj, null, 2), "utf8");
10512
10599
  await fsp6.rename(tmp, this.registryPath);
10513
10600
  }
10601
+ // ── Client registry internals ───────────────────────────────────────────
10602
+ async _ensureClientRegistry() {
10603
+ await fsp6.mkdir(path4.dirname(this.clientRegistryPath), { recursive: true });
10604
+ }
10605
+ async _readClientRegistry(opts) {
10606
+ if (!opts?.fresh && this._clientRegistryCache && Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS) {
10607
+ return new Map(this._clientRegistryCache);
10608
+ }
10609
+ try {
10610
+ const raw = await fsp6.readFile(this.clientRegistryPath, "utf8");
10611
+ const data = JSON.parse(raw);
10612
+ const map = /* @__PURE__ */ new Map();
10613
+ for (const [id, client] of Object.entries(data)) {
10614
+ map.set(id, client);
10615
+ }
10616
+ this._clientRegistryCache = map;
10617
+ this._clientRegistryCacheAt = Date.now();
10618
+ return new Map(map);
10619
+ } catch (err) {
10620
+ if (err.code === "ENOENT") {
10621
+ const empty = /* @__PURE__ */ new Map();
10622
+ this._clientRegistryCache = empty;
10623
+ this._clientRegistryCacheAt = Date.now();
10624
+ return empty;
10625
+ }
10626
+ throw err;
10627
+ }
10628
+ }
10629
+ _pruneStaleClientsInPlace(registry) {
10630
+ const cutoff = Date.now() - CLIENT_STALE_MS;
10631
+ for (const client of registry.values()) {
10632
+ if (new Date(client.lastSeenAt).getTime() < cutoff) {
10633
+ client.lastSeenAt = new Date(cutoff).toISOString();
10634
+ }
10635
+ }
10636
+ }
10637
+ async _writeClientRegistry(registry) {
10638
+ const obj = {};
10639
+ for (const [id, client] of registry) {
10640
+ obj[id] = client;
10641
+ }
10642
+ const tmp = `${this.clientRegistryPath}.${randomUUID().slice(0, 8)}.tmp`;
10643
+ await fsp6.writeFile(tmp, JSON.stringify(obj, null, 2), "utf8");
10644
+ await fsp6.rename(tmp, this.clientRegistryPath);
10645
+ }
10514
10646
  };
10515
10647
  function defaultResolveProjectDir(ctx) {
10516
10648
  return resolveProjectDir(ctx.projectRoot, wstackGlobalRoot());