@corva/ui 3.78.0-1 → 3.78.0-2

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.
@@ -224,7 +224,7 @@ const MCP_PROTOCOL_VERSION = '2025-03-26';
224
224
  const MCP_NETWORK_TRANSPORT = 'pipe';
225
225
  const UNKNOWN_CLIENT_ATTR = 'unknown';
226
226
  const DEFAULT_SAMPLING_RATE = 1.0;
227
- const TELEMETRY_CONFIG_TIMEOUT_MS = 10_000;
227
+ const TELEMETRY_CONFIG_TIMEOUT_MS = 5000;
228
228
  const TELEMETRY_INIT_TIMEOUT_MS = 10_000;
229
229
  const TELEMETRY_SHUTDOWN_TIMEOUT_MS = 5000;
230
230
  const OTLP_TRACES_ENDPOINT = 'https://otlp.uptrace.dev/v1/traces';
@@ -246,9 +246,9 @@ const validateDsn = dsn => {
246
246
  return url.href;
247
247
  };
248
248
 
249
- const MCP_SERVER_VERSION = '1.5.1';
249
+ const MCP_SERVER_VERSION = '1.5.2';
250
250
 
251
- var version = "3.78.0-1";
251
+ var version = "3.78.0-2";
252
252
 
253
253
  const CORVA_UI_VERSION = version;
254
254
 
@@ -38053,6 +38053,7 @@ const formatUptime = ms => {
38053
38053
  }
38054
38054
  return `${seconds}s`;
38055
38055
  };
38056
+ const formatSeconds = ms => `${(ms / 1000).toFixed(2)}s`;
38056
38057
  const formatBytes = bytes => {
38057
38058
  const mb = bytes / (1024 * 1024);
38058
38059
  return `${mb.toFixed(1)} MB`;
@@ -38069,7 +38070,15 @@ const handleGetDiagnostics = (stats, telemetry, identity, registeredPromptNames)
38069
38070
  text += h2('Server');
38070
38071
  text += `${bold('Version')}: ${MCP_SERVER_VERSION}\n\n`;
38071
38072
  text += h2('Uptime');
38072
- text += `${bold('Server running for')}: ${formatUptime(uptimeMs)}\n\n`;
38073
+ text += `${bold('Server running for')}: ${formatUptime(uptimeMs)}\n`;
38074
+ if (stats.startupMs !== undefined) {
38075
+ text += `${bold('Startup')}: ${formatSeconds(stats.startupMs)} from process start to transport connected`;
38076
+ if (stats.telemetryInitMs !== undefined) {
38077
+ text += `, of which telemetry init ${formatSeconds(stats.telemetryInitMs)}`;
38078
+ }
38079
+ text += '\n';
38080
+ }
38081
+ text += '\n';
38073
38082
  text += h2('Memory Usage');
38074
38083
  text += table(['Metric', 'Value'], [['Heap Used', formatBytes(heapUsed)], ['Heap Total', formatBytes(heapTotal)], ['Resident Set Size', formatBytes(rss)]]);
38075
38084
  text += '\n\n';
@@ -38888,6 +38897,9 @@ class CorvaUiMcpServer {
38888
38897
  isConnected = false;
38889
38898
  startTime = Date.now();
38890
38899
  requestCount = 0;
38900
+
38901
+ /** Process start → transport connected, in ms. Set once run() has connected. */
38902
+
38891
38903
  telemetry = createNoopTelemetryClient();
38892
38904
  telemetryInfo = null;
38893
38905
  telemetryInitPromise = null;
@@ -39123,29 +39135,39 @@ class CorvaUiMcpServer {
39123
39135
  });
39124
39136
  }
