@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 +63 -21
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
12231
|
-
|
|
12232
|
-
|
|
12233
|
-
|
|
12234
|
-
|
|
12235
|
-
|
|
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.
|
|
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
|
|
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
|
|
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")
|