@alfe.ai/gateway 0.2.5 → 0.3.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as installService, c as uninstallService, f as SOCKET_PATH, i as checkExistingDaemon, n as queryDaemonHealth, r as startDaemon, s as stopExistingDaemon, t as formatHealthReport } from "../health.js";
2
+ import { a as installService, c as uninstallService, i as checkExistingDaemon, n as queryDaemonHealth, r as startDaemon, s as stopExistingDaemon, t as formatHealthReport, v as SOCKET_PATH } from "../health.js";
3
3
  import { t as LOG_FILE } from "../logger.js";
4
4
  import { spawn } from "node:child_process";
5
5
  //#region bin/gateway.ts
package/dist/health.js CHANGED
@@ -7,7 +7,7 @@ import { dirname, join } from "node:path";
7
7
  import { homedir } from "node:os";
8
8
  import pino from "pino";
9
9
  import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
10
- import { getEndpointFromToken, readConfig } from "@alfe.ai/config";
10
+ import { getEndpointFromToken, readConfig, resolveConfig } from "@alfe.ai/config";
11
11
  import crypto from "crypto";
12
12
  import { parse } from "smol-toml";
13
13
  import WebSocket from "ws";
@@ -5330,6 +5330,195 @@ var NoopRuntimeGate = class {
5330
5330
  requestRestart() {}
5331
5331
  };
5332
5332
  //#endregion
