MCPcopy Create free account
hub / github.com/EvoMap/evolver / constructor

Method constructor

src/proxy/lifecycle/manager.js:448–513  ·  view source on GitHub ↗
({ hubUrl, store, logger, getTaskMeta } = {})

Source from the content-addressed store, hash-verified

446
447class LifecycleManager {
448 constructor({ hubUrl, store, logger, getTaskMeta } = {}) {
449 this.hubUrl = (hubUrl || process.env.A2A_HUB_URL || '').replace(/\/+$/, '');
450 this.store = store;
451 this.logger = logger || console;
452 this.getTaskMeta = getTaskMeta || null;
453 this._heartbeatTimer = null;
454 this._running = false;
455 this._startedAt = null;
456 this._lastHeartbeatTickAt = 0;
457 this._consecutiveFailures = 0;
458 this._reauthInProgress = false;
459 this._helloRateLimitUntil = 0;
460 this._reauthBackoffUntil = 0;
461 this._consecutiveReauthFailures = 0;
462 this._driftInterval = null;
463 this._lastDriftCheckAt = 0;
464 this._hubUnreachableFailures = 0;
465 this._hubUnreachableUntil = 0;
466 this._envSecretSuppressionMarker = normalizeNodeSecretEnvSuppression(this.store && this.store.getState
467 ? this.store.getState('node_secret_env_suppressed')
468 : null);
469 this._envSuppressionClearedForSecret = null;
470 this._suppressEnvSecret = Boolean(this._envSecretSuppressionMarker && getEnvNodeSecret());
471
472 // H4 fix: persist the legacy node_id file as soon as the in-memory
473 // node_id is known, NOT only after a successful hello(). The original
474 // code persisted only in hello() (see ~L390-398) — but proxy-mode boot
475 // can fire `reportForceUpdateOutcome` BEFORE hello() returns:
476 //
477 // - First-tick heartbeat hits 426 → executeForceUpdate() → exit(78)
478 // all happens BEFORE the hello() response is processed.
479 // - enrich.js force_update path can fire during the same window.
480 //
481 // `_shortNodeIdForStatePath` in a2aProtocol.js then picks the
482 // state-file suffix from `_cachedNodeId` (never set in proxy mode —
483 // only getNodeId() sets it, and proxy never calls getNodeId()) or the
484 // legacy ~/.evomap/node_id file. With both empty, it falls through
485 // to 'anon', and the outcome lands at `force_update_last.anon.json`.
486 // Next boot's hello() writes the real id, the heartbeat reads
487 // `force_update_last.<8hex>.json`, the anon file is orphaned and the
488 // outcome is silently lost.
489 //
490 // Persisting at construction closes the window. _persistLegacyNodeId
491 // early-returns on invalid input (NODE_ID_RE gate, same regex as the
492 // hello() path uses) so a malformed/empty store value is a no-op,
493 // and it is idempotent on matching content so the cost is one
494 // existsSync + one readFileSync per construction. We keep the
495 // existing post-hello call as a safety net in case hello() mints or
496 // mutates the id.
497 try {
498 const earlyNodeId = this.store && this.store.getState
499 ? this.store.getState('node_id')
500 : null;
501 if (earlyNodeId && NODE_ID_RE.test(earlyNodeId)) {
502 _persistLegacyNodeId(earlyNodeId);
503 }
504 } catch (e) {
505 // Best-effort: persistence failure must never break construction.

Callers

nothing calls this directly

Calls 4

getEnvNodeSecretFunction · 0.85
_persistLegacyNodeIdFunction · 0.85
getStateMethod · 0.80

Tested by

no test coverage detected