@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 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 content = serializeMemory2({ frontmatter: fm, body: `${mem.body}
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.20.1"}`;
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.20.1";
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.20.1"));
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.20.1";
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.20.1"));
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.20.1").option("--advanced", "show maintenance and experimental commands in help");
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);