5333
+ //#region src/sentry.ts
5334
+ /**
5335
+ * Agent-side error reporting (Sentry) for the Alfe CLI + gateway daemon.
5336
+ *
5337
+ * This module is the single Sentry bootstrap shared by both published
5338
+ * agent-side packages — `@alfe.ai/gateway` (the daemon) and `@alfe.ai/cli`
5339
+ * (which re-imports these helpers from `@alfe.ai/gateway`). It exists so
5340
+ * integration-installation failures on customer/managed VMs surface centrally
5341
+ * instead of silently rotting until someone SSHes into the box.
5342
+ *
5343
+ * Design constraints (see packages/gateway/DEVELOPING.md → "Error reporting"):
5344
+ * - Errors only. No tracing/profiling (`tracesSampleRate: 0`, `sampleRate: 1`).
5345
+ * - `@sentry/node` is lazy-imported so `alfe --version` doesn't pay for it.
5346
+ * - Sentry can NEVER break the CLI/daemon — every entry point is try/catch'd.
5347
+ * - The DSNs are baked as constants: published tarballs run on agent VMs and
5348
+ * cannot read the repo's `config/config.ts`. That file's `SENTRY_DSNS`
5349
+ * registry (keys `agentDaemon` + `cli`) mirrors them as the human reference.
5350
+ * - Secrets are scrubbed in `beforeSend`; request/env payloads are dropped.
5351
+ * - Opt-out via `ALFE_ERROR_REPORTING=0|false` or `errorReporting = false`
5352
+ * in `~/.alfe/config.toml`. Default ON.
5353
+ */
5354
+ /**
5355
+ * Baked per-surface Sentry DSNs (org `alfe-ai`). DSNs are public by design
5356
+ * (they only permit event ingestion). Mirrors of `config/config.ts` →
5357
+ * `SENTRY_DSNS.agentDaemon` / `SENTRY_DSNS.cli`. If you rotate a DSN, update
5358
+ * both places.
5359
+ */
5360
+ const AGENT_DAEMON_SENTRY_DSN = "https://a47f010d8d39fb4350f913492189f283@o4511008239452160.ingest.us.sentry.io/4511679448547328";
5361
+ /** Surface → Sentry project: `cli` and `agent-daemon` respectively. */
5362
+ const SURFACE_DSNS = {
5363
+ cli: "https://82dde4631336561f2fcc89d7531623de@o4511008239452160.ingest.us.sentry.io/4511679411191808",
5364
+ daemon: AGENT_DAEMON_SENTRY_DSN
5365
+ };
5366
+ /** Held after a successful init so the capture helpers can run synchronously. */
5367
+ let sentry = null;
5368
+ /**
5369
+ * Map the configured API URL to a coarse environment tag. Best-effort — returns
5370
+ * `"unknown"` when no config is present yet (e.g. `alfe login` pre-setup).
5371
+ */
5372
+ function deriveEnvironment() {
5373
+ try {
5374
+ const { apiUrl } = resolveConfig();
5375
+ if (apiUrl.includes("api.dev.alfe.ai") || apiUrl.includes("dev.alfe.ai")) return "dev";
5376
+ if (apiUrl.includes("api.test.alfe.ai")) return "test";
5377
+ if (apiUrl.includes("api.demo.alfe.ai")) return "demo";
5378
+ if (apiUrl.includes("api.alfe.ai")) return "prod";
5379
+ } catch {}
5380
+ return "unknown";
5381
+ }
5382
+ /** Active runtime (`openclaw`/`hermes`) from config, or undefined if unknown. */
5383
+ function deriveRuntime() {
5384
+ try {
5385
+ return resolveConfig().runtime;
5386
+ } catch {
5387
+ return;
5388
+ }
5389
+ }
5390
+ /** True when the operator has opted out of error reporting. */
5391
+ function errorReportingDisabled() {
5392
+ const env = process.env.ALFE_ERROR_REPORTING?.trim().toLowerCase();
5393
+ if (env === "0" || env === "false") return true;
5394
+ try {
5395
+ if (readConfig().errorReporting === false) return true;
5396
+ } catch {}
5397
+ return false;
5398
+ }
5399
+ const KV_SECRET_RE = /\b(authorization|api[_-]?key|apikey|token|secret|password|passwd|bearer)\b(\s*[:=]\s*|\s+)("?)([^\s"']+)\3/gi;
5400
+ const MIN_BARE_SECRET_LEN = 16;
5401
+ const ALFE_TOKEN_RE = /alfe_(?:dev|test|demo|live)_[A-Za-z0-9._-]+/g;
5402
+ const BEARER_RE = /\bbearer\s+[A-Za-z0-9._\-+/=]+/gi;
5403
+ function scrubString(value) {
5404
+ return value.replace(BEARER_RE, "Bearer [REDACTED]").replace(KV_SECRET_RE, (match, label, sep, _q, secret) => {
5405
+ if (!/[:=]/.test(sep) && secret.length < MIN_BARE_SECRET_LEN) return match;
5406
+ return `${label}${sep}[REDACTED]`;
5407
+ }).replace(ALFE_TOKEN_RE, "alfe_[REDACTED]");
5408
+ }
5409
+ /** Scrub secrets from a breadcrumb's message + string data values in place. */
5410
+ function scrubBreadcrumb(b) {
5411
+ if (typeof b.message === "string") b.message = scrubString(b.message);
5412
+ const data = b.data;
5413
+ if (data) for (const k of Object.keys(data)) {
5414
+ const dv = data[k];
5415
+ if (typeof dv === "string") data[k] = scrubString(dv);
5416
+ }
5417
+ return b;
5418
+ }
5419
+ /**
5420
+ * Scrub secrets and drop request/env payloads before an event is sent.
5421
+ * Generic so it preserves the caller's exact event subtype (`beforeSend`
5422
+ * receives — and must return — an `ErrorEvent`, not a widened `Event`).
5423
+ */
5424
+ function scrubEvent(event) {
5425
+ delete event.request;
5426
+ if (event.contexts) delete event.contexts.runtime;
5427
+ delete event.extra;
5428
+ delete event.server_name;
5429
+ if (typeof event.message === "string") event.message = scrubString(event.message);
5430
+ const values = event.exception?.values;
5431
+ if (values) {
5432
+ for (const v of values) if (typeof v.value === "string") v.value = scrubString(v.value);
5433
+ }
5434
+ if (event.breadcrumbs) for (const b of event.breadcrumbs) scrubBreadcrumb(b);
5435
+ return event;
5436
+ }
5437
+ /**
5438
+ * Initialise Sentry for the agent-side CLI/daemon. Idempotent, best-effort, and
5439
+ * a no-op when opted out or when the baked DSN is empty. Never throws.
5440
+ */
5441
+ async function initAgentSentry(options) {
5442
+ try {
5443
+ if (sentry) return;
5444
+ if (errorReportingDisabled()) return;
5445
+ const dsn = SURFACE_DSNS[options.surface].trim();
5446
+ if (!dsn) return;
5447
+ const mod = await import("@sentry/node");
5448
+ if (mod.getClient()) {
5449
+ sentry = mod;
5450
+ return;
5451
+ }
5452
+ mod.init({
5453
+ dsn,
5454
+ environment: deriveEnvironment(),
5455
+ ...options.release ? { release: options.release } : {},
5456
+ sampleRate: 1,
5457
+ tracesSampleRate: 0,
5458
+ sendDefaultPii: false,
5459
+ beforeSend: (event) => scrubEvent(event),
5460
+ beforeBreadcrumb: (breadcrumb) => scrubBreadcrumb(breadcrumb)
5461
+ });
5462
+ sentry = mod;
5463
+ mod.setTag("surface", options.surface);
5464
+ const runtime = deriveRuntime();
5465
+ if (runtime) mod.setTag("runtime", runtime);
5466
+ } catch {
5467
+ sentry = null;
5468
+ }
5469
+ }
5470
+ /**
5471
+ * Attach the resolved agent identity to all subsequent events. Called by the
5472
+ * daemon once `loadDaemonConfig()` has resolved `agentId`/`runtime`.
5473
+ */
5474
+ function setAgentContext(context) {
5475
+ if (!sentry) return;
5476
+ try {
5477
+ if (context.agentId) sentry.setTag("agentId", context.agentId);
5478
+ if (context.runtime) sentry.setTag("runtime", context.runtime);
5479
+ } catch {}
5480
+ }
5481
+ /**
5482
+ * Capture an integration lifecycle failure (install/activate/reinstall/remove)
5483
+ * with `{ integration, phase }` tags. Accepts an `Error` (captured with stack)
5484
+ * or a plain message string (captured as an error-level message). No-op when
5485
+ * Sentry is not initialised.
5486
+ */
5487
+ function captureIntegrationFailure(integration, phase, cause) {
5488
+ if (!sentry) return;
5489
+ try {
5490
+ if (cause instanceof Error) sentry.captureException(cause, { tags: {
5491
+ integration,
5492
+ phase
5493
+ } });
5494
+ else sentry.captureMessage(String(cause), {
5495
+ level: "error",
5496
+ tags: {
5497
+ integration,
5498
+ phase
5499
+ }
5500
+ });
5501
+ } catch {}
5502
+ }
5503
+ /** Flush queued events (small timeout) so short-lived commands deliver them. */
5504
+ async function flushSentry(timeoutMs = 2e3) {
5505
+ if (!sentry) return;
5506
+ try {
5507
+ await sentry.flush(timeoutMs);
5508
+ } catch {}
5509
+ }
5510
+ /**
5511
+ * Capture a fatal error — for the CLI's top-level catch. Does NOT flush: the
5512
+ * caller's `finally { await flushSentry() }` delivers it (flushing here too
5513
+ * doubled the worst-case exit delay on a failing command).
5514
+ */
5515
+ function captureFatal(cause) {
5516
+ if (!sentry) return;
5517
+ try {
5518
+ sentry.captureException(cause);
5519
+ } catch {}
5520
+ }
5521
+ //#endregion
5333
5522
  //#region src/reconciliation.ts
5334
5523
  const log$2 = logger$1.child({ component: "Reconciliation" });
5335
5524
  /**
@@ -5466,6 +5655,7 @@ var ReconciliationEngine = class {
5466
5655
  const attempts = this.manager.getReinstallAttempts(id);
5467
5656
  if (attempts >= 3) {
5468
5657
  log$2.error(`Auto-reinstall blocked for ${id} — ${String(attempts)} consecutive failures. Manual reinstall required.`);
5658
+ captureIntegrationFailure(id, "reinstall", `Max auto-reinstall attempts (${String(attempts)}) reached — manual reinstall required`);
5469
5659
  report.errors.push({
5470
5660
  integrationId: id,
5471
5661
  error: `Max auto-reinstall attempts (${String(attempts)}) reached`
@@ -5495,6 +5685,7 @@ var ReconciliationEngine = class {
5495
5685
  } catch (reinstallErr) {
5496
5686
  const reinstallMsg = reinstallErr instanceof Error ? reinstallErr.message : String(reinstallErr);
5497
5687
  log$2.error({ err: reinstallErr }, `Auto-reinstall failed for ${id}`);
5688
+ captureIntegrationFailure(id, "reinstall", reinstallErr);
5498
5689
  report.errors.push({
5499
5690
  integrationId: id,
5500
5691
  error: reinstallMsg
@@ -5526,6 +5717,7 @@ var ReconciliationEngine = class {
5526
5717
  } catch (reactivateErr) {
5527
5718
  const reactivateMsg = reactivateErr instanceof Error ? reactivateErr.message : String(reactivateErr);
5528
5719
  log$2.warn(`Re-activation of ${id} from error state failed (attempt ${String(activateAttempts + 1)}/${String(MAX_ERROR_ACTIVATE_ATTEMPTS)}): ${reactivateMsg}`);
5720
+ captureIntegrationFailure(id, "reactivate", reactivateErr);
5529
5721
  report.errors.push({
5530
5722
  integrationId: id,
5531
5723
  error: reactivateMsg
@@ -5540,6 +5732,7 @@ var ReconciliationEngine = class {
5540
5732
  }
5541
5733
  }
5542
5734
  log$2.warn(`Integration ${id} is in error state — re-activation exhausted, waiting for reinstall request`);
5735
+ captureIntegrationFailure(id, "reactivate", `Integration ${id} stuck in error state — re-activation attempts exhausted`);
5543
5736
  report.errors.push({
5544
5737
  integrationId: id,
5545
5738
  error: "Integration is in error state"
@@ -5588,6 +5781,7 @@ var ReconciliationEngine = class {
5588
5781
  } catch (err) {
5589
5782
  const message = err instanceof Error ? err.message : String(err);
5590
5783
  log$2.error({ err }, `Error reconciling ${id}`);
5784
+ captureIntegrationFailure(id, "reconcile_active", err);
5591
5785
  report.errors.push({
5592
5786
  integrationId: id,
5593
5787
  error: message
@@ -5626,6 +5820,7 @@ var ReconciliationEngine = class {
5626
5820
  } catch (err) {
5627
5821
  const message = err instanceof Error ? err.message : String(err);
5628
5822
  log$2.error({ err }, `Error removing ${id}`);
5823
+ captureIntegrationFailure(id, "reconcile_removed", err);
5629
5824
  report.errors.push({
5630
5825
  integrationId: id,
5631
5826
  error: message
@@ -22530,6 +22725,7 @@ async function getRuntimeVersion(runtime) {
22530
22725
  * process.exit() can drop buffered log lines — this ensures they're written first.
22531
22726
  */
22532
22727
  async function flushAndExit(code) {
22728
+ await flushSentry();
22533
22729
  await new Promise((resolve) => {
22534
22730
  logger$1.flush();
22535
22731
  setTimeout(resolve, 500);
@@ -22592,6 +22788,10 @@ async function startDaemon() {
22592
22788
  managed,
22593
22789
  pid: process.pid
22594
22790
  }, "Starting Alfe Gateway Daemon...");
22791
+ await initAgentSentry({
22792
+ surface: "daemon",
22793
+ release: await getCliVersion()
22794
+ });
22595
22795
  if (!managed) {
22596
22796
  await mkdir(join(homedir(), ".alfe"), { recursive: true });
22597
22797
  const existingPid = await checkExistingDaemon();
@@ -22608,6 +22808,10 @@ async function startDaemon() {
22608
22808
  orgId: config.orgId,
22609
22809
  wsUrl: config.gatewayWsUrl
22610
22810
  }, "Config loaded, identity resolved");
22811
+ setAgentContext({
22812
+ agentId: config.agentId,
22813
+ runtime: config.runtime
22814
+ });
22611
22815
  } catch (err) {
22612
22816
  const message = err instanceof Error ? err.message : String(err);
22613
22817
  const stack = err instanceof Error ? err.stack : void 0;
@@ -23575,4 +23779,4 @@ function formatDuration(ms) {
23575
23779
  return `${String(Math.round(seconds / 3600))}h`;
23576
23780
  }
23577
23781
  //#endregion
23578
- export { installService as a, uninstallService as c, PID_PATH as d, SOCKET_PATH as f, PINNED_OPENCLAW_VERSION as g, resolveAgentIdentity as h, checkExistingDaemon as i, PROTOCOL_VERSION as l, loadDaemonConfig as m, queryDaemonHealth as n, startService as o, fetchAgentConfig as p, startDaemon as r, stopExistingDaemon as s, formatHealthReport as t, ALFE_DIR as u };
23782
+ export { PINNED_OPENCLAW_VERSION as S, PID_PATH as _, installService as a, loadDaemonConfig as b, uninstallService as c, captureIntegrationFailure as d, flushSentry as f, ALFE_DIR as g, PROTOCOL_VERSION as h, checkExistingDaemon as i, AGENT_DAEMON_SENTRY_DSN as l, setAgentContext as m, queryDaemonHealth as n, startService as o, initAgentSentry as p, startDaemon as r, stopExistingDaemon as s, formatHealthReport as t, captureFatal as u, SOCKET_PATH as v, resolveAgentIdentity as x, fetchAgentConfig as y };
@@ -46,6 +46,71 @@ declare function startDaemon(): Promise<void>;
46
46
  */
47
47
  declare const PINNED_OPENCLAW_VERSION = "2026.6.8";
48
48
  //#endregion
49
+ //#region src/sentry.d.ts
50
+ /**
51
+ * Agent-side error reporting (Sentry) for the Alfe CLI + gateway daemon.
52
+ *
53
+ * This module is the single Sentry bootstrap shared by both published
54
+ * agent-side packages — `@alfe.ai/gateway` (the daemon) and `@alfe.ai/cli`
55
+ * (which re-imports these helpers from `@alfe.ai/gateway`). It exists so
56
+ * integration-installation failures on customer/managed VMs surface centrally
57
+ * instead of silently rotting until someone SSHes into the box.
58
+ *
59
+ * Design constraints (see packages/gateway/DEVELOPING.md → "Error reporting"):
60
+ * - Errors only. No tracing/profiling (`tracesSampleRate: 0`, `sampleRate: 1`).
61
+ * - `@sentry/node` is lazy-imported so `alfe --version` doesn't pay for it.
62
+ * - Sentry can NEVER break the CLI/daemon — every entry point is try/catch'd.
63
+ * - The DSNs are baked as constants: published tarballs run on agent VMs and
64
+ * cannot read the repo's `config/config.ts`. That file's `SENTRY_DSNS`
65
+ * registry (keys `agentDaemon` + `cli`) mirrors them as the human reference.
66
+ * - Secrets are scrubbed in `beforeSend`; request/env payloads are dropped.
67
+ * - Opt-out via `ALFE_ERROR_REPORTING=0|false` or `errorReporting = false`
68
+ * in `~/.alfe/config.toml`. Default ON.
69
+ */
70
+ /**
71
+ * Baked per-surface Sentry DSNs (org `alfe-ai`). DSNs are public by design
72
+ * (they only permit event ingestion). Mirrors of `config/config.ts` →
73
+ * `SENTRY_DSNS.agentDaemon` / `SENTRY_DSNS.cli`. If you rotate a DSN, update
74
+ * both places.
75
+ */
76
+ declare const AGENT_DAEMON_SENTRY_DSN = "https://a47f010d8d39fb4350f913492189f283@o4511008239452160.ingest.us.sentry.io/4511679448547328";
77
+ /** Which surface initialised Sentry — tagged on every event. */
78
+ type SentrySurface = "cli" | "daemon";
79
+ interface InitAgentSentryOptions {
80
+ /** `"cli"` or `"daemon"` — tagged as `surface`. */
81
+ surface: SentrySurface;
82
+ /** Release identifier — the package version. */
83
+ release?: string;
84
+ }
85
+ /**
86
+ * Initialise Sentry for the agent-side CLI/daemon. Idempotent, best-effort, and
87
+ * a no-op when opted out or when the baked DSN is empty. Never throws.
88
+ */
89
+ declare function initAgentSentry(options: InitAgentSentryOptions): Promise<void>;
90
+ /**
91
+ * Attach the resolved agent identity to all subsequent events. Called by the
92
+ * daemon once `loadDaemonConfig()` has resolved `agentId`/`runtime`.
93
+ */
94
+ declare function setAgentContext(context: {
95
+ agentId?: string;
96
+ runtime?: string;
97
+ }): void;
98
+ /**
99
+ * Capture an integration lifecycle failure (install/activate/reinstall/remove)
100
+ * with `{ integration, phase }` tags. Accepts an `Error` (captured with stack)
101
+ * or a plain message string (captured as an error-level message). No-op when
102
+ * Sentry is not initialised.
103
+ */
104
+ declare function captureIntegrationFailure(integration: string, phase: string, cause: unknown): void;
105
+ /** Flush queued events (small timeout) so short-lived commands deliver them. */
106
+ declare function flushSentry(timeoutMs?: number): Promise<void>;
107
+ /**
108
+ * Capture a fatal error — for the CLI's top-level catch. Does NOT flush: the
109
+ * caller's `finally { await flushSentry() }` delivers it (flushing here too
110
+ * doubled the worst-case exit delay on a failing command).
111
+ */
112
+ declare function captureFatal(cause: unknown): void;
113
+ //#endregion
49
114
  //#region src/config.d.ts
50
115
  /**
51
116
  * Daemon configuration — reads ~/.alfe/config.toml and resolves agent identity.
@@ -218,4 +283,4 @@ declare function checkExistingDaemon(): Promise<number | null>;
218
283
  */
219
284
  declare function stopExistingDaemon(): Promise<boolean>;
220
285
  //#endregion
221
- export { ALFE_DIR, type AgentIdentity, type AgentWorkspaceConfig, type DaemonConfig, type DaemonHealth, type IPCEvent, type IPCRequest, type IPCResponse, PID_PATH, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, SOCKET_PATH, checkExistingDaemon, fetchAgentConfig, formatHealthReport, installService, loadDaemonConfig, logger, queryDaemonHealth, resolveAgentIdentity, startDaemon, startService, stopExistingDaemon, uninstallService };
286
+ export { AGENT_DAEMON_SENTRY_DSN, ALFE_DIR, type AgentIdentity, type AgentWorkspaceConfig, type DaemonConfig, type DaemonHealth, type IPCEvent, type IPCRequest, type IPCResponse, type InitAgentSentryOptions, PID_PATH, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, SOCKET_PATH, type SentrySurface, captureFatal, captureIntegrationFailure, checkExistingDaemon, fetchAgentConfig, flushSentry, formatHealthReport, initAgentSentry, installService, loadDaemonConfig, logger, queryDaemonHealth, resolveAgentIdentity, setAgentContext, startDaemon, startService, stopExistingDaemon, uninstallService };
package/dist/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { a as installService, c as uninstallService, d as PID_PATH, f as SOCKET_PATH, g as PINNED_OPENCLAW_VERSION, h as resolveAgentIdentity, i as checkExistingDaemon, l as PROTOCOL_VERSION, m as loadDaemonConfig, n as queryDaemonHealth, o as startService, p as fetchAgentConfig, r as startDaemon, s as stopExistingDaemon, t as formatHealthReport, u as ALFE_DIR } from "../health.js";
1
+ import { S as PINNED_OPENCLAW_VERSION, _ as PID_PATH, a as installService, b as loadDaemonConfig, c as uninstallService, d as captureIntegrationFailure, f as flushSentry, g as ALFE_DIR, h as PROTOCOL_VERSION, i as checkExistingDaemon, l as AGENT_DAEMON_SENTRY_DSN, m as setAgentContext, n as queryDaemonHealth, o as startService, p as initAgentSentry, r as startDaemon, s as stopExistingDaemon, t as formatHealthReport, u as captureFatal, v as SOCKET_PATH, x as resolveAgentIdentity, y as fetchAgentConfig } from "../health.js";
2
2
  import { n as logger } from "../logger.js";
3
- export { ALFE_DIR, PID_PATH, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, SOCKET_PATH, checkExistingDaemon, fetchAgentConfig, formatHealthReport, installService, loadDaemonConfig, logger, queryDaemonHealth, resolveAgentIdentity, startDaemon, startService, stopExistingDaemon, uninstallService };
3
+ export { AGENT_DAEMON_SENTRY_DSN, ALFE_DIR, PID_PATH, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, SOCKET_PATH, captureFatal, captureIntegrationFailure, checkExistingDaemon, fetchAgentConfig, flushSentry, formatHealthReport, initAgentSentry, installService, loadDaemonConfig, logger, queryDaemonHealth, resolveAgentIdentity, setAgentContext, startDaemon, startService, stopExistingDaemon, uninstallService };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/gateway",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "Alfe local gateway daemon — persistent control plane for agent integrations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,7 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
+ "@sentry/node": "^10.42.0",
21
22
  "pino": "^9.6.0",
22
23
  "pino-roll": "^1.2.0",
23
24
  "smol-toml": ">=1.6.1",
@@ -26,7 +27,7 @@
26
27
  "@alfe.ai/ai-proxy-local": "^0.0.13",
27
28
  "@alfe.ai/config": "^0.3.0",
28
29
  "@alfe.ai/integration-manifest": "^0.3.1",
29
- "@alfe.ai/integrations": "^0.2.6",
30
+ "@alfe.ai/integrations": "^0.2.7",
30
31
  "@alfe.ai/mcp-bundler": "^0.2.2"
31
32
  },
32
33
  "license": "UNLICENSED",