@merittdev/horus 0.16.0 → 0.17.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.
- package/dist/index.cjs +97 -7
- 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.
|
|
65883
|
+
var HORUS_VERSION = true ? "0.17.0" : "dev";
|
|
65884
65884
|
var PINNED_SOURCE_VERSION = "2.0.2";
|
|
65885
65885
|
|
|
65886
65886
|
// ../../packages/core/src/evidence.ts
|
|
@@ -70670,10 +70670,23 @@ var connectorsSchema = external_exports.object({
|
|
|
70670
70670
|
).optional()
|
|
70671
70671
|
}).optional()
|
|
70672
70672
|
}).default({});
|
|
70673
|
+
var notifySchema = external_exports.object({
|
|
70674
|
+
/** Only dispatch when an auto-investigation's confidence is >= this (0..1). Default 0.6. */
|
|
70675
|
+
minConfidence: external_exports.number().min(0).max(1).default(0.6),
|
|
70676
|
+
/** Generic outbound webhook (Slack-compatible JSON, HMAC-signed when `secret` is set). */
|
|
70677
|
+
webhook: external_exports.object({
|
|
70678
|
+
url: external_exports.string().url(),
|
|
70679
|
+
/** HMAC-SHA256 signing secret; when set, payloads carry an `X-Horus-Signature` header. */
|
|
70680
|
+
secret: external_exports.string().min(1).optional()
|
|
70681
|
+
}).optional(),
|
|
70682
|
+
/** Also push the headline to Horus Cloud (uses the existing cloud session, if signed in). */
|
|
70683
|
+
cloud: external_exports.boolean().default(false)
|
|
70684
|
+
}).optional();
|
|
70673
70685
|
var environmentSchema = external_exports.object({
|
|
70674
70686
|
name: external_exports.string().min(1),
|
|
70675
70687
|
readOnly: external_exports.boolean().default(true),
|
|
70676
|
-
connectors: connectorsSchema
|
|
70688
|
+
connectors: connectorsSchema,
|
|
70689
|
+
notify: notifySchema
|
|
70677
70690
|
});
|
|
70678
70691
|
var projectSchema = external_exports.object({
|
|
70679
70692
|
name: external_exports.string().min(1),
|
|
@@ -70919,7 +70932,8 @@ function resolveEnvironment(config2, opts) {
|
|
|
70919
70932
|
readOnly: environment.readOnly,
|
|
70920
70933
|
repositories: repositories2,
|
|
70921
70934
|
path: primary?.path ?? "",
|
|
70922
|
-
connectors: resolved
|
|
70935
|
+
connectors: resolved,
|
|
70936
|
+
...environment.notify !== void 0 ? { notify: environment.notify } : {}
|
|
70923
70937
|
};
|
|
70924
70938
|
}
|
|
70925
70939
|
var CONFIG_EXAMPLES = {
|
|
@@ -98175,7 +98189,9 @@ async function investigate(input, deps) {
|
|
|
98175
98189
|
const seedFile = top?.filePath;
|
|
98176
98190
|
const seedInChanges = recentChangeRelevant;
|
|
98177
98191
|
const citation = formatRegressionCitation(recentChanges, changes, seedFile);
|
|
98178
|
-
const
|
|
98192
|
+
const seedFocus = seedInChanges ? seedTouchingCommitFocus(recentChanges, top?.filePath) : null;
|
|
98193
|
+
const isBroadChange = seedFocus !== null && seedFocus > 14;
|
|
98194
|
+
const regressionTitle = top && seedInChanges && !isBroadChange ? `Recent change${citation.commitClause} to ${top.name}${citation.symbolClause} in ${changeRangeLabel} may have introduced the regression` : top && seedInChanges && isBroadChange ? `No specific cause identified from the available evidence \u2014 a broad recent change (${seedFocus} files) in ${changeRangeLabel} touched ${top.name}'s file but isn't clearly linked to the symptom; connect runtime evidence (logs/metrics) for a code-aware cause` : top ? `Changes shipped in ${changeRangeLabel} but none touched ${top.name} \u2014 a regression here is unlikely to be a code change to the seed itself (check upstream deps, data, or config)` : `Recent change${citation.commitClause}${citation.symbolClause} in ${changeRangeLabel} may have introduced the regression`;
|
|
98179
98195
|
causeInputs.push({
|
|
98180
98196
|
id: "cause:deployment-regression",
|
|
98181
98197
|
title: regressionTitle,
|
|
@@ -98185,7 +98201,7 @@ async function investigate(input, deps) {
|
|
|
98185
98201
|
// HOR-451: scale the seed-touched prior by commit focus — a broad/diffuse commit that merely
|
|
98186
98202
|
// touched the seed no longer outranks an evidence-backed runtime cause.
|
|
98187
98203
|
baseScore: clamp015(
|
|
98188
|
-
(seedInChanges ? regressionSeedTouchedScore(
|
|
98204
|
+
(seedInChanges ? regressionSeedTouchedScore(seedFocus) : 0.18) + (queueHits.length > 0 ? 0.05 : 0)
|
|
98189
98205
|
),
|
|
98190
98206
|
metadata: { blastRadius }
|
|
98191
98207
|
});
|
|
@@ -118233,6 +118249,70 @@ async function runPacket(hintOrId, opts) {
|
|
|
118233
118249
|
// ../../packages/cli/src/commands/watch.ts
|
|
118234
118250
|
init_cjs_shims();
|
|
118235
118251
|
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
118252
|
+
|
|
118253
|
+
// ../../packages/cli/src/lib/notify-sink.ts
|
|
118254
|
+
init_cjs_shims();
|
|
118255
|
+
var import_node_crypto11 = require("crypto");
|
|
118256
|
+
function buildWebhookPayload(h3) {
|
|
118257
|
+
const pct2 = `${Math.round(h3.confidence * 100)}%`;
|
|
118258
|
+
return {
|
|
118259
|
+
text: `\u{1F52D} Horus: ${h3.hint} \u2192 ${h3.cause} (${pct2})`,
|
|
118260
|
+
investigationId: h3.investigationId,
|
|
118261
|
+
hint: h3.hint,
|
|
118262
|
+
cause: h3.cause,
|
|
118263
|
+
confidence: h3.confidence
|
|
118264
|
+
};
|
|
118265
|
+
}
|
|
118266
|
+
function signPayload(body2, secret) {
|
|
118267
|
+
return `sha256=${(0, import_node_crypto11.createHmac)("sha256", secret).update(body2).digest("hex")}`;
|
|
118268
|
+
}
|
|
118269
|
+
function shouldNotify(confidence, notify) {
|
|
118270
|
+
if (notify === void 0) return false;
|
|
118271
|
+
if (notify.webhook === void 0 && notify.cloud !== true) return false;
|
|
118272
|
+
return confidence >= notify.minConfidence;
|
|
118273
|
+
}
|
|
118274
|
+
async function postWebhook(url, secret, h3, timeoutMs) {
|
|
118275
|
+
const body2 = JSON.stringify(buildWebhookPayload(h3));
|
|
118276
|
+
const headers = { "content-type": "application/json" };
|
|
118277
|
+
if (secret !== void 0) headers["x-horus-signature"] = signPayload(body2, secret);
|
|
118278
|
+
const controller = new AbortController();
|
|
118279
|
+
const timer2 = setTimeout(() => controller.abort(), timeoutMs);
|
|
118280
|
+
try {
|
|
118281
|
+
const res = await fetch(url, { method: "POST", headers, body: body2, signal: controller.signal });
|
|
118282
|
+
if (!res.ok) return { target: "webhook", ok: false, detail: `HTTP ${res.status}` };
|
|
118283
|
+
return { target: "webhook", ok: true, detail: `HTTP ${res.status}` };
|
|
118284
|
+
} catch (err2) {
|
|
118285
|
+
return { target: "webhook", ok: false, detail: err2.message };
|
|
118286
|
+
} finally {
|
|
118287
|
+
clearTimeout(timer2);
|
|
118288
|
+
}
|
|
118289
|
+
}
|
|
118290
|
+
async function dispatchNotify(report, notify, opts = {}) {
|
|
118291
|
+
if (notify === void 0) return [];
|
|
118292
|
+
const h3 = {
|
|
118293
|
+
investigationId: report.id,
|
|
118294
|
+
hint: report.hint,
|
|
118295
|
+
cause: report.cause,
|
|
118296
|
+
confidence: report.confidence
|
|
118297
|
+
};
|
|
118298
|
+
if (!shouldNotify(report.confidence, notify)) return [];
|
|
118299
|
+
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
118300
|
+
const results = [];
|
|
118301
|
+
if (notify.webhook !== void 0) {
|
|
118302
|
+
results.push(await postWebhook(notify.webhook.url, notify.webhook.secret, h3, timeoutMs));
|
|
118303
|
+
}
|
|
118304
|
+
if (notify.cloud === true && opts.cloudPush !== void 0) {
|
|
118305
|
+
try {
|
|
118306
|
+
await opts.cloudPush();
|
|
118307
|
+
results.push({ target: "cloud", ok: true, detail: "pushed" });
|
|
118308
|
+
} catch (err2) {
|
|
118309
|
+
results.push({ target: "cloud", ok: false, detail: err2.message });
|
|
118310
|
+
}
|
|
118311
|
+
}
|
|
118312
|
+
return results;
|
|
118313
|
+
}
|
|
118314
|
+
|
|
118315
|
+
// ../../packages/cli/src/commands/watch.ts
|
|
118236
118316
|
function detectNewSentryIncidents(issues, seen) {
|
|
118237
118317
|
const fresh = [];
|
|
118238
118318
|
for (const issue2 of issues) {
|
|
@@ -118362,6 +118442,16 @@ async function runWatch(opts) {
|
|
|
118362
118442
|
console.log(
|
|
118363
118443
|
`${import_picocolors19.default.bold("\u25CF")} ${incident.hint} ${import_picocolors19.default.dim("\u2192")} ${cause} ${import_picocolors19.default.dim(`(${(confidence * 100).toFixed(0)}%)`)} ${import_picocolors19.default.dim(`id: ${report.id}`)}${persisted}`
|
|
118364
118444
|
);
|
|
118445
|
+
if (shouldNotify(confidence, renv.notify)) {
|
|
118446
|
+
const results = await dispatchNotify(
|
|
118447
|
+
{ id: report.id, confidence, hint: incident.hint, cause },
|
|
118448
|
+
renv.notify
|
|
118449
|
+
);
|
|
118450
|
+
for (const r of results) {
|
|
118451
|
+
if (r.ok) console.error(import_picocolors19.default.dim(`[watch] notified ${r.target} (${r.detail})`));
|
|
118452
|
+
else console.error(import_picocolors19.default.yellow(`[watch] notify ${r.target} failed \u2014 ${r.detail}`));
|
|
118453
|
+
}
|
|
118454
|
+
}
|
|
118365
118455
|
} catch (err2) {
|
|
118366
118456
|
console.error(
|
|
118367
118457
|
import_picocolors19.default.yellow(`[watch] investigation failed for "${incident.ref}" \u2014 ${err2.message}`)
|
|
@@ -125231,7 +125321,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
125231
125321
|
// ../../packages/cli/src/commands/telemetry.ts
|
|
125232
125322
|
init_cjs_shims();
|
|
125233
125323
|
var import_picocolors56 = __toESM(require_picocolors(), 1);
|
|
125234
|
-
var
|
|
125324
|
+
var import_node_crypto12 = require("crypto");
|
|
125235
125325
|
|
|
125236
125326
|
// ../../packages/cli/src/lib/telemetry/transport.ts
|
|
125237
125327
|
init_cjs_shims();
|
|
@@ -125423,7 +125513,7 @@ async function runTelemetryDisableContent() {
|
|
|
125423
125513
|
return 0;
|
|
125424
125514
|
}
|
|
125425
125515
|
async function runTelemetryResetId() {
|
|
125426
|
-
const next = (0,
|
|
125516
|
+
const next = (0, import_node_crypto12.randomUUID)();
|
|
125427
125517
|
updateTelemetryState((s5) => {
|
|
125428
125518
|
s5.installId = next;
|
|
125429
125519
|
});
|