@wrongstack/core 0.236.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 (49) hide show
  1. package/dist/{agent-bridge-Cimv7bK7.d.ts → agent-bridge-l_DsFEbr.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-C658wj_c.d.ts → agent-subagent-runner-DhYLgAJo.d.ts} +4 -4
  3. package/dist/{brain-sCZ3lCjq.d.ts → brain-BaQsRNka.d.ts} +17 -0
  4. package/dist/{config-Koq6f3fs.d.ts → config-eSsrto5d.d.ts} +6 -0
  5. package/dist/coordination/index.d.ts +11 -11
  6. package/dist/coordination/index.js +137 -3
  7. package/dist/coordination/index.js.map +1 -1
  8. package/dist/defaults/index.d.ts +14 -14
  9. package/dist/defaults/index.js +8 -10
  10. package/dist/defaults/index.js.map +1 -1
  11. package/dist/execution/index.d.ts +8 -8
  12. package/dist/execution/index.js +5 -3
  13. package/dist/execution/index.js.map +1 -1
  14. package/dist/extension/index.d.ts +4 -4
  15. package/dist/{goal-preamble-CnbzyVvl.d.ts → goal-preamble-BgoPmZ8l.d.ts} +5 -5
  16. package/dist/{index-BlMqh5GO.d.ts → index-BilZMsOK.d.ts} +4 -4
  17. package/dist/{index-C2eSNPsB.d.ts → index-Csoc_bKs.d.ts} +3 -3
  18. package/dist/index.d.ts +26 -26
  19. package/dist/index.js +168 -19
  20. package/dist/index.js.map +1 -1
  21. package/dist/infrastructure/index.d.ts +4 -4
  22. package/dist/infrastructure/index.js +12 -0
  23. package/dist/infrastructure/index.js.map +1 -1
  24. package/dist/kernel/index.d.ts +5 -5
  25. package/dist/kernel/index.js.map +1 -1
  26. package/dist/{mcp-servers-DFbirBv6.d.ts → mcp-servers-DfXxCASH.d.ts} +1 -1
  27. package/dist/models/index.d.ts +2 -2
  28. package/dist/{models-registry-CnJRjTXc.d.ts → models-registry-DpanBg8D.d.ts} +1 -1
  29. package/dist/{multi-agent-coordinator-60weDZoA.d.ts → multi-agent-coordinator-Bs-M0Mo6.d.ts} +1 -1
  30. package/dist/{null-fleet-bus-1068dEnr.d.ts → null-fleet-bus-CWdU1_cO.d.ts} +5 -5
  31. package/dist/observability/index.d.ts +1 -1
  32. package/dist/{package-outdated-watcher-pzJ5w7y8.d.ts → package-outdated-watcher-Dz-eNZlQ.d.ts} +23 -2
  33. package/dist/{parallel-eternal-engine-DtG1fjc9.d.ts → parallel-eternal-engine-CAMabk-X.d.ts} +5 -5
  34. package/dist/{path-resolver-CA1ULU0J.d.ts → path-resolver-B7VjhUHq.d.ts} +2 -2
  35. package/dist/{pipeline-DsmlwTXu.d.ts → pipeline-Bxa3wDcy.d.ts} +42 -2
  36. package/dist/{plan-templates-DPABrDvy.d.ts → plan-templates-D3guWwTi.d.ts} +2 -2
  37. package/dist/{provider-runner-D0HgUqwV.d.ts → provider-runner-C8_e4Lo1.d.ts} +1 -1
  38. package/dist/sdd/index.d.ts +5 -5
  39. package/dist/sdd/index.js +6 -8
  40. package/dist/sdd/index.js.map +1 -1
  41. package/dist/storage/index.d.ts +6 -6
  42. package/dist/storage/index.js.map +1 -1
  43. package/dist/types/index.d.ts +12 -12
  44. package/dist/types/index.js +17 -3
  45. package/dist/types/index.js.map +1 -1
  46. package/dist/utils/index.d.ts +11 -2
  47. package/dist/utils/index.js +8 -1
  48. package/dist/utils/index.js.map +1 -1
  49. 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-C658wj_c.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,12 +1,12 @@
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-C2eSNPsB.js';
2
- import { C as Container, R as ReadonlyPipeline, a as Renderer } from './pipeline-DsmlwTXu.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';
7
7
  import { P as PermissionPolicy } from './permission-DbWPbuoA.js';
8
8
  import { U as Usage, C as Context, J as JSONSchema, R as Request, b as Response, g as ContentBlock, n as TextBlock, T as Tool, P as Provider, o as RunOptions } from './context-CLz3z_E8.js';
9
- import { W as WireFamily, H as HookEvent, e as HookMatcher, I as InProcessHook, h as Config } from './config-Koq6f3fs.js';
9
+ import { W as WireFamily, H as HookEvent, e as HookMatcher, I as InProcessHook, h as Config } from './config-eSsrto5d.js';
10
10
 
11
11
  /**
12
12
  * Single fleet-wide event with subagent attribution. Whatever a child
@@ -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()`
@@ -393,6 +393,12 @@ interface IndexingConfig {
393
393
  watchExternal: boolean;
394
394
  /** Debounce window (ms) coalescing rapid edits to the same file. Default: 400. */
395
395
  debounceMs: number;
396
+ /**
397
+ * Watchdog timeout (ms) for a full index run. A run exceeding this is
398
+ * aborted (so it can never wedge the indexing mutex or freeze the terminal)
399
+ * and counts toward the indexing circuit breaker. Default: 120000.
400
+ */
401
+ indexTimeoutMs?: number | undefined;
396
402
  }
