@hiveai/cli 0.13.5 → 0.13.8
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 +139 -44
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -910,6 +910,10 @@ function registerBriefing(program2) {
|
|
|
910
910
|
return;
|
|
911
911
|
}
|
|
912
912
|
const ownMemories = await loadMemoriesFromDir3(paths.memoriesDir);
|
|
913
|
+
const POLICY_TYPES = /* @__PURE__ */ new Set(["decision", "gotcha", "architecture", "convention"]);
|
|
914
|
+
const anchoredPolicyIds = markerFiles.length > 0 ? ownMemories.map((m) => m.memory).filter(
|
|
915
|
+
(mem) => POLICY_TYPES.has(mem.frontmatter.type) && mem.frontmatter.status === "validated" && memoryMatchesAnchorPaths(mem, markerFiles)
|
|
916
|
+
).map((mem) => mem.frontmatter.id) : [];
|
|
913
917
|
const externalRoots = [];
|
|
914
918
|
if (opts.include && opts.include.length > 0) {
|
|
915
919
|
for (const includePath of opts.include) {
|
|
@@ -1063,11 +1067,14 @@ function registerBriefing(program2) {
|
|
|
1063
1067
|
if (ids.length > 0) {
|
|
1064
1068
|
await trackReads(paths, ids).catch(() => {
|
|
1065
1069
|
});
|
|
1070
|
+
}
|
|
1071
|
+
const markerIds = [.../* @__PURE__ */ new Set([...ids, ...anchoredPolicyIds])];
|
|
1072
|
+
if (markerIds.length > 0) {
|
|
1066
1073
|
await writeBriefingMarker(paths, {
|
|
1067
1074
|
task: opts.task ?? "CLI briefing",
|
|
1068
1075
|
source: "haive-briefing-cli",
|
|
1069
1076
|
sessionId: process.env.HAIVE_SESSION_ID,
|
|
1070
|
-
memoryIds:
|
|
1077
|
+
memoryIds: markerIds,
|
|
1071
1078
|
files: filePaths
|
|
1072
1079
|
}).catch(() => {
|
|
1073
1080
|
});
|
|
@@ -3012,7 +3019,7 @@ ${SEED_FOOTER(stack)}` });
|
|
|
3012
3019
|
}
|
|
3013
3020
|
|
|
3014
3021
|
// src/commands/init.ts
|
|
3015
|
-
var HAIVE_GITHUB_ACTION_REF = `v${"0.13.
|
|
3022
|
+
var HAIVE_GITHUB_ACTION_REF = `v${"0.13.8"}`;
|
|
3016
3023
|
var PROJECT_CONTEXT_TEMPLATE = `# Project context
|
|
3017
3024
|
|
|
3018
3025
|
> Generated by \`haive init\`. Run \`haive init --bootstrap\` to auto-fill from your codebase,
|
|
@@ -6065,7 +6072,7 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
6065
6072
|
return {
|
|
6066
6073
|
id,
|
|
6067
6074
|
summary,
|
|
6068
|
-
developer_message: quoteBlock || `
|
|
6075
|
+
developer_message: quoteBlock || `A potentially incompatible external change was detected (${id}). Do you want me to analyze the impact and propose updates?`
|
|
6069
6076
|
};
|
|
6070
6077
|
};
|
|
6071
6078
|
for (const m of outputMemories) {
|
|
@@ -7912,7 +7919,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
7912
7919
|
};
|
|
7913
7920
|
}
|
|
7914
7921
|
var SERVER_NAME = "haive";
|
|
7915
|
-
var SERVER_VERSION = "0.13.
|
|
7922
|
+
var SERVER_VERSION = "0.13.8";
|
|
7916
7923
|
function jsonResult(data) {
|
|
7917
7924
|
return {
|
|
7918
7925
|
content: [
|
|
@@ -9220,26 +9227,26 @@ function registerSync(program2) {
|
|
|
9220
9227
|
const slugParts = result.file.replace(/[^a-z0-9]/gi, "-").toLowerCase();
|
|
9221
9228
|
const slug = `dep-major-bump-${slugParts}-${Date.now().toString(36)}`;
|
|
9222
9229
|
const depList = majorBumps.map((c) => `- \u{1F534} **${c.name}** : \`${c.from}\` \u2192 \`${c.to}\``).join("\n");
|
|
9223
|
-
const body = `## \u26A0\uFE0F Action
|
|
9230
|
+
const body = `## \u26A0\uFE0F Action required \u2014 human confirmation required
|
|
9224
9231
|
|
|
9225
|
-
|
|
9226
|
-
|
|
9232
|
+
Dependencies in \`${result.file}\` changed major version.
|
|
9233
|
+
A major version can contain **breaking changes** that affect this project.
|
|
9227
9234
|
|
|
9228
9235
|
${depList}
|
|
9229
9236
|
|
|
9230
9237
|
---
|
|
9231
9238
|
|
|
9232
|
-
**\u{1F6AB}
|
|
9239
|
+
**\u{1F6AB} Do not modify code autonomously.**
|
|
9233
9240
|
|
|
9234
|
-
|
|
9241
|
+
Inform the developer with this message:
|
|
9235
9242
|
|
|
9236
|
-
>
|
|
9243
|
+
> *"I detected that ${majorBumps.map((c) => `\`${c.name}\``).join(", ")} changed major version (${majorBumps.map((c) => `${c.from} \u2192 ${c.to}`).join(", ")}). This can introduce incompatibilities in this project. Do you want me to analyze the impact and propose updates?"*
|
|
9237
9244
|
|
|
9238
|
-
|
|
9245
|
+
Wait for **explicit confirmation** before acting.
|
|
9239
9246
|
|
|
9240
|
-
**
|
|
9241
|
-
-
|
|
9242
|
-
-
|
|
9247
|
+
**Next steps (if confirmed):**
|
|
9248
|
+
- Check the CHANGELOG: \`haive memory import-changelog --from node_modules/<pkg>/CHANGELOG.md\`
|
|
9249
|
+
- Verify anchored memories: \`haive memory verify\``;
|
|
9243
9250
|
const fm = buildFrontmatter6({
|
|
9244
9251
|
type: "gotcha",
|
|
9245
9252
|
slug,
|
|
@@ -9287,28 +9294,28 @@ Attends une **confirmation explicite** avant d'agir.
|
|
|
9287
9294
|
const breakingList = breaking.map((c) => `- \u{1F534} **${c.kind}** : ${c.description}`).join("\n");
|
|
9288
9295
|
const addList = additive.length > 0 ? `
|
|
9289
9296
|
|
|
9290
|
-
###
|
|
9297
|
+
### Non-breaking changes (additive)
|
|
9291
9298
|
` + additive.map((c) => `- \u{1F7E2} ${c.description}`).join("\n") : "";
|
|
9292
|
-
const body = `## \u26A0\uFE0F Action
|
|
9299
|
+
const body = `## \u26A0\uFE0F Action required \u2014 human confirmation required
|
|
9293
9300
|
|
|
9294
|
-
|
|
9295
|
-
|
|
9301
|
+
Contract **\`${diff.contract}\`** (\`${diff.file}\`) was modified.
|
|
9302
|
+
**Breaking changes** were detected \u2014 this project may consume that contract.
|
|
9296
9303
|
|
|
9297
9304
|
${breakingList}${addList}
|
|
9298
9305
|
|
|
9299
9306
|
---
|
|
9300
9307
|
|
|
9301
|
-
**\u{1F6AB}
|
|
9308
|
+
**\u{1F6AB} Do not modify code autonomously.**
|
|
9302
9309
|
|
|
9303
|
-
|
|
9310
|
+
Inform the developer with this message:
|
|
9304
9311
|
|
|
9305
|
-
>
|
|
9312
|
+
> *"I detected that contract \`${diff.contract}\` changed: ${breaking.length} breaking change(s) detected. This project may depend on that contract. Do you want me to analyze the impact and propose updates?"*
|
|
9306
9313
|
|
|
9307
|
-
|
|
9314
|
+
Wait for **explicit confirmation** before acting.
|
|
9308
9315
|
|
|
9309
|
-
**
|
|
9310
|
-
-
|
|
9311
|
-
-
|
|
9316
|
+
**Next steps (if confirmed):**
|
|
9317
|
+
- Search usages: \`haive memory for-files <affected files>\`
|
|
9318
|
+
- Check related memories: \`haive memory search ${diff.contract}\``;
|
|
9312
9319
|
const fm = buildFrontmatter6({
|
|
9313
9320
|
type: "gotcha",
|
|
9314
9321
|
slug,
|
|
@@ -12671,7 +12678,7 @@ import {
|
|
|
12671
12678
|
} from "@hiveai/core";
|
|
12672
12679
|
function registerEval(program2) {
|
|
12673
12680
|
program2.command("eval").description(
|
|
12674
|
-
"Rigorous, repeatable quality eval: do the right memories surface (retrieval) and do the right sensors fire (catch-rate)? Emits a
|
|
12681
|
+
"Rigorous, repeatable quality eval: do the right memories surface (retrieval) and do the right sensors fire (catch-rate)? Emits a numeric 0\u2013100 score. Uses .ai/eval cases via --spec, or auto-synthesizes cases from anchored memories."
|
|
12675
12682
|
).option("--spec <file>", "JSON eval spec ({ retrieval: [...], sensors: [...] })").option("--semantic-only", "self-eval probes by title alone (no anchor files) \u2014 harder retrieval", false).option("-k, --top <n>", "briefing top-k considered a hit", "8").option("--json", "emit JSON", false).option("--out <file>", "write a Markdown report").option("--fail-under <score>", "exit non-zero if the overall score is below this (0\u2013100) \u2014 for CI gates").option("--baseline", "save this run as the baseline (.ai/eval/baseline.json) for future --compare", false).option("--compare", "diff this run against the saved baseline and print the delta", false).option("--baseline-file <path>", "baseline file to read/write (default: .ai/eval/baseline.json)").option("--fail-on-regression", "with --compare, exit non-zero if the score dropped vs the baseline", false).option("--regression-gate", "CI-safe gate: compare against the baseline IF one exists (fail on regression), else no-op", false).option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
12676
12683
|
const root = findProjectRoot42(opts.dir);
|
|
12677
12684
|
const paths = resolveHaivePaths38(root);
|
|
@@ -13481,7 +13488,7 @@ function registerDoctor(program2) {
|
|
|
13481
13488
|
fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
|
|
13482
13489
|
});
|
|
13483
13490
|
}
|
|
13484
|
-
findings.push(...await collectInstallFindings(root, "0.13.
|
|
13491
|
+
findings.push(...await collectInstallFindings(root, "0.13.8"));
|
|
13485
13492
|
findings.push(...await collectToolchainFindings(root));
|
|
13486
13493
|
try {
|
|
13487
13494
|
const legacyRaw = execSync3("haive-mcp --version", {
|
|
@@ -13489,7 +13496,7 @@ function registerDoctor(program2) {
|
|
|
13489
13496
|
timeout: 3e3,
|
|
13490
13497
|
stdio: ["ignore", "pipe", "ignore"]
|
|
13491
13498
|
}).trim();
|
|
13492
|
-
const cliVersion = "0.13.
|
|
13499
|
+
const cliVersion = "0.13.8";
|
|
13493
13500
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
13494
13501
|
findings.push({
|
|
13495
13502
|
severity: "warn",
|
|
@@ -14644,7 +14651,20 @@ function registerEnforce(program2) {
|
|
|
14644
14651
|
).option("-d, --dir <dir>", "project root").option("--explain", "group findings by blocking/review/info and show repair commands", false).option("--json", "emit JSON", false).action(async (opts) => {
|
|
14645
14652
|
const report = await buildFinishReport(opts.dir);
|
|
14646
14653
|
printReport(report, Boolean(opts.json), Boolean(opts.explain));
|
|
14647
|
-
if (report.should_block)
|
|
14654
|
+
if (report.should_block) {
|
|
14655
|
+
if (!opts.json) printNextRequiredAction(report);
|
|
14656
|
+
process.exit(2);
|
|
14657
|
+
}
|
|
14658
|
+
});
|
|
14659
|
+
enforce.command("commit-msg <msgfile>").description(
|
|
14660
|
+
"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."
|
|
14661
|
+
).option("-d, --dir <dir>", "project root").action(async (msgfile, opts) => {
|
|
14662
|
+
const root = findProjectRoot52(opts.dir);
|
|
14663
|
+
const verdict = await checkCommitMessageSkipCi(root, msgfile);
|
|
14664
|
+
if (verdict.block) {
|
|
14665
|
+
ui.error(verdict.message);
|
|
14666
|
+
process.exit(1);
|
|
14667
|
+
}
|
|
14648
14668
|
});
|
|
14649
14669
|
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) => {
|
|
14650
14670
|
const payload = await readHookPayload();
|
|
@@ -15085,7 +15105,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
15085
15105
|
findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
|
|
15086
15106
|
});
|
|
15087
15107
|
}
|
|
15088
|
-
findings.push(...await inspectIntegrationVersions(root, "0.13.
|
|
15108
|
+
findings.push(...await inspectIntegrationVersions(root, "0.13.8"));
|
|
15089
15109
|
if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
|
|
15090
15110
|
const hasBriefing = await hasRecentBriefingMarker2(paths, sessionId);
|
|
15091
15111
|
findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
|
|
@@ -15579,6 +15599,21 @@ var SHIPPABLE_PATH_PREFIXES = [
|
|
|
15579
15599
|
function isShippablePath(file) {
|
|
15580
15600
|
return SHIPPABLE_PATH_PREFIXES.some((prefix) => file.startsWith(prefix)) || VERSION_FILES.includes(file);
|
|
15581
15601
|
}
|
|
15602
|
+
var CI_SKIP_DIRECTIVE = /\[skip ci\]|\[ci skip\]|\[no ci\]|\[skip actions\]|\*\*\*NO_CI\*\*\*|skip-checks: *true/i;
|
|
15603
|
+
async function checkCommitMessageSkipCi(root, msgfile) {
|
|
15604
|
+
const file = path51.isAbsolute(msgfile) ? msgfile : path51.join(root, msgfile);
|
|
15605
|
+
const raw = await readFile23(file, "utf8").catch(() => "");
|
|
15606
|
+
const cleaned = raw.split("\n").filter((line) => !line.startsWith("#")).join("\n");
|
|
15607
|
+
if (!CI_SKIP_DIRECTIVE.test(cleaned)) return { block: false, message: "" };
|
|
15608
|
+
const staged = (await runCommand4("git", ["diff", "--cached", "--name-only"], root).catch(() => "")).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
15609
|
+
const shippable = staged.filter(isShippablePath);
|
|
15610
|
+
if (shippable.length === 0) return { block: false, message: "" };
|
|
15611
|
+
return {
|
|
15612
|
+
block: true,
|
|
15613
|
+
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 ? `
|
|
15614
|
+
\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."
|
|
15615
|
+
};
|
|
15616
|
+
}
|
|
15582
15617
|
async function inspectReleaseVersionState(root, upstream) {
|
|
15583
15618
|
const localEntries = await Promise.all(VERSION_FILES.map(async (file) => [file, await readPackageVersion(root, file)]));
|
|
15584
15619
|
const localVersions = new Map(localEntries);
|
|
@@ -15688,11 +15723,22 @@ async function verifyGithubActionsForHead(root, status) {
|
|
|
15688
15723
|
}];
|
|
15689
15724
|
}
|
|
15690
15725
|
if (runs.length === 0) {
|
|
15726
|
+
const headMsg = (await runCommand4("git", ["log", "-1", "--pretty=%B"], root).catch(() => "")).trim();
|
|
15727
|
+
if (/\[skip ci\]|\[ci skip\]|\[no ci\]|\*\*\*NO_CI\*\*\*|skip-checks: *true/i.test(headMsg)) {
|
|
15728
|
+
return [{
|
|
15729
|
+
severity: "error",
|
|
15730
|
+
code: "github-actions-skipped-by-message",
|
|
15731
|
+
message: "No GitHub Actions runs for HEAD because the HEAD commit message contains a CI-skip directive ([skip ci] / [ci skip] / [no ci]) \u2014 this skips the WHOLE push, including code.",
|
|
15732
|
+
fix: "Reword the HEAD commit so its message (subject AND body) does not contain the literal skip-ci directive \u2014 write it as 'skip-ci'. Then re-push, or trigger CI manually with `gh workflow run <workflow.yml> --ref <branch>`.",
|
|
15733
|
+
reason: "GitHub scans the entire commit message; a code commit whose message includes a skip-ci directive silently skips CI for the whole push.",
|
|
15734
|
+
impact: 60
|
|
15735
|
+
}];
|
|
15736
|
+
}
|
|
15691
15737
|
return [{
|
|
15692
15738
|
severity: "error",
|
|
15693
15739
|
code: "github-actions-runs-missing",
|
|
15694
15740
|
message: "No GitHub Actions runs were found for HEAD.",
|
|
15695
|
-
fix: "Wait for GitHub to create the workflow runs, or verify that the push was not skipped by a
|
|
15741
|
+
fix: "Wait for GitHub to create the workflow runs, or verify that the push was not skipped by a skip-ci head commit; rerun `haive enforce finish` after the runs appear.",
|
|
15696
15742
|
impact: 50
|
|
15697
15743
|
}];
|
|
15698
15744
|
}
|
|
@@ -15707,21 +15753,35 @@ async function verifyGithubActionsForHead(root, status) {
|
|
|
15707
15753
|
}];
|
|
15708
15754
|
}
|
|
15709
15755
|
const failed = runs.filter((run) => run.conclusion !== "success");
|
|
15710
|
-
|
|
15756
|
+
const failedCore = failed.filter((run) => !isExternalTransientWorkflow(run));
|
|
15757
|
+
const failedExternal = failed.filter((run) => isExternalTransientWorkflow(run));
|
|
15758
|
+
if (failedCore.length > 0) {
|
|
15711
15759
|
return [{
|
|
15712
15760
|
severity: "error",
|
|
15713
15761
|
code: "github-actions-failed",
|
|
15714
|
-
message: `${
|
|
15762
|
+
message: `${failedCore.length}/${runs.length} GitHub Actions workflow run(s) for HEAD did not pass: ${formatGithubRunNames(failedCore)}.`,
|
|
15715
15763
|
fix: "Inspect the failed run logs with `gh run view <run-id> --log`, fix the issue, push the fix, then rerun `haive enforce finish`.",
|
|
15716
15764
|
impact: 80
|
|
15717
15765
|
}];
|
|
15718
15766
|
}
|
|
15767
|
+
if (failedExternal.length > 0) {
|
|
15768
|
+
return [{
|
|
15769
|
+
severity: "info",
|
|
15770
|
+
code: "github-actions-external-transient",
|
|
15771
|
+
message: `${failedExternal.length} external/transient workflow run(s) for HEAD did not pass (non-blocking): ${formatGithubRunNames(failedExternal)}. All core workflows passed.`,
|
|
15772
|
+
fix: "External integrations can fail on transient network/timeout. Re-run with `gh run rerun <run-id>` if you want them green \u2014 not required to finish."
|
|
15773
|
+
}];
|
|
15774
|
+
}
|
|
15719
15775
|
return [{
|
|
15720
15776
|
severity: "ok",
|
|
15721
15777
|
code: "github-actions-pass",
|
|
15722
15778
|
message: `All ${runs.length} GitHub Actions workflow run(s) for HEAD completed successfully.`
|
|
15723
15779
|
}];
|
|
15724
15780
|
}
|
|
15781
|
+
function isExternalTransientWorkflow(run) {
|
|
15782
|
+
const label = `${run.workflowName ?? ""} ${run.name ?? ""}`.toLowerCase();
|
|
15783
|
+
return /\bsonar(qube|cloud)?\b|\bcodeql\b|\bsnyk\b|\bcodecov\b/.test(label);
|
|
15784
|
+
}
|
|
15725
15785
|
async function githubRemoteForCurrentBranch(root) {
|
|
15726
15786
|
const branch = (await runCommand4("git", ["branch", "--show-current"], root).catch(() => "")).trim();
|
|
15727
15787
|
const branchRemote = branch ? (await runCommand4("git", ["config", "--get", `branch.${branch}.remote`], root).catch(() => "")).trim() : "";
|
|
@@ -15777,6 +15837,13 @@ haive enforce check --stage pre-commit --dir . || exit $?
|
|
|
15777
15837
|
body: `#!/bin/sh
|
|
15778
15838
|
${ENFORCE_HOOK_MARKER}
|
|
15779
15839
|
haive enforce check --stage pre-push --dir . || exit $?
|
|
15840
|
+
`
|
|
15841
|
+
},
|
|
15842
|
+
{
|
|
15843
|
+
name: "commit-msg",
|
|
15844
|
+
body: `#!/bin/sh
|
|
15845
|
+
${ENFORCE_HOOK_MARKER}
|
|
15846
|
+
haive enforce commit-msg "$1" --dir . || exit $?
|
|
15780
15847
|
`
|
|
15781
15848
|
}
|
|
15782
15849
|
];
|
|
@@ -15796,7 +15863,7 @@ ${hook.body}`, "utf8");
|
|
|
15796
15863
|
}
|
|
15797
15864
|
await chmod2(file, 493);
|
|
15798
15865
|
}
|
|
15799
|
-
ui.success("Installed blocking git enforcement hooks: pre-commit, pre-push");
|
|
15866
|
+
ui.success("Installed blocking git enforcement hooks: pre-commit, pre-push, commit-msg");
|
|
15800
15867
|
}
|
|
15801
15868
|
async function installCiEnforcement(root) {
|
|
15802
15869
|
const workflowPath = path51.join(root, ".github", "workflows", "haive-enforcement.yml");
|
|
@@ -15871,6 +15938,13 @@ function printFinding(finding, explain = false) {
|
|
|
15871
15938
|
if (explain && finding.memory_ids?.length) console.log(ui.dim(` memories: ${finding.memory_ids.join(", ")}`));
|
|
15872
15939
|
if (finding.fix) console.log(ui.dim(`${explain ? " repair: " : " fix: "}${finding.fix}`));
|
|
15873
15940
|
}
|
|
15941
|
+
function printNextRequiredAction(report) {
|
|
15942
|
+
const blocker = report.findings.find((f) => f.severity === "error" && f.fix);
|
|
15943
|
+
if (!blocker) return;
|
|
15944
|
+
console.log("");
|
|
15945
|
+
console.log(ui.bold("\u2192 NEXT REQUIRED ACTION") + ui.dim(` (${blocker.code})`));
|
|
15946
|
+
for (const line of blocker.fix.split("\n")) console.log(` ${line}`);
|
|
15947
|
+
}
|
|
15874
15948
|
async function applyLightweightRepairs(root, paths) {
|
|
15875
15949
|
await applyAutopilotRepairs(root, paths, {
|
|
15876
15950
|
applyConfig: false,
|
|
@@ -15974,13 +16048,13 @@ async function readStdin2(maxBytes) {
|
|
|
15974
16048
|
setTimeout(finish, 2e3);
|
|
15975
16049
|
});
|
|
15976
16050
|
}
|
|
16051
|
+
var ATOMIC_STAGE_EXCLUDE = ["/.usage/", "/.runtime/", "/.cache/"];
|
|
15977
16052
|
async function stageResyncedArtifacts(root, paths) {
|
|
15978
|
-
const
|
|
15979
|
-
const
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
await runCommand4("git", ["add", "--", rel], root).catch(() => {
|
|
16053
|
+
const aiRel = path51.relative(root, paths.haiveDir);
|
|
16054
|
+
const out = await runCommand4("git", ["diff", "--name-only", "--", aiRel], root).catch(() => "");
|
|
16055
|
+
const toStage = out.split("\n").map((line) => line.trim()).filter(Boolean).filter((file) => !ATOMIC_STAGE_EXCLUDE.some((excl) => `/${file}`.includes(excl)));
|
|
16056
|
+
if (toStage.length === 0) return;
|
|
16057
|
+
await runCommand4("git", ["add", "--", ...toStage], root).catch(() => {
|
|
15984
16058
|
});
|
|
15985
16059
|
}
|
|
15986
16060
|
function runCommand4(cmd, args, cwd) {
|
|
@@ -16025,8 +16099,11 @@ import {
|
|
|
16025
16099
|
findProjectRoot as findProjectRoot53,
|
|
16026
16100
|
isRetiredMemory as isRetiredMemory3,
|
|
16027
16101
|
loadMemoriesFromDir as loadMemoriesFromDir39,
|
|
16102
|
+
loadUsageIndex as loadUsageIndex29,
|
|
16103
|
+
recordPrevention,
|
|
16028
16104
|
resolveHaivePaths as resolveHaivePaths49,
|
|
16029
16105
|
runSensors as runSensors2,
|
|
16106
|
+
saveUsageIndex as saveUsageIndex7,
|
|
16030
16107
|
sensorTargetsFromDiff as sensorTargetsFromDiff2,
|
|
16031
16108
|
serializeMemory as serializeMemory27
|
|
16032
16109
|
} from "@hiveai/core";
|
|
@@ -16061,6 +16138,14 @@ function registerSensors(program2) {
|
|
|
16061
16138
|
const diff = opts.diffFile ? await readFile24(path53.resolve(root, opts.diffFile), "utf8") : await stagedDiff(root);
|
|
16062
16139
|
const targets = sensorTargetsFromDiff2(diff);
|
|
16063
16140
|
const hits = runSensors2(memories, targets.length > 0 ? targets : [{ path: "", content: diff }]);
|
|
16141
|
+
const firedIds = [...new Set(hits.map((hit) => hit.memory_id))];
|
|
16142
|
+
if (firedIds.length > 0) {
|
|
16143
|
+
const usage = await loadUsageIndex29(paths);
|
|
16144
|
+
let recorded = 0;
|
|
16145
|
+
for (const id of firedIds) if (recordPrevention(usage, id)) recorded++;
|
|
16146
|
+
if (recorded > 0) await saveUsageIndex7(paths, usage).catch(() => {
|
|
16147
|
+
});
|
|
16148
|
+
}
|
|
16064
16149
|
const output = {
|
|
16065
16150
|
scanned: memories.length,
|
|
16066
16151
|
hits: hits.map((hit) => ({
|
|
@@ -16404,7 +16489,7 @@ import {
|
|
|
16404
16489
|
buildDashboard,
|
|
16405
16490
|
findProjectRoot as findProjectRoot55,
|
|
16406
16491
|
loadMemoriesFromDir as loadMemoriesFromDir41,
|
|
16407
|
-
loadUsageIndex as
|
|
16492
|
+
loadUsageIndex as loadUsageIndex30,
|
|
16408
16493
|
resolveHaivePaths as resolveHaivePaths51
|
|
16409
16494
|
} from "@hiveai/core";
|
|
16410
16495
|
function registerDashboard(program2) {
|
|
@@ -16419,7 +16504,7 @@ function registerDashboard(program2) {
|
|
|
16419
16504
|
return;
|
|
16420
16505
|
}
|
|
16421
16506
|
const memories = existsSync78(paths.memoriesDir) ? await loadMemoriesFromDir41(paths.memoriesDir) : [];
|
|
16422
|
-
const usage = await
|
|
16507
|
+
const usage = await loadUsageIndex30(paths);
|
|
16423
16508
|
const top = Math.max(1, Number.parseInt(opts.top ?? "10", 10) || 10);
|
|
16424
16509
|
const dormantDays = opts.dormantDays ? Number.parseInt(opts.dormantDays, 10) : void 0;
|
|
16425
16510
|
const report = buildDashboard(memories, usage, {
|
|
@@ -16434,7 +16519,7 @@ function registerDashboard(program2) {
|
|
|
16434
16519
|
});
|
|
16435
16520
|
}
|
|
16436
16521
|
function renderDashboard(r) {
|
|
16437
|
-
const { inventory: inv, impact, sensors, health, decay, corpus } = r;
|
|
16522
|
+
const { inventory: inv, impact, sensors, health, decay, corpus, prevention } = r;
|
|
16438
16523
|
console.log(ui.bold("hAIve dashboard"));
|
|
16439
16524
|
console.log(
|
|
16440
16525
|
` ${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`
|
|
@@ -16464,6 +16549,16 @@ function renderDashboard(r) {
|
|
|
16464
16549
|
console.log(` ${marker} ${s.id} ${ui.dim(`last fired ${s.last_fired.slice(0, 10)}`)}`);
|
|
16465
16550
|
}
|
|
16466
16551
|
console.log();
|
|
16552
|
+
console.log(ui.bold("Prevention") + ui.dim(" (outcome: sensors that caught a real diff)"));
|
|
16553
|
+
console.log(
|
|
16554
|
+
` ${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`
|
|
16555
|
+
);
|
|
16556
|
+
for (const p of prevention.top.slice(0, 5)) {
|
|
16557
|
+
console.log(
|
|
16558
|
+
` ${ui.green("\u2713")} ${p.prevented_count}\xD7 ${p.id}` + (p.last_prevented_at ? ui.dim(` last ${p.last_prevented_at.slice(0, 10)}`) : "")
|
|
16559
|
+
);
|
|
16560
|
+
}
|
|
16561
|
+
console.log();
|
|
16467
16562
|
console.log(ui.bold("Health"));
|
|
16468
16563
|
console.log(
|
|
16469
16564
|
` stale ${warnNum(health.stale)} \xB7 anchorless ${warnNum(health.anchorless)} \xB7 pending ${health.pending} \xB7 prune candidates ${warnNum(health.prune_candidates)}`
|
|
@@ -16500,7 +16595,7 @@ function warnNum(n) {
|
|
|
16500
16595
|
|
|
16501
16596
|
// src/index.ts
|
|
16502
16597
|
var program = new Command58();
|
|
16503
|
-
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.13.
|
|
16598
|
+
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.13.8").option("--advanced", "show maintenance and experimental commands in help");
|
|
16504
16599
|
registerInit(program);
|
|
16505
16600
|
registerWelcome(program);
|
|
16506
16601
|
registerResolveProject(program);
|