@hivelore/cli 0.38.0 → 0.39.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/{chunk-UOMGIXZN.js → chunk-I4VELI5K.js} +113 -64
- package/dist/chunk-I4VELI5K.js.map +1 -0
- package/dist/index.js +364 -208
- package/dist/index.js.map +1 -1
- package/dist/{server-HG2K3WOQ.js → server-47VOVJJT.js} +4 -2
- package/package.json +4 -4
- package/dist/chunk-UOMGIXZN.js.map +0 -1
- /package/dist/{server-HG2K3WOQ.js.map → server-47VOVJJT.js.map} +0 -0
|
@@ -149,6 +149,7 @@ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile10 } from
|
|
|
149
149
|
import path7 from "path";
|
|
150
150
|
import { z as z17 } from "zod";
|
|
151
151
|
import {
|
|
152
|
+
buildProposeCommand,
|
|
152
153
|
loadMemoriesFromDir as loadMemoriesFromDir14,
|
|
153
154
|
normalizeFramework,
|
|
154
155
|
parseLessonFields,
|
|
@@ -1391,6 +1392,7 @@ async function proposeSensor(input, ctx) {
|
|
|
1391
1392
|
if (!found) {
|
|
1392
1393
|
throw new Error(`No memory found with id ${input.memory_id}`);
|
|
1393
1394
|
}
|
|
1395
|
+
const personalScopeNudge = found.memory.frontmatter.scope === "personal" ? ` Note: this lesson is personal-scoped, so the sensor guards only YOUR machine (personal memories are gitignored). Promote it so the gate travels with the repo: hivelore memory promote ${input.memory_id}.` : "";
|
|
1394
1396
|
if (kind !== "regex") {
|
|
1395
1397
|
const verdictCmd = runCommandForValidation(input.command.trim(), ctx.paths.root, input.timeout_ms);
|
|
1396
1398
|
const anchorPathsCmd = input.paths.length > 0 ? input.paths : found.memory.frontmatter.anchor.paths;
|
|
@@ -1425,7 +1427,7 @@ ${verdictCmd.detail}`,
|
|
|
1425
1427
|
accepted: true,
|
|
1426
1428
|
memory_id: input.memory_id,
|
|
1427
1429
|
severity: input.severity,
|
|
1428
|
-
guidance: verdictCmd.status === "passed" ? "Command oracle passes on the current tree; the gate now runs it when the diff touches the sensor's paths (requires enforcement.runCommandSensors=true)." : `Accepted at warn severity, but note: ${verdictCmd.status} on the current tree (${verdictCmd.detail})
|
|
1430
|
+
guidance: (verdictCmd.status === "passed" ? "Command oracle passes on the current tree; the gate now runs it when the diff touches the sensor's paths (requires enforcement.runCommandSensors=true)." : `Accepted at warn severity, but note: ${verdictCmd.status} on the current tree (${verdictCmd.detail}).`) + personalScopeNudge,
|
|
1429
1431
|
self_check: { silent_on_current: verdictCmd.status === "passed", fires_on_bad: null, fired_on: [] }
|
|
1430
1432
|
};
|
|
1431
1433
|
}
|
|
@@ -1474,6 +1476,7 @@ ${verdictCmd.detail}`,
|
|
|
1474
1476
|
accepted: true,
|
|
1475
1477
|
memory_id: input.memory_id,
|
|
1476
1478
|
severity: input.severity,
|
|
1479
|
+
...personalScopeNudge ? { guidance: personalScopeNudge.trim() } : {},
|
|
1477
1480
|
self_check,
|
|
1478
1481
|
file_path: found.filePath
|
|
1479
1482
|
};
|
|
@@ -1482,7 +1485,9 @@ var MemTriedInputSchema = {
|
|
|
1482
1485
|
what: z16.string().min(1).describe("Brief description of the approach that was tried"),
|
|
1483
1486
|
why_failed: z16.string().min(1).describe("Why it failed or why it should NOT be used"),
|
|
1484
1487
|
instead: z16.string().optional().describe("What to use or do instead (recommended alternative)"),
|
|
1485
|
-
scope: z16.enum(["personal", "team", "module"]).
|
|
1488
|
+
scope: z16.enum(["personal", "team", "module"]).optional().describe(
|
|
1489
|
+
"Visibility scope. Defaults to personal \u2014 EXCEPT when a one-shot `sensor` is attached: an enforced lesson is team truth (the sensor must travel to every machine and CI), so it defaults to team. Pass scope explicitly to override."
|
|
1490
|
+
),
|
|
1486
1491
|
module: z16.string().optional().describe("Module name (required when scope=module)"),
|
|
1487
1492
|
tags: z16.array(z16.string()).default([]).describe("Tags for filtering"),
|
|
1488
1493
|
paths: z16.array(z16.string()).default([]).describe("Anchor file paths this applies to"),
|
|
@@ -1506,10 +1511,11 @@ async function memTried(input, ctx) {
|
|
|
1506
1511
|
throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'hivelore init' first.`);
|
|
1507
1512
|
}
|
|
1508
1513
|
const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
|
|
1514
|
+
const scope = input.scope ?? (input.sensor ? "team" : "personal");
|
|
1509
1515
|
const baseFm = buildFrontmatter2({
|
|
1510
1516
|
type: "attempt",
|
|
1511
1517
|
slug,
|
|
1512
|
-
scope
|
|
1518
|
+
scope,
|
|
1513
1519
|
module: input.module,
|
|
1514
1520
|
tags: input.tags,
|
|
1515
1521
|
paths: input.paths,
|
|
@@ -1557,7 +1563,7 @@ async function memTried(input, ctx) {
|
|
|
1557
1563
|
...verdict.reason ? { reason: verdict.reason } : {},
|
|
1558
1564
|
...verdict.guidance ? { guidance: verdict.guidance } : {}
|
|
1559
1565
|
},
|
|
1560
|
-
hint: verdict.accepted ? "Loop closed: the attempt is saved AND enforced \u2014 the gate now refuses a repeat deterministically." : `Attempt saved, but the sensor was rejected (${verdict.reason}). Revise per the guidance and re-propose with propose_sensor.`
|
|
1566
|
+
hint: (verdict.accepted ? "Loop closed: the attempt is saved AND enforced \u2014 the gate now refuses a repeat deterministically." : `Attempt saved, but the sensor was rejected (${verdict.reason}). Revise per the guidance and re-propose with propose_sensor.`) + (input.scope === void 0 ? " Saved team-scoped (an enforced lesson must travel with the repo) \u2014 pass scope:'personal' to keep it private." : "")
|
|
1561
1567
|
};
|
|
1562
1568
|
}
|
|
1563
1569
|
const seed = input.paths.length > 0 ? suggestSensorSeed2(body, input.paths) : null;
|
|
@@ -1578,39 +1584,55 @@ async function memTried(input, ctx) {
|
|
|
1578
1584
|
};
|
|
1579
1585
|
}
|
|
1580
1586
|
var PY_SIGNALS = ["pyproject.toml", "setup.py", "pytest.ini", "requirements.txt", "tox.ini"];
|
|
1581
|
-
async function
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
if (hasPkg
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
} catch {
|
|
1601
|
-
pkg = null;
|
|
1602
|
-
}
|
|
1587
|
+
async function detectForAnchor(root, rel) {
|
|
1588
|
+
let dir = path7.resolve(root, rel);
|
|
1589
|
+
try {
|
|
1590
|
+
if (!statSync(dir).isDirectory()) dir = path7.dirname(dir);
|
|
1591
|
+
} catch {
|
|
1592
|
+
if (path7.extname(dir)) dir = path7.dirname(dir);
|
|
1593
|
+
}
|
|
1594
|
+
while (dir.startsWith(root)) {
|
|
1595
|
+
const pkgJson = path7.join(dir, "package.json");
|
|
1596
|
+
const hasPkg = existsSync17(pkgJson);
|
|
1597
|
+
const goMod = existsSync17(path7.join(dir, "go.mod"));
|
|
1598
|
+
const pySignal = PY_SIGNALS.some((s) => existsSync17(path7.join(dir, s)));
|
|
1599
|
+
if (hasPkg || goMod || pySignal) {
|
|
1600
|
+
let pkg = null;
|
|
1601
|
+
if (hasPkg) {
|
|
1602
|
+
try {
|
|
1603
|
+
pkg = JSON.parse(await readFile4(pkgJson, "utf8"));
|
|
1604
|
+
} catch {
|
|
1605
|
+
pkg = null;
|
|
1603
1606
|
}
|
|
1604
|
-
const baseDir = path7.relative(root, dir).split(path7.sep).join("/");
|
|
1605
|
-
return { framework: pickTestFramework(pkg, { goMod, pySignal }), baseDir };
|
|
1606
1607
|
}
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
dir = parent;
|
|
1608
|
+
const baseDir = path7.relative(root, dir).split(path7.sep).join("/");
|
|
1609
|
+
return { framework: pickTestFramework(pkg, { goMod, pySignal }), baseDir };
|
|
1610
1610
|
}
|
|
1611
|
+
const parent = path7.dirname(dir);
|
|
1612
|
+
if (parent === dir || dir === root) break;
|
|
1613
|
+
dir = parent;
|
|
1614
|
+
}
|
|
1615
|
+
return null;
|
|
1616
|
+
}
|
|
1617
|
+
async function detectTestFrameworkForPaths(root, anchorPaths) {
|
|
1618
|
+
const starts = anchorPaths.length > 0 ? anchorPaths : ["."];
|
|
1619
|
+
for (const rel of starts) {
|
|
1620
|
+
const found = await detectForAnchor(root, rel);
|
|
1621
|
+
if (found) return found;
|
|
1611
1622
|
}
|
|
1612
1623
|
return { framework: "vitest", baseDir: "" };
|
|
1613
1624
|
}
|
|
1625
|
+
async function detectTestFrameworksForAnchors(root, anchorPaths) {
|
|
1626
|
+
const starts = anchorPaths.length > 0 ? anchorPaths : ["."];
|
|
1627
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1628
|
+
for (const rel of starts) {
|
|
1629
|
+
const found = await detectForAnchor(root, rel) ?? { framework: "vitest", baseDir: "" };
|
|
1630
|
+
const existing = groups.get(found.baseDir);
|
|
1631
|
+
if (existing) existing.anchors.push(rel);
|
|
1632
|
+
else groups.set(found.baseDir, { ...found, anchors: [rel] });
|
|
1633
|
+
}
|
|
1634
|
+
return [...groups.values()];
|
|
1635
|
+
}
|
|
1614
1636
|
var ScaffoldTestInputSchema = {
|
|
1615
1637
|
memory_id: z17.string().min(1).describe("Id of the attempt/gotcha lesson to scaffold a post-incident test from."),
|
|
1616
1638
|
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."),
|
|
@@ -1624,43 +1646,69 @@ async function scaffoldTest(input, ctx) {
|
|
|
1624
1646
|
return { ok: false, error: `No memory found with id ${input.memory_id}`, memory_id: input.memory_id };
|
|
1625
1647
|
}
|
|
1626
1648
|
const anchorPaths = found.memory.frontmatter.anchor.paths ?? [];
|
|
1627
|
-
const
|
|
1628
|
-
const
|
|
1649
|
+
const allGroups = await detectTestFrameworksForAnchors(ctx.paths.root, anchorPaths);
|
|
1650
|
+
const groups = input.out_path ? allGroups.slice(0, 1) : allGroups;
|
|
1651
|
+
const frameworkFor = (detected) => input.framework ? normalizeFramework(input.framework) ?? detected : detected;
|
|
1629
1652
|
const fields = parseLessonFields(found.memory.body);
|
|
1630
|
-
const
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
{ framework, outPath: input.out_path, baseDir:
|
|
1653
|
+
const lesson = {
|
|
1654
|
+
memoryId: input.memory_id,
|
|
1655
|
+
title: fields.title || input.memory_id,
|
|
1656
|
+
whyFailed: fields.whyFailed,
|
|
1657
|
+
instead: fields.instead,
|
|
1658
|
+
incident: found.memory.frontmatter.sensor?.incident,
|
|
1659
|
+
paths: anchorPaths
|
|
1660
|
+
};
|
|
1661
|
+
let scaffolds = groups.map(
|
|
1662
|
+
(g) => scaffoldPostIncidentTest(lesson, { framework: frameworkFor(g.framework), outPath: input.out_path, baseDir: g.baseDir })
|
|
1640
1663
|
);
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1664
|
+
let proposeCommand = scaffolds[0].proposeCommand;
|
|
1665
|
+
if (scaffolds.length > 1) {
|
|
1666
|
+
proposeCommand = buildProposeCommand(lesson, scaffolds.map((s) => s.runCommand).join(" && "));
|
|
1667
|
+
scaffolds = groups.map(
|
|
1668
|
+
(g) => scaffoldPostIncidentTest(lesson, {
|
|
1669
|
+
framework: frameworkFor(g.framework),
|
|
1670
|
+
baseDir: g.baseDir,
|
|
1671
|
+
proposeCommandOverride: proposeCommand
|
|
1672
|
+
})
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
const results = [];
|
|
1676
|
+
for (const scaffold of scaffolds) {
|
|
1677
|
+
const abs = path7.isAbsolute(scaffold.relPath) ? scaffold.relPath : path7.resolve(ctx.paths.root, scaffold.relPath);
|
|
1678
|
+
let written = false;
|
|
1679
|
+
let alreadyExists = false;
|
|
1680
|
+
if (input.write) {
|
|
1681
|
+
if (existsSync17(abs)) {
|
|
1682
|
+
alreadyExists = true;
|
|
1683
|
+
} else {
|
|
1684
|
+
await mkdir4(path7.dirname(abs), { recursive: true });
|
|
1685
|
+
await writeFile10(abs, scaffold.content, "utf8");
|
|
1686
|
+
written = true;
|
|
1687
|
+
}
|
|
1651
1688
|
}
|
|
1689
|
+
results.push({
|
|
1690
|
+
framework: scaffold.framework,
|
|
1691
|
+
path: scaffold.relPath,
|
|
1692
|
+
run_command: scaffold.runCommand,
|
|
1693
|
+
content: scaffold.content,
|
|
1694
|
+
written,
|
|
1695
|
+
already_exists: alreadyExists
|
|
1696
|
+
});
|
|
1652
1697
|
}
|
|
1698
|
+
const first = results[0];
|
|
1699
|
+
const anyExisting = results.some((r) => r.already_exists);
|
|
1653
1700
|
return {
|
|
1654
1701
|
ok: true,
|
|
1655
1702
|
memory_id: input.memory_id,
|
|
1656
|
-
framework,
|
|
1657
|
-
path:
|
|
1658
|
-
run_command:
|
|
1659
|
-
propose_command:
|
|
1660
|
-
content:
|
|
1661
|
-
written,
|
|
1662
|
-
already_exists:
|
|
1663
|
-
|
|
1703
|
+
framework: first.framework,
|
|
1704
|
+
path: first.path,
|
|
1705
|
+
run_command: first.run_command,
|
|
1706
|
+
propose_command: proposeCommand,
|
|
1707
|
+
content: first.content,
|
|
1708
|
+
written: first.written,
|
|
1709
|
+
already_exists: first.already_exists,
|
|
1710
|
+
...results.length > 1 ? { scaffolds: results } : {},
|
|
1711
|
+
notice: (results.length > 1 ? `Lesson spans ${results.length} packages \u2014 one pending test per owning package; ONE propose_command arms them all (chained oracle). ` : "") + (anyExisting ? "Some file(s) already exist \u2014 not overwritten. Delete them or pass out_path to write elsewhere." : "PENDING test scaffolded. Fill in the assertion (RED on the incident, GREEN once fixed), run it, then arm it with propose_command \u2014 propose_sensor stays the sole validated writer.")
|
|
1664
1712
|
};
|
|
1665
1713
|
}
|
|
1666
1714
|
var IngestFindingsInputSchema = {
|
|
@@ -2827,7 +2875,7 @@ function oneLine(value) {
|
|
|
2827
2875
|
return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
|
|
2828
2876
|
}
|
|
2829
2877
|
function serverVersion() {
|
|
2830
|
-
return true ? "0.
|
|
2878
|
+
return true ? "0.39.0" : "dev";
|
|
2831
2879
|
}
|
|
2832
2880
|
var CodeMapInputSchema = {
|
|
2833
2881
|
file: z21.string().optional().describe("Filter to files whose path contains this substring"),
|
|
@@ -4154,7 +4202,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
4154
4202
|
};
|
|
4155
4203
|
}
|
|
4156
4204
|
var SERVER_NAME = "hivelore";
|
|
4157
|
-
var SERVER_VERSION = "0.
|
|
4205
|
+
var SERVER_VERSION = "0.39.0";
|
|
4158
4206
|
function jsonResult(data) {
|
|
4159
4207
|
return {
|
|
4160
4208
|
content: [
|
|
@@ -5104,6 +5152,7 @@ export {
|
|
|
5104
5152
|
proposeSensor,
|
|
5105
5153
|
memTried,
|
|
5106
5154
|
detectTestFrameworkForPaths,
|
|
5155
|
+
detectTestFrameworksForAnchors,
|
|
5107
5156
|
scaffoldTest,
|
|
5108
5157
|
getBriefing,
|
|
5109
5158
|
codeMapTool,
|
|
@@ -5129,4 +5178,4 @@ export {
|
|
|
5129
5178
|
printHaiveMcpVersion,
|
|
5130
5179
|
runHaiveMcpStdio
|
|
5131
5180
|
};
|
|
5132
|
-
//# sourceMappingURL=chunk-
|
|
5181
|
+
//# sourceMappingURL=chunk-I4VELI5K.js.map
|