@hivelore/cli 0.43.2 → 0.46.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/README.md +7 -6
- package/dist/{chunk-FXDGOBPT.js → chunk-W7EPRKOZ.js} +75 -15
- package/dist/chunk-W7EPRKOZ.js.map +1 -0
- package/dist/index.js +251 -62
- package/dist/index.js.map +1 -1
- package/dist/{server-WW6JHBYY.js → server-V3ZGBTAG.js} +6 -4
- package/package.json +16 -5
- package/dist/chunk-FXDGOBPT.js.map +0 -1
- /package/dist/{server-WW6JHBYY.js.map → server-V3ZGBTAG.js.map} +0 -0
package/README.md
CHANGED
|
@@ -233,6 +233,7 @@ Run the repeatable quality gate for Hivelore itself or for a project using Hivel
|
|
|
233
233
|
```bash
|
|
234
234
|
hivelore eval
|
|
235
235
|
hivelore eval --semantic-only
|
|
236
|
+
hivelore eval --semantic-ranking # require and exercise the real embeddings-backed ranker
|
|
236
237
|
hivelore eval --spec .ai/eval/spec.json --fail-under 80
|
|
237
238
|
```
|
|
238
239
|
|
|
@@ -533,14 +534,14 @@ hivelore install-hooks --dir /path/to/project
|
|
|
533
534
|
|
|
534
535
|
---
|
|
535
536
|
|
|
536
|
-
### `hivelore
|
|
537
|
+
### `hivelore index`
|
|
537
538
|
|
|
538
539
|
Manage the local semantic search index (requires `@hivelore/embeddings` to be installed).
|
|
539
540
|
|
|
540
541
|
```bash
|
|
541
|
-
hivelore
|
|
542
|
-
hivelore
|
|
543
|
-
hivelore
|
|
542
|
+
hivelore index memories # Build or refresh the embeddings index
|
|
543
|
+
hivelore index status # Show index stats (count, last updated, model)
|
|
544
|
+
hivelore index query "how do we handle retries on payment failures"
|
|
544
545
|
```
|
|
545
546
|
|
|
546
547
|
The model (`bge-small-en-v1.5`, ~110MB) is downloaded on first use and cached locally. **No data leaves your machine.**
|
|
@@ -655,8 +656,8 @@ Install `@hivelore/embeddings` for similarity-based memory retrieval:
|
|
|
655
656
|
|
|
656
657
|
```bash
|
|
657
658
|
npm install -g @hivelore/embeddings
|
|
658
|
-
hivelore
|
|
659
|
-
hivelore
|
|
659
|
+
hivelore index memories # First run downloads the model (~110MB)
|
|
660
|
+
hivelore index query "payment retry logic"
|
|
660
661
|
```
|
|
661
662
|
|
|
662
663
|
From MCP: set `semantic: true` on `mem_search` or `get_briefing`.
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// ../mcp/dist/server.js
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { mkdir as mkdir8, writeFile as writeFile15 } from "fs/promises";
|
|
7
|
+
import path15 from "path";
|
|
6
8
|
import { findProjectRoot, resolveHaivePaths } from "@hivelore/core";
|
|
7
9
|
import { mkdir, writeFile } from "fs/promises";
|
|
8
10
|
import { existsSync } from "fs";
|
|
@@ -153,9 +155,12 @@ import path5 from "path";
|
|
|
153
155
|
import { existsSync as existsSync17, statSync } from "fs";
|
|
154
156
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile10 } from "fs/promises";
|
|
155
157
|
import path8 from "path";
|
|
158
|
+
import { execFile } from "child_process";
|
|
159
|
+
import { promisify } from "util";
|
|
156
160
|
import { z as z17 } from "zod";
|
|
157
161
|
import {
|
|
158
162
|
buildProposeCommand,
|
|
163
|
+
incidentHintsFromDiff,
|
|
159
164
|
loadMemoriesFromDir as loadMemoriesFromDir14,
|
|
160
165
|
normalizeFramework,
|
|
161
166
|
parseLessonFields,
|
|
@@ -1914,6 +1919,12 @@ async function memTried(input, ctx) {
|
|
|
1914
1919
|
hint
|
|
1915
1920
|
};
|
|
1916
1921
|
}
|
|
1922
|
+
var execFileAsync = promisify(execFile);
|
|
1923
|
+
async function gitDiffText(root, redRef, paths) {
|
|
1924
|
+
const args = ["diff", redRef, "HEAD", "--", ...paths];
|
|
1925
|
+
const { stdout } = await execFileAsync("git", args, { cwd: root, maxBuffer: 64 * 1024 * 1024 });
|
|
1926
|
+
return stdout;
|
|
1927
|
+
}
|
|
1917
1928
|
var PY_SIGNALS = ["pyproject.toml", "setup.py", "pytest.ini", "requirements.txt", "tox.ini"];
|
|
1918
1929
|
async function detectForAnchor(root, rel) {
|
|
1919
1930
|
let dir = path8.resolve(root, rel);
|
|
@@ -1968,6 +1979,9 @@ var ScaffoldTestInputSchema = {
|
|
|
1968
1979
|
memory_id: z17.string().min(1).describe("Id of the attempt/gotcha lesson to scaffold a post-incident test from."),
|
|
1969
1980
|
framework: z17.enum(["vitest", "jest", "pytest", "gotest"]).optional().describe("Test framework. Auto-detected from the package that owns the lesson's anchor paths when omitted."),
|
|
1970
1981
|
out_path: z17.string().optional().describe("Override the generated test file path (repo-relative)."),
|
|
1982
|
+
red_ref: z17.string().optional().describe(
|
|
1983
|
+
"Pre-fix incident commit/ref. When set, the scaffold names the symbols the fix (<red_ref>..HEAD) touched within the lesson's anchor scope and pre-fills the example around them, so the assertion is a targeted edit rather than a blank page. A bad ref falls back to the generic template."
|
|
1984
|
+
),
|
|
1971
1985
|
write: z17.boolean().default(true).describe("Write the file to disk (default). false = return the content for preview without writing.")
|
|
1972
1986
|
};
|
|
1973
1987
|
async function scaffoldTest(input, ctx) {
|
|
@@ -1981,13 +1995,23 @@ async function scaffoldTest(input, ctx) {
|
|
|
1981
1995
|
const groups = input.out_path ? allGroups.slice(0, 1) : allGroups;
|
|
1982
1996
|
const frameworkFor = (detected) => input.framework ? normalizeFramework(input.framework) ?? detected : detected;
|
|
1983
1997
|
const fields = parseLessonFields(found.memory.body);
|
|
1998
|
+
let incidentHints;
|
|
1999
|
+
if (input.red_ref) {
|
|
2000
|
+
try {
|
|
2001
|
+
const diff = await gitDiffText(ctx.paths.root, input.red_ref, anchorPaths);
|
|
2002
|
+
const hints = incidentHintsFromDiff(diff, { redRef: input.red_ref });
|
|
2003
|
+
if (hints.changedSymbols.length > 0 || hints.changedFiles.length > 0) incidentHints = hints;
|
|
2004
|
+
} catch {
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
1984
2007
|
const lesson = {
|
|
1985
2008
|
memoryId: input.memory_id,
|
|
1986
2009
|
title: fields.title || input.memory_id,
|
|
1987
2010
|
whyFailed: fields.whyFailed,
|
|
1988
2011
|
instead: fields.instead,
|
|
1989
2012
|
incident: found.memory.frontmatter.sensor?.incident,
|
|
1990
|
-
paths: anchorPaths
|
|
2013
|
+
paths: anchorPaths,
|
|
2014
|
+
incidentHints
|
|
1991
2015
|
};
|
|
1992
2016
|
let scaffolds = groups.map(
|
|
1993
2017
|
(g) => scaffoldPostIncidentTest(lesson, { framework: frameworkFor(g.framework), outPath: input.out_path, baseDir: g.baseDir })
|
|
@@ -3211,7 +3235,7 @@ function oneLine(value) {
|
|
|
3211
3235
|
return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
|
|
3212
3236
|
}
|
|
3213
3237
|
function serverVersion() {
|
|
3214
|
-
return true ? "0.
|
|
3238
|
+
return true ? "0.46.0" : "dev";
|
|
3215
3239
|
}
|
|
3216
3240
|
var CodeMapInputSchema = {
|
|
3217
3241
|
file: z21.string().optional().describe("Filter to files whose path contains this substring"),
|
|
@@ -3454,7 +3478,8 @@ var AntiPatternsCheckInputSchema = {
|
|
|
3454
3478
|
),
|
|
3455
3479
|
min_semantic_score: z26.number().min(0).max(1).default(0.45).describe(
|
|
3456
3480
|
"Minimum cosine score for semantic-only anti-pattern hits. Anchor/literal matches still surface. Default 0.45 keeps broad, weakly-related memories out of review noise."
|
|
3457
|
-
)
|
|
3481
|
+
),
|
|
3482
|
+
track: z26.boolean().default(true).describe("Record real prevention outcomes. Set false for eval/selftest probes so synthetic cases never inflate ROI.")
|
|
3458
3483
|
};
|
|
3459
3484
|
function tokenizeDiffForLiteral(diff) {
|
|
3460
3485
|
const lines = diff.split("\n");
|
|
@@ -3482,6 +3507,7 @@ function isHaiveOwnedPath(p) {
|
|
|
3482
3507
|
if (/^\.github\/workflows\/haive-.*\.ya?ml$/.test(p)) return true;
|
|
3483
3508
|
return false;
|
|
3484
3509
|
}
|
|
3510
|
+
var MAX_FUZZY_SCAN_LINES = 2e4;
|
|
3485
3511
|
var TEST_PATH_RE = /(?:^|\/)(?:tests?|__tests__|__mocks__|e2e|fixtures)\/|\.(?:test|spec)\.[cm]?[jt]sx?$/i;
|
|
3486
3512
|
function isTestPath(p) {
|
|
3487
3513
|
return TEST_PATH_RE.test(p);
|
|
@@ -3492,7 +3518,7 @@ function stripTestHunks(diff) {
|
|
|
3492
3518
|
let block = [];
|
|
3493
3519
|
let keep = true;
|
|
3494
3520
|
const flush = () => {
|
|
3495
|
-
if (keep) out.push(
|
|
3521
|
+
if (keep) for (const l of block) out.push(l);
|
|
3496
3522
|
block = [];
|
|
3497
3523
|
keep = true;
|
|
3498
3524
|
};
|
|
@@ -3513,7 +3539,7 @@ function stripAiDirHunks(diff) {
|
|
|
3513
3539
|
let block = [];
|
|
3514
3540
|
let keep = true;
|
|
3515
3541
|
const flush = () => {
|
|
3516
|
-
if (keep) out.push(
|
|
3542
|
+
if (keep) for (const l of block) out.push(l);
|
|
3517
3543
|
block = [];
|
|
3518
3544
|
keep = true;
|
|
3519
3545
|
};
|
|
@@ -3584,7 +3610,10 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
3584
3610
|
}
|
|
3585
3611
|
}
|
|
3586
3612
|
const scanDiff = input.diff ? stripTestHunks(stripAiDirHunks(input.diff)) : input.diff;
|
|
3587
|
-
|
|
3613
|
+
const scanAddedLineCount = scanDiff ? addedLinesFromDiff(scanDiff).split("\n").length : 0;
|
|
3614
|
+
const fuzzyScanTooLarge = scanAddedLineCount > MAX_FUZZY_SCAN_LINES;
|
|
3615
|
+
const notice = fuzzyScanTooLarge ? `Diff is very large (${scanAddedLineCount.toLocaleString()} added lines) \u2014 literal/semantic corroboration skipped for performance; anchored lessons and deterministic sensors were still evaluated in full. If this staged node_modules or a build artifact, unstage it.` : void 0;
|
|
3616
|
+
if (scanDiff && !fuzzyScanTooLarge) {
|
|
3588
3617
|
const tokens = tokenizeDiffForLiteral(scanDiff);
|
|
3589
3618
|
const added = addedLinesFromDiff(scanDiff);
|
|
3590
3619
|
const addedText = added.trim().length > 0 ? added : scanDiff;
|
|
@@ -3619,7 +3648,7 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
3619
3648
|
}
|
|
3620
3649
|
}
|
|
3621
3650
|
}
|
|
3622
|
-
if (input.semantic && scanDiff) {
|
|
3651
|
+
if (input.semantic && scanDiff && !fuzzyScanTooLarge) {
|
|
3623
3652
|
try {
|
|
3624
3653
|
const mod = await import("@hivelore/embeddings");
|
|
3625
3654
|
const added = addedLinesFromDiff(scanDiff);
|
|
@@ -3647,10 +3676,13 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
3647
3676
|
}).slice(0, input.limit);
|
|
3648
3677
|
const isHardBlockCatch = (w) => w.reasons.includes("sensor");
|
|
3649
3678
|
const strongCatches = warnings.filter(isHardBlockCatch);
|
|
3650
|
-
|
|
3679
|
+
if (input.track !== false) {
|
|
3680
|
+
await recordPreventionHits(ctx.paths, strongCatches.map((w) => w.id), "anti-pattern");
|
|
3681
|
+
}
|
|
3651
3682
|
return {
|
|
3652
3683
|
scanned: negative.length,
|
|
3653
|
-
warnings
|
|
3684
|
+
warnings,
|
|
3685
|
+
...notice ? { notice } : {}
|
|
3654
3686
|
};
|
|
3655
3687
|
}
|
|
3656
3688
|
var MemDistillInputSchema = {
|
|
@@ -3866,6 +3898,7 @@ async function preCommitCheck(input, ctx) {
|
|
|
3866
3898
|
relevant_memories: relevant_memories.length,
|
|
3867
3899
|
stale_anchors: staleHits.length
|
|
3868
3900
|
},
|
|
3901
|
+
...apResult.notice ? { notice: apResult.notice } : {},
|
|
3869
3902
|
warnings: classifiedWarnings,
|
|
3870
3903
|
relevant_memories,
|
|
3871
3904
|
stale_anchors: staleHits.map((r) => {
|
|
@@ -4376,13 +4409,14 @@ Main code areas detected: ${areas}
|
|
|
4376
4409
|
}
|
|
4377
4410
|
var PostTaskArgsSchema = {
|
|
4378
4411
|
task_summary: z35.string().optional().describe("One sentence describing what you just did"),
|
|
4379
|
-
files_touched: z35.
|
|
4412
|
+
files_touched: z35.string().optional().describe("Files you created or modified during the task, as CSV or a JSON array string")
|
|
4380
4413
|
};
|
|
4381
4414
|
function postTaskPrompt(args, ctx) {
|
|
4382
4415
|
const taskLine = args.task_summary ? `
|
|
4383
4416
|
Task just completed: **${args.task_summary}**` : "";
|
|
4384
|
-
const
|
|
4385
|
-
|
|
4417
|
+
const filesTouched = parsePromptFilesTouched(args.files_touched);
|
|
4418
|
+
const filesLine = filesTouched.length > 0 ? `
|
|
4419
|
+
Files touched: ${filesTouched.map((f) => `\`${f}\``).join(", ")}` : "";
|
|
4386
4420
|
const text = `You have just finished a task. Before closing this session, take 60 seconds to capture what you learned.
|
|
4387
4421
|
${taskLine}${filesLine}
|
|
4388
4422
|
|
|
@@ -4471,6 +4505,20 @@ When done, respond with a brief summary: "Saved N memories: [list of IDs]. Sessi
|
|
|
4471
4505
|
]
|
|
4472
4506
|
};
|
|
4473
4507
|
}
|
|
4508
|
+
function parsePromptFilesTouched(input) {
|
|
4509
|
+
const raw = input?.trim();
|
|
4510
|
+
if (!raw) return [];
|
|
4511
|
+
if (raw.startsWith("[")) {
|
|
4512
|
+
try {
|
|
4513
|
+
const parsed = JSON.parse(raw);
|
|
4514
|
+
if (Array.isArray(parsed)) {
|
|
4515
|
+
return parsed.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean);
|
|
4516
|
+
}
|
|
4517
|
+
} catch {
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
return raw.split(",").map((value) => value.trim()).filter(Boolean);
|
|
4521
|
+
}
|
|
4474
4522
|
var ImportDocsArgsSchema = {
|
|
4475
4523
|
content: z36.string().describe("The documentation content to analyze and import as memories (Markdown, README, ADR, etc.)"),
|
|
4476
4524
|
source: z36.string().optional().describe("Origin of the content (file path, URL, or document title) \u2014 used to anchor memories"),
|
|
@@ -4538,7 +4586,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
4538
4586
|
};
|
|
4539
4587
|
}
|
|
4540
4588
|
var SERVER_NAME = "hivelore";
|
|
4541
|
-
var SERVER_VERSION = "0.
|
|
4589
|
+
var SERVER_VERSION = "0.46.0";
|
|
4542
4590
|
function jsonResult(data) {
|
|
4543
4591
|
return {
|
|
4544
4592
|
content: [
|
|
@@ -5477,11 +5525,22 @@ function printHaiveMcpVersion() {
|
|
|
5477
5525
|
}
|
|
5478
5526
|
async function runHaiveMcpStdio(options) {
|
|
5479
5527
|
const { server, context } = createHaiveServer({ root: options.root, env: process.env });
|
|
5528
|
+
await writeMcpRuntimeMarker(context).catch(() => {
|
|
5529
|
+
});
|
|
5480
5530
|
console.error(
|
|
5481
5531
|
`[haive-mcp] starting server v${SERVER_VERSION} (project root: ${context.paths.root})`
|
|
5482
5532
|
);
|
|
5483
5533
|
await server.connect(new StdioServerTransport());
|
|
5484
5534
|
}
|
|
5535
|
+
async function writeMcpRuntimeMarker(context) {
|
|
5536
|
+
await mkdir8(context.paths.runtimeDir, { recursive: true });
|
|
5537
|
+
await writeFile15(path15.join(context.paths.runtimeDir, "mcp-server.json"), JSON.stringify({
|
|
5538
|
+
version: SERVER_VERSION,
|
|
5539
|
+
pid: process.pid,
|
|
5540
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5541
|
+
command: "hivelore mcp --stdio"
|
|
5542
|
+
}, null, 2), "utf8");
|
|
5543
|
+
}
|
|
5485
5544
|
|
|
5486
5545
|
export {
|
|
5487
5546
|
astEngineAvailable,
|
|
@@ -5516,6 +5575,7 @@ export {
|
|
|
5516
5575
|
createHaiveServer,
|
|
5517
5576
|
parseMcpCliArgs,
|
|
5518
5577
|
printHaiveMcpVersion,
|
|
5519
|
-
runHaiveMcpStdio
|
|
5578
|
+
runHaiveMcpStdio,
|
|
5579
|
+
writeMcpRuntimeMarker
|
|
5520
5580
|
};
|
|
5521
|
-
//# sourceMappingURL=chunk-
|
|
5581
|
+
//# sourceMappingURL=chunk-W7EPRKOZ.js.map
|