@hiveai/cli 0.20.1 → 0.21.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/index.js +60 -8
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -834,7 +834,7 @@ var TokenBudgetWriter = class {
|
|
|
834
834
|
function registerBriefing(program2) {
|
|
835
835
|
program2.command("briefing").description(
|
|
836
836
|
'Print the full project briefing: last session recap + project context + relevant memories.\n Equivalent to calling get_briefing via MCP. Run before starting any task.\n\n Examples:\n haive briefing\n haive briefing --task "add Stripe payment" --files src/payments/PaymentService.ts\n haive briefing --budget quick --task "tiny fix"\n'
|
|
837
|
-
).option("--task <text>", "what you are about to do \u2014 filters memories by relevance").option("--files <csv>", "comma-separated file paths being worked on (surfaces anchored memories)").option("--symbols <csv>", "symbol names to look up in the code-map (e.g. PaymentService,TenantFilter) \u2014 requires haive index code").option("--max-memories <n>", "cap on memories surfaced", "8").option("--max-tokens <n>", "approximate token budget for the entire briefing (truncates if exceeded)").option("--explain-source", "annotate each memory with [source: <relative-path> \xB7 anchors: <files>] for traceable citations").option("--radar", "force project radar (recent commits, open TODOs, hot files) even when memories are plentiful").option("--no-radar", "disable the project radar even when memories are scarce").option(
|
|
837
|
+
).option("--task <text>", "what you are about to do \u2014 filters memories by relevance").option("--files <csv>", "comma-separated file paths being worked on (surfaces anchored memories)").option("--symbols <csv>", "symbol names to look up in the code-map (e.g. PaymentService,TenantFilter) \u2014 requires haive index code").option("--max-memories <n>", "cap on memories surfaced", "8").option("--max-tokens <n>", "approximate token budget for the entire briefing (truncates if exceeded)").option("--explain-source", "annotate each memory with [source: <relative-path> \xB7 anchors: <files>] for traceable citations").option("--radar", "force project radar (recent commits, open TODOs, hot files) even when memories are plentiful").option("--no-radar", "disable the project radar even when memories are scarce").option("--json", "emit the ranked briefing as JSON (memories + scores + priority), like the MCP get_briefing tool", false).option(
|
|
838
838
|
"--budget <preset>",
|
|
839
839
|
"align with MCP get_briefing budget_preset: quick | balanced | deep \u2014 sets cap + truncation budget (overrides --max-memories / replaces default open-ended output)",
|
|
840
840
|
void 0
|
|
@@ -897,8 +897,10 @@ function registerBriefing(program2) {
|
|
|
897
897
|
budgetTokensCap = presetNums.max_tokens;
|
|
898
898
|
maxMemories = presetNums.max_memories;
|
|
899
899
|
}
|
|
900
|
+
const json = opts.json === true;
|
|
900
901
|
const writer = budgetTokensCap !== null ? new TokenBudgetWriter(budgetTokensCap * CHARS_PER_TOKEN) : null;
|
|
901
902
|
const out = (text) => {
|
|
903
|
+
if (json) return true;
|
|
902
904
|
if (writer) return writer.write(text);
|
|
903
905
|
console.log(text);
|
|
904
906
|
return true;
|
|
@@ -1015,6 +1017,10 @@ function registerBriefing(program2) {
|
|
|
1015
1017
|
scored.sort((a, b) => b.score - a.score);
|
|
1016
1018
|
const top = scored.slice(0, maxMemories);
|
|
1017
1019
|
if (top.length === 0) {
|
|
1020
|
+
if (json) {
|
|
1021
|
+
console.log(JSON.stringify({ task: opts.task ?? null, memories: [], briefing_quality: "thin" }, null, 2));
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1018
1024
|
ui.info("No relevant memories found.");
|
|
1019
1025
|
const draftCount = all.filter(
|
|
1020
1026
|
(m) => m.memory.frontmatter.status === "draft" && (scopeFilter === "all" || m.memory.frontmatter.scope === scopeFilter)
|
|
@@ -1046,6 +1052,26 @@ function registerBriefing(program2) {
|
|
|
1046
1052
|
const usefulCount = priorities.filter((p) => p === "useful").length;
|
|
1047
1053
|
const backgroundCount = priorities.filter((p) => p === "background").length;
|
|
1048
1054
|
const quality = mustReadCount > 0 || usefulCount > 0 ? backgroundCount > mustReadCount + usefulCount && backgroundCount > 2 ? "noisy" : "strong" : "thin";
|
|
1055
|
+
if (json) {
|
|
1056
|
+
console.log(JSON.stringify({
|
|
1057
|
+
task: opts.task ?? null,
|
|
1058
|
+
files: filePaths,
|
|
1059
|
+
briefing_quality: quality,
|
|
1060
|
+
counts: { must_read: mustReadCount, useful: usefulCount, background: backgroundCount },
|
|
1061
|
+
recap_id: recaps[0]?.memory.frontmatter.id ?? null,
|
|
1062
|
+
memories: top.map((item, i) => ({
|
|
1063
|
+
id: item.memory.frontmatter.id,
|
|
1064
|
+
scope: item.memory.frontmatter.scope,
|
|
1065
|
+
type: item.memory.frontmatter.type,
|
|
1066
|
+
status: item.memory.frontmatter.status,
|
|
1067
|
+
priority: priorities[i],
|
|
1068
|
+
score: item.score,
|
|
1069
|
+
file: path3.relative(root, item.filePath),
|
|
1070
|
+
summary: (item.memory.body.split("\n").map((l) => l.replace(/^#+\s*/, "").trim()).find((l) => l.length > 0) ?? "").slice(0, 140)
|
|
1071
|
+
}))
|
|
1072
|
+
}, null, 2));
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1049
1075
|
out(ui.dim(`briefing_quality: ${quality} \xB7 must_read=${mustReadCount} useful=${usefulCount} background=${backgroundCount}`));
|
|
1050
1076
|
out("");
|
|
1051
1077
|
for (const [idx, item] of top.entries()) {
|
|
@@ -3339,7 +3365,13 @@ async function seedStackPack(haivePaths, stack) {
|
|
|
3339
3365
|
});
|
|
3340
3366
|
const filePath = memoryFilePath(haivePaths, "team", fm.id);
|
|
3341
3367
|
if (existsSync10(filePath)) continue;
|
|
3342
|
-
const
|
|
3368
|
+
const ruleSlug = combinedSlug.startsWith(`${stack}-`) ? combinedSlug.slice(stack.length + 1) : combinedSlug;
|
|
3369
|
+
const titleCase = (s) => s.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3370
|
+
const heading = `${titleCase(stack)}: ${titleCase(ruleSlug)}`;
|
|
3371
|
+
const titledBody = /^#{1,3}\s+\S/m.test(mem.body.trim()) ? mem.body : `# ${heading}
|
|
3372
|
+
|
|
3373
|
+
${mem.body}`;
|
|
3374
|
+
const content = serializeMemory2({ frontmatter: fm, body: `${titledBody}
|
|
3343
3375
|
|
|
3344
3376
|
${SEED_FOOTER(stack)}` });
|
|
3345
3377
|
await mkdir5(path10.dirname(filePath), { recursive: true });
|
|
@@ -3354,7 +3386,7 @@ ${SEED_FOOTER(stack)}` });
|
|
|
3354
3386
|
|
|
3355
3387
|
// src/commands/init.ts
|
|
3356
3388
|
var execFileAsync = promisify2(execFile2);
|
|
3357
|
-
var HAIVE_GITHUB_ACTION_REF = `v${"0.
|
|
3389
|
+
var HAIVE_GITHUB_ACTION_REF = `v${"0.21.0"}`;
|
|
3358
3390
|
var PROJECT_CONTEXT_TEMPLATE = `# Project context
|
|
3359
3391
|
|
|
3360
3392
|
> Generated by \`haive init\`. Run \`haive init --bootstrap\` to auto-fill from your codebase,
|
|
@@ -8600,7 +8632,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
8600
8632
|
};
|
|
8601
8633
|
}
|
|
8602
8634
|
var SERVER_NAME = "haive";
|
|
8603
|
-
var SERVER_VERSION = "0.
|
|
8635
|
+
var SERVER_VERSION = "0.21.0";
|
|
8604
8636
|
function jsonResult(data) {
|
|
8605
8637
|
return {
|
|
8606
8638
|
content: [
|
|
@@ -14352,7 +14384,7 @@ function registerDoctor(program2) {
|
|
|
14352
14384
|
fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
|
|
14353
14385
|
});
|
|
14354
14386
|
}
|
|
14355
|
-
findings.push(...await collectInstallFindings(root, "0.
|
|
14387
|
+
findings.push(...await collectInstallFindings(root, "0.21.0"));
|
|
14356
14388
|
findings.push(...await collectToolchainFindings(root));
|
|
14357
14389
|
try {
|
|
14358
14390
|
const legacyRaw = execSync3("haive-mcp --version", {
|
|
@@ -14360,7 +14392,7 @@ function registerDoctor(program2) {
|
|
|
14360
14392
|
timeout: 3e3,
|
|
14361
14393
|
stdio: ["ignore", "pipe", "ignore"]
|
|
14362
14394
|
}).trim();
|
|
14363
|
-
const cliVersion = "0.
|
|
14395
|
+
const cliVersion = "0.21.0";
|
|
14364
14396
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
14365
14397
|
findings.push({
|
|
14366
14398
|
severity: "warn",
|
|
@@ -16060,7 +16092,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
16060
16092
|
findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
|
|
16061
16093
|
});
|
|
16062
16094
|
}
|
|
16063
|
-
findings.push(...await inspectIntegrationVersions(root, "0.
|
|
16095
|
+
findings.push(...await inspectIntegrationVersions(root, "0.21.0"));
|
|
16064
16096
|
if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
|
|
16065
16097
|
const hasBriefing = await hasRecentBriefingMarker2(paths, sessionId);
|
|
16066
16098
|
findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
|
|
@@ -16221,6 +16253,26 @@ async function verifyDecisionCoverage(paths, stage, sessionId) {
|
|
|
16221
16253
|
message: `Relevant decisions/policies were surfaced for ${changedFiles.length} changed file(s): ${relevant.length}/${relevant.length}.`
|
|
16222
16254
|
}];
|
|
16223
16255
|
}
|
|
16256
|
+
if (stage === "pre-commit" || stage === "pre-push") {
|
|
16257
|
+
const cfg = await loadConfig14(paths).catch(() => ({}));
|
|
16258
|
+
if (cfg.enforcement?.autoBrief !== false) {
|
|
16259
|
+
await writeBriefingMarker3(paths, {
|
|
16260
|
+
sessionId,
|
|
16261
|
+
source: "haive-autobrief",
|
|
16262
|
+
task: "decision-coverage auto-surfaced at commit",
|
|
16263
|
+
memoryIds: relevant.map(({ memory: memory2 }) => memory2.frontmatter.id),
|
|
16264
|
+
files: changedFiles
|
|
16265
|
+
}).catch(() => {
|
|
16266
|
+
});
|
|
16267
|
+
return [{
|
|
16268
|
+
severity: "ok",
|
|
16269
|
+
code: "decision-coverage-autosurfaced",
|
|
16270
|
+
message: `Surfaced ${relevant.length} relevant decision/policy memor${relevant.length === 1 ? "y" : "ies"} for ${changedFiles.length} changed file(s) at commit time` + (missing.length > 0 ? ` (${missing.length} not previously briefed \u2014 now recorded)` : "") + ". Set enforcement.autoBrief=false to require a manual briefing first.",
|
|
16271
|
+
memory_ids: relevant.slice(0, 12).map(({ memory: memory2 }) => memory2.frontmatter.id),
|
|
16272
|
+
affected_files: changedFiles.slice(0, 10)
|
|
16273
|
+
}];
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16224
16276
|
return [{
|
|
16225
16277
|
severity: stage === "local" ? "warn" : "error",
|
|
16226
16278
|
code: "decision-coverage-missing",
|
|
@@ -18100,7 +18152,7 @@ function registerBridges(program2) {
|
|
|
18100
18152
|
|
|
18101
18153
|
// src/index.ts
|
|
18102
18154
|
var program = new Command64();
|
|
18103
|
-
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.
|
|
18155
|
+
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.21.0").option("--advanced", "show maintenance and experimental commands in help");
|
|
18104
18156
|
registerInit(program);
|
|
18105
18157
|
registerWelcome(program);
|
|
18106
18158
|
registerResolveProject(program);
|