@hiveai/core 0.14.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.d.ts +374 -1
- package/dist/index.js +432 -15
- 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\/([^/]+)\//,
|
|
@@ -2833,11 +2843,24 @@ function briefingMarkerPath(paths, sessionId) {
|
|
|
2833
2843
|
return path16.join(briefingMarkersDir(paths), `${normalizeSessionId(sessionId)}.json`);
|
|
2834
2844
|
}
|
|
2835
2845
|
async function writeBriefingMarker(paths, input) {
|
|
2846
|
+
const sessionId = normalizeSessionId(input.sessionId);
|
|
2847
|
+
const accumulate = input.accumulate ?? true;
|
|
2848
|
+
let priorIds = [];
|
|
2849
|
+
let priorFiles = [];
|
|
2850
|
+
if (accumulate) {
|
|
2851
|
+
const existing = await readSessionBriefingMarker(paths, sessionId);
|
|
2852
|
+
if (existing) {
|
|
2853
|
+
priorIds = existing.memory_ids ?? [];
|
|
2854
|
+
priorFiles = existing.files ?? [];
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
const mergedIds = [.../* @__PURE__ */ new Set([...priorIds, ...input.memoryIds ?? []])];
|
|
2858
|
+
const mergedFiles = [.../* @__PURE__ */ new Set([...priorFiles, ...input.files ?? []])];
|
|
2836
2859
|
const marker = {
|
|
2837
|
-
session_id:
|
|
2860
|
+
session_id: sessionId,
|
|
2838
2861
|
...input.task?.trim() ? { task: input.task.trim() } : {},
|
|
2839
|
-
...
|
|
2840
|
-
...
|
|
2862
|
+
...mergedIds.length > 0 ? { memory_ids: mergedIds } : {},
|
|
2863
|
+
...mergedFiles.length > 0 ? { files: mergedFiles } : {},
|
|
2841
2864
|
source: input.source,
|
|
2842
2865
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2843
2866
|
root: paths.root
|
|
@@ -2850,6 +2873,18 @@ async function writeBriefingMarker(paths, input) {
|
|
|
2850
2873
|
);
|
|
2851
2874
|
return marker;
|
|
2852
2875
|
}
|
|
2876
|
+
async function readSessionBriefingMarker(paths, sessionId, ttlMs = BRIEFING_MARKER_TTL_MS) {
|
|
2877
|
+
const file = briefingMarkerPath(paths, sessionId);
|
|
2878
|
+
if (!existsSync14(file)) return null;
|
|
2879
|
+
try {
|
|
2880
|
+
const marker = JSON.parse(await readFile13(file, "utf8"));
|
|
2881
|
+
const created = Date.parse(marker.created_at);
|
|
2882
|
+
if (!Number.isFinite(created) || Date.now() - created > ttlMs) return null;
|
|
2883
|
+
return marker;
|
|
2884
|
+
} catch {
|
|
2885
|
+
return null;
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2853
2888
|
async function hasRecentBriefingMarker(paths, sessionId, ttlMs = BRIEFING_MARKER_TTL_MS) {
|
|
2854
2889
|
const now = Date.now();
|
|
2855
2890
|
const candidates = [];
|
|
@@ -2943,10 +2978,10 @@ function isRetiredMemory(fm, body = "", now = /* @__PURE__ */ new Date()) {
|
|
|
2943
2978
|
function normalizeProjectPath(value) {
|
|
2944
2979
|
return value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^[ab]\//, "").replace(/\/+$/g, "");
|
|
2945
2980
|
}
|
|
2946
|
-
function sensorAppliesToPath(sensor, anchorPaths,
|
|
2981
|
+
function sensorAppliesToPath(sensor, anchorPaths, path18) {
|
|
2947
2982
|
const scopes = sensor.paths.length > 0 ? sensor.paths : anchorPaths;
|
|
2948
2983
|
if (scopes.length === 0) return true;
|
|
2949
|
-
const target = normalizeProjectPath(
|
|
2984
|
+
const target = normalizeProjectPath(path18);
|
|
2950
2985
|
return scopes.some((rawScope) => {
|
|
2951
2986
|
const scope = normalizeProjectPath(rawScope);
|
|
2952
2987
|
if (!scope) return false;
|
|
@@ -2994,6 +3029,28 @@ function runSensors(memories, targets) {
|
|
|
2994
3029
|
}
|
|
2995
3030
|
return hits;
|
|
2996
3031
|
}
|
|
3032
|
+
function selectCommandSensors(memories, changedPaths) {
|
|
3033
|
+
const specs = [];
|
|
3034
|
+
for (const memory of memories) {
|
|
3035
|
+
const sensor = memory.frontmatter.sensor;
|
|
3036
|
+
if (!sensor) continue;
|
|
3037
|
+
if (sensor.kind !== "shell" && sensor.kind !== "test") continue;
|
|
3038
|
+
const command = sensor.command?.trim();
|
|
3039
|
+
if (!command) continue;
|
|
3040
|
+
const anchorPaths = memory.frontmatter.anchor.paths;
|
|
3041
|
+
const applies = changedPaths.length === 0 ? true : changedPaths.some((p) => sensorAppliesToPath(sensor, anchorPaths, p));
|
|
3042
|
+
if (!applies) continue;
|
|
3043
|
+
specs.push({
|
|
3044
|
+
memory_id: memory.frontmatter.id,
|
|
3045
|
+
command,
|
|
3046
|
+
kind: sensor.kind,
|
|
3047
|
+
severity: sensor.severity,
|
|
3048
|
+
message: sensor.message,
|
|
3049
|
+
paths: sensor.paths.length > 0 ? sensor.paths : anchorPaths
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
return specs;
|
|
3053
|
+
}
|
|
2997
3054
|
function sensorTargetsFromDiff(diff) {
|
|
2998
3055
|
const targets = [];
|
|
2999
3056
|
let currentPath = null;
|
|
@@ -3220,8 +3277,8 @@ function normalizeFindingSeverity(raw) {
|
|
|
3220
3277
|
return "info";
|
|
3221
3278
|
}
|
|
3222
3279
|
}
|
|
3223
|
-
function findingKey(tool, ruleId,
|
|
3224
|
-
return `${tool}:${ruleId}:${
|
|
3280
|
+
function findingKey(tool, ruleId, path18) {
|
|
3281
|
+
return `${tool}:${ruleId}:${path18}`;
|
|
3225
3282
|
}
|
|
3226
3283
|
function coerceJson(input) {
|
|
3227
3284
|
if (typeof input === "string") {
|
|
@@ -3255,8 +3312,8 @@ function parseSarif(input) {
|
|
|
3255
3312
|
const physical = asRecord(location.physicalLocation);
|
|
3256
3313
|
const artifact = asRecord(physical.artifactLocation);
|
|
3257
3314
|
const region = asRecord(physical.region);
|
|
3258
|
-
const
|
|
3259
|
-
if (!
|
|
3315
|
+
const path18 = typeof artifact.uri === "string" ? normalizeUri(artifact.uri) : "";
|
|
3316
|
+
if (!path18) continue;
|
|
3260
3317
|
const line = typeof region.startLine === "number" ? region.startLine : void 0;
|
|
3261
3318
|
const snippet = typeof asRecord(region.snippet).text === "string" ? asRecord(region.snippet).text.trim() : void 0;
|
|
3262
3319
|
findings.push({
|
|
@@ -3264,10 +3321,10 @@ function parseSarif(input) {
|
|
|
3264
3321
|
ruleId,
|
|
3265
3322
|
message: message.trim(),
|
|
3266
3323
|
severity,
|
|
3267
|
-
path:
|
|
3324
|
+
path: path18,
|
|
3268
3325
|
...line !== void 0 ? { line } : {},
|
|
3269
3326
|
...snippet ? { snippet } : {},
|
|
3270
|
-
key: findingKey(tool, ruleId,
|
|
3327
|
+
key: findingKey(tool, ruleId, path18)
|
|
3271
3328
|
});
|
|
3272
3329
|
}
|
|
3273
3330
|
}
|
|
@@ -3286,17 +3343,17 @@ function parseSonar(input) {
|
|
|
3286
3343
|
(typeof issue.severity === "string" ? issue.severity : void 0) ?? impactSeverity
|
|
3287
3344
|
);
|
|
3288
3345
|
const component = typeof issue.component === "string" ? issue.component : "";
|
|
3289
|
-
const
|
|
3290
|
-
if (!
|
|
3346
|
+
const path18 = componentToPath(component);
|
|
3347
|
+
if (!path18) continue;
|
|
3291
3348
|
const line = typeof issue.line === "number" ? issue.line : void 0;
|
|
3292
3349
|
findings.push({
|
|
3293
3350
|
tool: "sonar",
|
|
3294
3351
|
ruleId,
|
|
3295
3352
|
message,
|
|
3296
3353
|
severity,
|
|
3297
|
-
path:
|
|
3354
|
+
path: path18,
|
|
3298
3355
|
...line !== void 0 ? { line } : {},
|
|
3299
|
-
key: findingKey("sonar", ruleId,
|
|
3356
|
+
key: findingKey("sonar", ruleId, path18)
|
|
3300
3357
|
});
|
|
3301
3358
|
}
|
|
3302
3359
|
return findings;
|
|
@@ -3373,6 +3430,52 @@ function filterNewDrafts(drafts, existingTopics) {
|
|
|
3373
3430
|
return drafts.filter((d) => !existing.has(d.topic));
|
|
3374
3431
|
}
|
|
3375
3432
|
|
|
3433
|
+
// src/gate-precision.ts
|
|
3434
|
+
function round33(n) {
|
|
3435
|
+
return Math.round(n * 1e3) / 1e3;
|
|
3436
|
+
}
|
|
3437
|
+
function computeGatePrecision(events, usage, currentGate = "anchored") {
|
|
3438
|
+
let sensorCatches = 0;
|
|
3439
|
+
let antiPatternCatches = 0;
|
|
3440
|
+
for (const e of events) {
|
|
3441
|
+
if (e.source === "sensor") sensorCatches += 1;
|
|
3442
|
+
else if (e.source === "anti-pattern") antiPatternCatches += 1;
|
|
3443
|
+
}
|
|
3444
|
+
let applied = 0;
|
|
3445
|
+
let rejections = 0;
|
|
3446
|
+
for (const mem of Object.values(usage.by_id ?? {})) {
|
|
3447
|
+
applied += mem.applied_count ?? 0;
|
|
3448
|
+
rejections += mem.rejected_count ?? 0;
|
|
3449
|
+
}
|
|
3450
|
+
const useful = sensorCatches + antiPatternCatches + applied;
|
|
3451
|
+
const denom = useful + rejections;
|
|
3452
|
+
const precision = denom === 0 ? null : round33(useful / denom);
|
|
3453
|
+
return {
|
|
3454
|
+
sensor_catches: sensorCatches,
|
|
3455
|
+
anti_pattern_catches: antiPatternCatches,
|
|
3456
|
+
useful,
|
|
3457
|
+
rejections,
|
|
3458
|
+
precision,
|
|
3459
|
+
suggestion: suggestGate(precision, rejections, currentGate)
|
|
3460
|
+
};
|
|
3461
|
+
}
|
|
3462
|
+
function suggestGate(precision, rejections, currentGate) {
|
|
3463
|
+
if (precision === null || rejections < 3) return null;
|
|
3464
|
+
if (precision < 0.5 && (currentGate === "anchored" || currentGate === "strict")) {
|
|
3465
|
+
return {
|
|
3466
|
+
recommended: "review",
|
|
3467
|
+
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.`
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
if (precision >= 0.85 && currentGate === "review") {
|
|
3471
|
+
return {
|
|
3472
|
+
recommended: "anchored",
|
|
3473
|
+
reason: `Gate precision ${precision} \u2014 catches are reliably real. Tighten to "anchored" so corroborated anti-patterns hard-block.`
|
|
3474
|
+
};
|
|
3475
|
+
}
|
|
3476
|
+
return null;
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3376
3479
|
// src/dashboard.ts
|
|
3377
3480
|
var MS_PER_DAY4 = 24 * 60 * 60 * 1e3;
|
|
3378
3481
|
function isAnchorless(fm) {
|
|
@@ -3514,6 +3617,11 @@ function buildDashboard(memories, usage, options = {}) {
|
|
|
3514
3617
|
top: computeRecurrence(options.preventionEvents ?? []).top.slice(0, top)
|
|
3515
3618
|
}
|
|
3516
3619
|
},
|
|
3620
|
+
gate_precision: computeGatePrecision(
|
|
3621
|
+
options.preventionEvents ?? [],
|
|
3622
|
+
usage,
|
|
3623
|
+
options.antiPatternGate ?? "anchored"
|
|
3624
|
+
),
|
|
3517
3625
|
corpus: {
|
|
3518
3626
|
memory_files: inventory.total,
|
|
3519
3627
|
body_chars: bodyChars,
|
|
@@ -3521,6 +3629,293 @@ function buildDashboard(memories, usage, options = {}) {
|
|
|
3521
3629
|
}
|
|
3522
3630
|
};
|
|
3523
3631
|
}
|
|
3632
|
+
|
|
3633
|
+
// src/failure-coverage.ts
|
|
3634
|
+
var MS_PER_HOUR = 36e5;
|
|
3635
|
+
function normalizeSummary(summary) {
|
|
3636
|
+
return summary.toLowerCase().replace(/\s+/g, " ").trim().slice(0, 160);
|
|
3637
|
+
}
|
|
3638
|
+
function findUncapturedFailures(failures, captureTimes, options = {}) {
|
|
3639
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
3640
|
+
const windowMs = (options.windowHours ?? 24) * MS_PER_HOUR;
|
|
3641
|
+
const dedupe = options.dedupe ?? true;
|
|
3642
|
+
let latestCapture = 0;
|
|
3643
|
+
for (const iso of captureTimes) {
|
|
3644
|
+
const t = Date.parse(iso);
|
|
3645
|
+
if (Number.isFinite(t) && now - t <= windowMs && t > latestCapture) latestCapture = t;
|
|
3646
|
+
}
|
|
3647
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3648
|
+
const out = [];
|
|
3649
|
+
for (const f of failures) {
|
|
3650
|
+
const t = Date.parse(f.ts);
|
|
3651
|
+
if (!Number.isFinite(t)) continue;
|
|
3652
|
+
if (now - t > windowMs) continue;
|
|
3653
|
+
if (t <= latestCapture) continue;
|
|
3654
|
+
if (dedupe) {
|
|
3655
|
+
const key = normalizeSummary(f.summary);
|
|
3656
|
+
if (seen.has(key)) continue;
|
|
3657
|
+
seen.add(key);
|
|
3658
|
+
}
|
|
3659
|
+
out.push({ ts: f.ts, tool: f.tool, summary: f.summary });
|
|
3660
|
+
}
|
|
3661
|
+
out.sort((a, b) => a.ts.localeCompare(b.ts));
|
|
3662
|
+
return out;
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
// src/coverage.ts
|
|
3666
|
+
var DEFAULT_COVERING_TYPES = ["decision", "convention", "gotcha", "architecture"];
|
|
3667
|
+
function normalizePath(value) {
|
|
3668
|
+
return value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/g, "");
|
|
3669
|
+
}
|
|
3670
|
+
function buildCoverageIndex(memories, coveringTypes = DEFAULT_COVERING_TYPES) {
|
|
3671
|
+
const types = new Set(coveringTypes);
|
|
3672
|
+
const covered = /* @__PURE__ */ new Set();
|
|
3673
|
+
for (const { memory } of memories) {
|
|
3674
|
+
const fm = memory.frontmatter;
|
|
3675
|
+
if (!types.has(fm.type)) continue;
|
|
3676
|
+
if (fm.status === "stale" || fm.status === "deprecated" || fm.status === "rejected") continue;
|
|
3677
|
+
for (const p of fm.anchor.paths) {
|
|
3678
|
+
const norm = normalizePath(p);
|
|
3679
|
+
if (norm) covered.add(norm);
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
return covered;
|
|
3683
|
+
}
|
|
3684
|
+
function isCovered(file, coverage) {
|
|
3685
|
+
const target = normalizePath(file);
|
|
3686
|
+
if (coverage.has(target)) return true;
|
|
3687
|
+
for (const scope of coverage) {
|
|
3688
|
+
if (target === scope || target.startsWith(`${scope}/`)) return true;
|
|
3689
|
+
}
|
|
3690
|
+
return false;
|
|
3691
|
+
}
|
|
3692
|
+
function findCoverageGaps(hotFiles, memories, options = {}) {
|
|
3693
|
+
const minChanges = options.minChanges ?? 3;
|
|
3694
|
+
const limit = options.limit ?? 20;
|
|
3695
|
+
const coverage = buildCoverageIndex(memories, options.coveringTypes);
|
|
3696
|
+
const gaps = [];
|
|
3697
|
+
for (const hot of hotFiles) {
|
|
3698
|
+
if (hot.changes < minChanges) continue;
|
|
3699
|
+
if (isCovered(hot.path, coverage)) continue;
|
|
3700
|
+
gaps.push({ path: normalizePath(hot.path), changes: hot.changes });
|
|
3701
|
+
}
|
|
3702
|
+
gaps.sort((a, b) => b.changes - a.changes);
|
|
3703
|
+
return gaps.slice(0, limit);
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3706
|
+
// src/eval-history.ts
|
|
3707
|
+
import { appendFile as appendFile4, mkdir as mkdir11, readFile as readFile14 } from "fs/promises";
|
|
3708
|
+
import { existsSync as existsSync15 } from "fs";
|
|
3709
|
+
import path17 from "path";
|
|
3710
|
+
function evalHistoryPath(paths) {
|
|
3711
|
+
return path17.join(paths.haiveDir, ".cache", "eval-history.jsonl");
|
|
3712
|
+
}
|
|
3713
|
+
async function appendEvalHistory(paths, entry) {
|
|
3714
|
+
const file = evalHistoryPath(paths);
|
|
3715
|
+
await mkdir11(path17.dirname(file), { recursive: true });
|
|
3716
|
+
await appendFile4(file, JSON.stringify(entry) + "\n", "utf8");
|
|
3717
|
+
}
|
|
3718
|
+
async function loadEvalHistory(paths) {
|
|
3719
|
+
const file = evalHistoryPath(paths);
|
|
3720
|
+
if (!existsSync15(file)) return [];
|
|
3721
|
+
const raw = await readFile14(file, "utf8").catch(() => "");
|
|
3722
|
+
const out = [];
|
|
3723
|
+
for (const line of raw.split("\n")) {
|
|
3724
|
+
const trimmed = line.trim();
|
|
3725
|
+
if (!trimmed) continue;
|
|
3726
|
+
try {
|
|
3727
|
+
const e = JSON.parse(trimmed);
|
|
3728
|
+
if (e && typeof e.at === "string" && typeof e.score === "number") out.push(e);
|
|
3729
|
+
} catch {
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
return out;
|
|
3733
|
+
}
|
|
3734
|
+
function computeEvalTrend(entries, recentN = 10) {
|
|
3735
|
+
const sorted = [...entries].sort((a, b) => a.at.localeCompare(b.at));
|
|
3736
|
+
const scores = sorted.map((e) => e.score);
|
|
3737
|
+
const latest = scores.length > 0 ? scores[scores.length - 1] : null;
|
|
3738
|
+
const previous = scores.length > 1 ? scores[scores.length - 2] : null;
|
|
3739
|
+
const delta = latest !== null && previous !== null ? Math.round((latest - previous) * 1e3) / 1e3 : null;
|
|
3740
|
+
const best = scores.length > 0 ? Math.max(...scores) : null;
|
|
3741
|
+
return {
|
|
3742
|
+
latest,
|
|
3743
|
+
previous,
|
|
3744
|
+
delta,
|
|
3745
|
+
best,
|
|
3746
|
+
runs: scores.length,
|
|
3747
|
+
recent: scores.slice(-recentN),
|
|
3748
|
+
regressed: delta !== null && delta < 0
|
|
3749
|
+
};
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
// src/conflict-resolve.ts
|
|
3753
|
+
var STATUS_RANK = {
|
|
3754
|
+
validated: 4,
|
|
3755
|
+
proposed: 3,
|
|
3756
|
+
draft: 2,
|
|
3757
|
+
stale: 1,
|
|
3758
|
+
deprecated: 0,
|
|
3759
|
+
rejected: 0
|
|
3760
|
+
};
|
|
3761
|
+
function statusRank(fm) {
|
|
3762
|
+
return STATUS_RANK[fm.status] ?? 2;
|
|
3763
|
+
}
|
|
3764
|
+
function planConflictResolution(a, b) {
|
|
3765
|
+
const fa = a.memory.frontmatter;
|
|
3766
|
+
const fb = b.memory.frontmatter;
|
|
3767
|
+
const ra = statusRank(fa);
|
|
3768
|
+
const rb = statusRank(fb);
|
|
3769
|
+
let winner;
|
|
3770
|
+
let loser;
|
|
3771
|
+
let reason;
|
|
3772
|
+
if (ra !== rb) {
|
|
3773
|
+
[winner, loser] = ra > rb ? [a, b] : [b, a];
|
|
3774
|
+
reason = `status (${winner.memory.frontmatter.status} beats ${loser.memory.frontmatter.status})`;
|
|
3775
|
+
} else if (fa.revision_count !== fb.revision_count) {
|
|
3776
|
+
[winner, loser] = fa.revision_count > fb.revision_count ? [a, b] : [b, a];
|
|
3777
|
+
reason = `revision_count (${winner.memory.frontmatter.revision_count} > ${loser.memory.frontmatter.revision_count})`;
|
|
3778
|
+
} else {
|
|
3779
|
+
const cmp = fa.created_at.localeCompare(fb.created_at);
|
|
3780
|
+
[winner, loser] = cmp >= 0 ? [a, b] : [b, a];
|
|
3781
|
+
reason = `recency (${winner.memory.frontmatter.created_at} is newer)`;
|
|
3782
|
+
}
|
|
3783
|
+
const keepId = winner.memory.frontmatter.id;
|
|
3784
|
+
const supersedeId = loser.memory.frontmatter.id;
|
|
3785
|
+
return {
|
|
3786
|
+
keep_id: keepId,
|
|
3787
|
+
supersede_id: supersedeId,
|
|
3788
|
+
reason,
|
|
3789
|
+
stale_reason: `Superseded by ${keepId} (conflict resolved on ${reason}).`
|
|
3790
|
+
};
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
// src/seed-git.ts
|
|
3794
|
+
var REVERT_RE = /^Revert\s+"(.+)"\s*$/i;
|
|
3795
|
+
var FIXUP_RE = /^(?:fixup!|hotfix[:!]|fix[:!]\s*revert|revert\s+revert)/i;
|
|
3796
|
+
var URGENT_FIX_RE = /\b(hotfix|urgent fix|emergency fix|critical fix|broke production|broken build)\b/i;
|
|
3797
|
+
function slugify(text) {
|
|
3798
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "reverted-change";
|
|
3799
|
+
}
|
|
3800
|
+
function proposeSeedsFromCommits(commits, limit = 20) {
|
|
3801
|
+
const out = [];
|
|
3802
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3803
|
+
for (const commit of commits) {
|
|
3804
|
+
const subject = commit.subject.trim();
|
|
3805
|
+
let what = null;
|
|
3806
|
+
let kind = null;
|
|
3807
|
+
const revert = subject.match(REVERT_RE);
|
|
3808
|
+
if (revert) {
|
|
3809
|
+
what = revert[1].trim();
|
|
3810
|
+
kind = "revert";
|
|
3811
|
+
} else if (FIXUP_RE.test(subject) || URGENT_FIX_RE.test(subject)) {
|
|
3812
|
+
what = subject.replace(FIXUP_RE, "").trim() || subject;
|
|
3813
|
+
kind = "fixup";
|
|
3814
|
+
}
|
|
3815
|
+
if (!what || !kind) continue;
|
|
3816
|
+
const slug = slugify(what);
|
|
3817
|
+
if (seen.has(slug)) continue;
|
|
3818
|
+
seen.add(slug);
|
|
3819
|
+
out.push({
|
|
3820
|
+
slug,
|
|
3821
|
+
what,
|
|
3822
|
+
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.`,
|
|
3823
|
+
paths: (commit.files ?? []).slice(0, 8),
|
|
3824
|
+
source_sha: commit.sha,
|
|
3825
|
+
kind
|
|
3826
|
+
});
|
|
3827
|
+
if (out.length >= limit) break;
|
|
3828
|
+
}
|
|
3829
|
+
return out;
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
// src/merge-memory.ts
|
|
3833
|
+
function safeParse(raw) {
|
|
3834
|
+
try {
|
|
3835
|
+
return parseMemory(raw);
|
|
3836
|
+
} catch {
|
|
3837
|
+
return null;
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
function mergeMemoryVersions(ours, theirs) {
|
|
3841
|
+
if (ours === theirs) {
|
|
3842
|
+
return { content: ours, winner: "ours", reason: "identical" };
|
|
3843
|
+
}
|
|
3844
|
+
const a = safeParse(ours);
|
|
3845
|
+
const b = safeParse(theirs);
|
|
3846
|
+
if (!a || !b) {
|
|
3847
|
+
return { content: ours, winner: "ours", reason: "unparseable side \u2014 kept ours" };
|
|
3848
|
+
}
|
|
3849
|
+
const ra = a.frontmatter.revision_count ?? 0;
|
|
3850
|
+
const rb = b.frontmatter.revision_count ?? 0;
|
|
3851
|
+
if (ra !== rb) {
|
|
3852
|
+
return rb > ra ? { content: theirs, winner: "theirs", reason: `higher revision_count (${rb} > ${ra})` } : { content: ours, winner: "ours", reason: `higher revision_count (${ra} > ${rb})` };
|
|
3853
|
+
}
|
|
3854
|
+
const ca = a.frontmatter.created_at ?? "";
|
|
3855
|
+
const cb = b.frontmatter.created_at ?? "";
|
|
3856
|
+
const cmp = cb.localeCompare(ca);
|
|
3857
|
+
if (cmp > 0) return { content: theirs, winner: "theirs", reason: `newer created_at (${cb})` };
|
|
3858
|
+
if (cmp < 0) return { content: ours, winner: "ours", reason: `newer created_at (${ca})` };
|
|
3859
|
+
return { content: ours, winner: "ours", reason: "tie \u2014 kept ours" };
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3862
|
+
// src/recap.ts
|
|
3863
|
+
function isAutoRecap(body) {
|
|
3864
|
+
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);
|
|
3865
|
+
}
|
|
3866
|
+
function compactAutoRecapBody(body, maxChars = 600) {
|
|
3867
|
+
if (!isAutoRecap(body)) return body;
|
|
3868
|
+
const goalMatch = body.match(/##+\s*Goal[^\n]*\n+([^\n]+)/i);
|
|
3869
|
+
const callsMatch = body.match(/Auto-captured session \(([^)]+)\)/i);
|
|
3870
|
+
const header = goalMatch?.[1]?.trim() ? `_${goalMatch[1].trim()}_` : callsMatch ? `_Auto-captured session (${callsMatch[1]})._` : "_Auto-captured session._";
|
|
3871
|
+
const discMatch = body.match(/##+\s*Discoveries[^\n]*\n([\s\S]*?)(?=\n##+\s|\n*$)/i);
|
|
3872
|
+
const discovery = discMatch?.[1]?.trim() ?? "";
|
|
3873
|
+
const trivialDiscovery = discovery === "" || /^no (new memories|surprising)/i.test(discovery) || /No new memories saved this session\.?$/i.test(discovery);
|
|
3874
|
+
if (trivialDiscovery) {
|
|
3875
|
+
return `${header}
|
|
3876
|
+
|
|
3877
|
+
_No notable discoveries captured. Run post_task / \`mem_session_end\` for a richer recap._`;
|
|
3878
|
+
}
|
|
3879
|
+
const trimmed = discovery.length > maxChars ? discovery.slice(0, maxChars) + "\u2026" : discovery;
|
|
3880
|
+
return `${header}
|
|
3881
|
+
|
|
3882
|
+
**Discoveries:**
|
|
3883
|
+
${trimmed}`;
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
// src/priority.ts
|
|
3887
|
+
var DEFAULT_PRIORITY_SIGNALS = {
|
|
3888
|
+
type: "",
|
|
3889
|
+
tags: [],
|
|
3890
|
+
requiresHumanApproval: false,
|
|
3891
|
+
directAnchor: false,
|
|
3892
|
+
directSymbol: false,
|
|
3893
|
+
exactTaskMatch: false,
|
|
3894
|
+
strongSemantic: false,
|
|
3895
|
+
usefulSemantic: false,
|
|
3896
|
+
moduleOrDomainMatch: false,
|
|
3897
|
+
tagTaskMatch: false
|
|
3898
|
+
};
|
|
3899
|
+
function prioritySignals(partial) {
|
|
3900
|
+
return { ...DEFAULT_PRIORITY_SIGNALS, ...partial };
|
|
3901
|
+
}
|
|
3902
|
+
function classifyMemoryPriority(signals) {
|
|
3903
|
+
const isNegative = signals.type === "attempt";
|
|
3904
|
+
const isSkill2 = signals.type === "skill";
|
|
3905
|
+
if (signals.requiresHumanApproval || signals.directAnchor || signals.directSymbol || isNegative && (signals.exactTaskMatch || signals.strongSemantic) || isSkill2 && (signals.exactTaskMatch || signals.strongSemantic)) {
|
|
3906
|
+
return "must_read";
|
|
3907
|
+
}
|
|
3908
|
+
if (isStackPackSeed({ tags: signals.tags }) || isEnvWorkaroundMemory({ tags: signals.tags })) {
|
|
3909
|
+
return "background";
|
|
3910
|
+
}
|
|
3911
|
+
if (isSkill2 || signals.moduleOrDomainMatch || signals.exactTaskMatch || signals.usefulSemantic || signals.tagTaskMatch) {
|
|
3912
|
+
return "useful";
|
|
3913
|
+
}
|
|
3914
|
+
return "background";
|
|
3915
|
+
}
|
|
3916
|
+
function priorityRank(priority) {
|
|
3917
|
+
return priority === "must_read" ? 3 : priority === "useful" ? 2 : 1;
|
|
3918
|
+
}
|
|
3524
3919
|
export {
|
|
3525
3920
|
AUTOPILOT_DEFAULTS,
|
|
3526
3921
|
ActivationSchema,
|
|
@@ -3537,6 +3932,8 @@ export {
|
|
|
3537
3932
|
DEFAULT_CONFIDENCE_THRESHOLDS,
|
|
3538
3933
|
DEFAULT_CONFIG,
|
|
3539
3934
|
DEFAULT_DORMANT_DAYS,
|
|
3935
|
+
DEFAULT_PRIORITY_SIGNALS,
|
|
3936
|
+
ENV_WORKAROUND_TAGS,
|
|
3540
3937
|
GUESSABLE_THRESHOLD,
|
|
3541
3938
|
HAIVE_DIR,
|
|
3542
3939
|
MEMORIES_DIR,
|
|
@@ -3561,22 +3958,28 @@ export {
|
|
|
3561
3958
|
aggregateUsage,
|
|
3562
3959
|
allocateBudget,
|
|
3563
3960
|
antiPatternGateParams,
|
|
3961
|
+
appendEvalHistory,
|
|
3564
3962
|
appendPreventionEvent,
|
|
3565
3963
|
appendRuntimeJournalEntry,
|
|
3566
3964
|
appendUsageEvent,
|
|
3567
3965
|
briefingMarkerPath,
|
|
3568
3966
|
briefingMarkersDir,
|
|
3569
3967
|
buildCodeMap,
|
|
3968
|
+
buildCoverageIndex,
|
|
3570
3969
|
buildDashboard,
|
|
3571
3970
|
buildDocFrequency,
|
|
3572
3971
|
buildFrontmatter,
|
|
3573
3972
|
buildReport,
|
|
3574
3973
|
bumpRead,
|
|
3974
|
+
classifyMemoryPriority,
|
|
3575
3975
|
codeMapPath,
|
|
3576
3976
|
collectTimelineEntries,
|
|
3977
|
+
compactAutoRecapBody,
|
|
3577
3978
|
compareEvalReports,
|
|
3578
3979
|
compareImpact,
|
|
3579
3980
|
compileRegexSensor,
|
|
3981
|
+
computeEvalTrend,
|
|
3982
|
+
computeGatePrecision,
|
|
3580
3983
|
computeImpact,
|
|
3581
3984
|
computePreventionTrend,
|
|
3582
3985
|
computeRecurrence,
|
|
@@ -3591,13 +3994,16 @@ export {
|
|
|
3591
3994
|
emptyUsageIndex,
|
|
3592
3995
|
enforcementDir,
|
|
3593
3996
|
estimateTokens,
|
|
3997
|
+
evalHistoryPath,
|
|
3594
3998
|
evaluateSkillActivation,
|
|
3595
3999
|
extractActionsBriefBody,
|
|
3596
4000
|
extractSnippet,
|
|
3597
4001
|
filterNewDrafts,
|
|
4002
|
+
findCoverageGaps,
|
|
3598
4003
|
findLexicalConflictPairs,
|
|
3599
4004
|
findProjectRoot,
|
|
3600
4005
|
findTopicStatusConflictPairs,
|
|
4006
|
+
findUncapturedFailures,
|
|
3601
4007
|
findingBody,
|
|
3602
4008
|
findingToDraft,
|
|
3603
4009
|
firstMemoryOneLine,
|
|
@@ -3607,8 +4013,11 @@ export {
|
|
|
3607
4013
|
hashProjectContext,
|
|
3608
4014
|
inferModulesFromPaths,
|
|
3609
4015
|
isAutoPromoteEligible,
|
|
4016
|
+
isAutoRecap,
|
|
4017
|
+
isCovered,
|
|
3610
4018
|
isDecaying,
|
|
3611
4019
|
isDistinctiveToken,
|
|
4020
|
+
isEnvWorkaroundMemory,
|
|
3612
4021
|
isFreshIsoDate,
|
|
3613
4022
|
isGlobPath,
|
|
3614
4023
|
isLikelyGuessable,
|
|
@@ -3622,12 +4031,14 @@ export {
|
|
|
3622
4031
|
loadCodeMap,
|
|
3623
4032
|
loadConfig,
|
|
3624
4033
|
loadConfigSync,
|
|
4034
|
+
loadEvalHistory,
|
|
3625
4035
|
loadMemoriesFromDir,
|
|
3626
4036
|
loadMemory,
|
|
3627
4037
|
loadPreventionEvents,
|
|
3628
4038
|
loadUsageIndex,
|
|
3629
4039
|
memoryFilePath,
|
|
3630
4040
|
memoryMatchesAnchorPaths,
|
|
4041
|
+
mergeMemoryVersions,
|
|
3631
4042
|
newMemoryId,
|
|
3632
4043
|
normalizeFindingSeverity,
|
|
3633
4044
|
normalizeSessionId,
|
|
@@ -3639,8 +4050,12 @@ export {
|
|
|
3639
4050
|
parseSonar,
|
|
3640
4051
|
pathsOverlap,
|
|
3641
4052
|
pickSnippetNeedle,
|
|
4053
|
+
planConflictResolution,
|
|
3642
4054
|
preventionLogPath,
|
|
4055
|
+
priorityRank,
|
|
4056
|
+
prioritySignals,
|
|
3643
4057
|
projectContextRecentlyEmitted,
|
|
4058
|
+
proposeSeedsFromCommits,
|
|
3644
4059
|
pullCrossRepoSources,
|
|
3645
4060
|
queryCodeMap,
|
|
3646
4061
|
rankMemoriesLexical,
|
|
@@ -3665,12 +4080,14 @@ export {
|
|
|
3665
4080
|
saveUsageIndex,
|
|
3666
4081
|
scoreRetrievalCase,
|
|
3667
4082
|
scoreSensorCase,
|
|
4083
|
+
selectCommandSensors,
|
|
3668
4084
|
sensorAppliesToPath,
|
|
3669
4085
|
sensorTargetsFromDiff,
|
|
3670
4086
|
serializeMemory,
|
|
3671
4087
|
snapshotContract,
|
|
3672
4088
|
specificityScore,
|
|
3673
4089
|
stripPrivate,
|
|
4090
|
+
suggestGate,
|
|
3674
4091
|
suggestSensorFromMemory,
|
|
3675
4092
|
suggestTopicKey,
|
|
3676
4093
|
summarizeImpact,
|