@merittdev/horus 0.12.4 → 0.12.5

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 (2) hide show
  1. package/dist/index.cjs +127 -153
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -65880,7 +65880,7 @@ init_cjs_shims();
65880
65880
 
65881
65881
  // ../../packages/core/src/version.ts
65882
65882
  init_cjs_shims();
65883
- var HORUS_VERSION = true ? "0.12.4" : "dev";
65883
+ var HORUS_VERSION = true ? "0.12.5" : "dev";
65884
65884
  var PINNED_SOURCE_VERSION = "2.0.2";
65885
65885
 
65886
65886
  // ../../packages/core/src/evidence.ts
@@ -121842,6 +121842,120 @@ function extractPort2(hostUrl) {
121842
121842
  init_cjs_shims();
121843
121843
  var import_picocolors44 = __toESM(require_picocolors(), 1);
121844
121844
  var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
121845
+ var CONNECTOR_CHECKS = {
121846
+ // Elasticsearch (runtime logs)
121847
+ elasticsearch: {
121848
+ label: "Elasticsearch",
121849
+ absentNext: "add connectors.elasticsearch to an environment in your Horus config for runtime log evidence",
121850
+ check: (es, ctx) => !es.indexPattern ? {
121851
+ label: "Elasticsearch",
121852
+ status: "warn",
121853
+ detail: `${ctx} \u2014 indexPattern not set`,
121854
+ next: "set indexPattern in connectors.elasticsearch"
121855
+ } : {
121856
+ label: "Elasticsearch",
121857
+ status: "pass",
121858
+ detail: `${ctx} \u2014 ${es.indexPattern} [runtime ingestion pending]`
121859
+ }
121860
+ },
121861
+ // Grafana (metrics)
121862
+ grafana: {
121863
+ label: "Grafana",
121864
+ absentNext: "add connectors.grafana to an environment for metric evidence",
121865
+ check: (g4, ctx) => !g4.url ? {
121866
+ label: "Grafana",
121867
+ status: "warn",
121868
+ detail: `${ctx} \u2014 URL not set`,
121869
+ next: "set grafana.url or grafana.urlEnv in your Horus config"
121870
+ } : {
121871
+ label: "Grafana",
121872
+ status: "pass",
121873
+ detail: `${ctx} \u2014 URL configured${g4.dashboard ? ` (${g4.dashboard})` : ""} [runtime ingestion pending]`
121874
+ }
121875
+ },
121876
+ // MongoDB (state)
121877
+ mongodb: {
121878
+ label: "MongoDB",
121879
+ absentNext: "add connectors.mongodb to an environment for database state evidence",
121880
+ check: (m5, ctx) => !m5.url ? {
121881
+ label: "MongoDB",
121882
+ status: "warn",
121883
+ detail: `${ctx} \u2014 URL not set`,
121884
+ next: "set mongodb.url or mongodb.urlEnv in your Horus config"
121885
+ } : {
121886
+ label: "MongoDB",
121887
+ status: "pass",
121888
+ detail: `${ctx} \u2014 ${m5.database} [runtime ingestion pending]`
121889
+ }
121890
+ },
121891
+ // Postgres (state)
121892
+ postgres: {
121893
+ label: "Postgres",
121894
+ absentNext: "add connectors.postgres to an environment for database state evidence",
121895
+ check: (p5, ctx) => !p5.url ? {
121896
+ label: "Postgres",
121897
+ status: "warn",
121898
+ detail: `${ctx} \u2014 URL not set`,
121899
+ next: "set postgres.url or postgres.urlEnv in your Horus config"
121900
+ } : {
121901
+ label: "Postgres",
121902
+ status: "pass",
121903
+ detail: `${ctx} \u2014 ${p5.database ?? p5.schema ?? "postgres"} [runtime ingestion pending]`
121904
+ }
121905
+ },
121906
+ // Sentry (error tracking)
121907
+ sentry: {
121908
+ label: "Sentry",
121909
+ absentNext: "add connectors.sentry to an environment for error-tracking evidence",
121910
+ check: (s5, ctx) => {
121911
+ const tokenSet = s5.authToken || process.env[s5.authTokenEnv ?? "SENTRY_AUTH_TOKEN"];
121912
+ return !tokenSet ? {
121913
+ label: "Sentry",
121914
+ status: "warn",
121915
+ detail: `${ctx} \u2014 auth token not set`,
121916
+ next: "set sentry.authToken or sentry.authTokenEnv (default SENTRY_AUTH_TOKEN) in your Horus config"
121917
+ } : {
121918
+ label: "Sentry",
121919
+ status: "pass",
121920
+ detail: `${ctx} \u2014 ${s5.org}/${s5.project} [runtime ingestion pending]`
121921
+ };
121922
+ }
121923
+ },
121924
+ // Axiom (structured logs) — HOR-437: previously omitted from doctor entirely.
121925
+ axiom: {
121926
+ label: "Axiom",
121927
+ absentNext: "add connectors.axiom to an environment for structured log evidence",
121928
+ check: (a2, ctx) => {
121929
+ const tokenSet = a2.token || process.env[a2.tokenEnv ?? "AXIOM_TOKEN"];
121930
+ return !tokenSet ? {
121931
+ label: "Axiom",
121932
+ status: "warn",
121933
+ detail: `${ctx} \u2014 API token not set`,
121934
+ next: "set axiom.token or axiom.tokenEnv (default AXIOM_TOKEN) in your Horus config"
121935
+ } : {
121936
+ label: "Axiom",
121937
+ status: "pass",
121938
+ detail: `${ctx} \u2014 ${a2.dataset} [runtime ingestion pending]`
121939
+ };
121940
+ }
121941
+ },
121942
+ // Redis / BullMQ (queue + cache/state)
121943
+ redis: {
121944
+ label: "Redis",
121945
+ absentNext: "add connectors.redis to an environment for queue state evidence",
121946
+ check: (r, ctx) => !r.url ? {
121947
+ label: "Redis",
121948
+ status: "warn",
121949
+ detail: `${ctx} \u2014 URL not set`,
121950
+ next: "set redis.url or redis.urlEnv in your Horus config"
121951
+ } : {
121952
+ label: "Redis",
121953
+ status: "pass",
121954
+ detail: `${ctx} \u2014 URL configured [runtime ingestion pending]`
121955
+ }
121956
+ }
121957
+ };
121958
+ var DOCTOR_CONNECTOR_KEYS = Object.keys(CONNECTOR_CHECKS);
121845
121959
  function mark2(status) {
121846
121960
  if (status === "pass") return import_picocolors44.default.green("\u2713");
121847
121961
  if (status === "warn") return import_picocolors44.default.yellow("~");
@@ -121943,168 +122057,28 @@ async function runDoctor(opts) {
121943
122057
  }
121944
122058
  try {
121945
122059
  const globalConfig2 = await loadConfig(opts?.config, { cwd });
121946
- let anyEs = false;
121947
- let anyGrafana = false;
121948
- let anyMongo = false;
121949
- let anyPostgres = false;
121950
- let anySentry = false;
121951
- let anyRedis = false;
122060
+ const configured = /* @__PURE__ */ new Set();
121952
122061
  for (const project of globalConfig2.projects) {
121953
122062
  for (const env of project.environments) {
121954
122063
  const ctx = `${project.name}/${env.name}`;
121955
122064
  const c4 = env.connectors;
121956
- if (c4.elasticsearch) {
121957
- anyEs = true;
121958
- if (!c4.elasticsearch.indexPattern) {
121959
- checks.push({
121960
- label: "Elasticsearch",
121961
- status: "warn",
121962
- detail: `${ctx} \u2014 indexPattern not set`,
121963
- next: "set indexPattern in connectors.elasticsearch"
121964
- });
121965
- } else {
121966
- checks.push({
121967
- label: "Elasticsearch",
121968
- status: "pass",
121969
- detail: `${ctx} \u2014 ${c4.elasticsearch.indexPattern} [runtime ingestion pending]`
121970
- });
121971
- }
121972
- }
121973
- if (c4.grafana) {
121974
- anyGrafana = true;
121975
- if (!c4.grafana.url) {
121976
- checks.push({
121977
- label: "Grafana",
121978
- status: "warn",
121979
- detail: `${ctx} \u2014 URL not set`,
121980
- next: "set grafana.url or grafana.urlEnv in your Horus config"
121981
- });
121982
- } else {
121983
- const dashHint = c4.grafana.dashboard ? ` (${c4.grafana.dashboard})` : "";
121984
- checks.push({
121985
- label: "Grafana",
121986
- status: "pass",
121987
- detail: `${ctx} \u2014 URL configured${dashHint} [runtime ingestion pending]`
121988
- });
121989
- }
121990
- }
121991
- if (c4.mongodb) {
121992
- anyMongo = true;
121993
- if (!c4.mongodb.url) {
121994
- checks.push({
121995
- label: "MongoDB",
121996
- status: "warn",
121997
- detail: `${ctx} \u2014 URL not set`,
121998
- next: "set mongodb.url or mongodb.urlEnv in your Horus config"
121999
- });
122000
- } else {
122001
- checks.push({
122002
- label: "MongoDB",
122003
- status: "pass",
122004
- detail: `${ctx} \u2014 ${c4.mongodb.database} [runtime ingestion pending]`
122005
- });
122006
- }
122007
- }
122008
- if (c4.postgres) {
122009
- anyPostgres = true;
122010
- if (!c4.postgres.url) {
122011
- checks.push({
122012
- label: "Postgres",
122013
- status: "warn",
122014
- detail: `${ctx} \u2014 URL not set`,
122015
- next: "set postgres.url or postgres.urlEnv in your Horus config"
122016
- });
122017
- } else {
122018
- checks.push({
122019
- label: "Postgres",
122020
- status: "pass",
122021
- detail: `${ctx} \u2014 ${c4.postgres.database ?? c4.postgres.schema ?? "postgres"} [runtime ingestion pending]`
122022
- });
122023
- }
122024
- }
122025
- if (c4.sentry) {
122026
- anySentry = true;
122027
- const tokenSet = c4.sentry.authToken || process.env[c4.sentry.authTokenEnv ?? "SENTRY_AUTH_TOKEN"];
122028
- if (!tokenSet) {
122029
- checks.push({
122030
- label: "Sentry",
122031
- status: "warn",
122032
- detail: `${ctx} \u2014 auth token not set`,
122033
- next: "set sentry.authToken or sentry.authTokenEnv (default SENTRY_AUTH_TOKEN) in your Horus config"
122034
- });
122035
- } else {
122036
- checks.push({
122037
- label: "Sentry",
122038
- status: "pass",
122039
- detail: `${ctx} \u2014 ${c4.sentry.org}/${c4.sentry.project} [runtime ingestion pending]`
122040
- });
122041
- }
122042
- }
122043
- if (c4.redis) {
122044
- anyRedis = true;
122045
- if (!c4.redis.url) {
122046
- checks.push({
122047
- label: "Redis",
122048
- status: "warn",
122049
- detail: `${ctx} \u2014 URL not set`,
122050
- next: "set redis.url or redis.urlEnv in your Horus config"
122051
- });
122052
- } else {
122053
- checks.push({
122054
- label: "Redis",
122055
- status: "pass",
122056
- detail: `${ctx} \u2014 URL configured [runtime ingestion pending]`
122057
- });
122058
- }
122065
+ for (const key of DOCTOR_CONNECTOR_KEYS) {
122066
+ const cfg = c4[key];
122067
+ if (cfg === void 0) continue;
122068
+ configured.add(key);
122069
+ const run3 = CONNECTOR_CHECKS[key].check;
122070
+ checks.push(run3(cfg, ctx));
122059
122071
  }
122060
122072
  }
122061
122073
  }
122062
- if (!anyEs) {
122063
- checks.push({
122064
- label: "Elasticsearch",
122065
- status: "warn",
122066
- detail: "not configured",
122067
- next: "add connectors.elasticsearch to an environment in your Horus config for runtime log evidence"
122068
- });
122069
- }
122070
- if (!anyGrafana) {
122071
- checks.push({
122072
- label: "Grafana",
122073
- status: "warn",
122074
- detail: "not configured",
122075
- next: "add connectors.grafana to an environment for metric evidence"
122076
- });
122077
- }
122078
- if (!anyMongo) {
122079
- checks.push({
122080
- label: "MongoDB",
122081
- status: "warn",
122082
- detail: "not configured",
122083
- next: "add connectors.mongodb to an environment for database state evidence"
122084
- });
122085
- }
122086
- if (!anyPostgres) {
122074
+ for (const key of DOCTOR_CONNECTOR_KEYS) {
122075
+ if (configured.has(key)) continue;
122076
+ const desc2 = CONNECTOR_CHECKS[key];
122087
122077
  checks.push({
122088
- label: "Postgres",
122089
- status: "warn",
122090
- detail: "not configured",
122091
- next: "add connectors.postgres to an environment for database state evidence"
122092
- });
122093
- }
122094
- if (!anySentry) {
122095
- checks.push({
122096
- label: "Sentry",
122097
- status: "warn",
122098
- detail: "not configured",
122099
- next: "add connectors.sentry to an environment for error-tracking evidence"
122100
- });
122101
- }
122102
- if (!anyRedis) {
122103
- checks.push({
122104
- label: "Redis",
122078
+ label: desc2.label,
122105
122079
  status: "warn",
122106
122080
  detail: "not configured",
122107
- next: "add connectors.redis to an environment for queue state evidence"
122081
+ next: desc2.absentNext
122108
122082
  });
122109
122083
  }
122110
122084
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@merittdev/horus",
3
- "version": "0.12.4",
3
+ "version": "0.12.5",
4
4
  "description": "Local-first, source-aware production-incident investigation engine",
5
5
  "type": "module",
6
6
  "bin": {