@hiveai/cli 0.13.7 → 0.13.9
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.js +110 -16
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3019,7 +3019,7 @@ ${SEED_FOOTER(stack)}` });
|
|
|
3019
3019
|
}
|
|
3020
3020
|
|
|
3021
3021
|
// src/commands/init.ts
|
|
3022
|
-
var HAIVE_GITHUB_ACTION_REF = `v${"0.13.
|
|
3022
|
+
var HAIVE_GITHUB_ACTION_REF = `v${"0.13.9"}`;
|
|
3023
3023
|
var PROJECT_CONTEXT_TEMPLATE = `# Project context
|
|
3024
3024
|
|
|
3025
3025
|
> Generated by \`haive init\`. Run \`haive init --bootstrap\` to auto-fill from your codebase,
|
|
@@ -4133,6 +4133,7 @@ import { z as z25 } from "zod";
|
|
|
4133
4133
|
import { existsSync as existsSync25 } from "fs";
|
|
4134
4134
|
import {
|
|
4135
4135
|
addedLinesFromDiff,
|
|
4136
|
+
appendPreventionEvent,
|
|
4136
4137
|
buildDocFrequency,
|
|
4137
4138
|
CODE_STOPWORDS,
|
|
4138
4139
|
deriveConfidence as deriveConfidence6,
|
|
@@ -4143,7 +4144,9 @@ import {
|
|
|
4143
4144
|
loadUsageIndex as loadUsageIndex10,
|
|
4144
4145
|
literalMatchesAnyToken as literalMatchesAnyToken3,
|
|
4145
4146
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths4,
|
|
4147
|
+
recordPrevention,
|
|
4146
4148
|
runSensors,
|
|
4149
|
+
saveUsageIndex as saveUsageIndex4,
|
|
4147
4150
|
sensorTargetsFromDiff,
|
|
4148
4151
|
tokenizeQuery as tokenizeQuery3
|
|
4149
4152
|
} from "@hiveai/core";
|
|
@@ -6669,6 +6672,22 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
6669
6672
|
};
|
|
6670
6673
|
return score(b) - score(a);
|
|
6671
6674
|
}).slice(0, input.limit);
|
|
6675
|
+
const strongCatches = warnings.filter(
|
|
6676
|
+
(w) => w.reasons.includes("sensor") || w.distinctive_literal === true || w.reasons.includes("anchor") && w.reasons.includes("literal")
|
|
6677
|
+
);
|
|
6678
|
+
if (strongCatches.length > 0) {
|
|
6679
|
+
const recordedIds = [];
|
|
6680
|
+
for (const w of strongCatches) if (recordPrevention(usage, w.id)) recordedIds.push(w.id);
|
|
6681
|
+
if (recordedIds.length > 0) {
|
|
6682
|
+
await saveUsageIndex4(ctx.paths, usage).catch(() => {
|
|
6683
|
+
});
|
|
6684
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
6685
|
+
for (const id of recordedIds) {
|
|
6686
|
+
await appendPreventionEvent(ctx.paths, { at, id, source: "anti-pattern" }).catch(() => {
|
|
6687
|
+
});
|
|
6688
|
+
}
|
|
6689
|
+
}
|
|
6690
|
+
}
|
|
6672
6691
|
return {
|
|
6673
6692
|
scanned: negative.length,
|
|
6674
6693
|
warnings
|
|
@@ -7919,7 +7938,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
7919
7938
|
};
|
|
7920
7939
|
}
|
|
7921
7940
|
var SERVER_NAME = "haive";
|
|
7922
|
-
var SERVER_VERSION = "0.13.
|
|
7941
|
+
var SERVER_VERSION = "0.13.9";
|
|
7923
7942
|
function jsonResult(data) {
|
|
7924
7943
|
return {
|
|
7925
7944
|
content: [
|
|
@@ -10688,7 +10707,7 @@ import {
|
|
|
10688
10707
|
loadUsageIndex as loadUsageIndex18,
|
|
10689
10708
|
recordRejection as recordRejection3,
|
|
10690
10709
|
resolveHaivePaths as resolveHaivePaths23,
|
|
10691
|
-
saveUsageIndex as
|
|
10710
|
+
saveUsageIndex as saveUsageIndex5,
|
|
10692
10711
|
serializeMemory as serializeMemory19
|
|
10693
10712
|
} from "@hiveai/core";
|
|
10694
10713
|
function registerMemoryReject(memory2) {
|
|
@@ -10721,7 +10740,7 @@ function registerMemoryReject(memory2) {
|
|
|
10721
10740
|
);
|
|
10722
10741
|
const idx = await loadUsageIndex18(paths);
|
|
10723
10742
|
recordRejection3(idx, id, opts.reason ?? null);
|
|
10724
|
-
await
|
|
10743
|
+
await saveUsageIndex5(paths, idx);
|
|
10725
10744
|
const u = idx.by_id[id];
|
|
10726
10745
|
ui.success(
|
|
10727
10746
|
`Rejected ${id} (status=rejected, ${u.rejected_count} rejection${u.rejected_count === 1 ? "" : "s"})`
|
|
@@ -10740,7 +10759,7 @@ import {
|
|
|
10740
10759
|
findProjectRoot as findProjectRoot27,
|
|
10741
10760
|
loadUsageIndex as loadUsageIndex19,
|
|
10742
10761
|
resolveHaivePaths as resolveHaivePaths24,
|
|
10743
|
-
saveUsageIndex as
|
|
10762
|
+
saveUsageIndex as saveUsageIndex6
|
|
10744
10763
|
} from "@hiveai/core";
|
|
10745
10764
|
function registerMemoryRm(memory2) {
|
|
10746
10765
|
memory2.command("delete <id>").alias("rm").description("Delete a memory file (and its usage entry by default). Mirrors MCP mem_delete. Alias: rm").option("-y, --yes", "skip the confirmation prompt").option("--keep-usage", "do not remove the usage.json entry").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
@@ -10774,7 +10793,7 @@ function registerMemoryRm(memory2) {
|
|
|
10774
10793
|
const idx = await loadUsageIndex19(paths);
|
|
10775
10794
|
if (idx.by_id[id]) {
|
|
10776
10795
|
delete idx.by_id[id];
|
|
10777
|
-
await
|
|
10796
|
+
await saveUsageIndex6(paths, idx);
|
|
10778
10797
|
ui.info("Removed usage entry");
|
|
10779
10798
|
}
|
|
10780
10799
|
}
|
|
@@ -10984,7 +11003,7 @@ import {
|
|
|
10984
11003
|
recordApplied as recordApplied2,
|
|
10985
11004
|
recordRejection as recordRejection4,
|
|
10986
11005
|
resolveHaivePaths as resolveHaivePaths28,
|
|
10987
|
-
saveUsageIndex as
|
|
11006
|
+
saveUsageIndex as saveUsageIndex7
|
|
10988
11007
|
} from "@hiveai/core";
|
|
10989
11008
|
function registerMemoryFeedback(memory2) {
|
|
10990
11009
|
memory2.command("feedback <id>").description(
|
|
@@ -11013,7 +11032,7 @@ function registerMemoryFeedback(memory2) {
|
|
|
11013
11032
|
const outcome = opts.applied ? "applied" : "rejected";
|
|
11014
11033
|
if (opts.applied) recordApplied2(index, id);
|
|
11015
11034
|
else recordRejection4(index, id, opts.reason ?? null);
|
|
11016
|
-
await
|
|
11035
|
+
await saveUsageIndex7(paths, index);
|
|
11017
11036
|
const usage = getUsage19(index, id);
|
|
11018
11037
|
const impact = computeImpact4(target.memory.frontmatter, usage);
|
|
11019
11038
|
if (opts.json) {
|
|
@@ -13488,7 +13507,7 @@ function registerDoctor(program2) {
|
|
|
13488
13507
|
fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
|
|
13489
13508
|
});
|
|
13490
13509
|
}
|
|
13491
|
-
findings.push(...await collectInstallFindings(root, "0.13.
|
|
13510
|
+
findings.push(...await collectInstallFindings(root, "0.13.9"));
|
|
13492
13511
|
findings.push(...await collectToolchainFindings(root));
|
|
13493
13512
|
try {
|
|
13494
13513
|
const legacyRaw = execSync3("haive-mcp --version", {
|
|
@@ -13496,7 +13515,7 @@ function registerDoctor(program2) {
|
|
|
13496
13515
|
timeout: 3e3,
|
|
13497
13516
|
stdio: ["ignore", "pipe", "ignore"]
|
|
13498
13517
|
}).trim();
|
|
13499
|
-
const cliVersion = "0.13.
|
|
13518
|
+
const cliVersion = "0.13.9";
|
|
13500
13519
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
13501
13520
|
findings.push({
|
|
13502
13521
|
severity: "warn",
|
|
@@ -14656,6 +14675,16 @@ function registerEnforce(program2) {
|
|
|
14656
14675
|
process.exit(2);
|
|
14657
14676
|
}
|
|
14658
14677
|
});
|
|
14678
|
+
enforce.command("commit-msg <msgfile>").description(
|
|
14679
|
+
"git commit-msg hook: block a CI-skip directive in a commit that also changes shippable code (GitHub scans the whole message and would skip CI for the entire push). `.ai/`-only sync commits are allowed."
|
|
14680
|
+
).option("-d, --dir <dir>", "project root").action(async (msgfile, opts) => {
|
|
14681
|
+
const root = findProjectRoot52(opts.dir);
|
|
14682
|
+
const verdict = await checkCommitMessageSkipCi(root, msgfile);
|
|
14683
|
+
if (verdict.block) {
|
|
14684
|
+
ui.error(verdict.message);
|
|
14685
|
+
process.exit(1);
|
|
14686
|
+
}
|
|
14687
|
+
});
|
|
14659
14688
|
enforce.command("session-start").description("Claude Code SessionStart hook: inject briefing and write a local briefing marker.").option("-d, --dir <dir>", "project root").option("--task <text>", "task text to rank memories").option("--source <name>", "marker source", "claude-session-start").option("--session-id <id>", "agent session id").action(async (opts) => {
|
|
14660
14689
|
const payload = await readHookPayload();
|
|
14661
14690
|
const root = resolveRoot(opts.dir, payload);
|
|
@@ -15095,7 +15124,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
15095
15124
|
findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
|
|
15096
15125
|
});
|
|
15097
15126
|
}
|
|
15098
|
-
findings.push(...await inspectIntegrationVersions(root, "0.13.
|
|
15127
|
+
findings.push(...await inspectIntegrationVersions(root, "0.13.9"));
|
|
15099
15128
|
if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
|
|
15100
15129
|
const hasBriefing = await hasRecentBriefingMarker2(paths, sessionId);
|
|
15101
15130
|
findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
|
|
@@ -15589,6 +15618,21 @@ var SHIPPABLE_PATH_PREFIXES = [
|
|
|
15589
15618
|
function isShippablePath(file) {
|
|
15590
15619
|
return SHIPPABLE_PATH_PREFIXES.some((prefix) => file.startsWith(prefix)) || VERSION_FILES.includes(file);
|
|
15591
15620
|
}
|
|
15621
|
+
var CI_SKIP_DIRECTIVE = /\[skip ci\]|\[ci skip\]|\[no ci\]|\[skip actions\]|\*\*\*NO_CI\*\*\*|skip-checks: *true/i;
|
|
15622
|
+
async function checkCommitMessageSkipCi(root, msgfile) {
|
|
15623
|
+
const file = path51.isAbsolute(msgfile) ? msgfile : path51.join(root, msgfile);
|
|
15624
|
+
const raw = await readFile23(file, "utf8").catch(() => "");
|
|
15625
|
+
const cleaned = raw.split("\n").filter((line) => !line.startsWith("#")).join("\n");
|
|
15626
|
+
if (!CI_SKIP_DIRECTIVE.test(cleaned)) return { block: false, message: "" };
|
|
15627
|
+
const staged = (await runCommand4("git", ["diff", "--cached", "--name-only"], root).catch(() => "")).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
15628
|
+
const shippable = staged.filter(isShippablePath);
|
|
15629
|
+
if (shippable.length === 0) return { block: false, message: "" };
|
|
15630
|
+
return {
|
|
15631
|
+
block: true,
|
|
15632
|
+
message: "This commit message contains a CI-skip directive ([skip ci] / [ci skip] / [no ci]) but the commit changes shippable code:\n" + shippable.slice(0, 6).map((f) => ` - ${f}`).join("\n") + (shippable.length > 6 ? `
|
|
15633
|
+
\u2026and ${shippable.length - 6} more` : "") + "\nGitHub scans the whole commit message and would skip CI for the ENTIRE push \u2014 your code would land untested.\nFix: reword the message so it does not contain the literal directive (e.g. write 'skip-ci'), or move the\nskip-ci sync into a separate `.ai/`-only commit."
|
|
15634
|
+
};
|
|
15635
|
+
}
|
|
15592
15636
|
async function inspectReleaseVersionState(root, upstream) {
|
|
15593
15637
|
const localEntries = await Promise.all(VERSION_FILES.map(async (file) => [file, await readPackageVersion(root, file)]));
|
|
15594
15638
|
const localVersions = new Map(localEntries);
|
|
@@ -15812,6 +15856,13 @@ haive enforce check --stage pre-commit --dir . || exit $?
|
|
|
15812
15856
|
body: `#!/bin/sh
|
|
15813
15857
|
${ENFORCE_HOOK_MARKER}
|
|
15814
15858
|
haive enforce check --stage pre-push --dir . || exit $?
|
|
15859
|
+
`
|
|
15860
|
+
},
|
|
15861
|
+
{
|
|
15862
|
+
name: "commit-msg",
|
|
15863
|
+
body: `#!/bin/sh
|
|
15864
|
+
${ENFORCE_HOOK_MARKER}
|
|
15865
|
+
haive enforce commit-msg "$1" --dir . || exit $?
|
|
15815
15866
|
`
|
|
15816
15867
|
}
|
|
15817
15868
|
];
|
|
@@ -15831,7 +15882,7 @@ ${hook.body}`, "utf8");
|
|
|
15831
15882
|
}
|
|
15832
15883
|
await chmod2(file, 493);
|
|
15833
15884
|
}
|
|
15834
|
-
ui.success("Installed blocking git enforcement hooks: pre-commit, pre-push");
|
|
15885
|
+
ui.success("Installed blocking git enforcement hooks: pre-commit, pre-push, commit-msg");
|
|
15835
15886
|
}
|
|
15836
15887
|
async function installCiEnforcement(root) {
|
|
15837
15888
|
const workflowPath = path51.join(root, ".github", "workflows", "haive-enforcement.yml");
|
|
@@ -16064,11 +16115,15 @@ import path53 from "path";
|
|
|
16064
16115
|
import { promisify as promisify2 } from "util";
|
|
16065
16116
|
import "commander";
|
|
16066
16117
|
import {
|
|
16118
|
+
appendPreventionEvent as appendPreventionEvent2,
|
|
16067
16119
|
findProjectRoot as findProjectRoot53,
|
|
16068
16120
|
isRetiredMemory as isRetiredMemory3,
|
|
16069
16121
|
loadMemoriesFromDir as loadMemoriesFromDir39,
|
|
16122
|
+
loadUsageIndex as loadUsageIndex29,
|
|
16123
|
+
recordPrevention as recordPrevention2,
|
|
16070
16124
|
resolveHaivePaths as resolveHaivePaths49,
|
|
16071
16125
|
runSensors as runSensors2,
|
|
16126
|
+
saveUsageIndex as saveUsageIndex8,
|
|
16072
16127
|
sensorTargetsFromDiff as sensorTargetsFromDiff2,
|
|
16073
16128
|
serializeMemory as serializeMemory27
|
|
16074
16129
|
} from "@hiveai/core";
|
|
@@ -16103,6 +16158,21 @@ function registerSensors(program2) {
|
|
|
16103
16158
|
const diff = opts.diffFile ? await readFile24(path53.resolve(root, opts.diffFile), "utf8") : await stagedDiff(root);
|
|
16104
16159
|
const targets = sensorTargetsFromDiff2(diff);
|
|
16105
16160
|
const hits = runSensors2(memories, targets.length > 0 ? targets : [{ path: "", content: diff }]);
|
|
16161
|
+
const firedIds = [...new Set(hits.map((hit) => hit.memory_id))];
|
|
16162
|
+
if (firedIds.length > 0) {
|
|
16163
|
+
const usage = await loadUsageIndex29(paths);
|
|
16164
|
+
const recordedIds = [];
|
|
16165
|
+
for (const id of firedIds) if (recordPrevention2(usage, id)) recordedIds.push(id);
|
|
16166
|
+
if (recordedIds.length > 0) {
|
|
16167
|
+
await saveUsageIndex8(paths, usage).catch(() => {
|
|
16168
|
+
});
|
|
16169
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
16170
|
+
for (const id of recordedIds) {
|
|
16171
|
+
await appendPreventionEvent2(paths, { at, id, source: "sensor" }).catch(() => {
|
|
16172
|
+
});
|
|
16173
|
+
}
|
|
16174
|
+
}
|
|
16175
|
+
}
|
|
16106
16176
|
const output = {
|
|
16107
16177
|
scanned: memories.length,
|
|
16108
16178
|
hits: hits.map((hit) => ({
|
|
@@ -16446,7 +16516,8 @@ import {
|
|
|
16446
16516
|
buildDashboard,
|
|
16447
16517
|
findProjectRoot as findProjectRoot55,
|
|
16448
16518
|
loadMemoriesFromDir as loadMemoriesFromDir41,
|
|
16449
|
-
|
|
16519
|
+
loadPreventionEvents,
|
|
16520
|
+
loadUsageIndex as loadUsageIndex30,
|
|
16450
16521
|
resolveHaivePaths as resolveHaivePaths51
|
|
16451
16522
|
} from "@hiveai/core";
|
|
16452
16523
|
function registerDashboard(program2) {
|
|
@@ -16461,11 +16532,13 @@ function registerDashboard(program2) {
|
|
|
16461
16532
|
return;
|
|
16462
16533
|
}
|
|
16463
16534
|
const memories = existsSync78(paths.memoriesDir) ? await loadMemoriesFromDir41(paths.memoriesDir) : [];
|
|
16464
|
-
const usage = await
|
|
16535
|
+
const usage = await loadUsageIndex30(paths);
|
|
16536
|
+
const preventionEvents = await loadPreventionEvents(paths);
|
|
16465
16537
|
const top = Math.max(1, Number.parseInt(opts.top ?? "10", 10) || 10);
|
|
16466
16538
|
const dormantDays = opts.dormantDays ? Number.parseInt(opts.dormantDays, 10) : void 0;
|
|
16467
16539
|
const report = buildDashboard(memories, usage, {
|
|
16468
16540
|
top,
|
|
16541
|
+
preventionEvents,
|
|
16469
16542
|
...dormantDays !== void 0 && Number.isFinite(dormantDays) ? { dormantDays } : {}
|
|
16470
16543
|
});
|
|
16471
16544
|
if (opts.json) {
|
|
@@ -16476,7 +16549,7 @@ function registerDashboard(program2) {
|
|
|
16476
16549
|
});
|
|
16477
16550
|
}
|
|
16478
16551
|
function renderDashboard(r) {
|
|
16479
|
-
const { inventory: inv, impact, sensors, health, decay, corpus } = r;
|
|
16552
|
+
const { inventory: inv, impact, sensors, health, decay, corpus, prevention } = r;
|
|
16480
16553
|
console.log(ui.bold("hAIve dashboard"));
|
|
16481
16554
|
console.log(
|
|
16482
16555
|
` ${ui.dim("corpus:")} ${inv.total} policy memor${inv.total === 1 ? "y" : "ies"} (${inv.active} active, ${inv.retired} retired) \xB7 ${inv.session_recaps} recap(s) \xB7 ~${corpus.est_tokens.toLocaleString()} tokens`
|
|
@@ -16506,6 +16579,27 @@ function renderDashboard(r) {
|
|
|
16506
16579
|
console.log(` ${marker} ${s.id} ${ui.dim(`last fired ${s.last_fired.slice(0, 10)}`)}`);
|
|
16507
16580
|
}
|
|
16508
16581
|
console.log();
|
|
16582
|
+
console.log(ui.bold("Prevention") + ui.dim(" (outcome: sensors that caught a real diff)"));
|
|
16583
|
+
console.log(
|
|
16584
|
+
` ${prevention.total_events > 0 ? ui.green(`${prevention.total_events} catch event(s)`) : "0 catch events"} \xB7 ${prevention.memories_with_catches} memor${prevention.memories_with_catches === 1 ? "y" : "ies"} with catches`
|
|
16585
|
+
);
|
|
16586
|
+
console.log(
|
|
16587
|
+
` ${ui.dim("trend:")} ${prevention.trend.last_7d} in 7d \xB7 ${prevention.trend.last_30d} in 30d ${ui.dim("weekly")} [${prevention.trend.weekly.join(" ")}]`
|
|
16588
|
+
);
|
|
16589
|
+
for (const p of prevention.top.slice(0, 5)) {
|
|
16590
|
+
console.log(
|
|
16591
|
+
` ${ui.green("\u2713")} ${p.prevented_count}\xD7 ${p.id}` + (p.last_prevented_at ? ui.dim(` last ${p.last_prevented_at.slice(0, 10)}`) : "")
|
|
16592
|
+
);
|
|
16593
|
+
}
|
|
16594
|
+
if (prevention.recurrence.recurring_count > 0) {
|
|
16595
|
+
console.log(
|
|
16596
|
+
` ${ui.yellow("recurrence:")} ${prevention.recurrence.recurring_count} lesson(s) re-introduced after capture ` + ui.dim("(caught on \u22652 distinct days)")
|
|
16597
|
+
);
|
|
16598
|
+
for (const r2 of prevention.recurrence.top.slice(0, 5)) {
|
|
16599
|
+
console.log(` ${ui.yellow("\u21BB")} ${r2.distinct_days} days \xB7 ${r2.catches}\xD7 ${r2.id}`);
|
|
16600
|
+
}
|
|
16601
|
+
}
|
|
16602
|
+
console.log();
|
|
16509
16603
|
console.log(ui.bold("Health"));
|
|
16510
16604
|
console.log(
|
|
16511
16605
|
` stale ${warnNum(health.stale)} \xB7 anchorless ${warnNum(health.anchorless)} \xB7 pending ${health.pending} \xB7 prune candidates ${warnNum(health.prune_candidates)}`
|
|
@@ -16542,7 +16636,7 @@ function warnNum(n) {
|
|
|
16542
16636
|
|
|
16543
16637
|
// src/index.ts
|
|
16544
16638
|
var program = new Command58();
|
|
16545
|
-
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.13.
|
|
16639
|
+
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.13.9").option("--advanced", "show maintenance and experimental commands in help");
|
|
16546
16640
|
registerInit(program);
|
|
16547
16641
|
registerWelcome(program);
|
|
16548
16642
|
registerResolveProject(program);
|