@hivelore/cli 0.35.1 → 0.37.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-QQANGHJK.js → chunk-VLRQ4MRO.js} +10 -3
- package/dist/chunk-VLRQ4MRO.js.map +1 -0
- package/dist/index.js +130 -16
- package/dist/index.js.map +1 -1
- package/dist/{server-W5Q35K7Q.js → server-J6TDFG2C.js} +2 -2
- package/package.json +5 -5
- package/dist/chunk-QQANGHJK.js.map +0 -1
- /package/dist/{server-W5Q35K7Q.js.map → server-J6TDFG2C.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
preCommitCheck,
|
|
11
11
|
readPresumedCorrectTargets,
|
|
12
12
|
runHaiveMcpStdio
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-VLRQ4MRO.js";
|
|
14
14
|
import {
|
|
15
15
|
registerMemoryPending
|
|
16
16
|
} from "./chunk-OYJKHD22.js";
|
|
@@ -3755,7 +3755,7 @@ ${SEED_FOOTER(stack)}` });
|
|
|
3755
3755
|
|
|
3756
3756
|
// src/commands/init.ts
|
|
3757
3757
|
var execFileAsync = promisify2(execFile2);
|
|
3758
|
-
var HAIVE_GITHUB_ACTION_REF = `v${"0.
|
|
3758
|
+
var HAIVE_GITHUB_ACTION_REF = `v${"0.37.0"}`;
|
|
3759
3759
|
var PROJECT_CONTEXT_TEMPLATE = `# Project context
|
|
3760
3760
|
|
|
3761
3761
|
> Generated by \`hivelore init\`. Run \`hivelore init --bootstrap\` to auto-fill from your codebase,
|
|
@@ -6090,6 +6090,7 @@ function registerMemoryTried(memory2) {
|
|
|
6090
6090
|
} else if (result.hint) {
|
|
6091
6091
|
ui.warn(result.hint);
|
|
6092
6092
|
}
|
|
6093
|
+
ui.info(` Prefer a real test? \`hivelore sensors scaffold ${result.id}\` generates a pending test + the wiring command.`);
|
|
6093
6094
|
});
|
|
6094
6095
|
}
|
|
6095
6096
|
|
|
@@ -7325,13 +7326,15 @@ import {
|
|
|
7325
7326
|
loadPreventionEvents as loadPreventionEvents2,
|
|
7326
7327
|
parseSince,
|
|
7327
7328
|
readUsageEvents,
|
|
7329
|
+
renderPreventionReceiptShare,
|
|
7328
7330
|
resolveHaivePaths as resolveHaivePaths27,
|
|
7329
7331
|
usageLogSize
|
|
7330
7332
|
} from "@hivelore/core";
|
|
7331
7333
|
function registerStats(program2) {
|
|
7332
7334
|
const stats = program2.command("stats").description("Show MCP tool-usage stats and prevention receipts.");
|
|
7333
|
-
stats.command("receipt").description("Show documented mistakes refused by the gate over a time window").addHelpText("after", "\nParent options also apply: --since <window> (default 7d here), --json, --dir <dir>.").action(async () => {
|
|
7335
|
+
const receiptCmd = stats.command("receipt").description("Show documented mistakes refused by the gate over a time window").option("--share", "emit a Markdown block ready to paste into Slack or a PR (with attribution)", false).addHelpText("after", "\nParent options also apply: --since <window> (default 7d here), --json, --dir <dir>.").action(async () => {
|
|
7334
7336
|
const opts = stats.opts();
|
|
7337
|
+
const sub = receiptCmd.opts();
|
|
7335
7338
|
const root = findProjectRoot28(opts.dir);
|
|
7336
7339
|
const paths = resolveHaivePaths27(root);
|
|
7337
7340
|
const sinceRaw = stats.getOptionValueSource("since") === "default" ? "7d" : opts.since ?? "7d";
|
|
@@ -7342,7 +7345,8 @@ function registerStats(program2) {
|
|
|
7342
7345
|
existsSync33(paths.memoriesDir) ? loadMemoriesFromDir11(paths.memoriesDir) : Promise.resolve([])
|
|
7343
7346
|
]);
|
|
7344
7347
|
const receipt = buildPreventionReceipt(events, memories, usage, { since });
|
|
7345
|
-
|
|
7348
|
+
const output = sub.share ? renderPreventionReceiptShare(receipt) : opts.json ? JSON.stringify(receipt, null, 2) : renderPreventionReceipt(receipt);
|
|
7349
|
+
console.log(output);
|
|
7346
7350
|
});
|
|
7347
7351
|
stats.option("--since <window>", "ISO date or relative (e.g. '7d', '24h', '30m')", "30d").option("--json", "emit JSON instead of human-readable output", false).option("--memory-hits", "show top-read memories (which mems are actually being used)", false).option(
|
|
7348
7352
|
"--export-report <path>",
|
|
@@ -8956,7 +8960,7 @@ function registerDoctor(program2) {
|
|
|
8956
8960
|
fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `hivelore init` without --manual)."
|
|
8957
8961
|
});
|
|
8958
8962
|
}
|
|
8959
|
-
findings.push(...await collectInstallFindings(root, "0.
|
|
8963
|
+
findings.push(...await collectInstallFindings(root, "0.37.0"));
|
|
8960
8964
|
findings.push(...await collectToolchainFindings(root));
|
|
8961
8965
|
try {
|
|
8962
8966
|
const legacyRaw = execSync("haive-mcp --version", {
|
|
@@ -8964,7 +8968,7 @@ function registerDoctor(program2) {
|
|
|
8964
8968
|
timeout: 3e3,
|
|
8965
8969
|
stdio: ["ignore", "pipe", "ignore"]
|
|
8966
8970
|
}).trim();
|
|
8967
|
-
const cliVersion = "0.
|
|
8971
|
+
const cliVersion = "0.37.0";
|
|
8968
8972
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
8969
8973
|
findings.push({
|
|
8970
8974
|
severity: "warn",
|
|
@@ -9723,6 +9727,7 @@ import {
|
|
|
9723
9727
|
readRecentBriefingMarker,
|
|
9724
9728
|
recordPreventionHits,
|
|
9725
9729
|
resolveBriefingBudget as resolveBriefingBudget2,
|
|
9730
|
+
incidentSuffix,
|
|
9726
9731
|
resolveHaivePaths as resolveHaivePaths35,
|
|
9727
9732
|
runSensors,
|
|
9728
9733
|
saveConfig as saveConfig3,
|
|
@@ -9872,7 +9877,8 @@ async function executeCommandSensor(spec, root) {
|
|
|
9872
9877
|
command: spec.command,
|
|
9873
9878
|
kind: spec.kind,
|
|
9874
9879
|
severity: spec.severity,
|
|
9875
|
-
message: spec.message
|
|
9880
|
+
message: spec.message,
|
|
9881
|
+
...spec.incident ? { incident: spec.incident } : {}
|
|
9876
9882
|
};
|
|
9877
9883
|
try {
|
|
9878
9884
|
const { stdout, stderr } = await exec2("bash", ["-c", spec.command], {
|
|
@@ -10665,7 +10671,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
10665
10671
|
findings: [{ severity: "info", code: "enforcement-off", message: "Hivelore enforcement is disabled." }]
|
|
10666
10672
|
});
|
|
10667
10673
|
}
|
|
10668
|
-
findings.push(...await inspectIntegrationVersions(root, "0.
|
|
10674
|
+
findings.push(...await inspectIntegrationVersions(root, "0.37.0"));
|
|
10669
10675
|
if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
|
|
10670
10676
|
const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
|
|
10671
10677
|
findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent Hivelore briefing marker exists." } : {
|
|
@@ -11020,7 +11026,7 @@ async function runSensorGate(paths, diff, stage) {
|
|
|
11020
11026
|
findings.push({
|
|
11021
11027
|
severity: "error",
|
|
11022
11028
|
code: "sensor-block",
|
|
11023
|
-
message: `Block sensor fired \u2014 ${hit.memory_id}: ${hit.message}${where}`,
|
|
11029
|
+
message: `Block sensor fired \u2014 ${hit.memory_id}: ${hit.message}${where}${incidentSuffix(hit.sensor.incident)}`,
|
|
11024
11030
|
fix: "Remove the flagged pattern, or run `hivelore sensors check` to inspect the match.",
|
|
11025
11031
|
impact: 45,
|
|
11026
11032
|
memory_ids: [hit.memory_id]
|
|
@@ -11029,7 +11035,7 @@ async function runSensorGate(paths, diff, stage) {
|
|
|
11029
11035
|
findings.push({
|
|
11030
11036
|
severity: "warn",
|
|
11031
11037
|
code: "sensor-warn",
|
|
11032
|
-
message: `Sensor flagged ${hit.memory_id}: ${hit.message}${where}`,
|
|
11038
|
+
message: `Sensor flagged ${hit.memory_id}: ${hit.message}${where}${incidentSuffix(hit.sensor.incident)}`,
|
|
11033
11039
|
fix: "Review the flagged line; `hivelore sensors check` shows the matched code.",
|
|
11034
11040
|
impact: 5,
|
|
11035
11041
|
memory_ids: [hit.memory_id]
|
|
@@ -11091,7 +11097,7 @@ ${run.output_tail}` : "";
|
|
|
11091
11097
|
findings.push({
|
|
11092
11098
|
severity: "error",
|
|
11093
11099
|
code: "sensor-block",
|
|
11094
|
-
message: `Block ${run.kind} sensor fired \u2014 ${run.memory_id}: ${run.message}
|
|
11100
|
+
message: `Block ${run.kind} sensor fired \u2014 ${run.memory_id}: ${run.message}${incidentSuffix(run.incident)}
|
|
11095
11101
|
command: ${run.command} (exit ${run.exit_code}, ${run.duration_ms}ms)${outputBlock}`,
|
|
11096
11102
|
fix: "Fix the behaviour the command checks, or run `hivelore sensors check --commands` to inspect it.",
|
|
11097
11103
|
impact: 45,
|
|
@@ -11101,7 +11107,7 @@ command: ${run.command} (exit ${run.exit_code}, ${run.duration_ms}ms)${outputBlo
|
|
|
11101
11107
|
findings.push({
|
|
11102
11108
|
severity: "warn",
|
|
11103
11109
|
code: "sensor-warn",
|
|
11104
|
-
message: `${run.kind} sensor flagged ${run.memory_id}: ${run.message} (exit ${run.exit_code})${outputBlock}`,
|
|
11110
|
+
message: `${run.kind} sensor flagged ${run.memory_id}: ${run.message}${incidentSuffix(run.incident)} (exit ${run.exit_code})${outputBlock}`,
|
|
11105
11111
|
fix: "Review the failing command; `hivelore sensors check --commands` re-runs it.",
|
|
11106
11112
|
impact: 5,
|
|
11107
11113
|
memory_ids: [run.memory_id]
|
|
@@ -11795,7 +11801,10 @@ jobs:
|
|
|
11795
11801
|
"
|
|
11796
11802
|
|
|
11797
11803
|
Weekly total: **" + ($receipt.total|tostring) + "** refused; previous window: **" +
|
|
11798
|
-
($receipt.previous_total|tostring) + "**."
|
|
11804
|
+
($receipt.previous_total|tostring) + "**." +
|
|
11805
|
+
"
|
|
11806
|
+
|
|
11807
|
+
<sub>\u{1F6E1}\uFE0F Generated by [Hivelore](https://github.com/Doucs91/hivelore) \u2014 the deterministic policy gate for agent-written code.</sub>"
|
|
11799
11808
|
')" || exit 0
|
|
11800
11809
|
comments="$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" --paginate 2>/dev/null)" || exit 0
|
|
11801
11810
|
comment_id="$(printf '%s' "$comments" | jq -r '.[] | select(.body | contains("<!-- haive:prevention-receipt -->")) | .id' | head -1)"
|
|
@@ -11810,6 +11819,30 @@ Weekly total: **" + ($receipt.total|tostring) + "** refused; previous window: **
|
|
|
11810
11819
|
# haive:enforcement-workflow:end
|
|
11811
11820
|
`;
|
|
11812
11821
|
}
|
|
11822
|
+
var CONTENT_CATCH_CODES = /* @__PURE__ */ new Set(["sensor-block", "precommit-policy-block"]);
|
|
11823
|
+
var SETUP_GATE_CODES = /* @__PURE__ */ new Set([
|
|
11824
|
+
"briefing-missing",
|
|
11825
|
+
"session-recap-missing",
|
|
11826
|
+
"decision-coverage-missing",
|
|
11827
|
+
"bootstrap-incomplete",
|
|
11828
|
+
"enforcement-score-below-threshold"
|
|
11829
|
+
]);
|
|
11830
|
+
function printBlockHeadline(report) {
|
|
11831
|
+
const blocking = report.categories?.blocking ?? report.findings.filter((f) => f.severity === "error");
|
|
11832
|
+
if (blocking.length === 0) return;
|
|
11833
|
+
const catches = blocking.filter((f) => CONTENT_CATCH_CODES.has(f.code));
|
|
11834
|
+
console.log();
|
|
11835
|
+
if (catches.length > 0) {
|
|
11836
|
+
console.log(ui.red(ui.bold("\u{1F6E1}\uFE0F A documented lesson refused this commit \u2014 about the change you just made:")));
|
|
11837
|
+
for (const c of catches) {
|
|
11838
|
+
const id = c.memory_ids?.[0] ?? c.code;
|
|
11839
|
+
console.log(` ${ui.red("\u2022")} ${ui.bold(id)} ${c.message.split("\n")[0]}`);
|
|
11840
|
+
}
|
|
11841
|
+
} else if (blocking.every((f) => SETUP_GATE_CODES.has(f.code))) {
|
|
11842
|
+
console.log(ui.yellow(ui.bold("\u2699 Setup gate \u2014 about your repo's baseline, not the change you just made.")));
|
|
11843
|
+
console.log(ui.dim(" Fill the knowledge layer once (bootstrap / load a briefing); later commits pass silently."));
|
|
11844
|
+
}
|
|
11845
|
+
}
|
|
11813
11846
|
function printReport(report, json, explain = false) {
|
|
11814
11847
|
if (json) {
|
|
11815
11848
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -11818,6 +11851,7 @@ function printReport(report, json, explain = false) {
|
|
|
11818
11851
|
console.log(ui.bold(`Hivelore enforcement \u2014 ${report.mode}${report.actor ? ` \xB7 ${report.actor}` : ""}`));
|
|
11819
11852
|
console.log(ui.dim(` root: ${report.root}`));
|
|
11820
11853
|
console.log(ui.dim(` score: ${report.score.score}% / threshold ${report.score.threshold}%`));
|
|
11854
|
+
if (report.should_block) printBlockHeadline(report);
|
|
11821
11855
|
if (explain) {
|
|
11822
11856
|
printFindingGroup("Blocking", report.categories.blocking, "error");
|
|
11823
11857
|
printFindingGroup("Review", report.categories.review, "warn");
|
|
@@ -12126,10 +12160,13 @@ import {
|
|
|
12126
12160
|
loadConfig as loadConfig13,
|
|
12127
12161
|
loadSensorLedger as loadSensorLedger4,
|
|
12128
12162
|
loadMemoriesFromDir as loadMemoriesFromDir15,
|
|
12163
|
+
parseLessonFields,
|
|
12129
12164
|
recordPreventionHits as recordPreventionHits2,
|
|
12130
12165
|
resolveHaivePaths as resolveHaivePaths36,
|
|
12131
12166
|
runSensors as runSensors2,
|
|
12167
|
+
scaffoldPostIncidentTest,
|
|
12132
12168
|
selectCommandSensors as selectCommandSensors2,
|
|
12169
|
+
TEST_FRAMEWORKS,
|
|
12133
12170
|
sensorPatternBrittleness as sensorPatternBrittleness2,
|
|
12134
12171
|
sensorSelfCheck as sensorSelfCheck2,
|
|
12135
12172
|
sensorAppliesToPath as sensorAppliesToPath3,
|
|
@@ -12364,7 +12401,7 @@ function registerSensors(program2) {
|
|
|
12364
12401
|
});
|
|
12365
12402
|
sensors.command("propose").description(
|
|
12366
12403
|
"Propose a discriminating sensor for a memory \u2014 you write the pattern, Hivelore validates it before\n trusting it to block. Mirrors the MCP `propose_sensor` tool (the agent-authored path).\n\n A `block` proposal is accepted ONLY if it is not brittle, stays SILENT on the current code,\n and FIRES on the bad example. Rejected proposals are not written \u2014 fix and re-run.\n\n Example:\n hivelore sensors propose <memory-id> \\\n --pattern 'stripe\\.paymentIntents\\.create' --absent 'idempotencyKey' \\\n --bad-example 'stripe.paymentIntents.create({ amount })'"
|
|
12367
|
-
).argument("<memory-id>", "memory id to attach the sensor to").option("--kind <kind>", "regex (default) | shell | test \u2014 command kinds route the team's own oracle to this lesson", "regex").option("--pattern <regex>", "kind=regex: regex matching the FAULTY usage").option("--command <cmd>", "kind=shell|test: command the gate runs when the diff touches the sensor's paths").option("--timeout <ms>", "kind=shell|test: max runtime in ms (default 120000)").option("--absent <regex>", "regex for the CORRECT-usage marker (makes it discriminate)").option("--bad-example <code>", "a snippet that SHOULD match (else examples are read from the lesson)").option("--severity <severity>", "block | warn", "block").option("--message <text>", "fix message shown when it fires").option("--flags <flags>", "regex flags (e.g. i)").option("--paths <csv>", "override scope paths (defaults to the memory anchors)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
12404
|
+
).argument("<memory-id>", "memory id to attach the sensor to").option("--kind <kind>", "regex (default) | shell | test \u2014 command kinds route the team's own oracle to this lesson", "regex").option("--pattern <regex>", "kind=regex: regex matching the FAULTY usage").option("--command <cmd>", "kind=shell|test: command the gate runs when the diff touches the sensor's paths").option("--timeout <ms>", "kind=shell|test: max runtime in ms (default 120000)").option("--absent <regex>", "regex for the CORRECT-usage marker (makes it discriminate)").option("--bad-example <code>", "a snippet that SHOULD match (else examples are read from the lesson)").option("--severity <severity>", "block | warn", "block").option("--message <text>", "fix message shown when it fires").option("--incident <ref>", "provenance: the incident this sensor guards (e.g. 'prod #442') \u2014 shown when it fires and in the receipt").option("--flags <flags>", "regex flags (e.g. i)").option("--paths <csv>", "override scope paths (defaults to the memory anchors)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
12368
12405
|
if (opts.kind === "shell" || opts.kind === "test") {
|
|
12369
12406
|
if (!opts.command?.trim()) {
|
|
12370
12407
|
ui.error("--kind shell|test requires --command.");
|
|
@@ -12372,7 +12409,7 @@ function registerSensors(program2) {
|
|
|
12372
12409
|
return;
|
|
12373
12410
|
}
|
|
12374
12411
|
const root2 = findProjectRoot39(opts.dir);
|
|
12375
|
-
const { proposeSensor } = await import("./server-
|
|
12412
|
+
const { proposeSensor } = await import("./server-J6TDFG2C.js");
|
|
12376
12413
|
const out = await proposeSensor(
|
|
12377
12414
|
{
|
|
12378
12415
|
memory_id: id,
|
|
@@ -12384,6 +12421,7 @@ function registerSensors(program2) {
|
|
|
12384
12421
|
bad_example: void 0,
|
|
12385
12422
|
severity: opts.severity === "warn" ? "warn" : "block",
|
|
12386
12423
|
message: opts.message,
|
|
12424
|
+
incident: opts.incident,
|
|
12387
12425
|
flags: void 0,
|
|
12388
12426
|
paths: opts.paths ? opts.paths.split(",").map((p) => p.trim()).filter(Boolean) : []
|
|
12389
12427
|
},
|
|
@@ -12435,6 +12473,7 @@ function registerSensors(program2) {
|
|
|
12435
12473
|
...opts.flags ? { flags: opts.flags } : {},
|
|
12436
12474
|
paths: anchorPaths,
|
|
12437
12475
|
message: opts.message?.trim() || deriveProposedMessage(found.memory.body, opts.pattern, opts.absent),
|
|
12476
|
+
...opts.incident?.trim() ? { incident: opts.incident.trim() } : {},
|
|
12438
12477
|
severity,
|
|
12439
12478
|
autogen: false,
|
|
12440
12479
|
last_fired: null
|
|
@@ -12459,6 +12498,56 @@ function registerSensors(program2) {
|
|
|
12459
12498
|
`self-check: silent on current=${verdict.self_check.silent_on_current}` + (verdict.self_check.fires_on_bad === null ? "; no bad example tested" : `; fires on bad=${verdict.self_check.fires_on_bad}`)
|
|
12460
12499
|
);
|
|
12461
12500
|
});
|
|
12501
|
+
sensors.command("scaffold").description(
|
|
12502
|
+
"Generate a PENDING post-incident test from a lesson (mem_tried/attempt/gotcha) \u2014 the on-ramp to\n a command sensor. Writes a test stub carrying the incident's provenance, then prints the exact\n `sensors propose --kind test` line to arm it once you've written the assertion. It never arms a\n sensor itself \u2014 propose_sensor stays the sole validated writer.\n\n Example:\n hivelore sensors scaffold 2026-07-03-attempt-refund-exceeds-capture --framework vitest"
|
|
12503
|
+
).argument("<memory-id>", "lesson id to scaffold a test from").option("--framework <fw>", `test framework: ${TEST_FRAMEWORKS.join(" | ")} (auto-detected when omitted)`).option("--out <path>", "override the generated test file path (project-relative)").option("--stdout", "print the test to stdout instead of writing a file", false).option("--force", "overwrite an existing file at the target path", false).option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
12504
|
+
const root = findProjectRoot39(opts.dir);
|
|
12505
|
+
const paths = resolveHaivePaths36(root);
|
|
12506
|
+
const loaded = existsSync43(paths.memoriesDir) ? await loadMemoriesFromDir15(paths.memoriesDir) : [];
|
|
12507
|
+
const found = loaded.find(({ memory: memory2 }) => memory2.frontmatter.id === id);
|
|
12508
|
+
if (!found) {
|
|
12509
|
+
ui.error(`No memory found with id ${id}`);
|
|
12510
|
+
process.exitCode = 1;
|
|
12511
|
+
return;
|
|
12512
|
+
}
|
|
12513
|
+
const framework = opts.framework ? normalizeFramework(opts.framework) : await detectTestFramework(root);
|
|
12514
|
+
if (!framework) {
|
|
12515
|
+
ui.error(`Unknown --framework "${opts.framework}". Use one of: ${TEST_FRAMEWORKS.join(", ")}.`);
|
|
12516
|
+
process.exitCode = 1;
|
|
12517
|
+
return;
|
|
12518
|
+
}
|
|
12519
|
+
const fields = parseLessonFields(found.memory.body);
|
|
12520
|
+
const fm = found.memory.frontmatter;
|
|
12521
|
+
const scaffold = scaffoldPostIncidentTest(
|
|
12522
|
+
{
|
|
12523
|
+
memoryId: id,
|
|
12524
|
+
title: fields.title || id,
|
|
12525
|
+
whyFailed: fields.whyFailed,
|
|
12526
|
+
instead: fields.instead,
|
|
12527
|
+
incident: fm.sensor?.incident,
|
|
12528
|
+
paths: fm.anchor.paths
|
|
12529
|
+
},
|
|
12530
|
+
{ framework, outPath: opts.out }
|
|
12531
|
+
);
|
|
12532
|
+
if (opts.stdout) {
|
|
12533
|
+
console.log(scaffold.content);
|
|
12534
|
+
ui.info(`Arm it once written: ${scaffold.proposeCommand}`);
|
|
12535
|
+
return;
|
|
12536
|
+
}
|
|
12537
|
+
const abs = path41.isAbsolute(scaffold.relPath) ? scaffold.relPath : path41.resolve(root, scaffold.relPath);
|
|
12538
|
+
if (existsSync43(abs) && !opts.force) {
|
|
12539
|
+
ui.error(`${scaffold.relPath} already exists \u2014 pass --force to overwrite, or --out <path> for a different file.`);
|
|
12540
|
+
process.exitCode = 1;
|
|
12541
|
+
return;
|
|
12542
|
+
}
|
|
12543
|
+
await mkdir17(path41.dirname(abs), { recursive: true });
|
|
12544
|
+
await writeFile27(abs, scaffold.content, "utf8");
|
|
12545
|
+
ui.success(`Wrote ${framework} post-incident test \u2192 ${scaffold.relPath}`);
|
|
12546
|
+
ui.info(" 1. Fill in the assertion (RED on the incident, GREEN once fixed).");
|
|
12547
|
+
ui.info(` 2. Run it: ${scaffold.runCommand}`);
|
|
12548
|
+
ui.info(" 3. Arm it as a deterministic gate:");
|
|
12549
|
+
console.log(` ${scaffold.proposeCommand}`);
|
|
12550
|
+
});
|
|
12462
12551
|
sensors.command("export").description("Export regex sensors into .ai/generated for external toolchains").option("--format <format>", "grep | eslint", "grep").option("--out-dir <dir>", "output directory", ".ai/generated").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
12463
12552
|
const format = opts.format ?? "grep";
|
|
12464
12553
|
if (format !== "grep" && format !== "eslint") {
|
|
@@ -12548,6 +12637,31 @@ function renderGrepScript(rows) {
|
|
|
12548
12637
|
function shellQuote(value) {
|
|
12549
12638
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
12550
12639
|
}
|
|
12640
|
+
function normalizeFramework(input) {
|
|
12641
|
+
const v = input.trim().toLowerCase();
|
|
12642
|
+
if (v === "vitest") return "vitest";
|
|
12643
|
+
if (v === "jest") return "jest";
|
|
12644
|
+
if (v === "pytest" || v === "py" || v === "python") return "pytest";
|
|
12645
|
+
if (v === "go" || v === "gotest" || v === "go-test") return "gotest";
|
|
12646
|
+
return null;
|
|
12647
|
+
}
|
|
12648
|
+
async function detectTestFramework(root) {
|
|
12649
|
+
try {
|
|
12650
|
+
const pkgPath = path41.join(root, "package.json");
|
|
12651
|
+
if (existsSync43(pkgPath)) {
|
|
12652
|
+
const pkg = JSON.parse(await readFile20(pkgPath, "utf8"));
|
|
12653
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12654
|
+
if (deps.vitest) return "vitest";
|
|
12655
|
+
if (deps.jest || deps["ts-jest"]) return "jest";
|
|
12656
|
+
}
|
|
12657
|
+
} catch {
|
|
12658
|
+
}
|
|
12659
|
+
if (existsSync43(path41.join(root, "go.mod"))) return "gotest";
|
|
12660
|
+
for (const signal of ["pyproject.toml", "setup.py", "pytest.ini", "requirements.txt", "tox.ini"]) {
|
|
12661
|
+
if (existsSync43(path41.join(root, signal))) return "pytest";
|
|
12662
|
+
}
|
|
12663
|
+
return "vitest";
|
|
12664
|
+
}
|
|
12551
12665
|
|
|
12552
12666
|
// src/commands/ingest.ts
|
|
12553
12667
|
import { existsSync as existsSync44 } from "fs";
|
|
@@ -13209,7 +13323,7 @@ function registerBridges(program2) {
|
|
|
13209
13323
|
|
|
13210
13324
|
// src/index.ts
|
|
13211
13325
|
var program = new Command48();
|
|
13212
|
-
program.name("hivelore").description("Hivelore -
|
|
13326
|
+
program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.37.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
|
|
13213
13327
|
registerInit(program);
|
|
13214
13328
|
registerResolveProject(program);
|
|
13215
13329
|
registerEnforce(program);
|