@hiveai/core 0.14.0 → 0.15.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 +287 -1
- package/dist/index.js +328 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2943,10 +2943,10 @@ function isRetiredMemory(fm, body = "", now = /* @__PURE__ */ new Date()) {
|
|
|
2943
2943
|
function normalizeProjectPath(value) {
|
|
2944
2944
|
return value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^[ab]\//, "").replace(/\/+$/g, "");
|
|
2945
2945
|
}
|
|
2946
|
-
function sensorAppliesToPath(sensor, anchorPaths,
|
|
2946
|
+
function sensorAppliesToPath(sensor, anchorPaths, path18) {
|
|
2947
2947
|
const scopes = sensor.paths.length > 0 ? sensor.paths : anchorPaths;
|
|
2948
2948
|
if (scopes.length === 0) return true;
|
|
2949
|
-
const target = normalizeProjectPath(
|
|
2949
|
+
const target = normalizeProjectPath(path18);
|
|
2950
2950
|
return scopes.some((rawScope) => {
|
|
2951
2951
|
const scope = normalizeProjectPath(rawScope);
|
|
2952
2952
|
if (!scope) return false;
|
|
@@ -2994,6 +2994,28 @@ function runSensors(memories, targets) {
|
|
|
2994
2994
|
}
|
|
2995
2995
|
return hits;
|
|
2996
2996
|
}
|
|
2997
|
+
function selectCommandSensors(memories, changedPaths) {
|
|
2998
|
+
const specs = [];
|
|
2999
|
+
for (const memory of memories) {
|
|
3000
|
+
const sensor = memory.frontmatter.sensor;
|
|
3001
|
+
if (!sensor) continue;
|
|
3002
|
+
if (sensor.kind !== "shell" && sensor.kind !== "test") continue;
|
|
3003
|
+
const command = sensor.command?.trim();
|
|
3004
|
+
if (!command) continue;
|
|
3005
|
+
const anchorPaths = memory.frontmatter.anchor.paths;
|
|
3006
|
+
const applies = changedPaths.length === 0 ? true : changedPaths.some((p) => sensorAppliesToPath(sensor, anchorPaths, p));
|
|
3007
|
+
if (!applies) continue;
|
|
3008
|
+
specs.push({
|
|
3009
|
+
memory_id: memory.frontmatter.id,
|
|
3010
|
+
command,
|
|
3011
|
+
kind: sensor.kind,
|
|
3012
|
+
severity: sensor.severity,
|
|
3013
|
+
message: sensor.message,
|
|
3014
|
+
paths: sensor.paths.length > 0 ? sensor.paths : anchorPaths
|
|
3015
|
+
});
|
|
3016
|
+
}
|
|
3017
|
+
return specs;
|
|
3018
|
+
}
|
|
2997
3019
|
function sensorTargetsFromDiff(diff) {
|
|
2998
3020
|
const targets = [];
|
|
2999
3021
|
let currentPath = null;
|
|
@@ -3220,8 +3242,8 @@ function normalizeFindingSeverity(raw) {
|
|
|
3220
3242
|
return "info";
|
|
3221
3243
|
}
|
|
3222
3244
|
}
|
|
3223
|
-
function findingKey(tool, ruleId,
|
|
3224
|
-
return `${tool}:${ruleId}:${
|
|
3245
|
+
function findingKey(tool, ruleId, path18) {
|
|
3246
|
+
return `${tool}:${ruleId}:${path18}`;
|
|
3225
3247
|
}
|
|
3226
3248
|
function coerceJson(input) {
|
|
3227
3249
|
if (typeof input === "string") {
|
|
@@ -3255,8 +3277,8 @@ function parseSarif(input) {
|
|
|
3255
3277
|
const physical = asRecord(location.physicalLocation);
|
|
3256
3278
|
const artifact = asRecord(physical.artifactLocation);
|
|
3257
3279
|
const region = asRecord(physical.region);
|
|
3258
|
-
const
|
|
3259
|
-
if (!
|
|
3280
|
+
const path18 = typeof artifact.uri === "string" ? normalizeUri(artifact.uri) : "";
|
|
3281
|
+
if (!path18) continue;
|
|
3260
3282
|
const line = typeof region.startLine === "number" ? region.startLine : void 0;
|
|
3261
3283
|
const snippet = typeof asRecord(region.snippet).text === "string" ? asRecord(region.snippet).text.trim() : void 0;
|
|
3262
3284
|
findings.push({
|
|
@@ -3264,10 +3286,10 @@ function parseSarif(input) {
|
|
|
3264
3286
|
ruleId,
|
|
3265
3287
|
message: message.trim(),
|
|
3266
3288
|
severity,
|
|
3267
|
-
path:
|
|
3289
|
+
path: path18,
|
|
3268
3290
|
...line !== void 0 ? { line } : {},
|
|
3269
3291
|
...snippet ? { snippet } : {},
|
|
3270
|
-
key: findingKey(tool, ruleId,
|
|
3292
|
+
key: findingKey(tool, ruleId, path18)
|
|
3271
3293
|
});
|
|
3272
3294
|
}
|
|
3273
3295
|
}
|
|
@@ -3286,17 +3308,17 @@ function parseSonar(input) {
|
|
|
3286
3308
|
(typeof issue.severity === "string" ? issue.severity : void 0) ?? impactSeverity
|
|
3287
3309
|
);
|
|
3288
3310
|
const component = typeof issue.component === "string" ? issue.component : "";
|
|
3289
|
-
const
|
|
3290
|
-
if (!
|
|
3311
|
+
const path18 = componentToPath(component);
|
|
3312
|
+
if (!path18) continue;
|
|
3291
3313
|
const line = typeof issue.line === "number" ? issue.line : void 0;
|
|
3292
3314
|
findings.push({
|
|
3293
3315
|
tool: "sonar",
|
|
3294
3316
|
ruleId,
|
|
3295
3317
|
message,
|
|
3296
3318
|
severity,
|
|
3297
|
-
path:
|
|
3319
|
+
path: path18,
|
|
3298
3320
|
...line !== void 0 ? { line } : {},
|
|
3299
|
-
key: findingKey("sonar", ruleId,
|
|
3321
|
+
key: findingKey("sonar", ruleId, path18)
|
|
3300
3322
|
});
|
|
3301
3323
|
}
|
|
3302
3324
|
return findings;
|
|
@@ -3373,6 +3395,52 @@ function filterNewDrafts(drafts, existingTopics) {
|
|
|
3373
3395
|
return drafts.filter((d) => !existing.has(d.topic));
|
|
3374
3396
|
}
|
|
3375
3397
|
|
|
3398
|
+
// src/gate-precision.ts
|
|
3399
|
+
function round33(n) {
|
|
3400
|
+
return Math.round(n * 1e3) / 1e3;
|
|
3401
|
+
}
|
|
3402
|
+
function computeGatePrecision(events, usage, currentGate = "anchored") {
|
|
3403
|
+
let sensorCatches = 0;
|
|
3404
|
+
let antiPatternCatches = 0;
|
|
3405
|
+
for (const e of events) {
|
|
3406
|
+
if (e.source === "sensor") sensorCatches += 1;
|
|
3407
|
+
else if (e.source === "anti-pattern") antiPatternCatches += 1;
|
|
3408
|
+
}
|
|
3409
|
+
let applied = 0;
|
|
3410
|
+
let rejections = 0;
|
|
3411
|
+
for (const mem of Object.values(usage.by_id ?? {})) {
|
|
3412
|
+
applied += mem.applied_count ?? 0;
|
|
3413
|
+
rejections += mem.rejected_count ?? 0;
|
|
3414
|
+
}
|
|
3415
|
+
const useful = sensorCatches + antiPatternCatches + applied;
|
|
3416
|
+
const denom = useful + rejections;
|
|
3417
|
+
const precision = denom === 0 ? null : round33(useful / denom);
|
|
3418
|
+
return {
|
|
3419
|
+
sensor_catches: sensorCatches,
|
|
3420
|
+
anti_pattern_catches: antiPatternCatches,
|
|
3421
|
+
useful,
|
|
3422
|
+
rejections,
|
|
3423
|
+
precision,
|
|
3424
|
+
suggestion: suggestGate(precision, rejections, currentGate)
|
|
3425
|
+
};
|
|
3426
|
+
}
|
|
3427
|
+
function suggestGate(precision, rejections, currentGate) {
|
|
3428
|
+
if (precision === null || rejections < 3) return null;
|
|
3429
|
+
if (precision < 0.5 && (currentGate === "anchored" || currentGate === "strict")) {
|
|
3430
|
+
return {
|
|
3431
|
+
recommended: "review",
|
|
3432
|
+
reason: `Gate precision ${precision} with ${rejections} rejection(s) \u2014 the gate is crying wolf. Loosen to "review" (surface, don't hard-block) until the corpus is cleaner.`
|
|
3433
|
+
};
|
|
3434
|
+
}
|
|
3435
|
+
if (precision >= 0.85 && currentGate === "review") {
|
|
3436
|
+
return {
|
|
3437
|
+
recommended: "anchored",
|
|
3438
|
+
reason: `Gate precision ${precision} \u2014 catches are reliably real. Tighten to "anchored" so corroborated anti-patterns hard-block.`
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
return null;
|
|
3442
|
+
}
|
|
3443
|
+
|
|
3376
3444
|
// src/dashboard.ts
|
|
3377
3445
|
var MS_PER_DAY4 = 24 * 60 * 60 * 1e3;
|
|
3378
3446
|
function isAnchorless(fm) {
|
|
@@ -3514,6 +3582,11 @@ function buildDashboard(memories, usage, options = {}) {
|
|
|
3514
3582
|
top: computeRecurrence(options.preventionEvents ?? []).top.slice(0, top)
|
|
3515
3583
|
}
|
|
3516
3584
|
},
|
|
3585
|
+
gate_precision: computeGatePrecision(
|
|
3586
|
+
options.preventionEvents ?? [],
|
|
3587
|
+
usage,
|
|
3588
|
+
options.antiPatternGate ?? "anchored"
|
|
3589
|
+
),
|
|
3517
3590
|
corpus: {
|
|
3518
3591
|
memory_files: inventory.total,
|
|
3519
3592
|
body_chars: bodyChars,
|
|
@@ -3521,6 +3594,235 @@ function buildDashboard(memories, usage, options = {}) {
|
|
|
3521
3594
|
}
|
|
3522
3595
|
};
|
|
3523
3596
|
}
|
|
3597
|
+
|
|
3598
|
+
// src/failure-coverage.ts
|
|
3599
|
+
var MS_PER_HOUR = 36e5;
|
|
3600
|
+
function normalizeSummary(summary) {
|
|
3601
|
+
return summary.toLowerCase().replace(/\s+/g, " ").trim().slice(0, 160);
|
|
3602
|
+
}
|
|
3603
|
+
function findUncapturedFailures(failures, captureTimes, options = {}) {
|
|
3604
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
3605
|
+
const windowMs = (options.windowHours ?? 24) * MS_PER_HOUR;
|
|
3606
|
+
const dedupe = options.dedupe ?? true;
|
|
3607
|
+
let latestCapture = 0;
|
|
3608
|
+
for (const iso of captureTimes) {
|
|
3609
|
+
const t = Date.parse(iso);
|
|
3610
|
+
if (Number.isFinite(t) && now - t <= windowMs && t > latestCapture) latestCapture = t;
|
|
3611
|
+
}
|
|
3612
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3613
|
+
const out = [];
|
|
3614
|
+
for (const f of failures) {
|
|
3615
|
+
const t = Date.parse(f.ts);
|
|
3616
|
+
if (!Number.isFinite(t)) continue;
|
|
3617
|
+
if (now - t > windowMs) continue;
|
|
3618
|
+
if (t <= latestCapture) continue;
|
|
3619
|
+
if (dedupe) {
|
|
3620
|
+
const key = normalizeSummary(f.summary);
|
|
3621
|
+
if (seen.has(key)) continue;
|
|
3622
|
+
seen.add(key);
|
|
3623
|
+
}
|
|
3624
|
+
out.push({ ts: f.ts, tool: f.tool, summary: f.summary });
|
|
3625
|
+
}
|
|
3626
|
+
out.sort((a, b) => a.ts.localeCompare(b.ts));
|
|
3627
|
+
return out;
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
// src/coverage.ts
|
|
3631
|
+
var DEFAULT_COVERING_TYPES = ["decision", "convention", "gotcha", "architecture"];
|
|
3632
|
+
function normalizePath(value) {
|
|
3633
|
+
return value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/g, "");
|
|
3634
|
+
}
|
|
3635
|
+
function buildCoverageIndex(memories, coveringTypes = DEFAULT_COVERING_TYPES) {
|
|
3636
|
+
const types = new Set(coveringTypes);
|
|
3637
|
+
const covered = /* @__PURE__ */ new Set();
|
|
3638
|
+
for (const { memory } of memories) {
|
|
3639
|
+
const fm = memory.frontmatter;
|
|
3640
|
+
if (!types.has(fm.type)) continue;
|
|
3641
|
+
if (fm.status === "stale" || fm.status === "deprecated" || fm.status === "rejected") continue;
|
|
3642
|
+
for (const p of fm.anchor.paths) {
|
|
3643
|
+
const norm = normalizePath(p);
|
|
3644
|
+
if (norm) covered.add(norm);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
return covered;
|
|
3648
|
+
}
|
|
3649
|
+
function isCovered(file, coverage) {
|
|
3650
|
+
const target = normalizePath(file);
|
|
3651
|
+
if (coverage.has(target)) return true;
|
|
3652
|
+
for (const scope of coverage) {
|
|
3653
|
+
if (target === scope || target.startsWith(`${scope}/`)) return true;
|
|
3654
|
+
}
|
|
3655
|
+
return false;
|
|
3656
|
+
}
|
|
3657
|
+
function findCoverageGaps(hotFiles, memories, options = {}) {
|
|
3658
|
+
const minChanges = options.minChanges ?? 3;
|
|
3659
|
+
const limit = options.limit ?? 20;
|
|
3660
|
+
const coverage = buildCoverageIndex(memories, options.coveringTypes);
|
|
3661
|
+
const gaps = [];
|
|
3662
|
+
for (const hot of hotFiles) {
|
|
3663
|
+
if (hot.changes < minChanges) continue;
|
|
3664
|
+
if (isCovered(hot.path, coverage)) continue;
|
|
3665
|
+
gaps.push({ path: normalizePath(hot.path), changes: hot.changes });
|
|
3666
|
+
}
|
|
3667
|
+
gaps.sort((a, b) => b.changes - a.changes);
|
|
3668
|
+
return gaps.slice(0, limit);
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
// src/eval-history.ts
|
|
3672
|
+
import { appendFile as appendFile4, mkdir as mkdir11, readFile as readFile14 } from "fs/promises";
|
|
3673
|
+
import { existsSync as existsSync15 } from "fs";
|
|
3674
|
+
import path17 from "path";
|
|
3675
|
+
function evalHistoryPath(paths) {
|
|
3676
|
+
return path17.join(paths.haiveDir, ".cache", "eval-history.jsonl");
|
|
3677
|
+
}
|
|
3678
|
+
async function appendEvalHistory(paths, entry) {
|
|
3679
|
+
const file = evalHistoryPath(paths);
|
|
3680
|
+
await mkdir11(path17.dirname(file), { recursive: true });
|
|
3681
|
+
await appendFile4(file, JSON.stringify(entry) + "\n", "utf8");
|
|
3682
|
+
}
|
|
3683
|
+
async function loadEvalHistory(paths) {
|
|
3684
|
+
const file = evalHistoryPath(paths);
|
|
3685
|
+
if (!existsSync15(file)) return [];
|
|
3686
|
+
const raw = await readFile14(file, "utf8").catch(() => "");
|
|
3687
|
+
const out = [];
|
|
3688
|
+
for (const line of raw.split("\n")) {
|
|
3689
|
+
const trimmed = line.trim();
|
|
3690
|
+
if (!trimmed) continue;
|
|
3691
|
+
try {
|
|
3692
|
+
const e = JSON.parse(trimmed);
|
|
3693
|
+
if (e && typeof e.at === "string" && typeof e.score === "number") out.push(e);
|
|
3694
|
+
} catch {
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
return out;
|
|
3698
|
+
}
|
|
3699
|
+
function computeEvalTrend(entries, recentN = 10) {
|
|
3700
|
+
const sorted = [...entries].sort((a, b) => a.at.localeCompare(b.at));
|
|
3701
|
+
const scores = sorted.map((e) => e.score);
|
|
3702
|
+
const latest = scores.length > 0 ? scores[scores.length - 1] : null;
|
|
3703
|
+
const previous = scores.length > 1 ? scores[scores.length - 2] : null;
|
|
3704
|
+
const delta = latest !== null && previous !== null ? Math.round((latest - previous) * 1e3) / 1e3 : null;
|
|
3705
|
+
const best = scores.length > 0 ? Math.max(...scores) : null;
|
|
3706
|
+
return {
|
|
3707
|
+
latest,
|
|
3708
|
+
previous,
|
|
3709
|
+
delta,
|
|
3710
|
+
best,
|
|
3711
|
+
runs: scores.length,
|
|
3712
|
+
recent: scores.slice(-recentN),
|
|
3713
|
+
regressed: delta !== null && delta < 0
|
|
3714
|
+
};
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
// src/conflict-resolve.ts
|
|
3718
|
+
var STATUS_RANK = {
|
|
3719
|
+
validated: 4,
|
|
3720
|
+
proposed: 3,
|
|
3721
|
+
draft: 2,
|
|
3722
|
+
stale: 1,
|
|
3723
|
+
deprecated: 0,
|
|
3724
|
+
rejected: 0
|
|
3725
|
+
};
|
|
3726
|
+
function statusRank(fm) {
|
|
3727
|
+
return STATUS_RANK[fm.status] ?? 2;
|
|
3728
|
+
}
|
|
3729
|
+
function planConflictResolution(a, b) {
|
|
3730
|
+
const fa = a.memory.frontmatter;
|
|
3731
|
+
const fb = b.memory.frontmatter;
|
|
3732
|
+
const ra = statusRank(fa);
|
|
3733
|
+
const rb = statusRank(fb);
|
|
3734
|
+
let winner;
|
|
3735
|
+
let loser;
|
|
3736
|
+
let reason;
|
|
3737
|
+
if (ra !== rb) {
|
|
3738
|
+
[winner, loser] = ra > rb ? [a, b] : [b, a];
|
|
3739
|
+
reason = `status (${winner.memory.frontmatter.status} beats ${loser.memory.frontmatter.status})`;
|
|
3740
|
+
} else if (fa.revision_count !== fb.revision_count) {
|
|
3741
|
+
[winner, loser] = fa.revision_count > fb.revision_count ? [a, b] : [b, a];
|
|
3742
|
+
reason = `revision_count (${winner.memory.frontmatter.revision_count} > ${loser.memory.frontmatter.revision_count})`;
|
|
3743
|
+
} else {
|
|
3744
|
+
const cmp = fa.created_at.localeCompare(fb.created_at);
|
|
3745
|
+
[winner, loser] = cmp >= 0 ? [a, b] : [b, a];
|
|
3746
|
+
reason = `recency (${winner.memory.frontmatter.created_at} is newer)`;
|
|
3747
|
+
}
|
|
3748
|
+
const keepId = winner.memory.frontmatter.id;
|
|
3749
|
+
const supersedeId = loser.memory.frontmatter.id;
|
|
3750
|
+
return {
|
|
3751
|
+
keep_id: keepId,
|
|
3752
|
+
supersede_id: supersedeId,
|
|
3753
|
+
reason,
|
|
3754
|
+
stale_reason: `Superseded by ${keepId} (conflict resolved on ${reason}).`
|
|
3755
|
+
};
|
|
3756
|
+
}
|
|
3757
|
+
|
|
3758
|
+
// src/seed-git.ts
|
|
3759
|
+
var REVERT_RE = /^Revert\s+"(.+)"\s*$/i;
|
|
3760
|
+
var FIXUP_RE = /^(?:fixup!|hotfix[:!]|fix[:!]\s*revert|revert\s+revert)/i;
|
|
3761
|
+
var URGENT_FIX_RE = /\b(hotfix|urgent fix|emergency fix|critical fix|broke production|broken build)\b/i;
|
|
3762
|
+
function slugify(text) {
|
|
3763
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "reverted-change";
|
|
3764
|
+
}
|
|
3765
|
+
function proposeSeedsFromCommits(commits, limit = 20) {
|
|
3766
|
+
const out = [];
|
|
3767
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3768
|
+
for (const commit of commits) {
|
|
3769
|
+
const subject = commit.subject.trim();
|
|
3770
|
+
let what = null;
|
|
3771
|
+
let kind = null;
|
|
3772
|
+
const revert = subject.match(REVERT_RE);
|
|
3773
|
+
if (revert) {
|
|
3774
|
+
what = revert[1].trim();
|
|
3775
|
+
kind = "revert";
|
|
3776
|
+
} else if (FIXUP_RE.test(subject) || URGENT_FIX_RE.test(subject)) {
|
|
3777
|
+
what = subject.replace(FIXUP_RE, "").trim() || subject;
|
|
3778
|
+
kind = "fixup";
|
|
3779
|
+
}
|
|
3780
|
+
if (!what || !kind) continue;
|
|
3781
|
+
const slug = slugify(what);
|
|
3782
|
+
if (seen.has(slug)) continue;
|
|
3783
|
+
seen.add(slug);
|
|
3784
|
+
out.push({
|
|
3785
|
+
slug,
|
|
3786
|
+
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.`,
|
|
3788
|
+
paths: (commit.files ?? []).slice(0, 8),
|
|
3789
|
+
source_sha: commit.sha,
|
|
3790
|
+
kind
|
|
3791
|
+
});
|
|
3792
|
+
if (out.length >= limit) break;
|
|
3793
|
+
}
|
|
3794
|
+
return out;
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
// src/merge-memory.ts
|
|
3798
|
+
function safeParse(raw) {
|
|
3799
|
+
try {
|
|
3800
|
+
return parseMemory(raw);
|
|
3801
|
+
} catch {
|
|
3802
|
+
return null;
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
function mergeMemoryVersions(ours, theirs) {
|
|
3806
|
+
if (ours === theirs) {
|
|
3807
|
+
return { content: ours, winner: "ours", reason: "identical" };
|
|
3808
|
+
}
|
|
3809
|
+
const a = safeParse(ours);
|
|
3810
|
+
const b = safeParse(theirs);
|
|
3811
|
+
if (!a || !b) {
|
|
3812
|
+
return { content: ours, winner: "ours", reason: "unparseable side \u2014 kept ours" };
|
|
3813
|
+
}
|
|
3814
|
+
const ra = a.frontmatter.revision_count ?? 0;
|
|
3815
|
+
const rb = b.frontmatter.revision_count ?? 0;
|
|
3816
|
+
if (ra !== rb) {
|
|
3817
|
+
return rb > ra ? { content: theirs, winner: "theirs", reason: `higher revision_count (${rb} > ${ra})` } : { content: ours, winner: "ours", reason: `higher revision_count (${ra} > ${rb})` };
|
|
3818
|
+
}
|
|
3819
|
+
const ca = a.frontmatter.created_at ?? "";
|
|
3820
|
+
const cb = b.frontmatter.created_at ?? "";
|
|
3821
|
+
const cmp = cb.localeCompare(ca);
|
|
3822
|
+
if (cmp > 0) return { content: theirs, winner: "theirs", reason: `newer created_at (${cb})` };
|
|
3823
|
+
if (cmp < 0) return { content: ours, winner: "ours", reason: `newer created_at (${ca})` };
|
|
3824
|
+
return { content: ours, winner: "ours", reason: "tie \u2014 kept ours" };
|
|
3825
|
+
}
|
|
3524
3826
|
export {
|
|
3525
3827
|
AUTOPILOT_DEFAULTS,
|
|
3526
3828
|
ActivationSchema,
|
|
@@ -3561,12 +3863,14 @@ export {
|
|
|
3561
3863
|
aggregateUsage,
|
|
3562
3864
|
allocateBudget,
|
|
3563
3865
|
antiPatternGateParams,
|
|
3866
|
+
appendEvalHistory,
|
|
3564
3867
|
appendPreventionEvent,
|
|
3565
3868
|
appendRuntimeJournalEntry,
|
|
3566
3869
|
appendUsageEvent,
|
|
3567
3870
|
briefingMarkerPath,
|
|
3568
3871
|
briefingMarkersDir,
|
|
3569
3872
|
buildCodeMap,
|
|
3873
|
+
buildCoverageIndex,
|
|
3570
3874
|
buildDashboard,
|
|
3571
3875
|
buildDocFrequency,
|
|
3572
3876
|
buildFrontmatter,
|
|
@@ -3577,6 +3881,8 @@ export {
|
|
|
3577
3881
|
compareEvalReports,
|
|
3578
3882
|
compareImpact,
|
|
3579
3883
|
compileRegexSensor,
|
|
3884
|
+
computeEvalTrend,
|
|
3885
|
+
computeGatePrecision,
|
|
3580
3886
|
computeImpact,
|
|
3581
3887
|
computePreventionTrend,
|
|
3582
3888
|
computeRecurrence,
|
|
@@ -3591,13 +3897,16 @@ export {
|
|
|
3591
3897
|
emptyUsageIndex,
|
|
3592
3898
|
enforcementDir,
|
|
3593
3899
|
estimateTokens,
|
|
3900
|
+
evalHistoryPath,
|
|
3594
3901
|
evaluateSkillActivation,
|
|
3595
3902
|
extractActionsBriefBody,
|
|
3596
3903
|
extractSnippet,
|
|
3597
3904
|
filterNewDrafts,
|
|
3905
|
+
findCoverageGaps,
|
|
3598
3906
|
findLexicalConflictPairs,
|
|
3599
3907
|
findProjectRoot,
|
|
3600
3908
|
findTopicStatusConflictPairs,
|
|
3909
|
+
findUncapturedFailures,
|
|
3601
3910
|
findingBody,
|
|
3602
3911
|
findingToDraft,
|
|
3603
3912
|
firstMemoryOneLine,
|
|
@@ -3607,6 +3916,7 @@ export {
|
|
|
3607
3916
|
hashProjectContext,
|
|
3608
3917
|
inferModulesFromPaths,
|
|
3609
3918
|
isAutoPromoteEligible,
|
|
3919
|
+
isCovered,
|
|
3610
3920
|
isDecaying,
|
|
3611
3921
|
isDistinctiveToken,
|
|
3612
3922
|
isFreshIsoDate,
|
|
@@ -3622,12 +3932,14 @@ export {
|
|
|
3622
3932
|
loadCodeMap,
|
|
3623
3933
|
loadConfig,
|
|
3624
3934
|
loadConfigSync,
|
|
3935
|
+
loadEvalHistory,
|
|
3625
3936
|
loadMemoriesFromDir,
|
|
3626
3937
|
loadMemory,
|
|
3627
3938
|
loadPreventionEvents,
|
|
3628
3939
|
loadUsageIndex,
|
|
3629
3940
|
memoryFilePath,
|
|
3630
3941
|
memoryMatchesAnchorPaths,
|
|
3942
|
+
mergeMemoryVersions,
|
|
3631
3943
|
newMemoryId,
|
|
3632
3944
|
normalizeFindingSeverity,
|
|
3633
3945
|
normalizeSessionId,
|
|
@@ -3639,8 +3951,10 @@ export {
|
|
|
3639
3951
|
parseSonar,
|
|
3640
3952
|
pathsOverlap,
|
|
3641
3953
|
pickSnippetNeedle,
|
|
3954
|
+
planConflictResolution,
|
|
3642
3955
|
preventionLogPath,
|
|
3643
3956
|
projectContextRecentlyEmitted,
|
|
3957
|
+
proposeSeedsFromCommits,
|
|
3644
3958
|
pullCrossRepoSources,
|
|
3645
3959
|
queryCodeMap,
|
|
3646
3960
|
rankMemoriesLexical,
|
|
@@ -3665,12 +3979,14 @@ export {
|
|
|
3665
3979
|
saveUsageIndex,
|
|
3666
3980
|
scoreRetrievalCase,
|
|
3667
3981
|
scoreSensorCase,
|
|
3982
|
+
selectCommandSensors,
|
|
3668
3983
|
sensorAppliesToPath,
|
|
3669
3984
|
sensorTargetsFromDiff,
|
|
3670
3985
|
serializeMemory,
|
|
3671
3986
|
snapshotContract,
|
|
3672
3987
|
specificityScore,
|
|
3673
3988
|
stripPrivate,
|
|
3989
|
+
suggestGate,
|
|
3674
3990
|
suggestSensorFromMemory,
|
|
3675
3991
|
suggestTopicKey,
|
|
3676
3992
|
summarizeImpact,
|