@hiveai/cli 0.13.1 → 0.13.7
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 +121 -55
- 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.7"}`;
|
|
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,
|
|
@@ -3749,7 +3756,7 @@ async function installClaudeHooks(opts) {
|
|
|
3749
3756
|
}
|
|
3750
3757
|
function registerInstallHooks(program2) {
|
|
3751
3758
|
program2.command("install-hooks [target]").description(
|
|
3752
|
-
"Install hAIve hooks. Targets:\n\n git (default) post-merge / post-rewrite / pre-push for haive sync + precommit\n claude SessionStart + PreToolUse + PostToolUse + SessionEnd hooks\n for briefing injection, pre-edit blocking, and capture (Claude Code only)\n\n Examples:\n haive install-hooks # git hooks (legacy default)\n haive install-hooks git\n haive install-hooks claude\n haive install-hooks claude --scope project\n haive install-hooks claude --uninstall\n"
|
|
3759
|
+
"Install hAIve hooks (same effect as `haive enforce install`, kept for back-compat). Targets:\n\n git (default) post-merge / post-rewrite / pre-push for haive sync + precommit\n claude SessionStart + PreToolUse + PostToolUse + SessionEnd hooks\n for briefing injection, pre-edit blocking, and capture (Claude Code only)\n\n Examples:\n haive install-hooks # git hooks (legacy default)\n haive install-hooks git\n haive install-hooks claude\n haive install-hooks claude --scope project\n haive install-hooks claude --uninstall\n"
|
|
3753
3760
|
).option("-d, --dir <dir>", "project root").option("--force", "overwrite existing hooks (git target only)").option("--scope <scope>", "claude target: 'user' (~/.claude) or 'project' (.claude/)", "user").option("--uninstall", "remove previously installed hAIve hooks (claude target only)").option("--settings <path>", "explicit path to settings.json (claude target only)").action(async (target, opts) => {
|
|
3754
3761
|
const t = (target ?? "git").toLowerCase();
|
|
3755
3762
|
if (t === "git") {
|
|
@@ -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.7";
|
|
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,
|
|
@@ -9505,8 +9512,8 @@ import {
|
|
|
9505
9512
|
suggestSensorFromMemory as suggestSensorFromMemory3
|
|
9506
9513
|
} from "@hiveai/core";
|
|
9507
9514
|
function registerMemoryAdd(memory2) {
|
|
9508
|
-
memory2.command("add").description(
|
|
9509
|
-
`Save a piece of knowledge as a persistent memory.
|
|
9515
|
+
memory2.command("save").alias("add").description(
|
|
9516
|
+
`Save a piece of knowledge as a persistent memory. Mirrors MCP mem_save. Alias: add.
|
|
9510
9517
|
|
|
9511
9518
|
Memory types:
|
|
9512
9519
|
skill \u2014 reusable procedure/playbook agents follow for a recurring task (e.g. deploy, review)
|
|
@@ -10555,7 +10562,7 @@ function registerMemoryPending(memory2) {
|
|
|
10555
10562
|
const pending = all.filter(filterFn);
|
|
10556
10563
|
if (pending.length === 0) {
|
|
10557
10564
|
ui.info("No draft or proposed memories awaiting review.");
|
|
10558
|
-
ui.info("Drafts are created by `haive memory
|
|
10565
|
+
ui.info("Drafts are created by `haive memory save` without `--status validated`.");
|
|
10559
10566
|
return;
|
|
10560
10567
|
}
|
|
10561
10568
|
pending.sort(
|
|
@@ -10612,7 +10619,7 @@ import {
|
|
|
10612
10619
|
trackReads as trackReads4
|
|
10613
10620
|
} from "@hiveai/core";
|
|
10614
10621
|
function registerMemoryQuery(memory2) {
|
|
10615
|
-
memory2.command("
|
|
10622
|
+
memory2.command("search <text>").alias("query").description("Search memories by id, tag, or substring (AND, OR fallback). Mirrors MCP mem_search. Alias: query").option("-d, --dir <dir>", "project root").option("--limit <n>", "max results", "20").option("--scope <scope>", "personal | team | module").option("--status <csv>", "filter by status (draft,proposed,validated,stale,rejected)").option("--show-rejected", "include rejected memories (hidden by default)").action(async (text, opts) => {
|
|
10616
10623
|
const root = findProjectRoot25(opts.dir);
|
|
10617
10624
|
const paths = resolveHaivePaths22(root);
|
|
10618
10625
|
if (!existsSync47(paths.memoriesDir)) {
|
|
@@ -10736,7 +10743,7 @@ import {
|
|
|
10736
10743
|
saveUsageIndex as saveUsageIndex5
|
|
10737
10744
|
} from "@hiveai/core";
|
|
10738
10745
|
function registerMemoryRm(memory2) {
|
|
10739
|
-
memory2.command("
|
|
10746
|
+
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) => {
|
|
10740
10747
|
const root = findProjectRoot27(opts.dir);
|
|
10741
10748
|
const paths = resolveHaivePaths24(root);
|
|
10742
10749
|
if (!existsSync49(paths.memoriesDir)) {
|
|
@@ -10787,7 +10794,7 @@ import {
|
|
|
10787
10794
|
resolveHaivePaths as resolveHaivePaths25
|
|
10788
10795
|
} from "@hiveai/core";
|
|
10789
10796
|
function registerMemoryShow(memory2) {
|
|
10790
|
-
memory2.command("
|
|
10797
|
+
memory2.command("get <id>").alias("show").description("Print a memory's frontmatter, body, and confidence/usage. Mirrors MCP mem_get. Alias: show").option("--raw", "print the raw file contents instead of a summary").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
10791
10798
|
const root = findProjectRoot28(opts.dir);
|
|
10792
10799
|
const paths = resolveHaivePaths25(root);
|
|
10793
10800
|
if (!existsSync50(paths.memoriesDir)) {
|
|
@@ -12355,7 +12362,7 @@ async function renderMemoryHits(paths, opts) {
|
|
|
12355
12362
|
console.log(ui.bold(`Memory hits (${window})`));
|
|
12356
12363
|
if (entries.length === 0) {
|
|
12357
12364
|
ui.info(
|
|
12358
|
-
`No memory reads recorded in window. Reads are logged when \`haive briefing\` or \`haive memory
|
|
12365
|
+
`No memory reads recorded in window. Reads are logged when \`haive briefing\` or \`haive memory search\` surface a memory.`
|
|
12359
12366
|
);
|
|
12360
12367
|
return;
|
|
12361
12368
|
}
|
|
@@ -12388,7 +12395,7 @@ import {
|
|
|
12388
12395
|
resolveHaivePaths as resolveHaivePaths37
|
|
12389
12396
|
} from "@hiveai/core";
|
|
12390
12397
|
function registerBench(program2) {
|
|
12391
|
-
program2.command("bench").description("Self-test the
|
|
12398
|
+
program2.command("selftest").alias("bench").description("Self-test the LOCAL hAIve install: runs core MCP tools against this project and reports latency + payload size. Different from `benchmark` (which measures hAIve-vs-plain agent value). Alias: bench").option("-t, --task <task>", "task description for ranking-aware tools", "audit dependencies for security risks").option("--json", "emit JSON instead of a table", false).option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
12392
12399
|
const root = findProjectRoot40(opts.dir);
|
|
12393
12400
|
const paths = resolveHaivePaths37(root);
|
|
12394
12401
|
const ctx = { paths };
|
|
@@ -12515,7 +12522,7 @@ import path41 from "path";
|
|
|
12515
12522
|
import "commander";
|
|
12516
12523
|
import { estimateTokens as estimateTokens4, findProjectRoot as findProjectRoot41 } from "@hiveai/core";
|
|
12517
12524
|
function registerBenchmark(program2) {
|
|
12518
|
-
const benchmark = program2.command("benchmark").description("
|
|
12525
|
+
const benchmark = program2.command("benchmark").description("Measure hAIve's VALUE: paired hAIve-vs-plain agent runs (correctness, tokens, tools). Different from `selftest` (which only checks local install latency).");
|
|
12519
12526
|
benchmark.command("report").description("Summarize BENCHMARK_AGENT_REPORT.md files from a paired hAIve/plain agent benchmark.").option("-d, --dir <dir>", "benchmark root", "benchmarks/agent-benchmark").option("--out <file>", "write a Markdown report").option("--json", "emit JSON", false).action(async (opts) => {
|
|
12520
12527
|
const root = resolveBenchmarkRoot(opts.dir);
|
|
12521
12528
|
const rows = await collectRows(root);
|
|
@@ -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);
|
|
@@ -13344,7 +13351,7 @@ function registerDoctor(program2) {
|
|
|
13344
13351
|
severity: "warn",
|
|
13345
13352
|
code: "stale-draft-memories",
|
|
13346
13353
|
message: `${oldDrafts.length} draft memor${oldDrafts.length === 1 ? "y has" : "ies have"} been in draft status for 30+ days: ${ids}${more}`,
|
|
13347
|
-
fix: "haive memory approve <id> # activate\nhaive memory
|
|
13354
|
+
fix: "haive memory approve <id> # activate\nhaive memory delete <id> # or delete if obsolete"
|
|
13348
13355
|
});
|
|
13349
13356
|
}
|
|
13350
13357
|
const policyMemories = memories.filter((m) => !isStackPackSeed4(m.memory.frontmatter));
|
|
@@ -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.7"));
|
|
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.7";
|
|
13493
13500
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
13494
13501
|
findings.push({
|
|
13495
13502
|
severity: "warn",
|
|
@@ -13705,7 +13712,7 @@ async function collectHarnessCoverageFindings(codeMap, memories) {
|
|
|
13705
13712
|
code: "harness-coverage",
|
|
13706
13713
|
coverage_percent: pct2,
|
|
13707
13714
|
message: `${covered}/${total} code-map files have validated memory anchors (${pct2}%). ` + coverageDesc + uncoveredHint,
|
|
13708
|
-
fix: pct2 < 50 && total > 10 ? `haive memory
|
|
13715
|
+
fix: pct2 < 50 && total > 10 ? `haive memory save --type gotcha|convention|architecture --paths <key-file> --scope team` : void 0,
|
|
13709
13716
|
section: "Harness coverage"
|
|
13710
13717
|
});
|
|
13711
13718
|
return findings;
|
|
@@ -14166,7 +14173,7 @@ import {
|
|
|
14166
14173
|
} from "@hiveai/core";
|
|
14167
14174
|
function registerPrecommit(program2) {
|
|
14168
14175
|
program2.command("precommit").description(
|
|
14169
|
-
"Run a pre-commit safety check
|
|
14176
|
+
"Run a pre-commit safety check (manual variant of `haive enforce check --stage pre-commit`):\n scans `git diff --cached` against known anti-patterns,\n surfaces conventions/decisions anchored to touched files, and warns about stale anchored memories.\n\n Wire it into git as: `.git/hooks/pre-commit` running `haive precommit` (exit 1 = block).\n\n Examples:\n haive precommit # auto-detects staged diff\n haive precommit --block-on any # block on any warning, not just high-confidence\n haive precommit --paths src/auth.ts src/db.ts # explicit paths instead of git diff"
|
|
14170
14177
|
).option(
|
|
14171
14178
|
"--block-on <mode>",
|
|
14172
14179
|
"'any' | 'high-confidence' | 'never' (report only). Default: derived from enforcement.antiPatternGate."
|
|
@@ -14356,7 +14363,7 @@ function registerWelcome(program2) {
|
|
|
14356
14363
|
console.log(ui.bold(`hAIve welcome \u2014 ${pick.length} team memories (${root})`));
|
|
14357
14364
|
console.log(ui.dim(`Next: invoke get_briefing with your task or run 'haive briefing --task "\u2026"'`));
|
|
14358
14365
|
if (pick.length === 0) {
|
|
14359
|
-
ui.warn("No team memories yet \u2014 add some with 'haive memory
|
|
14366
|
+
ui.warn("No team memories yet \u2014 add some with 'haive memory save' or promote personal ones.");
|
|
14360
14367
|
return;
|
|
14361
14368
|
}
|
|
14362
14369
|
let i = 1;
|
|
@@ -14644,7 +14651,10 @@ 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
|
+
}
|
|
14648
14658
|
});
|
|
14649
14659
|
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
14660
|
const payload = await readHookPayload();
|
|
@@ -15053,7 +15063,10 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
15053
15063
|
const paths = resolveHaivePaths48(root);
|
|
15054
15064
|
const initialized = existsSync75(paths.haiveDir);
|
|
15055
15065
|
const config = initialized ? await loadConfig13(paths) : {};
|
|
15056
|
-
if (initialized)
|
|
15066
|
+
if (initialized) {
|
|
15067
|
+
await applyLightweightRepairs(root, paths);
|
|
15068
|
+
if (stage === "pre-commit") await stageResyncedArtifacts(root, paths);
|
|
15069
|
+
}
|
|
15057
15070
|
const mode = config.enforcement?.mode ?? "strict";
|
|
15058
15071
|
const findings = [];
|
|
15059
15072
|
if (!initialized) {
|
|
@@ -15082,7 +15095,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
15082
15095
|
findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
|
|
15083
15096
|
});
|
|
15084
15097
|
}
|
|
15085
|
-
findings.push(...await inspectIntegrationVersions(root, "0.13.
|
|
15098
|
+
findings.push(...await inspectIntegrationVersions(root, "0.13.7"));
|
|
15086
15099
|
if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
|
|
15087
15100
|
const hasBriefing = await hasRecentBriefingMarker2(paths, sessionId);
|
|
15088
15101
|
findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
|
|
@@ -15685,11 +15698,22 @@ async function verifyGithubActionsForHead(root, status) {
|
|
|
15685
15698
|
}];
|
|
15686
15699
|
}
|
|
15687
15700
|
if (runs.length === 0) {
|
|
15701
|
+
const headMsg = (await runCommand4("git", ["log", "-1", "--pretty=%B"], root).catch(() => "")).trim();
|
|
15702
|
+
if (/\[skip ci\]|\[ci skip\]|\[no ci\]|\*\*\*NO_CI\*\*\*|skip-checks: *true/i.test(headMsg)) {
|
|
15703
|
+
return [{
|
|
15704
|
+
severity: "error",
|
|
15705
|
+
code: "github-actions-skipped-by-message",
|
|
15706
|
+
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.",
|
|
15707
|
+
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>`.",
|
|
15708
|
+
reason: "GitHub scans the entire commit message; a code commit whose message includes a skip-ci directive silently skips CI for the whole push.",
|
|
15709
|
+
impact: 60
|
|
15710
|
+
}];
|
|
15711
|
+
}
|
|
15688
15712
|
return [{
|
|
15689
15713
|
severity: "error",
|
|
15690
15714
|
code: "github-actions-runs-missing",
|
|
15691
15715
|
message: "No GitHub Actions runs were found for HEAD.",
|
|
15692
|
-
fix: "Wait for GitHub to create the workflow runs, or verify that the push was not skipped by a
|
|
15716
|
+
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.",
|
|
15693
15717
|
impact: 50
|
|
15694
15718
|
}];
|
|
15695
15719
|
}
|
|
@@ -15704,21 +15728,35 @@ async function verifyGithubActionsForHead(root, status) {
|
|
|
15704
15728
|
}];
|
|
15705
15729
|
}
|
|
15706
15730
|
const failed = runs.filter((run) => run.conclusion !== "success");
|
|
15707
|
-
|
|
15731
|
+
const failedCore = failed.filter((run) => !isExternalTransientWorkflow(run));
|
|
15732
|
+
const failedExternal = failed.filter((run) => isExternalTransientWorkflow(run));
|
|
15733
|
+
if (failedCore.length > 0) {
|
|
15708
15734
|
return [{
|
|
15709
15735
|
severity: "error",
|
|
15710
15736
|
code: "github-actions-failed",
|
|
15711
|
-
message: `${
|
|
15737
|
+
message: `${failedCore.length}/${runs.length} GitHub Actions workflow run(s) for HEAD did not pass: ${formatGithubRunNames(failedCore)}.`,
|
|
15712
15738
|
fix: "Inspect the failed run logs with `gh run view <run-id> --log`, fix the issue, push the fix, then rerun `haive enforce finish`.",
|
|
15713
15739
|
impact: 80
|
|
15714
15740
|
}];
|
|
15715
15741
|
}
|
|
15742
|
+
if (failedExternal.length > 0) {
|
|
15743
|
+
return [{
|
|
15744
|
+
severity: "info",
|
|
15745
|
+
code: "github-actions-external-transient",
|
|
15746
|
+
message: `${failedExternal.length} external/transient workflow run(s) for HEAD did not pass (non-blocking): ${formatGithubRunNames(failedExternal)}. All core workflows passed.`,
|
|
15747
|
+
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."
|
|
15748
|
+
}];
|
|
15749
|
+
}
|
|
15716
15750
|
return [{
|
|
15717
15751
|
severity: "ok",
|
|
15718
15752
|
code: "github-actions-pass",
|
|
15719
15753
|
message: `All ${runs.length} GitHub Actions workflow run(s) for HEAD completed successfully.`
|
|
15720
15754
|
}];
|
|
15721
15755
|
}
|
|
15756
|
+
function isExternalTransientWorkflow(run) {
|
|
15757
|
+
const label = `${run.workflowName ?? ""} ${run.name ?? ""}`.toLowerCase();
|
|
15758
|
+
return /\bsonar(qube|cloud)?\b|\bcodeql\b|\bsnyk\b|\bcodecov\b/.test(label);
|
|
15759
|
+
}
|
|
15722
15760
|
async function githubRemoteForCurrentBranch(root) {
|
|
15723
15761
|
const branch = (await runCommand4("git", ["branch", "--show-current"], root).catch(() => "")).trim();
|
|
15724
15762
|
const branchRemote = branch ? (await runCommand4("git", ["config", "--get", `branch.${branch}.remote`], root).catch(() => "")).trim() : "";
|
|
@@ -15868,6 +15906,13 @@ function printFinding(finding, explain = false) {
|
|
|
15868
15906
|
if (explain && finding.memory_ids?.length) console.log(ui.dim(` memories: ${finding.memory_ids.join(", ")}`));
|
|
15869
15907
|
if (finding.fix) console.log(ui.dim(`${explain ? " repair: " : " fix: "}${finding.fix}`));
|
|
15870
15908
|
}
|
|
15909
|
+
function printNextRequiredAction(report) {
|
|
15910
|
+
const blocker = report.findings.find((f) => f.severity === "error" && f.fix);
|
|
15911
|
+
if (!blocker) return;
|
|
15912
|
+
console.log("");
|
|
15913
|
+
console.log(ui.bold("\u2192 NEXT REQUIRED ACTION") + ui.dim(` (${blocker.code})`));
|
|
15914
|
+
for (const line of blocker.fix.split("\n")) console.log(` ${line}`);
|
|
15915
|
+
}
|
|
15871
15916
|
async function applyLightweightRepairs(root, paths) {
|
|
15872
15917
|
await applyAutopilotRepairs(root, paths, {
|
|
15873
15918
|
applyConfig: false,
|
|
@@ -15971,6 +16016,15 @@ async function readStdin2(maxBytes) {
|
|
|
15971
16016
|
setTimeout(finish, 2e3);
|
|
15972
16017
|
});
|
|
15973
16018
|
}
|
|
16019
|
+
var ATOMIC_STAGE_EXCLUDE = ["/.usage/", "/.runtime/", "/.cache/"];
|
|
16020
|
+
async function stageResyncedArtifacts(root, paths) {
|
|
16021
|
+
const aiRel = path51.relative(root, paths.haiveDir);
|
|
16022
|
+
const out = await runCommand4("git", ["diff", "--name-only", "--", aiRel], root).catch(() => "");
|
|
16023
|
+
const toStage = out.split("\n").map((line) => line.trim()).filter(Boolean).filter((file) => !ATOMIC_STAGE_EXCLUDE.some((excl) => `/${file}`.includes(excl)));
|
|
16024
|
+
if (toStage.length === 0) return;
|
|
16025
|
+
await runCommand4("git", ["add", "--", ...toStage], root).catch(() => {
|
|
16026
|
+
});
|
|
16027
|
+
}
|
|
15974
16028
|
function runCommand4(cmd, args, cwd) {
|
|
15975
16029
|
return new Promise((resolve, reject) => {
|
|
15976
16030
|
const proc = spawn6(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -16488,7 +16542,7 @@ function warnNum(n) {
|
|
|
16488
16542
|
|
|
16489
16543
|
// src/index.ts
|
|
16490
16544
|
var program = new Command58();
|
|
16491
|
-
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.13.
|
|
16545
|
+
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.13.7").option("--advanced", "show maintenance and experimental commands in help");
|
|
16492
16546
|
registerInit(program);
|
|
16493
16547
|
registerWelcome(program);
|
|
16494
16548
|
registerResolveProject(program);
|
|
@@ -16564,14 +16618,14 @@ var CORE_ROOT_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
16564
16618
|
"session"
|
|
16565
16619
|
]);
|
|
16566
16620
|
var CORE_MEMORY_COMMANDS = /* @__PURE__ */ new Set([
|
|
16567
|
-
"
|
|
16621
|
+
"save",
|
|
16568
16622
|
"list",
|
|
16569
|
-
"
|
|
16570
|
-
"
|
|
16623
|
+
"search",
|
|
16624
|
+
"get",
|
|
16571
16625
|
"verify",
|
|
16572
16626
|
"lint",
|
|
16573
16627
|
"tried",
|
|
16574
|
-
"
|
|
16628
|
+
"delete"
|
|
16575
16629
|
]);
|
|
16576
16630
|
var CORE_SESSION_COMMANDS = /* @__PURE__ */ new Set(["end"]);
|
|
16577
16631
|
applySurfaceVisibility(program);
|
|
@@ -16589,12 +16643,24 @@ program.parseAsync(process.argv).catch((err) => {
|
|
|
16589
16643
|
function applySurfaceVisibility(root) {
|
|
16590
16644
|
const showAdvanced = process.argv.includes("--advanced") || process.env.HAIVE_SHOW_ADVANCED === "1";
|
|
16591
16645
|
if (!showAdvanced) hideNonCoreCommands(root);
|
|
16646
|
+
const familiesBlock = showAdvanced ? [
|
|
16647
|
+
"",
|
|
16648
|
+
"Advanced surface, by family:",
|
|
16649
|
+
" reports: dashboard \xB7 stats \xB7 playback eval: eval \xB7 benchmark \xB7 selftest (alias: bench)",
|
|
16650
|
+
" index: index \xB7 code-search \xB7 embeddings runtime: runtime \xB7 observe \xB7 snapshot",
|
|
16651
|
+
" ops: memory <sub> \xB7 sensors \xB7 ingest \xB7 hub \xB7 sync \xB7 install-hooks (= enforce install) \xB7 precommit (= enforce check)"
|
|
16652
|
+
] : [];
|
|
16592
16653
|
root.addHelpText(
|
|
16593
16654
|
"after",
|
|
16594
16655
|
[
|
|
16595
16656
|
"",
|
|
16596
|
-
"
|
|
16597
|
-
"
|
|
16657
|
+
"Golden path (what you type day to day):",
|
|
16658
|
+
" init \u2192 doctor \u2192 agent setup \u2192 briefing \u2192 memory save/tried \u2192 sensors check \u2192 enforce finish \u2192 sync \u2192 session end",
|
|
16659
|
+
"",
|
|
16660
|
+
"Memory verbs mirror the MCP tools: memory save/search/get/delete <-> mem_save/mem_search/mem_get/mem_delete",
|
|
16661
|
+
"(old verbs add/query/show/rm still work as aliases).",
|
|
16662
|
+
...familiesBlock,
|
|
16663
|
+
"",
|
|
16598
16664
|
"Run `haive --advanced --help` or set HAIVE_SHOW_ADVANCED=1 to show maintenance and experimental commands."
|
|
16599
16665
|
].join("\n")
|
|
16600
16666
|
);
|