@hiveai/cli 0.9.19 → 0.9.20

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
@@ -3294,8 +3294,8 @@ async function memList(input, ctx) {
3294
3294
  return { memories };
3295
3295
  }
3296
3296
  var MemSaveInputSchema = {
3297
- type: z4.enum(["convention", "decision", "gotcha", "architecture", "glossary", "attempt", "session_recap"]).describe(
3298
- "Kind of memory being saved. Use 'attempt' for failed approaches (auto-validated). Use 'session_recap' via mem_session_end instead."
3297
+ type: z4.enum(["convention", "decision", "gotcha", "architecture", "glossary", "skill", "attempt", "session_recap"]).describe(
3298
+ "Kind of memory being saved. Use 'skill' for reusable procedures/playbooks agents should follow for recurring tasks (feedforward harness guide). Use 'attempt' for failed approaches (auto-validated). Use 'session_recap' via mem_session_end instead."
3299
3299
  ),
3300
3300
  slug: z4.string().min(1).describe("Short human-readable identifier \u2014 becomes part of the filename"),
3301
3301
  body: z4.string().describe("Markdown body of the memory"),
@@ -4895,10 +4895,10 @@ function classifyMemoryPriority(memory2, loaded, inputFiles, inputSymbols) {
4895
4895
  );
4896
4896
  const strongSemantic = (memory2.semantic_score ?? 0) >= 0.65;
4897
4897
  const usefulSemantic = (memory2.semantic_score ?? 0) >= 0.35;
4898
- if (fm?.requires_human_approval || directAnchor || directSymbol || memory2.type === "attempt" && (memory2.match_quality === "exact" || strongSemantic)) {
4898
+ if (fm?.requires_human_approval || directAnchor || directSymbol || memory2.type === "attempt" && (memory2.match_quality === "exact" || strongSemantic) || memory2.type === "skill" && (memory2.match_quality === "exact" || strongSemantic)) {
4899
4899
  return "must_read";
4900
4900
  }
4901
- if (memory2.reasons.includes("module") || memory2.reasons.includes("domain") || memory2.match_quality === "exact" || usefulSemantic) {
4901
+ if (memory2.type === "skill" || memory2.reasons.includes("module") || memory2.reasons.includes("domain") || memory2.match_quality === "exact" || usefulSemantic) {
4902
4902
  return "useful";
4903
4903
  }
4904
4904
  return "background";
@@ -4978,6 +4978,7 @@ function explainWhySurfaced(memory2, loaded, inputFiles, inferredModules) {
4978
4978
  }
4979
4979
  why.push(`Confidence: ${memory2.confidence}; read ${memory2.read_count} time${memory2.read_count === 1 ? "" : "s"}.`);
4980
4980
  if (memory2.type === "attempt") why.push("Failed-approach record; read before repeating the same path.");
4981
+ if (memory2.type === "skill") why.push("Skill (reusable procedure/playbook) \u2014 follow the steps described when doing this type of task.");
4981
4982
  if (memory2.status === "proposed" || memory2.status === "draft") {
4982
4983
  why.push("Unvalidated record; use cautiously or ask a human before treating it as policy.");
4983
4984
  }
@@ -6515,7 +6516,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
6515
6516
  };
6516
6517
  }
6517
6518
  var SERVER_NAME = "haive";
6518
- var SERVER_VERSION = "0.9.19";
6519
+ var SERVER_VERSION = "0.9.20";
6519
6520
  function jsonResult(data) {
6520
6521
  return {
6521
6522
  content: [
@@ -8496,6 +8497,7 @@ function registerMemoryAdd(memory2) {
8496
8497
  `Save a piece of knowledge as a persistent memory.
8497
8498
 
8498
8499
  Memory types:
8500
+ skill \u2014 reusable procedure/playbook agents follow for a recurring task (e.g. deploy, review)
8499
8501
  convention \u2014 how things are done here (naming, patterns, tooling)
8500
8502
  decision \u2014 a choice made and WHY (tradeoffs, constraints)
8501
8503
  gotcha \u2014 non-obvious behavior that surprises newcomers
@@ -8515,7 +8517,7 @@ function registerMemoryAdd(memory2) {
8515
8517
  haive memory add --type convention --slug flyway-no-modify --topic flyway \\\\
8516
8518
  --scope team --body "Never modify existing migrations. Create V{n+1}__desc.sql."
8517
8519
  `
8518
- ).requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary | attempt").requiredOption("--slug <slug>", "short kebab-case identifier used in the file name").option("--title <text>", "memory title \u2014 becomes the first heading of the body").option("--scope <scope>", "personal | team | module (default: config default; team in autopilot)").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags for easier retrieval").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor to source files \u2014 used for staleness detection by haive sync").option("--symbols <csv>", "anchor to specific symbols (class/function names)").option("--commit <sha>", "anchor to a specific commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--body-file <path>", "read memory body from a Markdown file \u2014 for long content").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("--topic <key>", "stable key for upsert: if a memory with this topic+scope already exists, update it in-place (revision_count++)").option("-d, --dir <dir>", "project root").action(async (opts) => {
8520
+ ).requiredOption("--type <type>", "skill | convention | decision | gotcha | architecture | glossary | attempt").requiredOption("--slug <slug>", "short kebab-case identifier used in the file name").option("--title <text>", "memory title \u2014 becomes the first heading of the body").option("--scope <scope>", "personal | team | module (default: config default; team in autopilot)").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags for easier retrieval").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor to source files \u2014 used for staleness detection by haive sync").option("--symbols <csv>", "anchor to specific symbols (class/function names)").option("--commit <sha>", "anchor to a specific commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--body-file <path>", "read memory body from a Markdown file \u2014 for long content").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("--topic <key>", "stable key for upsert: if a memory with this topic+scope already exists, update it in-place (revision_count++)").option("-d, --dir <dir>", "project root").action(async (opts) => {
8519
8521
  const root = findProjectRoot13(opts.dir);
8520
8522
  const paths = resolveHaivePaths10(root);
8521
8523
  if (!existsSync33(paths.haiveDir)) {
@@ -8639,7 +8641,8 @@ TODO \u2014 write the memory body.
8639
8641
  if (inferredTags.length > 0) {
8640
8642
  ui.info(`auto-tagged: ${inferredTags.join(", ")} (use --no-auto-tag to disable)`);
8641
8643
  }
8642
- if (anchorPaths.length === 0) {
8644
+ const typeNeedsAnchor = !["skill", "glossary", "session_recap"].includes(opts.type);
8645
+ if (anchorPaths.length === 0 && typeNeedsAnchor) {
8643
8646
  ui.warn(
8644
8647
  `This memory has no anchor paths \u2014 staleness cannot be detected automatically.
8645
8648
  Add file anchors: haive memory update ${frontmatter.id} --paths <file1,file2>`
@@ -11563,7 +11566,7 @@ function registerDoctor(program2) {
11563
11566
  });
11564
11567
  }
11565
11568
  const anchorless = memories.filter(
11566
- (m) => m.memory.frontmatter.anchor.paths.length === 0 && m.memory.frontmatter.anchor.symbols.length === 0 && m.memory.frontmatter.type !== "session_recap" && m.memory.frontmatter.type !== "glossary"
11569
+ (m) => m.memory.frontmatter.anchor.paths.length === 0 && m.memory.frontmatter.anchor.symbols.length === 0 && m.memory.frontmatter.type !== "session_recap" && m.memory.frontmatter.type !== "glossary" && m.memory.frontmatter.type !== "skill"
11567
11570
  );
11568
11571
  if (anchorless.length / Math.max(memories.length, 1) > 0.3) {
11569
11572
  findings.push({
@@ -11621,6 +11624,7 @@ function registerDoctor(program2) {
11621
11624
  });
11622
11625
  }
11623
11626
  }
11627
+ findings.push(...await collectHarnessCoverageFindings(codeMap, memories));
11624
11628
  findings.push(...await collectSemanticIndexFindings(paths, config, memories.length, codeMap));
11625
11629
  const events = await readUsageEvents4(paths);
11626
11630
  if (events.length === 0) {
@@ -11686,14 +11690,14 @@ function registerDoctor(program2) {
11686
11690
  fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
11687
11691
  });
11688
11692
  }
11689
- findings.push(...await collectInstallFindings(root, "0.9.19"));
11693
+ findings.push(...await collectInstallFindings(root, "0.9.20"));
11690
11694
  try {
11691
11695
  const legacyRaw = execSync3("haive-mcp --version", {
11692
11696
  encoding: "utf8",
11693
11697
  timeout: 3e3,
11694
11698
  stdio: ["ignore", "pipe", "ignore"]
11695
11699
  }).trim();
11696
- const cliVersion = "0.9.19";
11700
+ const cliVersion = "0.9.20";
11697
11701
  if (legacyRaw && legacyRaw !== cliVersion) {
11698
11702
  findings.push({
11699
11703
  severity: "warn",
@@ -11741,7 +11745,7 @@ function emit(findings, opts, repairs = []) {
11741
11745
  console.log(ui.bold(`hAIve doctor \u2014 ${classified.length} finding${classified.length === 1 ? "" : "s"}`));
11742
11746
  console.log(
11743
11747
  ui.dim(
11744
- ` protection=${scores.protection_score} context=${scores.context_quality_score} corpus=${scores.corpus_quality_score}`
11748
+ ` protection=${scores.protection_score} context=${scores.context_quality_score} corpus=${scores.corpus_quality_score} harness-coverage=${scores.harness_coverage_score}%`
11745
11749
  )
11746
11750
  );
11747
11751
  console.log();
@@ -11750,6 +11754,7 @@ function emit(findings, opts, repairs = []) {
11750
11754
  "Agent coverage",
11751
11755
  "Context quality",
11752
11756
  "Corpus health",
11757
+ "Harness coverage",
11753
11758
  "Index health",
11754
11759
  "Next actions"
11755
11760
  ];
@@ -11787,6 +11792,7 @@ function emit(findings, opts, repairs = []) {
11787
11792
  function sectionForFinding(finding) {
11788
11793
  if (finding.code.includes("haive") || finding.code.includes("integration") || finding.code.includes("claude") || finding.code.includes("autopilot")) return "Agent coverage";
11789
11794
  if (finding.code.includes("context") || finding.code.includes("briefing") || finding.code.includes("search")) return "Context quality";
11795
+ if (finding.code.includes("harness-coverage")) return "Harness coverage";
11790
11796
  if (finding.code.includes("code-map") || finding.code.includes("index")) return "Index health";
11791
11797
  if (finding.code.includes("memory") || finding.code.includes("anchor") || finding.code.includes("pending") || finding.code.includes("decay")) return "Corpus health";
11792
11798
  if (finding.severity === "error") return "Protection";
@@ -11802,10 +11808,13 @@ function computeDoctorScores(findings) {
11802
11808
  }, 0);
11803
11809
  return Math.max(0, 100 - penalty);
11804
11810
  };
11811
+ const coverageFinding = findings.find((f) => f.code === "harness-coverage");
11812
+ const harnessCoverageScore = coverageFinding ? parseInt((coverageFinding.message.match(/\((\d+)%\)/) ?? [])[1] ?? "0", 10) : 0;
11805
11813
  return {
11806
11814
  protection_score: scoreFor(["Protection", "Agent coverage"]),
11807
11815
  context_quality_score: scoreFor(["Context quality", "Index health"]),
11808
- corpus_quality_score: scoreFor(["Corpus health"])
11816
+ corpus_quality_score: scoreFor(["Corpus health"]),
11817
+ harness_coverage_score: harnessCoverageScore
11809
11818
  };
11810
11819
  }
11811
11820
  function groupBySection(findings) {
@@ -11814,6 +11823,7 @@ function groupBySection(findings) {
11814
11823
  "Agent coverage": [],
11815
11824
  "Context quality": [],
11816
11825
  "Corpus health": [],
11826
+ "Harness coverage": [],
11817
11827
  "Index health": [],
11818
11828
  "Next actions": []
11819
11829
  };
@@ -11823,6 +11833,37 @@ function groupBySection(findings) {
11823
11833
  function nextActions(findings) {
11824
11834
  return [...new Set(findings.flatMap((finding) => finding.fix ? finding.fix.split("\n") : []))].filter(Boolean);
11825
11835
  }
11836
+ async function collectHarnessCoverageFindings(codeMap, memories) {
11837
+ if (!codeMap) return [];
11838
+ const codeFiles = Object.keys(codeMap.files);
11839
+ const total = codeFiles.length;
11840
+ if (total === 0) return [];
11841
+ const validatedWithAnchors = memories.filter(
11842
+ (m) => (m.memory.frontmatter.status === "validated" || m.memory.frontmatter.status === "proposed") && m.memory.frontmatter.anchor.paths.length > 0
11843
+ );
11844
+ const coveredFiles = /* @__PURE__ */ new Set();
11845
+ for (const m of validatedWithAnchors) {
11846
+ for (const anchorPath of m.memory.frontmatter.anchor.paths) {
11847
+ const normalized = anchorPath.replace(/^\/+/, "");
11848
+ for (const codeFile of codeFiles) {
11849
+ if (codeFile === normalized || codeFile.startsWith(normalized + "/") || normalized.startsWith(codeFile + "/")) {
11850
+ coveredFiles.add(codeFile);
11851
+ }
11852
+ }
11853
+ }
11854
+ }
11855
+ const covered = coveredFiles.size;
11856
+ const pct = Math.round(covered / total * 100);
11857
+ const findings = [];
11858
+ findings.push({
11859
+ severity: pct < 10 && total > 10 ? "info" : "info",
11860
+ code: "harness-coverage",
11861
+ message: `${covered}/${total} code-map files have validated memory anchors (${pct}%). ` + (pct < 10 && total > 10 ? "Low coverage \u2014 add memory anchors on key modules to improve harness enforcement." : pct < 30 ? "Partial coverage \u2014 consider anchoring critical modules and patterns." : "Good harness coverage."),
11862
+ fix: pct < 10 && total > 10 ? "haive memory add --type gotcha|convention|architecture --paths <key-file> --scope team" : void 0,
11863
+ section: "Harness coverage"
11864
+ });
11865
+ return findings;
11866
+ }
11826
11867
  async function collectSemanticIndexFindings(paths, config, memoryCount, codeMap) {
11827
11868
  const findings = [];
11828
11869
  const autoWantsCodeSearch = Boolean(config.autopilot || config.autoRepair?.codeSearch);
@@ -12227,12 +12268,13 @@ import {
12227
12268
  resolveHaivePaths as resolveHaivePaths40
12228
12269
  } from "@hiveai/core";
12229
12270
  var TYPE_RANK = {
12230
- decision: 0,
12231
- architecture: 1,
12232
- convention: 2,
12233
- glossary: 3,
12234
- gotcha: 4,
12235
- attempt: 5
12271
+ skill: 0,
12272
+ decision: 1,
12273
+ architecture: 2,
12274
+ convention: 3,
12275
+ glossary: 4,
12276
+ gotcha: 5,
12277
+ attempt: 6
12236
12278
  };
12237
12279
  function registerWelcome(program2) {
12238
12280
  program2.command("welcome").description(
@@ -12758,7 +12800,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
12758
12800
  findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
12759
12801
  });
12760
12802
  }
12761
- findings.push(...await inspectIntegrationVersions(root, "0.9.19"));
12803
+ findings.push(...await inspectIntegrationVersions(root, "0.9.20"));
12762
12804
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
12763
12805
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
12764
12806
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
@@ -13246,7 +13288,7 @@ function registerRun(program2) {
13246
13288
 
13247
13289
  // src/index.ts
13248
13290
  var program = new Command51();
13249
- program.name("haive").description("hAIve \u2014 policy enforcement layer for AI coding agents").version("0.9.19").option("--advanced", "show maintenance and experimental commands in help");
13291
+ program.name("haive").description("hAIve \u2014 the memory and enforcement layer of your agent harness").version("0.9.20").option("--advanced", "show maintenance and experimental commands in help");
13250
13292
  registerInit(program);
13251
13293
  registerWelcome(program);
13252
13294
  registerResolveProject(program);
@@ -13343,7 +13385,7 @@ function applySurfaceVisibility(root) {
13343
13385
  "after",
13344
13386
  [
13345
13387
  "",
13346
- "Default help shows the core hAIve harness: init, doctor, agent setup, briefing, enforcement,",
13388
+ "Default help shows the core harness workflow: init, doctor, agent setup, briefing, enforcement,",
13347
13389
  "sync, session recaps, and high-signal memory commands.",
13348
13390
  "Run `haive --advanced --help` or set HAIVE_SHOW_ADVANCED=1 to show maintenance and experimental commands."
13349
13391
  ].join("\n")