39125
39137
  async run() {
39126
- const connectTimer = this.mcpLogger.time('transport-connect');
39127
- this.transport = new StdioServerTransport();
39128
- await this.server.connect(this.transport);
39129
- this.isConnected = true;
39130
- this.mcpLogger.timeEnd('transport-connect', connectTimer);
39131
- this.mcpLogger.info('Corva UI MCP Server running on stdio');
39132
- // Non-blocking: tool calls can begin; first calls within the 10s window may miss telemetry
39138
+ // Telemetry settles before the transport connects, so no request can reach a handler while
39139
+ // telemetry initialization is pending. Agents call tools right after initialize, and the
39140
+ // calls that landed during the config fetch used to get no span and no metric (AI-369). The
39141
+ // cost is an initialize response delayed by the fetch: ~2 s, at most the config timeout.
39142
+ // stdin stays paused until connect(), so nothing the client sends meanwhile is lost.
39143
+ const telemetryTimer = this.mcpLogger.time('telemetry-init');
39133
39144
  this.telemetryInitPromise = initTelemetry(this.mcpLogger).then(({
39134
39145
  client,
39135
39146
  info
39136
39147
  }) => {
39137
- if (this.shutdownRequested) {
39138
- client.shutdown().catch(() => {
39139
- /* shutting down anyway — a failed shutdown of a discarded client changes nothing */
39140
- });
39141
- } else {
39142
- this.telemetry = client;
39143
- this.telemetryInfo = info;
39144
- this.flushPendingInitData();
39145
- }
39148
+ this.telemetry = client;
39149
+ this.telemetryInfo = info;
39146
39150
  }).catch(() => {
39147
39151
  /* telemetry is best-effort — it must never take the server down */
39148
39152
  });
39153
+ await this.telemetryInitPromise;
39154
+ this.telemetryInitMs = telemetryTimer.stop();
39155
+ this.mcpLogger.timeEnd('telemetry-init', telemetryTimer);
39156
+
39157
+ // If shutdown was requested during the wait (a signal; a closed stdin is usually noticed only
39158
+ // once reading starts), shutdown() already runs and owns the client.
39159
+ if (this.shutdownRequested) {
39160
+ return;
39161
+ }
39162
+ const connectTimer = this.mcpLogger.time('transport-connect');
39163
+ this.transport = new StdioServerTransport();
39164
+ await this.server.connect(this.transport);
39165
+ this.isConnected = true;
39166
+ // performance.now() counts from process start, so this is the time to ready as the client saw
39167
+ // it, minus whatever ran before the process (the data regeneration in `yarn mcp:dev`).
39168
+ this.startupMs = performance.now();
39169
+ this.mcpLogger.timeEnd('transport-connect', connectTimer);
39170
+ this.mcpLogger.info('Corva UI MCP Server running on stdio');
39149
39171
  }
39150
39172
  async shutdown() {
39151
39173
  this.mcpLogger.info('Shutting down MCP server...');
@@ -39157,7 +39179,10 @@ class CorvaUiMcpServer {
39157
39179
  if (this.identityPromise) {
39158
39180
  await withTimeout(this.identityPromise, TELEMETRY_INIT_TIMEOUT_MS);
39159
39181
  }
39160
- if (this.telemetry.isEnabled()) {
39182
+
39183
+ // No transport means shutdown came during the telemetry wait: the client never connected, so
39184
+ // there is no session to end.
39185
+ if (this.telemetry.isEnabled() && this.transport) {
39161
39186
  const sessionDurationMs = Date.now() - this.startTime;
39162
39187
  const clientInfo = this.server.server.getClientVersion();
39163
39188
  this.telemetry.metrics.recordSessionEnd(sessionDurationMs, this.requestCount, clientInfo?.name, clientInfo?.version, this.projectIdentity);
@@ -39179,7 +39204,9 @@ class CorvaUiMcpServer {
39179
39204
  getStats() {
39180
39205
  return {
39181
39206
  startTime: this.startTime,
39182
- requestCount: this.requestCount
39207
+ requestCount: this.requestCount,
39208
+ startupMs: this.startupMs,
39209
+ telemetryInitMs: this.telemetryInitMs
39183
39210
  };
39184
39211
  }
39185
39212
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corva/ui",
3
- "version": "3.78.0-1",
3
+ "version": "3.78.0-2",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Shared components/utils for Corva ui projects",
6
6
  "repository": {