@hiveai/core 0.15.0 → 0.18.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.d.ts +317 -16
- package/dist/index.js +553 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -318,6 +318,16 @@ var STACK_PACK_TAG = "stack-pack";
|
|
|
318
318
|
function isStackPackSeed(fm) {
|
|
319
319
|
return Boolean(fm?.tags?.includes(STACK_PACK_TAG));
|
|
320
320
|
}
|
|
321
|
+
var ENV_WORKAROUND_TAGS = /* @__PURE__ */ new Set([
|
|
322
|
+
"dev-workflow",
|
|
323
|
+
"dev-env",
|
|
324
|
+
"hotswap",
|
|
325
|
+
"local-setup",
|
|
326
|
+
"tooling-debt"
|
|
327
|
+
]);
|
|
328
|
+
function isEnvWorkaroundMemory(fm) {
|
|
329
|
+
return Boolean(fm?.tags?.some((t) => ENV_WORKAROUND_TAGS.has(t)));
|
|
330
|
+
}
|
|
321
331
|
var MODULE_PATTERNS = [
|
|
322
332
|
/^packages\/([^/]+)\//,
|
|
323
333
|
/^apps\/([^/]+)\//,
|
|
@@ -790,6 +800,45 @@ function summarizeImpact(scores) {
|
|
|
790
800
|
}
|
|
791
801
|
return summary;
|
|
792
802
|
}
|
|
803
|
+
function recommendFeedbackAdjustment(fm, usage, options = {}) {
|
|
804
|
+
const rejectionThreshold = options.rejectionThreshold ?? 2;
|
|
805
|
+
const hasPositiveOutcome = usage.applied_count > 0 || usage.prevented_count > 0;
|
|
806
|
+
if (fm.sensor?.severity === "block" && usage.rejected_count >= 1) {
|
|
807
|
+
return {
|
|
808
|
+
action: "downgrade-block-sensor",
|
|
809
|
+
reason: "A human contested a blocking guardrail; downgrade it to warn so the gate stays helpful while the lesson is reviewed."
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
if (!hasPositiveOutcome && usage.rejected_count >= rejectionThreshold) {
|
|
813
|
+
return {
|
|
814
|
+
action: "deprecate-memory",
|
|
815
|
+
reason: `${usage.rejected_count} rejection(s) and no applied/prevented outcomes; deprecate until the lesson is refined.`
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
return { action: "none", reason: "No automatic adjustment needed." };
|
|
819
|
+
}
|
|
820
|
+
function applyFeedbackAdjustment(fm, adjustment, now = /* @__PURE__ */ new Date()) {
|
|
821
|
+
if (adjustment.action === "none") return fm;
|
|
822
|
+
const tags = [.../* @__PURE__ */ new Set([...fm.tags, "feedback-contested"])];
|
|
823
|
+
if (adjustment.action === "downgrade-block-sensor" && fm.sensor) {
|
|
824
|
+
return {
|
|
825
|
+
...fm,
|
|
826
|
+
tags,
|
|
827
|
+
verified_at: now.toISOString(),
|
|
828
|
+
sensor: { ...fm.sensor, severity: "warn" }
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
if (adjustment.action === "deprecate-memory") {
|
|
832
|
+
return {
|
|
833
|
+
...fm,
|
|
834
|
+
tags,
|
|
835
|
+
status: "deprecated",
|
|
836
|
+
stale_reason: adjustment.reason,
|
|
837
|
+
verified_at: now.toISOString()
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
return fm;
|
|
841
|
+
}
|
|
793
842
|
|
|
794
843
|
// src/prevention.ts
|
|
795
844
|
import { appendFile, mkdir as mkdir2, readFile as readFile4 } from "fs/promises";
|
|
@@ -855,6 +904,84 @@ function computeRecurrence(events) {
|
|
|
855
904
|
rows.sort((a, b) => b.distinct_days - a.distinct_days || b.catches - a.catches);
|
|
856
905
|
return { recurring_count: rows.length, top: rows };
|
|
857
906
|
}
|
|
907
|
+
function briefingProofLine(events, options = {}) {
|
|
908
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
909
|
+
const days = options.days ?? 30;
|
|
910
|
+
const since = now.getTime() - days * MS_PER_DAY2;
|
|
911
|
+
let count = 0;
|
|
912
|
+
for (const e of events) {
|
|
913
|
+
const t = Date.parse(e.at);
|
|
914
|
+
if (!Number.isFinite(t)) continue;
|
|
915
|
+
if (t >= since && t <= now.getTime()) count += 1;
|
|
916
|
+
}
|
|
917
|
+
if (count === 0) return null;
|
|
918
|
+
return `This harness prevented ${count} repeated mistake${count === 1 ? "" : "s"} in the last ${days} days.`;
|
|
919
|
+
}
|
|
920
|
+
function titleFromMemory(loaded) {
|
|
921
|
+
if (!loaded) return "";
|
|
922
|
+
for (const line of loaded.memory.body.split("\n")) {
|
|
923
|
+
const heading = /^#+\s*(.+)$/.exec(line.trim());
|
|
924
|
+
if (heading) return heading[1].trim().slice(0, 96);
|
|
925
|
+
}
|
|
926
|
+
for (const line of loaded.memory.body.split("\n")) {
|
|
927
|
+
const t = line.trim();
|
|
928
|
+
if (t) return t.replace(/^[-*]\s*/, "").slice(0, 96);
|
|
929
|
+
}
|
|
930
|
+
return "";
|
|
931
|
+
}
|
|
932
|
+
function sourceRank(source) {
|
|
933
|
+
return source === "anti-pattern" ? 0 : 1;
|
|
934
|
+
}
|
|
935
|
+
function summarizeCaughtForYou(events, memories, usage, options = {}) {
|
|
936
|
+
const until = options.now ?? /* @__PURE__ */ new Date();
|
|
937
|
+
const sinceMs = options.since === void 0 ? null : options.since instanceof Date ? options.since.getTime() : Date.parse(options.since);
|
|
938
|
+
const untilMs = until.getTime();
|
|
939
|
+
const byIdSource = /* @__PURE__ */ new Map();
|
|
940
|
+
for (const e of events) {
|
|
941
|
+
const t = Date.parse(e.at);
|
|
942
|
+
if (!Number.isFinite(t)) continue;
|
|
943
|
+
if (sinceMs !== null && Number.isFinite(sinceMs) && t < sinceMs) continue;
|
|
944
|
+
if (t > untilMs) continue;
|
|
945
|
+
const key = `${e.id}\0${e.source}`;
|
|
946
|
+
const current = byIdSource.get(key) ?? { id: e.id, source: e.source, catches: 0, last_at: e.at };
|
|
947
|
+
current.catches += 1;
|
|
948
|
+
if (e.at > current.last_at) current.last_at = e.at;
|
|
949
|
+
byIdSource.set(key, current);
|
|
950
|
+
}
|
|
951
|
+
const memoryById = new Map(memories.map((m) => [m.memory.frontmatter.id, m]));
|
|
952
|
+
const rows = [...byIdSource.values()].map((row) => {
|
|
953
|
+
const current = getUsage(usage, row.id).prevented_count;
|
|
954
|
+
const previous = Math.max(0, current - row.catches);
|
|
955
|
+
return {
|
|
956
|
+
id: row.id,
|
|
957
|
+
title: titleFromMemory(memoryById.get(row.id)) || row.id,
|
|
958
|
+
source: row.source,
|
|
959
|
+
catches: row.catches,
|
|
960
|
+
previous_count: previous,
|
|
961
|
+
current_count: current,
|
|
962
|
+
last_at: row.last_at
|
|
963
|
+
};
|
|
964
|
+
}).sort((a, b) => b.last_at.localeCompare(a.last_at) || sourceRank(a.source) - sourceRank(b.source)).slice(0, options.limit ?? 5);
|
|
965
|
+
return {
|
|
966
|
+
total_catches: [...byIdSource.values()].reduce((sum, row) => sum + row.catches, 0),
|
|
967
|
+
since: sinceMs !== null && Number.isFinite(sinceMs) ? new Date(sinceMs).toISOString() : null,
|
|
968
|
+
until: until.toISOString(),
|
|
969
|
+
rows
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
function renderCaughtForYou(summary) {
|
|
973
|
+
if (summary.total_catches === 0 || summary.rows.length === 0) return null;
|
|
974
|
+
const lines = [
|
|
975
|
+
`Caught for you: ${summary.total_catches} prevented repeat${summary.total_catches === 1 ? "" : "s"} this session.`
|
|
976
|
+
];
|
|
977
|
+
for (const row of summary.rows) {
|
|
978
|
+
const gate = row.source === "anti-pattern" ? "Blocked" : "Caught";
|
|
979
|
+
lines.push(
|
|
980
|
+
`- ${gate}: ${row.title} (${row.id}). Prevention ${row.previous_count}->${row.current_count}.`
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
return lines.join("\n");
|
|
984
|
+
}
|
|
858
985
|
|
|
859
986
|
// src/context-throttle.ts
|
|
860
987
|
import { createHash } from "crypto";
|
|
@@ -1687,7 +1814,8 @@ var DEFAULT_CONFIG = {
|
|
|
1687
1814
|
scoreThreshold: 80,
|
|
1688
1815
|
cleanupGeneratedArtifacts: true,
|
|
1689
1816
|
toolProfile: "enforcement",
|
|
1690
|
-
policyPacks: ["architecture", "gotchas", "security", "domain", "release"]
|
|
1817
|
+
policyPacks: ["architecture", "gotchas", "security", "domain", "release"],
|
|
1818
|
+
releaseBranch: "main"
|
|
1691
1819
|
}
|
|
1692
1820
|
};
|
|
1693
1821
|
var AUTOPILOT_DEFAULTS = {
|
|
@@ -1715,7 +1843,8 @@ var AUTOPILOT_DEFAULTS = {
|
|
|
1715
1843
|
scoreThreshold: 85,
|
|
1716
1844
|
cleanupGeneratedArtifacts: true,
|
|
1717
1845
|
toolProfile: "enforcement",
|
|
1718
|
-
policyPacks: ["architecture", "gotchas", "security", "domain", "release"]
|
|
1846
|
+
policyPacks: ["architecture", "gotchas", "security", "domain", "release"],
|
|
1847
|
+
releaseBranch: "main"
|
|
1719
1848
|
}
|
|
1720
1849
|
};
|
|
1721
1850
|
function antiPatternGateParams(gate) {
|
|
@@ -2833,11 +2962,24 @@ function briefingMarkerPath(paths, sessionId) {
|
|
|
2833
2962
|
return path16.join(briefingMarkersDir(paths), `${normalizeSessionId(sessionId)}.json`);
|
|
2834
2963
|
}
|
|
2835
2964
|
async function writeBriefingMarker(paths, input) {
|
|
2965
|
+
const sessionId = normalizeSessionId(input.sessionId);
|
|
2966
|
+
const accumulate = input.accumulate ?? true;
|
|
2967
|
+
let priorIds = [];
|
|
2968
|
+
let priorFiles = [];
|
|
2969
|
+
if (accumulate) {
|
|
2970
|
+
const existing = await readSessionBriefingMarker(paths, sessionId);
|
|
2971
|
+
if (existing) {
|
|
2972
|
+
priorIds = existing.memory_ids ?? [];
|
|
2973
|
+
priorFiles = existing.files ?? [];
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
const mergedIds = [.../* @__PURE__ */ new Set([...priorIds, ...input.memoryIds ?? []])];
|
|
2977
|
+
const mergedFiles = [.../* @__PURE__ */ new Set([...priorFiles, ...input.files ?? []])];
|
|
2836
2978
|
const marker = {
|
|
2837
|
-
session_id:
|
|
2979
|
+
session_id: sessionId,
|
|
2838
2980
|
...input.task?.trim() ? { task: input.task.trim() } : {},
|
|
2839
|
-
...
|
|
2840
|
-
...
|
|
2981
|
+
...mergedIds.length > 0 ? { memory_ids: mergedIds } : {},
|
|
2982
|
+
...mergedFiles.length > 0 ? { files: mergedFiles } : {},
|
|
2841
2983
|
source: input.source,
|
|
2842
2984
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2843
2985
|
root: paths.root
|
|
@@ -2850,6 +2992,18 @@ async function writeBriefingMarker(paths, input) {
|
|
|
2850
2992
|
);
|
|
2851
2993
|
return marker;
|
|
2852
2994
|
}
|
|
2995
|
+
async function readSessionBriefingMarker(paths, sessionId, ttlMs = BRIEFING_MARKER_TTL_MS) {
|
|
2996
|
+
const file = briefingMarkerPath(paths, sessionId);
|
|
2997
|
+
if (!existsSync14(file)) return null;
|
|
2998
|
+
try {
|
|
2999
|
+
const marker = JSON.parse(await readFile13(file, "utf8"));
|
|
3000
|
+
const created = Date.parse(marker.created_at);
|
|
3001
|
+
if (!Number.isFinite(created) || Date.now() - created > ttlMs) return null;
|
|
3002
|
+
return marker;
|
|
3003
|
+
} catch {
|
|
3004
|
+
return null;
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
2853
3007
|
async function hasRecentBriefingMarker(paths, sessionId, ttlMs = BRIEFING_MARKER_TTL_MS) {
|
|
2854
3008
|
const now = Date.now();
|
|
2855
3009
|
const candidates = [];
|
|
@@ -3323,8 +3477,75 @@ function parseSonar(input) {
|
|
|
3323
3477
|
}
|
|
3324
3478
|
return findings;
|
|
3325
3479
|
}
|
|
3326
|
-
function
|
|
3327
|
-
|
|
3480
|
+
function parseEslintJson(input, opts = {}) {
|
|
3481
|
+
const docs = asArray(coerceJson(input));
|
|
3482
|
+
const findings = [];
|
|
3483
|
+
const cwd = opts.cwd ? opts.cwd.replace(/\/+$/, "") + "/" : "";
|
|
3484
|
+
for (const fileRaw of docs) {
|
|
3485
|
+
const file = asRecord(fileRaw);
|
|
3486
|
+
const rawPath = typeof file.filePath === "string" ? file.filePath : "";
|
|
3487
|
+
if (!rawPath) continue;
|
|
3488
|
+
const path18 = cwd && rawPath.startsWith(cwd) ? rawPath.slice(cwd.length) : rawPath;
|
|
3489
|
+
for (const msgRaw of asArray(file.messages)) {
|
|
3490
|
+
const msg = asRecord(msgRaw);
|
|
3491
|
+
const ruleId = typeof msg.ruleId === "string" && msg.ruleId ? msg.ruleId : "parse-error";
|
|
3492
|
+
const message = typeof msg.message === "string" ? msg.message.trim() : ruleId;
|
|
3493
|
+
const severity = normalizeFindingSeverity(msg.severity === 2 ? "error" : "warning");
|
|
3494
|
+
const line = typeof msg.line === "number" ? msg.line : void 0;
|
|
3495
|
+
findings.push({
|
|
3496
|
+
tool: "eslint",
|
|
3497
|
+
ruleId,
|
|
3498
|
+
message,
|
|
3499
|
+
severity,
|
|
3500
|
+
path: path18,
|
|
3501
|
+
...line !== void 0 ? { line } : {},
|
|
3502
|
+
key: findingKey("eslint", ruleId, path18)
|
|
3503
|
+
});
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
return findings;
|
|
3507
|
+
}
|
|
3508
|
+
var NPM_AUDIT_SEVERITY = {
|
|
3509
|
+
critical: "blocker",
|
|
3510
|
+
high: "critical",
|
|
3511
|
+
moderate: "major",
|
|
3512
|
+
low: "minor",
|
|
3513
|
+
info: "info"
|
|
3514
|
+
};
|
|
3515
|
+
function parseNpmAudit(input) {
|
|
3516
|
+
const doc = asRecord(coerceJson(input));
|
|
3517
|
+
const vulns = asRecord(doc.vulnerabilities);
|
|
3518
|
+
const findings = [];
|
|
3519
|
+
for (const [name, vulnRaw] of Object.entries(vulns)) {
|
|
3520
|
+
const vuln = asRecord(vulnRaw);
|
|
3521
|
+
const sev = typeof vuln.severity === "string" ? vuln.severity.toLowerCase() : "info";
|
|
3522
|
+
const severity = NPM_AUDIT_SEVERITY[sev] ?? "info";
|
|
3523
|
+
const via = asArray(vuln.via);
|
|
3524
|
+
const firstAdvisory = via.map(asRecord).find((v) => typeof v.title === "string");
|
|
3525
|
+
const title = firstAdvisory && typeof firstAdvisory.title === "string" ? firstAdvisory.title : `Vulnerable dependency: ${name}`;
|
|
3526
|
+
const range = typeof vuln.range === "string" ? ` (affected range: ${vuln.range})` : "";
|
|
3527
|
+
findings.push({
|
|
3528
|
+
tool: "npm-audit",
|
|
3529
|
+
ruleId: name,
|
|
3530
|
+
message: `${title}${range}`,
|
|
3531
|
+
severity,
|
|
3532
|
+
path: "package.json",
|
|
3533
|
+
key: findingKey("npm-audit", name, "package.json")
|
|
3534
|
+
});
|
|
3535
|
+
}
|
|
3536
|
+
return findings;
|
|
3537
|
+
}
|
|
3538
|
+
function parseFindings(format, input, opts = {}) {
|
|
3539
|
+
switch (format) {
|
|
3540
|
+
case "sonar":
|
|
3541
|
+
return parseSonar(input);
|
|
3542
|
+
case "eslint":
|
|
3543
|
+
return parseEslintJson(input, opts);
|
|
3544
|
+
case "npm-audit":
|
|
3545
|
+
return parseNpmAudit(input);
|
|
3546
|
+
default:
|
|
3547
|
+
return parseSarif(input);
|
|
3548
|
+
}
|
|
3328
3549
|
}
|
|
3329
3550
|
function normalizeUri(uri) {
|
|
3330
3551
|
return uri.replace(/^file:\/\//, "").replace(/^\.\//, "");
|
|
@@ -3440,6 +3661,23 @@ function suggestGate(precision, rejections, currentGate) {
|
|
|
3440
3661
|
}
|
|
3441
3662
|
return null;
|
|
3442
3663
|
}
|
|
3664
|
+
function nullableMetricDelta(baseline, current) {
|
|
3665
|
+
if (baseline === null || current === null) return { baseline, current, delta: null };
|
|
3666
|
+
return { baseline: round33(baseline), current: round33(current), delta: round33(current - baseline) };
|
|
3667
|
+
}
|
|
3668
|
+
function compareGatePrecision(baseline, current) {
|
|
3669
|
+
const precision = nullableMetricDelta(baseline.precision, current.precision);
|
|
3670
|
+
const rejections = nullableMetricDelta(baseline.rejections, current.rejections);
|
|
3671
|
+
const falsePositivesIncreased = current.rejections > baseline.rejections;
|
|
3672
|
+
const precisionRegressed = precision.delta !== null && precision.delta < 0;
|
|
3673
|
+
return {
|
|
3674
|
+
precision,
|
|
3675
|
+
rejections,
|
|
3676
|
+
false_positives_increased: falsePositivesIncreased,
|
|
3677
|
+
precision_regressed: precisionRegressed,
|
|
3678
|
+
regressed: falsePositivesIncreased || precisionRegressed
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3443
3681
|
|
|
3444
3682
|
// src/dashboard.ts
|
|
3445
3683
|
var MS_PER_DAY4 = 24 * 60 * 60 * 1e3;
|
|
@@ -3548,9 +3786,26 @@ function buildDashboard(memories, usage, options = {}) {
|
|
|
3548
3786
|
);
|
|
3549
3787
|
sensorRows.sort((a, b) => b.last_fired.localeCompare(a.last_fired));
|
|
3550
3788
|
dormantRows.sort((a, b) => b.age_days - a.age_days);
|
|
3789
|
+
const eventLog = options.preventionEvents ?? [];
|
|
3790
|
+
const recurrence = computeRecurrence(eventLog);
|
|
3551
3791
|
return {
|
|
3552
3792
|
generated_at: now.toISOString(),
|
|
3553
3793
|
inventory,
|
|
3794
|
+
prevention: {
|
|
3795
|
+
total_events: preventionEvents,
|
|
3796
|
+
memories_with_catches: preventionRows.length,
|
|
3797
|
+
top: preventionRows.sort((a, b) => b.prevented_count - a.prevented_count).slice(0, top),
|
|
3798
|
+
trend: computePreventionTrend(eventLog, now),
|
|
3799
|
+
recurrence: {
|
|
3800
|
+
...recurrence,
|
|
3801
|
+
top: recurrence.top.slice(0, top)
|
|
3802
|
+
}
|
|
3803
|
+
},
|
|
3804
|
+
gate_precision: computeGatePrecision(
|
|
3805
|
+
eventLog,
|
|
3806
|
+
usage,
|
|
3807
|
+
options.antiPatternGate ?? "anchored"
|
|
3808
|
+
),
|
|
3554
3809
|
impact: { ...summarizeImpact(impactScores), top: impactRows.slice(0, top) },
|
|
3555
3810
|
sensors: {
|
|
3556
3811
|
total: sensorTotal,
|
|
@@ -3572,21 +3827,6 @@ function buildDashboard(memories, usage, options = {}) {
|
|
|
3572
3827
|
decaying,
|
|
3573
3828
|
top_dormant: dormantRows.slice(0, top)
|
|
3574
3829
|
},
|
|
3575
|
-
prevention: {
|
|
3576
|
-
total_events: preventionEvents,
|
|
3577
|
-
memories_with_catches: preventionRows.length,
|
|
3578
|
-
top: preventionRows.sort((a, b) => b.prevented_count - a.prevented_count).slice(0, top),
|
|
3579
|
-
trend: computePreventionTrend(options.preventionEvents ?? [], now),
|
|
3580
|
-
recurrence: {
|
|
3581
|
-
...computeRecurrence(options.preventionEvents ?? []),
|
|
3582
|
-
top: computeRecurrence(options.preventionEvents ?? []).top.slice(0, top)
|
|
3583
|
-
}
|
|
3584
|
-
},
|
|
3585
|
-
gate_precision: computeGatePrecision(
|
|
3586
|
-
options.preventionEvents ?? [],
|
|
3587
|
-
usage,
|
|
3588
|
-
options.antiPatternGate ?? "anchored"
|
|
3589
|
-
),
|
|
3590
3830
|
corpus: {
|
|
3591
3831
|
memory_files: inventory.total,
|
|
3592
3832
|
body_chars: bodyChars,
|
|
@@ -3759,6 +3999,7 @@ function planConflictResolution(a, b) {
|
|
|
3759
3999
|
var REVERT_RE = /^Revert\s+"(.+)"\s*$/i;
|
|
3760
4000
|
var FIXUP_RE = /^(?:fixup!|hotfix[:!]|fix[:!]\s*revert|revert\s+revert)/i;
|
|
3761
4001
|
var URGENT_FIX_RE = /\b(hotfix|urgent fix|emergency fix|critical fix|broke production|broken build)\b/i;
|
|
4002
|
+
var WORKAROUND_RE = /\b(workaround|work around|hack(?:y|ish)?|band[- ]?aid|temporary fix|temp fix|quick fix|kludge|monkey[- ]?patch|stop[- ]?gap|FIXME|XXX)\b/i;
|
|
3762
4003
|
function slugify(text) {
|
|
3763
4004
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "reverted-change";
|
|
3764
4005
|
}
|
|
@@ -3776,6 +4017,9 @@ function proposeSeedsFromCommits(commits, limit = 20) {
|
|
|
3776
4017
|
} else if (FIXUP_RE.test(subject) || URGENT_FIX_RE.test(subject)) {
|
|
3777
4018
|
what = subject.replace(FIXUP_RE, "").trim() || subject;
|
|
3778
4019
|
kind = "fixup";
|
|
4020
|
+
} else if (WORKAROUND_RE.test(subject)) {
|
|
4021
|
+
what = subject;
|
|
4022
|
+
kind = "workaround";
|
|
3779
4023
|
}
|
|
3780
4024
|
if (!what || !kind) continue;
|
|
3781
4025
|
const slug = slugify(what);
|
|
@@ -3784,7 +4028,7 @@ function proposeSeedsFromCommits(commits, limit = 20) {
|
|
|
3784
4028
|
out.push({
|
|
3785
4029
|
slug,
|
|
3786
4030
|
what,
|
|
3787
|
-
why_failed: kind === "revert" ? `This change was reverted in commit ${commit.sha} \u2014 it caused a regression and was backed out. Verify the root cause before re-attempting.` : `This area required an urgent fix (commit ${commit.sha}: "${subject}") \u2014 it shipped broken once. Treat changes here with extra care.`,
|
|
4031
|
+
why_failed: kind === "revert" ? `This change was reverted in commit ${commit.sha} \u2014 it caused a regression and was backed out. Verify the root cause before re-attempting.` : kind === "workaround" ? `This area carries a known workaround/stop-gap (commit ${commit.sha}: "${subject}") \u2014 the proper fix is still owed. Understand why the workaround exists before changing it.` : `This area required an urgent fix (commit ${commit.sha}: "${subject}") \u2014 it shipped broken once. Treat changes here with extra care.`,
|
|
3788
4032
|
paths: (commit.files ?? []).slice(0, 8),
|
|
3789
4033
|
source_sha: commit.sha,
|
|
3790
4034
|
kind
|
|
@@ -3794,6 +4038,75 @@ function proposeSeedsFromCommits(commits, limit = 20) {
|
|
|
3794
4038
|
return out;
|
|
3795
4039
|
}
|
|
3796
4040
|
|
|
4041
|
+
// src/seed.ts
|
|
4042
|
+
var JS_DETECTORS = [
|
|
4043
|
+
["nestjs", ["@nestjs/core"]],
|
|
4044
|
+
["nextjs", ["next"]],
|
|
4045
|
+
["remix", ["@remix-run/react", "@remix-run/node"]],
|
|
4046
|
+
["react", ["react"]],
|
|
4047
|
+
["express", ["express"]],
|
|
4048
|
+
["fastify", ["fastify"]],
|
|
4049
|
+
["prisma", ["@prisma/client", "prisma"]],
|
|
4050
|
+
["drizzle", ["drizzle-orm"]],
|
|
4051
|
+
["zustand", ["zustand"]],
|
|
4052
|
+
["redux", ["@reduxjs/toolkit", "redux"]],
|
|
4053
|
+
["reactquery", ["@tanstack/react-query", "react-query"]],
|
|
4054
|
+
["trpc", ["@trpc/server", "@trpc/client"]],
|
|
4055
|
+
["mongoose", ["mongoose"]],
|
|
4056
|
+
["graphql", ["@apollo/client", "@apollo/server", "apollo-server", "graphql"]],
|
|
4057
|
+
["vue", ["vue", "@vue/core"]],
|
|
4058
|
+
["tailwind", ["tailwindcss"]],
|
|
4059
|
+
["vite", ["vite"]],
|
|
4060
|
+
["sveltekit", ["@sveltejs/kit"]],
|
|
4061
|
+
["astro", ["astro"]],
|
|
4062
|
+
["typescript", ["typescript"]],
|
|
4063
|
+
["monorepo", ["turbo", "nx", "@nrwl/workspace", "@nx/workspace"]]
|
|
4064
|
+
];
|
|
4065
|
+
var PYTHON_DETECTORS = [
|
|
4066
|
+
["fastapi", /\bfastapi\b/i],
|
|
4067
|
+
["django", /\bdjango\b/i],
|
|
4068
|
+
["flask", /\bflask\b/i]
|
|
4069
|
+
];
|
|
4070
|
+
function detectFromPackageJson(deps) {
|
|
4071
|
+
const detected = [];
|
|
4072
|
+
for (const [stack, signals] of JS_DETECTORS) {
|
|
4073
|
+
if (signals.some((s) => s in deps)) detected.push(stack);
|
|
4074
|
+
}
|
|
4075
|
+
if (detected.includes("nextjs") || detected.includes("remix")) {
|
|
4076
|
+
return detected.filter((s) => s !== "react");
|
|
4077
|
+
}
|
|
4078
|
+
return detected;
|
|
4079
|
+
}
|
|
4080
|
+
function detectFromRequirementsTxt(content) {
|
|
4081
|
+
return PYTHON_DETECTORS.filter(([, re]) => re.test(content)).map(([s]) => s);
|
|
4082
|
+
}
|
|
4083
|
+
function detectFromGoMod(content) {
|
|
4084
|
+
return /^\s*module\s+\S/m.test(content) ? ["go"] : [];
|
|
4085
|
+
}
|
|
4086
|
+
function detectFromPomXml(content) {
|
|
4087
|
+
return /org\.springframework|spring-boot/.test(content) ? ["spring"] : [];
|
|
4088
|
+
}
|
|
4089
|
+
function detectFromComposerJson(content) {
|
|
4090
|
+
return /laravel\/framework|illuminate\//.test(content) ? ["laravel"] : [];
|
|
4091
|
+
}
|
|
4092
|
+
function detectFromGemfile(content) {
|
|
4093
|
+
return /^\s*gem\s+["']rails["']/m.test(content) || /\brails\b/.test(content) ? ["rails"] : [];
|
|
4094
|
+
}
|
|
4095
|
+
function detectStacksFromManifests(input) {
|
|
4096
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4097
|
+
const add = (stacks) => stacks.forEach((s) => seen.add(s));
|
|
4098
|
+
if (input.packageJsonDeps) add(detectFromPackageJson(input.packageJsonDeps));
|
|
4099
|
+
if (input.requirementsTxt) add(detectFromRequirementsTxt(input.requirementsTxt));
|
|
4100
|
+
if (input.goMod) add(detectFromGoMod(input.goMod));
|
|
4101
|
+
if (input.pomXml) add(detectFromPomXml(input.pomXml));
|
|
4102
|
+
if (input.composerJson) add(detectFromComposerJson(input.composerJson));
|
|
4103
|
+
if (input.gemfile) add(detectFromGemfile(input.gemfile));
|
|
4104
|
+
if (input.hasCsproj) add(["dotnet"]);
|
|
4105
|
+
if (input.hasDockerfile) add(["docker"]);
|
|
4106
|
+
if (input.hasTurboJson || input.hasNxJson) add(["monorepo"]);
|
|
4107
|
+
return Array.from(seen);
|
|
4108
|
+
}
|
|
4109
|
+
|
|
3797
4110
|
// src/merge-memory.ts
|
|
3798
4111
|
function safeParse(raw) {
|
|
3799
4112
|
try {
|
|
@@ -3823,10 +4136,207 @@ function mergeMemoryVersions(ours, theirs) {
|
|
|
3823
4136
|
if (cmp < 0) return { content: ours, winner: "ours", reason: `newer created_at (${ca})` };
|
|
3824
4137
|
return { content: ours, winner: "ours", reason: "tie \u2014 kept ours" };
|
|
3825
4138
|
}
|
|
4139
|
+
|
|
4140
|
+
// src/recap.ts
|
|
4141
|
+
function isAutoRecap(body) {
|
|
4142
|
+
return /Auto-captured session/i.test(body) || /\bEdited \d+ files? across \d+ tool calls?/i.test(body) || /\b\d+ tool calls?\b/i.test(body);
|
|
4143
|
+
}
|
|
4144
|
+
function compactAutoRecapBody(body, maxChars = 600) {
|
|
4145
|
+
if (!isAutoRecap(body)) return body;
|
|
4146
|
+
const goalMatch = body.match(/##+\s*Goal[^\n]*\n+([^\n]+)/i);
|
|
4147
|
+
const callsMatch = body.match(/Auto-captured session \(([^)]+)\)/i);
|
|
4148
|
+
const header = goalMatch?.[1]?.trim() ? `_${goalMatch[1].trim()}_` : callsMatch ? `_Auto-captured session (${callsMatch[1]})._` : "_Auto-captured session._";
|
|
4149
|
+
const discMatch = body.match(/##+\s*Discoveries[^\n]*\n([\s\S]*?)(?=\n##+\s|\n*$)/i);
|
|
4150
|
+
const discovery = discMatch?.[1]?.trim() ?? "";
|
|
4151
|
+
const trivialDiscovery = discovery === "" || /^no (new memories|surprising)/i.test(discovery) || /No new memories saved this session\.?$/i.test(discovery);
|
|
4152
|
+
if (trivialDiscovery) {
|
|
4153
|
+
return `${header}
|
|
4154
|
+
|
|
4155
|
+
_No notable discoveries captured. Run post_task / \`mem_session_end\` for a richer recap._`;
|
|
4156
|
+
}
|
|
4157
|
+
const trimmed = discovery.length > maxChars ? discovery.slice(0, maxChars) + "\u2026" : discovery;
|
|
4158
|
+
return `${header}
|
|
4159
|
+
|
|
4160
|
+
**Discoveries:**
|
|
4161
|
+
${trimmed}`;
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
// src/priority.ts
|
|
4165
|
+
var DEFAULT_PRIORITY_SIGNALS = {
|
|
4166
|
+
type: "",
|
|
4167
|
+
tags: [],
|
|
4168
|
+
requiresHumanApproval: false,
|
|
4169
|
+
directAnchor: false,
|
|
4170
|
+
directSymbol: false,
|
|
4171
|
+
exactTaskMatch: false,
|
|
4172
|
+
strongSemantic: false,
|
|
4173
|
+
usefulSemantic: false,
|
|
4174
|
+
moduleOrDomainMatch: false,
|
|
4175
|
+
tagTaskMatch: false
|
|
4176
|
+
};
|
|
4177
|
+
function prioritySignals(partial) {
|
|
4178
|
+
return { ...DEFAULT_PRIORITY_SIGNALS, ...partial };
|
|
4179
|
+
}
|
|
4180
|
+
function classifyMemoryPriority(signals) {
|
|
4181
|
+
const isNegative = signals.type === "attempt";
|
|
4182
|
+
const isSkill2 = signals.type === "skill";
|
|
4183
|
+
if (signals.requiresHumanApproval || signals.directAnchor || signals.directSymbol || isNegative && (signals.exactTaskMatch || signals.strongSemantic) || isSkill2 && (signals.exactTaskMatch || signals.strongSemantic)) {
|
|
4184
|
+
return "must_read";
|
|
4185
|
+
}
|
|
4186
|
+
if (isStackPackSeed({ tags: signals.tags }) || isEnvWorkaroundMemory({ tags: signals.tags })) {
|
|
4187
|
+
return "background";
|
|
4188
|
+
}
|
|
4189
|
+
if (isSkill2 || signals.moduleOrDomainMatch || signals.exactTaskMatch || signals.usefulSemantic || signals.tagTaskMatch) {
|
|
4190
|
+
return "useful";
|
|
4191
|
+
}
|
|
4192
|
+
return "background";
|
|
4193
|
+
}
|
|
4194
|
+
function priorityRank(priority) {
|
|
4195
|
+
return priority === "must_read" ? 3 : priority === "useful" ? 2 : 1;
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
// src/bridges.ts
|
|
4199
|
+
var BRIDGE_TARGET_PATH = {
|
|
4200
|
+
claude: "CLAUDE.md",
|
|
4201
|
+
cursor: ".cursor/rules/haive-memories.mdc",
|
|
4202
|
+
cline: ".clinerules",
|
|
4203
|
+
windsurf: ".windsurfrules",
|
|
4204
|
+
continue: ".continuerules",
|
|
4205
|
+
cody: ".sourcegraph/cody-rules.md",
|
|
4206
|
+
zed: ".rules",
|
|
4207
|
+
roo: ".roo/rules/haive.md",
|
|
4208
|
+
gemini: "GEMINI.md",
|
|
4209
|
+
aider: "CONVENTIONS.md",
|
|
4210
|
+
agents: "AGENTS.md",
|
|
4211
|
+
copilot: ".github/copilot-instructions.md"
|
|
4212
|
+
};
|
|
4213
|
+
var BRIDGE_TARGETS = Object.keys(BRIDGE_TARGET_PATH);
|
|
4214
|
+
var BRIDGE_MARKERS = {
|
|
4215
|
+
memoriesStart: "<!-- haive:memories-start -->",
|
|
4216
|
+
memoriesEnd: "<!-- haive:memories-end -->",
|
|
4217
|
+
sensorsStart: "<!-- haive:sensors-start -->",
|
|
4218
|
+
sensorsEnd: "<!-- haive:sensors-end -->"
|
|
4219
|
+
};
|
|
4220
|
+
function bridgeMemorySummary(body) {
|
|
4221
|
+
const firstLine = body.split("\n").map((l) => l.replace(/^#+\s*/, "").trim()).find((l) => l.length > 0) ?? "";
|
|
4222
|
+
const oneLine = firstLine.replace(/\s+/g, " ");
|
|
4223
|
+
return oneLine.length > 140 ? oneLine.slice(0, 137) + "\u2026" : oneLine;
|
|
4224
|
+
}
|
|
4225
|
+
function prepareBridgeData(memories, sensors, opts) {
|
|
4226
|
+
const max = opts?.maxMemories ?? 8;
|
|
4227
|
+
const topMemories = memories.filter((m) => {
|
|
4228
|
+
const s = m.frontmatter.status;
|
|
4229
|
+
if (m.frontmatter.type === "session_recap") return false;
|
|
4230
|
+
if (m.frontmatter.tags?.includes("stack-pack") || m.frontmatter.tags?.includes("seed")) return false;
|
|
4231
|
+
return s === "validated" || s === "proposed";
|
|
4232
|
+
}).sort((a, b) => {
|
|
4233
|
+
const score = (m) => m.frontmatter.status === "validated" ? 2 : 1;
|
|
4234
|
+
return score(b) - score(a);
|
|
4235
|
+
}).slice(0, max).map((m) => ({
|
|
4236
|
+
id: m.frontmatter.id,
|
|
4237
|
+
scope: m.frontmatter.scope,
|
|
4238
|
+
type: m.frontmatter.type,
|
|
4239
|
+
summary: bridgeMemorySummary(m.body),
|
|
4240
|
+
paths: m.frontmatter.anchor?.paths ?? []
|
|
4241
|
+
}));
|
|
4242
|
+
const blockSensors = sensors.filter((s) => s.severity === "block");
|
|
4243
|
+
return { topMemories, blockSensors };
|
|
4244
|
+
}
|
|
4245
|
+
function renderMemoriesBlock(topMemories) {
|
|
4246
|
+
const lines = [
|
|
4247
|
+
BRIDGE_MARKERS.memoriesStart,
|
|
4248
|
+
"<!-- AUTO-GENERATED by haive bridges sync \u2014 do not edit between these markers -->",
|
|
4249
|
+
"<!-- Top memories \u2014 call get_briefing / mem_get for the full body. -->",
|
|
4250
|
+
""
|
|
4251
|
+
];
|
|
4252
|
+
if (topMemories.length === 0) {
|
|
4253
|
+
lines.push("_(no validated memories yet \u2014 run `haive sync` to populate)_");
|
|
4254
|
+
} else {
|
|
4255
|
+
for (const m of topMemories) {
|
|
4256
|
+
const scopeNote = m.paths.length > 0 ? ` _(applies to: ${m.paths.slice(0, 4).join(", ")}${m.paths.length > 4 ? ", \u2026" : ""})_` : "";
|
|
4257
|
+
lines.push(`- \`${m.id}\` (${m.scope}/${m.type}) \u2014 ${m.summary}${scopeNote}`);
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
lines.push("", BRIDGE_MARKERS.memoriesEnd);
|
|
4261
|
+
return lines.join("\n");
|
|
4262
|
+
}
|
|
4263
|
+
function renderSensorsBlock(blockSensors) {
|
|
4264
|
+
if (blockSensors.length === 0) return "";
|
|
4265
|
+
const lines = [
|
|
4266
|
+
BRIDGE_MARKERS.sensorsStart,
|
|
4267
|
+
"<!-- AUTO-GENERATED by haive bridges sync \u2014 do not edit between these markers -->",
|
|
4268
|
+
"",
|
|
4269
|
+
"## Hard rules \u2014 hAIve block sensors",
|
|
4270
|
+
"",
|
|
4271
|
+
"The patterns below are blocked by the repo enforcement gate.",
|
|
4272
|
+
"Introducing them will fail the pre-commit check (`haive enforce check`).",
|
|
4273
|
+
""
|
|
4274
|
+
];
|
|
4275
|
+
for (const s of blockSensors) {
|
|
4276
|
+
const pathNote = s.paths.length > 0 ? ` _(applies to: ${s.paths.join(", ")})_` : "";
|
|
4277
|
+
lines.push(`- **${s.id}**${pathNote}: ${s.message}`);
|
|
4278
|
+
if (s.pattern) lines.push(` - Pattern: \`${s.pattern}\``);
|
|
4279
|
+
}
|
|
4280
|
+
lines.push("", BRIDGE_MARKERS.sensorsEnd);
|
|
4281
|
+
return lines.join("\n");
|
|
4282
|
+
}
|
|
4283
|
+
var HAIVE_PREAMBLE = "This repo uses **[hAIve](https://github.com/Doucs91/hAIve)** for shared context and enforcement.\n\n**Before editing** for a goal: call `get_briefing` (task + files/symbols) to load ranked context.\n**When an approach fails**: call `mem_tried` right away.\n**Before closing**: run `haive enforce finish` and capture learnings via the `post_task` prompt.\n\nIf `get_briefing` returns `action_required`, surface each item to the developer and wait for\nexplicit confirmation before modifying any code.";
|
|
4284
|
+
function renderMarkdownBridge(topMemories, blockSensors, title) {
|
|
4285
|
+
const parts = [
|
|
4286
|
+
`# ${title}`,
|
|
4287
|
+
"",
|
|
4288
|
+
HAIVE_PREAMBLE,
|
|
4289
|
+
"",
|
|
4290
|
+
"## Memories",
|
|
4291
|
+
"",
|
|
4292
|
+
renderMemoriesBlock(topMemories)
|
|
4293
|
+
];
|
|
4294
|
+
const sensorsBlock = renderSensorsBlock(blockSensors);
|
|
4295
|
+
if (sensorsBlock) {
|
|
4296
|
+
parts.push("", sensorsBlock);
|
|
4297
|
+
}
|
|
4298
|
+
return parts.join("\n") + "\n";
|
|
4299
|
+
}
|
|
4300
|
+
function renderCursorBridge(topMemories, blockSensors) {
|
|
4301
|
+
const frontmatter = [
|
|
4302
|
+
"---",
|
|
4303
|
+
"description: hAIve shared memories & block sensors (auto-generated)",
|
|
4304
|
+
"alwaysApply: true",
|
|
4305
|
+
"---",
|
|
4306
|
+
""
|
|
4307
|
+
].join("\n");
|
|
4308
|
+
return frontmatter + renderMarkdownBridge(topMemories, blockSensors, "hAIve rules (Cursor)");
|
|
4309
|
+
}
|
|
4310
|
+
var FORMATTERS = {
|
|
4311
|
+
claude: (m, s) => renderMarkdownBridge(m, s, "CLAUDE.md \u2014 hAIve context"),
|
|
4312
|
+
cursor: (m, s) => renderCursorBridge(m, s),
|
|
4313
|
+
cline: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Cline)"),
|
|
4314
|
+
windsurf: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Windsurf)"),
|
|
4315
|
+
continue: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Continue)"),
|
|
4316
|
+
cody: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Cody / Sourcegraph)"),
|
|
4317
|
+
zed: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Zed)"),
|
|
4318
|
+
roo: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Roo Code)"),
|
|
4319
|
+
gemini: (m, s) => renderMarkdownBridge(m, s, "GEMINI.md \u2014 hAIve context"),
|
|
4320
|
+
aider: (m, s) => renderMarkdownBridge(m, s, "CONVENTIONS.md \u2014 hAIve context (Aider)"),
|
|
4321
|
+
agents: (m, s) => renderMarkdownBridge(m, s, "AGENTS.md \u2014 hAIve context"),
|
|
4322
|
+
copilot: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (GitHub Copilot)")
|
|
4323
|
+
};
|
|
4324
|
+
function generateBridges(memories, sensors, opts) {
|
|
4325
|
+
const { topMemories, blockSensors } = prepareBridgeData(memories, sensors, opts);
|
|
4326
|
+
const targets = opts?.targets ?? BRIDGE_TARGETS;
|
|
4327
|
+
return targets.map((target) => ({
|
|
4328
|
+
target,
|
|
4329
|
+
path: BRIDGE_TARGET_PATH[target],
|
|
4330
|
+
content: FORMATTERS[target](topMemories, blockSensors)
|
|
4331
|
+
}));
|
|
4332
|
+
}
|
|
3826
4333
|
export {
|
|
3827
4334
|
AUTOPILOT_DEFAULTS,
|
|
3828
4335
|
ActivationSchema,
|
|
3829
4336
|
AnchorSchema,
|
|
4337
|
+
BRIDGE_MARKERS,
|
|
4338
|
+
BRIDGE_TARGETS,
|
|
4339
|
+
BRIDGE_TARGET_PATH,
|
|
3830
4340
|
BRIEFING_MARKER_TTL_MS,
|
|
3831
4341
|
BRIEFING_PRESET_DEFAULTS,
|
|
3832
4342
|
CHARS_PER_TOKEN,
|
|
@@ -3839,6 +4349,8 @@ export {
|
|
|
3839
4349
|
DEFAULT_CONFIDENCE_THRESHOLDS,
|
|
3840
4350
|
DEFAULT_CONFIG,
|
|
3841
4351
|
DEFAULT_DORMANT_DAYS,
|
|
4352
|
+
DEFAULT_PRIORITY_SIGNALS,
|
|
4353
|
+
ENV_WORKAROUND_TAGS,
|
|
3842
4354
|
GUESSABLE_THRESHOLD,
|
|
3843
4355
|
HAIVE_DIR,
|
|
3844
4356
|
MEMORIES_DIR,
|
|
@@ -3867,8 +4379,11 @@ export {
|
|
|
3867
4379
|
appendPreventionEvent,
|
|
3868
4380
|
appendRuntimeJournalEntry,
|
|
3869
4381
|
appendUsageEvent,
|
|
4382
|
+
applyFeedbackAdjustment,
|
|
4383
|
+
bridgeMemorySummary,
|
|
3870
4384
|
briefingMarkerPath,
|
|
3871
4385
|
briefingMarkersDir,
|
|
4386
|
+
briefingProofLine,
|
|
3872
4387
|
buildCodeMap,
|
|
3873
4388
|
buildCoverageIndex,
|
|
3874
4389
|
buildDashboard,
|
|
@@ -3876,9 +4391,12 @@ export {
|
|
|
3876
4391
|
buildFrontmatter,
|
|
3877
4392
|
buildReport,
|
|
3878
4393
|
bumpRead,
|
|
4394
|
+
classifyMemoryPriority,
|
|
3879
4395
|
codeMapPath,
|
|
3880
4396
|
collectTimelineEntries,
|
|
4397
|
+
compactAutoRecapBody,
|
|
3881
4398
|
compareEvalReports,
|
|
4399
|
+
compareGatePrecision,
|
|
3882
4400
|
compareImpact,
|
|
3883
4401
|
compileRegexSensor,
|
|
3884
4402
|
computeEvalTrend,
|
|
@@ -3889,6 +4407,7 @@ export {
|
|
|
3889
4407
|
configPath,
|
|
3890
4408
|
contractLockPath,
|
|
3891
4409
|
deriveConfidence,
|
|
4410
|
+
detectStacksFromManifests,
|
|
3892
4411
|
diffContract,
|
|
3893
4412
|
diffHasDistinctiveOverlap,
|
|
3894
4413
|
distinctiveCap,
|
|
@@ -3910,15 +4429,18 @@ export {
|
|
|
3910
4429
|
findingBody,
|
|
3911
4430
|
findingToDraft,
|
|
3912
4431
|
firstMemoryOneLine,
|
|
4432
|
+
generateBridges,
|
|
3913
4433
|
getUsage,
|
|
3914
4434
|
globToRegExp,
|
|
3915
4435
|
hasRecentBriefingMarker,
|
|
3916
4436
|
hashProjectContext,
|
|
3917
4437
|
inferModulesFromPaths,
|
|
3918
4438
|
isAutoPromoteEligible,
|
|
4439
|
+
isAutoRecap,
|
|
3919
4440
|
isCovered,
|
|
3920
4441
|
isDecaying,
|
|
3921
4442
|
isDistinctiveToken,
|
|
4443
|
+
isEnvWorkaroundMemory,
|
|
3922
4444
|
isFreshIsoDate,
|
|
3923
4445
|
isGlobPath,
|
|
3924
4446
|
isLikelyGuessable,
|
|
@@ -3944,15 +4466,20 @@ export {
|
|
|
3944
4466
|
normalizeFindingSeverity,
|
|
3945
4467
|
normalizeSessionId,
|
|
3946
4468
|
overallScore,
|
|
4469
|
+
parseEslintJson,
|
|
3947
4470
|
parseFindings,
|
|
3948
4471
|
parseMemory,
|
|
4472
|
+
parseNpmAudit,
|
|
3949
4473
|
parseSarif,
|
|
3950
4474
|
parseSince,
|
|
3951
4475
|
parseSonar,
|
|
3952
4476
|
pathsOverlap,
|
|
3953
4477
|
pickSnippetNeedle,
|
|
3954
4478
|
planConflictResolution,
|
|
4479
|
+
prepareBridgeData,
|
|
3955
4480
|
preventionLogPath,
|
|
4481
|
+
priorityRank,
|
|
4482
|
+
prioritySignals,
|
|
3956
4483
|
projectContextRecentlyEmitted,
|
|
3957
4484
|
proposeSeedsFromCommits,
|
|
3958
4485
|
pullCrossRepoSources,
|
|
@@ -3961,11 +4488,13 @@ export {
|
|
|
3961
4488
|
readRecentBriefingMarker,
|
|
3962
4489
|
readRuntimeJournalTail,
|
|
3963
4490
|
readUsageEvents,
|
|
4491
|
+
recommendFeedbackAdjustment,
|
|
3964
4492
|
recordApplied,
|
|
3965
4493
|
recordPrevention,
|
|
3966
4494
|
recordProjectContextEmission,
|
|
3967
4495
|
recordRejection,
|
|
3968
4496
|
relPathFrom,
|
|
4497
|
+
renderCaughtForYou,
|
|
3969
4498
|
resolveBriefingBudget,
|
|
3970
4499
|
resolveHaivePaths,
|
|
3971
4500
|
resolveManifestFiles,
|
|
@@ -3989,6 +4518,7 @@ export {
|
|
|
3989
4518
|
suggestGate,
|
|
3990
4519
|
suggestSensorFromMemory,
|
|
3991
4520
|
suggestTopicKey,
|
|
4521
|
+
summarizeCaughtForYou,
|
|
3992
4522
|
summarizeImpact,
|
|
3993
4523
|
synthesizeSelfEvalCases,
|
|
3994
4524
|
titleFromBody,
|