397
403
  /**
398
404
  * Saved launch preferences — restored on next boot so the pre-launch prompt
@@ -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-1068dEnr.js';
3
- import { A as AgentDefinition } from '../multi-agent-coordinator-60weDZoA.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-60weDZoA.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-C658wj_c.js';
6
- export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-Cimv7bK7.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-pzJ5w7y8.js';
8
- import { b as Mailbox } from '../pipeline-DsmlwTXu.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-DsmlwTXu.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
- import '../config-Koq6f3fs.js';
14
- import '../index-C2eSNPsB.js';
13
+ import '../config-eSsrto5d.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';
@@ -5295,6 +5295,11 @@ var SubagentBudget = class _SubagentBudget {
5295
5295
  }
5296
5296
  };
5297
5297
 
5298
+ // src/utils/string.ts
5299
+ function truncate(s, max) {
5300
+ return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
5301
+ }
5302
+
5298
5303
  // src/types/provider.ts
5299
5304
  var ProviderError = class extends WrongStackError {
5300
5305
  status;
@@ -5353,9 +5358,6 @@ function describeStatus(status, type) {
5353
5358
  if (type) return `${type} (${status})`;
5354
5359
  return `HTTP ${status}`;
5355
5360
  }
5356
- function truncate(s, n) {
5357
- return s.length <= n ? s : `${s.slice(0, n - 1)}\u2026`;
5358
- }
5359
5361
  function providerStatusToCode(status, type) {
5360
5362
  if (status === 0) return ERROR_CODES.PROVIDER_NETWORK_ERROR;
5361
5363
  if (type === "rate_limit_error" || status === 429) return ERROR_CODES.PROVIDER_RATE_LIMITED;
@@ -10039,6 +10041,14 @@ var DefaultMailbox = class {
10039
10041
  await fsp6.writeFile(this.filePath, "", "utf8");
10040
10042
  });
10041
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
+ }
10042
10052
  // ── Internal ──────────────────────────────────────────────────────────
10043
10053
  async _readAll() {
10044
10054
  try {
@@ -10215,7 +10225,9 @@ function wstackGlobalRoot() {
10215
10225
 
10216
10226
  // src/coordination/global-mailbox.ts
10217
10227
  var MAILBOX_FILE2 = "_mailbox.jsonl";
10228
+ var CLIENT_REGISTRY_FILE = "_mailbox.clients.json";
10218
10229
  var AGENT_STALE_MS = 6e4;
10230
+ var CLIENT_STALE_MS = 6e4;
10219
10231
  var HEARTBEAT_THROTTLE_MS = 5e3;
10220
10232
  var REGISTRY_CACHE_TTL_MS = 2e3;
10221
10233
  var LINE_SEPARATOR2 = "\n";
@@ -10227,6 +10239,8 @@ var GlobalMailbox = class {
10227
10239
  messagePath;
10228
10240
  /** Path to the JSON agent registry file. */
10229
10241
  registryPath;
10242
+ /** Path to the JSON client registry file. */
10243
+ clientRegistryPath;
10230
10244
  /** Optional event bus for emitting agent registration/heartbeat events. */
10231
10245
  _events;
10232
10246
  /**
@@ -10238,8 +10252,17 @@ var GlobalMailbox = class {
10238
10252
  _registryCache = null;
10239
10253
  /** When the registry cache was last refreshed from disk (epoch ms). */
10240
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;
10241
10262
  /** Last time each local agent sent a heartbeat (throttle). */
10242
10263
  _lastHeartbeat = /* @__PURE__ */ new Map();
10264
+ /** Last time each local client sent a heartbeat (throttle). */
10265
+ _lastClientHeartbeat = /* @__PURE__ */ new Map();
10243
10266
  /**
10244
10267
  * @param projectDir — `~/.wrongstack/projects/<slug>/`
10245
10268
  * @param events — optional EventBus for real-time TUI/WebUI notifications
@@ -10247,6 +10270,7 @@ var GlobalMailbox = class {
10247
10270
  constructor(projectDir, events) {
10248
10271
  this.messagePath = path4.join(projectDir, MAILBOX_FILE2);
10249
10272
  this.registryPath = path4.join(projectDir, "_mailbox.registry.json");
10273
+ this.clientRegistryPath = path4.join(projectDir, CLIENT_REGISTRY_FILE);
10250
10274
  this._events = events;
10251
10275
  }
10252
10276
  // ── Messages ────────────────────────────────────────────────────────────
@@ -10428,9 +10452,74 @@ var GlobalMailbox = class {
10428
10452
  const all = await this.getAgentStatuses();
10429
10453
  return all.filter((a) => a.online);
10430
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
+ }
10431
10519
  // ── Lifecycle ───────────────────────────────────────────────────────────
10432
10520
  async close() {
10433
10521
  this._registryCache = null;
10522
+ this._clientRegistryCache = null;
10434
10523
  }
10435
10524
  async clearAll() {
10436
10525
  await withFileLock(this.messagePath, async () => {
@@ -10509,6 +10598,51 @@ var GlobalMailbox = class {
10509
10598
  await fsp6.writeFile(tmp, JSON.stringify(obj, null, 2), "utf8");
10510
10599
  await fsp6.rename(tmp, this.registryPath);
10511
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
+ }
10512
10646
  };
10513
10647
  function defaultResolveProjectDir(ctx) {
10514
10648
  return resolveProjectDir(ctx.projectRoot, wstackGlobalRoot());