@hiveai/cli 0.9.5 → 0.9.6
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 +246 -23
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command47 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/briefing.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -197,7 +197,7 @@ async function getHotFiles(root, daysBack, maxHotFiles, filePaths) {
|
|
|
197
197
|
if (!f) continue;
|
|
198
198
|
counts.set(f, (counts.get(f) ?? 0) + 1);
|
|
199
199
|
}
|
|
200
|
-
let entries = [...counts.entries()].map(([
|
|
200
|
+
let entries = [...counts.entries()].map(([path45, changes]) => ({ path: path45, changes }));
|
|
201
201
|
const lowerPaths = filePaths.map((p) => p.toLowerCase());
|
|
202
202
|
if (lowerPaths.length > 0) {
|
|
203
203
|
entries = entries.filter((e) => lowerPaths.some((p) => e.path.toLowerCase().includes(p)));
|
|
@@ -2297,6 +2297,8 @@ var RUNTIME_README_BODY = `# .ai/.runtime \u2014 disposable local layer
|
|
|
2297
2297
|
Not team truth. Use for machine-local session notes or tooling scratch files.
|
|
2298
2298
|
Official memories belong in .ai/memories/ (versioned in Git).
|
|
2299
2299
|
Only .gitignore and this README are meant to commit; everything else stays untracked.
|
|
2300
|
+
|
|
2301
|
+
Session continuity (local): agents may append \`session-journal.ndjson\` via MCP \`runtime_journal_append\` or \`haive runtime journal append\`.
|
|
2300
2302
|
`;
|
|
2301
2303
|
var RUNTIME_GITIGNORE_BODY = `*
|
|
2302
2304
|
!.gitignore
|
|
@@ -2795,7 +2797,11 @@ import {
|
|
|
2795
2797
|
serializeMemory as serializeMemory8
|
|
2796
2798
|
} from "@hiveai/core";
|
|
2797
2799
|
import { z as z16 } from "zod";
|
|
2798
|
-
import {
|
|
2800
|
+
import {
|
|
2801
|
+
appendUsageEvent,
|
|
2802
|
+
appendRuntimeJournalEntry,
|
|
2803
|
+
loadConfig as loadConfig2
|
|
2804
|
+
} from "@hiveai/core";
|
|
2799
2805
|
import { mkdir as mkdir52, writeFile as writeFile9, rm } from "fs/promises";
|
|
2800
2806
|
import { existsSync as existsSync16 } from "fs";
|
|
2801
2807
|
import path72 from "path";
|
|
@@ -2900,7 +2906,11 @@ import {
|
|
|
2900
2906
|
} from "@hiveai/core";
|
|
2901
2907
|
import { z as z29 } from "zod";
|
|
2902
2908
|
import { existsSync as existsSync27 } from "fs";
|
|
2903
|
-
import {
|
|
2909
|
+
import {
|
|
2910
|
+
findLexicalConflictPairs,
|
|
2911
|
+
findTopicStatusConflictPairs,
|
|
2912
|
+
loadMemoriesFromDir as loadMemoriesFromDir21
|
|
2913
|
+
} from "@hiveai/core";
|
|
2904
2914
|
import { z as z30 } from "zod";
|
|
2905
2915
|
import { resolveProjectInfo } from "@hiveai/core";
|
|
2906
2916
|
import { z as z31 } from "zod";
|
|
@@ -2909,9 +2919,13 @@ import { z as z32 } from "zod";
|
|
|
2909
2919
|
import { existsSync as existsSync28 } from "fs";
|
|
2910
2920
|
import { collectTimelineEntries, loadMemoriesFromDir as loadMemoriesFromDir222 } from "@hiveai/core";
|
|
2911
2921
|
import { z as z33 } from "zod";
|
|
2922
|
+
import { appendRuntimeJournalEntry as appendRuntimeJournalEntry2 } from "@hiveai/core";
|
|
2912
2923
|
import { z as z34 } from "zod";
|
|
2924
|
+
import { readRuntimeJournalTail } from "@hiveai/core";
|
|
2913
2925
|
import { z as z35 } from "zod";
|
|
2914
2926
|
import { z as z36 } from "zod";
|
|
2927
|
+
import { z as z37 } from "zod";
|
|
2928
|
+
import { z as z38 } from "zod";
|
|
2915
2929
|
function createContext(options = {}) {
|
|
2916
2930
|
const env = options.env ?? process.env;
|
|
2917
2931
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -3936,6 +3950,14 @@ var SessionTracker = class {
|
|
|
3936
3950
|
recapId = result.id;
|
|
3937
3951
|
} catch {
|
|
3938
3952
|
}
|
|
3953
|
+
void appendRuntimeJournalEntry(this.ctx.paths, {
|
|
3954
|
+
kind: "session_end",
|
|
3955
|
+
message: recapId ? `auto session close | ${toolSummary} | recap:${recapId}` : `auto session close | ${toolSummary}`,
|
|
3956
|
+
meta: {
|
|
3957
|
+
recap_id: recapId ?? null,
|
|
3958
|
+
total_tool_calls: totalCalls
|
|
3959
|
+
}
|
|
3960
|
+
});
|
|
3939
3961
|
const ranPostTask = this.events.some(
|
|
3940
3962
|
(e) => e.tool === "mem_session_end" && !e.summary?.startsWith("Auto-captured")
|
|
3941
3963
|
);
|
|
@@ -5681,12 +5703,16 @@ var MemConflictCandidatesInputSchema = {
|
|
|
5681
5703
|
types: z30.array(z30.enum(["decision", "architecture", "convention", "gotcha"])).default(["decision", "architecture"]).describe("Memory types scanned for pairwise lexical overlap"),
|
|
5682
5704
|
min_jaccard: z30.number().min(0).max(1).default(0.45).describe("Minimum Jaccard token similarity to surface as a candidate pair"),
|
|
5683
5705
|
max_pairs: z30.number().int().positive().max(100).default(20).describe("Cap pairs returned"),
|
|
5684
|
-
max_scan: z30.number().int().positive().max(2e3).default(500).describe("Maximum memories sampled for O(n\xB2) scan \u2014 excess dropped after chronological sort.")
|
|
5706
|
+
max_scan: z30.number().int().positive().max(2e3).default(500).describe("Maximum memories sampled for O(n\xB2) scan \u2014 excess dropped after chronological sort."),
|
|
5707
|
+
max_topic_pairs: z30.number().int().positive().max(100).default(20).describe(
|
|
5708
|
+
"Cap for extra signal: memories sharing the same topic with validated vs rejected status."
|
|
5709
|
+
)
|
|
5685
5710
|
};
|
|
5686
5711
|
async function memConflictCandidates(input, ctx) {
|
|
5687
5712
|
if (!existsSync27(ctx.paths.memoriesDir)) {
|
|
5688
5713
|
return {
|
|
5689
5714
|
pairs: [],
|
|
5715
|
+
topic_status_pairs: [],
|
|
5690
5716
|
scanned: 0,
|
|
5691
5717
|
truncated: false,
|
|
5692
5718
|
notice: "No .ai/memories directory."
|
|
@@ -5700,8 +5726,9 @@ async function memConflictCandidates(input, ctx) {
|
|
|
5700
5726
|
maxPairs: input.max_pairs,
|
|
5701
5727
|
maxScan: input.max_scan
|
|
5702
5728
|
});
|
|
5703
|
-
const
|
|
5704
|
-
|
|
5729
|
+
const topicStatusPairs = findTopicStatusConflictPairs(all, input.max_topic_pairs);
|
|
5730
|
+
const notice = pairs.length === 0 && topicStatusPairs.length === 0 ? "No lexical or topic-status candidates \u2014 widen since_days/types or lower min_jaccard." : void 0;
|
|
5731
|
+
return { pairs, topic_status_pairs: topicStatusPairs, scanned, truncated, notice };
|
|
5705
5732
|
}
|
|
5706
5733
|
var MemResolveProjectInputSchema = {
|
|
5707
5734
|
cwd: z31.string().optional().describe("Directory used for root discovery when HAIVE_PROJECT_ROOT is unset.")
|
|
@@ -5741,11 +5768,37 @@ async function memTimeline(input, ctx) {
|
|
|
5741
5768
|
});
|
|
5742
5769
|
return { entries, total: entries.length, notice };
|
|
5743
5770
|
}
|
|
5771
|
+
var RuntimeJournalAppendInputSchema = {
|
|
5772
|
+
message: z34.string().min(1).describe("Short line to append to the runtime session journal"),
|
|
5773
|
+
kind: z34.enum(["note", "session_end", "mcp"]).default("note"),
|
|
5774
|
+
tool: z34.string().optional().describe("When kind=mcp, which tool name (optional)")
|
|
5775
|
+
};
|
|
5776
|
+
async function runtimeJournalAppend(input, ctx) {
|
|
5777
|
+
await appendRuntimeJournalEntry2(ctx.paths, {
|
|
5778
|
+
kind: input.kind,
|
|
5779
|
+
message: input.message,
|
|
5780
|
+
...input.tool ? { tool: input.tool } : {}
|
|
5781
|
+
});
|
|
5782
|
+
return {
|
|
5783
|
+
ok: true,
|
|
5784
|
+
path_hint: `${ctx.paths.runtimeDir}/session-journal.ndjson`
|
|
5785
|
+
};
|
|
5786
|
+
}
|
|
5787
|
+
var RuntimeJournalTailInputSchema = {
|
|
5788
|
+
limit: z35.number().int().positive().max(500).default(30).describe("Last N journal entries to return")
|
|
5789
|
+
};
|
|
5790
|
+
async function runtimeJournalTail(input, ctx) {
|
|
5791
|
+
const entries = await readRuntimeJournalTail(ctx.paths, input.limit);
|
|
5792
|
+
if (entries.length === 0) {
|
|
5793
|
+
return { entries: [], empty: true };
|
|
5794
|
+
}
|
|
5795
|
+
return { entries };
|
|
5796
|
+
}
|
|
5744
5797
|
var BootstrapProjectArgsSchema = {
|
|
5745
|
-
module:
|
|
5798
|
+
module: z36.string().optional().describe(
|
|
5746
5799
|
"Optional module name to scope the analysis to (writes to .ai/modules/<module>/context.md)"
|
|
5747
5800
|
),
|
|
5748
|
-
focus:
|
|
5801
|
+
focus: z36.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
|
|
5749
5802
|
};
|
|
5750
5803
|
var ROOT_TEMPLATE = `# Project context
|
|
5751
5804
|
|
|
@@ -5826,8 +5879,8 @@ ${template}\`\`\`
|
|
|
5826
5879
|
};
|
|
5827
5880
|
}
|
|
5828
5881
|
var PostTaskArgsSchema = {
|
|
5829
|
-
task_summary:
|
|
5830
|
-
files_touched:
|
|
5882
|
+
task_summary: z37.string().optional().describe("One sentence describing what you just did"),
|
|
5883
|
+
files_touched: z37.array(z37.string()).optional().describe("Files you created or modified during the task")
|
|
5831
5884
|
};
|
|
5832
5885
|
function postTaskPrompt(args, ctx) {
|
|
5833
5886
|
const taskLine = args.task_summary ? `
|
|
@@ -5910,10 +5963,10 @@ When done, respond with a brief summary: "Saved N memories: [list of IDs]. Sessi
|
|
|
5910
5963
|
};
|
|
5911
5964
|
}
|
|
5912
5965
|
var ImportDocsArgsSchema = {
|
|
5913
|
-
content:
|
|
5914
|
-
source:
|
|
5915
|
-
scope:
|
|
5916
|
-
dry_run:
|
|
5966
|
+
content: z38.string().describe("The documentation content to analyze and import as memories (Markdown, README, ADR, etc.)"),
|
|
5967
|
+
source: z38.string().optional().describe("Origin of the content (file path, URL, or document title) \u2014 used to anchor memories"),
|
|
5968
|
+
scope: z38.enum(["personal", "team"]).default("team").describe("Scope to assign to created memories"),
|
|
5969
|
+
dry_run: z38.boolean().default(false).describe("If true, describe what would be saved without actually calling mem_save")
|
|
5917
5970
|
};
|
|
5918
5971
|
function importDocsPrompt(args, ctx) {
|
|
5919
5972
|
const sourceLine = args.source ? `
|
|
@@ -5976,7 +6029,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
5976
6029
|
};
|
|
5977
6030
|
}
|
|
5978
6031
|
var SERVER_NAME = "haive";
|
|
5979
|
-
var SERVER_VERSION = "0.9.
|
|
6032
|
+
var SERVER_VERSION = "0.9.6";
|
|
5980
6033
|
function jsonResult(data) {
|
|
5981
6034
|
return {
|
|
5982
6035
|
content: [
|
|
@@ -6659,14 +6712,17 @@ function createHaiveServer(options = {}) {
|
|
|
6659
6712
|
server.tool(
|
|
6660
6713
|
"mem_conflict_candidates",
|
|
6661
6714
|
[
|
|
6662
|
-
"Bulk
|
|
6715
|
+
"Bulk scan for conflict CANDIDATES (not proof):",
|
|
6716
|
+
"",
|
|
6717
|
+
" 1. Lexical similarity (Jaccard) on decision/architecture-like pairs",
|
|
6718
|
+
" 2. Same frontmatter.topic with validated vs rejected \u2014 quick human-review signal",
|
|
6663
6719
|
"",
|
|
6664
|
-
"Advisory only \u2014 follow with mem_conflicts_with on specific ids
|
|
6720
|
+
"Advisory only \u2014 follow with mem_conflicts_with on specific ids.",
|
|
6665
6721
|
"",
|
|
6666
6722
|
"PARAMETERS:",
|
|
6667
|
-
" since_days, types, min_jaccard, max_pairs, max_scan",
|
|
6723
|
+
" since_days, types, min_jaccard, max_pairs, max_scan, max_topic_pairs",
|
|
6668
6724
|
"",
|
|
6669
|
-
"RETURNS: { pairs
|
|
6725
|
+
"RETURNS: { pairs, topic_status_pairs, scanned, truncated, notice? }"
|
|
6670
6726
|
].join("\n"),
|
|
6671
6727
|
MemConflictCandidatesInputSchema,
|
|
6672
6728
|
async (input) => {
|
|
@@ -6674,6 +6730,32 @@ function createHaiveServer(options = {}) {
|
|
|
6674
6730
|
return jsonResult(await memConflictCandidates(input, context));
|
|
6675
6731
|
}
|
|
6676
6732
|
);
|
|
6733
|
+
server.tool(
|
|
6734
|
+
"runtime_journal_append",
|
|
6735
|
+
[
|
|
6736
|
+
"Append one line to `.ai/.runtime/session-journal.ndjson` \u2014 machine-local session continuity.",
|
|
6737
|
+
"",
|
|
6738
|
+
"Does NOT replace team memories; complements mem_session_end recaps for local traces.",
|
|
6739
|
+
"",
|
|
6740
|
+
"PARAMETERS: message, kind (note|session_end|mcp), optional tool",
|
|
6741
|
+
"",
|
|
6742
|
+
"RETURNS: { ok, path_hint }"
|
|
6743
|
+
].join("\n"),
|
|
6744
|
+
RuntimeJournalAppendInputSchema,
|
|
6745
|
+
async (input) => jsonResult(await runtimeJournalAppend(input, context))
|
|
6746
|
+
);
|
|
6747
|
+
server.tool(
|
|
6748
|
+
"runtime_journal_tail",
|
|
6749
|
+
[
|
|
6750
|
+
"Read the last N entries from the runtime session journal (parsed JSON lines).",
|
|
6751
|
+
"",
|
|
6752
|
+
"PARAMETERS: limit (default 30, max 500)",
|
|
6753
|
+
"",
|
|
6754
|
+
"RETURNS: { entries: [...], empty?: true }"
|
|
6755
|
+
].join("\n"),
|
|
6756
|
+
RuntimeJournalTailInputSchema,
|
|
6757
|
+
async (input) => jsonResult(await runtimeJournalTail(input, context))
|
|
6758
|
+
);
|
|
6677
6759
|
server.tool(
|
|
6678
6760
|
"pre_commit_check",
|
|
6679
6761
|
[
|
|
@@ -10284,7 +10366,7 @@ function registerDoctor(program2) {
|
|
|
10284
10366
|
timeout: 3e3,
|
|
10285
10367
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10286
10368
|
}).trim();
|
|
10287
|
-
const cliVersion = "0.9.
|
|
10369
|
+
const cliVersion = "0.9.6";
|
|
10288
10370
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
10289
10371
|
findings.push({
|
|
10290
10372
|
severity: "warn",
|
|
@@ -10748,12 +10830,151 @@ function registerResolveProject(program2) {
|
|
|
10748
10830
|
});
|
|
10749
10831
|
}
|
|
10750
10832
|
|
|
10833
|
+
// src/commands/runtime-journal.ts
|
|
10834
|
+
import { existsSync as existsSync64 } from "fs";
|
|
10835
|
+
import path41 from "path";
|
|
10836
|
+
import "commander";
|
|
10837
|
+
import {
|
|
10838
|
+
appendRuntimeJournalEntry as appendRuntimeJournalEntry3,
|
|
10839
|
+
findProjectRoot as findProjectRoot43,
|
|
10840
|
+
readRuntimeJournalTail as readRuntimeJournalTail2,
|
|
10841
|
+
resolveHaivePaths as resolveHaivePaths40
|
|
10842
|
+
} from "@hiveai/core";
|
|
10843
|
+
function registerRuntime(program2) {
|
|
10844
|
+
const runtime = program2.command("runtime").description(
|
|
10845
|
+
"Local-only .ai/.runtime helpers (not versioned team memory). See session-journal.ndjson."
|
|
10846
|
+
);
|
|
10847
|
+
const journal = runtime.command("journal").description("Append or read the machine-local session journal (NDJSON)");
|
|
10848
|
+
journal.command("append").description("Append one JSON line to .ai/.runtime/session-journal.ndjson").argument("<message>", "short text to log").option("-k, --kind <kind>", "note | session_end | mcp", "note").option("-d, --dir <dir>", "project root", process.cwd()).action(async (message, opts) => {
|
|
10849
|
+
const root = path41.resolve(opts.dir ?? process.cwd());
|
|
10850
|
+
const paths = resolveHaivePaths40(findProjectRoot43(root));
|
|
10851
|
+
const raw = opts.kind ?? "note";
|
|
10852
|
+
const kind = ["note", "session_end", "mcp"].includes(raw) ? raw : "note";
|
|
10853
|
+
await appendRuntimeJournalEntry3(paths, { kind, message });
|
|
10854
|
+
ui.success(`Appended to ${path41.relative(root, paths.runtimeDir)}/session-journal.ndjson`);
|
|
10855
|
+
});
|
|
10856
|
+
journal.command("tail").description("Print the last N entries from the runtime session journal as JSON").option("-n, --limit <n>", "number of lines", "30").option("-d, --dir <dir>", "project root", process.cwd()).action(async (opts) => {
|
|
10857
|
+
const root = path41.resolve(opts.dir ?? process.cwd());
|
|
10858
|
+
const paths = resolveHaivePaths40(findProjectRoot43(root));
|
|
10859
|
+
const limit = Math.min(500, Math.max(1, parseInt(opts.limit, 10) || 30));
|
|
10860
|
+
if (!existsSync64(paths.haiveDir)) {
|
|
10861
|
+
ui.error("No .ai/ \u2014 run `haive init` first.");
|
|
10862
|
+
process.exitCode = 1;
|
|
10863
|
+
return;
|
|
10864
|
+
}
|
|
10865
|
+
const entries = await readRuntimeJournalTail2(paths, limit);
|
|
10866
|
+
if (entries.length === 0) {
|
|
10867
|
+
ui.info("Journal empty or missing.");
|
|
10868
|
+
return;
|
|
10869
|
+
}
|
|
10870
|
+
console.log(JSON.stringify({ entries, count: entries.length }, null, 2));
|
|
10871
|
+
});
|
|
10872
|
+
}
|
|
10873
|
+
|
|
10874
|
+
// src/commands/memory-timeline.ts
|
|
10875
|
+
import { existsSync as existsSync65 } from "fs";
|
|
10876
|
+
import path43 from "path";
|
|
10877
|
+
import "commander";
|
|
10878
|
+
import {
|
|
10879
|
+
collectTimelineEntries as collectTimelineEntries2,
|
|
10880
|
+
findProjectRoot as findProjectRoot44,
|
|
10881
|
+
resolveHaivePaths as resolveHaivePaths41
|
|
10882
|
+
} from "@hiveai/core";
|
|
10883
|
+
function registerMemoryTimeline(memory2) {
|
|
10884
|
+
memory2.command("timeline").description(
|
|
10885
|
+
"List related memories chronologically (topic, related_ids, anchors) \u2014 same logic as MCP mem_timeline."
|
|
10886
|
+
).option("--id <id>", "seed memory id").option("--topic <key>", "filter by frontmatter.topic (use without --id for topic-only)").option("-n, --limit <n>", "max entries", "30").option("-d, --dir <dir>", "project root", process.cwd()).action(async (opts) => {
|
|
10887
|
+
if (!opts.id && !opts.topic) {
|
|
10888
|
+
ui.error("Provide --id and/or --topic.");
|
|
10889
|
+
process.exitCode = 1;
|
|
10890
|
+
return;
|
|
10891
|
+
}
|
|
10892
|
+
const root = path43.resolve(opts.dir ?? process.cwd());
|
|
10893
|
+
const paths = resolveHaivePaths41(findProjectRoot44(root));
|
|
10894
|
+
if (!existsSync65(paths.memoriesDir)) {
|
|
10895
|
+
ui.error("No memories \u2014 run `haive init`.");
|
|
10896
|
+
process.exitCode = 1;
|
|
10897
|
+
return;
|
|
10898
|
+
}
|
|
10899
|
+
const limit = Math.min(100, Math.max(1, parseInt(opts.limit, 10) || 30));
|
|
10900
|
+
const all = await loadMemoriesFromDir25(paths.memoriesDir);
|
|
10901
|
+
const { entries, notice } = collectTimelineEntries2(all, {
|
|
10902
|
+
memoryId: opts.id,
|
|
10903
|
+
topic: opts.topic,
|
|
10904
|
+
limit
|
|
10905
|
+
});
|
|
10906
|
+
if (notice) ui.warn(notice);
|
|
10907
|
+
console.log(JSON.stringify({ entries, total: entries.length }, null, 2));
|
|
10908
|
+
});
|
|
10909
|
+
}
|
|
10910
|
+
|
|
10911
|
+
// src/commands/memory-conflict-candidates.ts
|
|
10912
|
+
import { existsSync as existsSync66 } from "fs";
|
|
10913
|
+
import path44 from "path";
|
|
10914
|
+
import "commander";
|
|
10915
|
+
import {
|
|
10916
|
+
findLexicalConflictPairs as findLexicalConflictPairs2,
|
|
10917
|
+
findTopicStatusConflictPairs as findTopicStatusConflictPairs2,
|
|
10918
|
+
findProjectRoot as findProjectRoot45,
|
|
10919
|
+
resolveHaivePaths as resolveHaivePaths42
|
|
10920
|
+
} from "@hiveai/core";
|
|
10921
|
+
function parseTypes(csv) {
|
|
10922
|
+
const allowed = ["decision", "architecture", "convention", "gotcha"];
|
|
10923
|
+
const parts = csv.split(",").map((s) => s.trim().toLowerCase());
|
|
10924
|
+
const out = parts.filter((p) => allowed.includes(p));
|
|
10925
|
+
return out.length ? out : ["decision", "architecture"];
|
|
10926
|
+
}
|
|
10927
|
+
function registerMemoryConflictCandidates(memory2) {
|
|
10928
|
+
memory2.command("conflict-candidates").description(
|
|
10929
|
+
"Heuristic conflict candidates (lexical Jaccard + same-topic validated/rejected pairs) \u2014 aligns with MCP mem_conflict_candidates."
|
|
10930
|
+
).option("-d, --dir <dir>", "project root", process.cwd()).option("--since-days <n>", "only memories created within N days (lexical scan)", "365").option(
|
|
10931
|
+
"--types <csv>",
|
|
10932
|
+
"decision,architecture,convention,gotcha (lexical scan)",
|
|
10933
|
+
"decision,architecture"
|
|
10934
|
+
).option("--min-jaccard <x>", "minimum Jaccard for lexical pairs", "0.45").option("--max-pairs <n>", "cap lexical pairs", "20").option("--max-scan <n>", "max memories scanned (lexical)", "500").option("--max-topic-pairs <n>", "cap topic/status pairs", "20").action(async (opts) => {
|
|
10935
|
+
const root = path44.resolve(opts.dir ?? process.cwd());
|
|
10936
|
+
const paths = resolveHaivePaths42(findProjectRoot45(root));
|
|
10937
|
+
if (!existsSync66(paths.memoriesDir)) {
|
|
10938
|
+
ui.error("No memories \u2014 run `haive init`.");
|
|
10939
|
+
process.exitCode = 1;
|
|
10940
|
+
return;
|
|
10941
|
+
}
|
|
10942
|
+
const sinceDays = Math.max(1, parseInt(opts.sinceDays, 10) || 365);
|
|
10943
|
+
const minJaccard = parseFloat(opts.minJaccard) || 0.45;
|
|
10944
|
+
const maxPairs = Math.min(100, Math.max(1, parseInt(opts.maxPairs, 10) || 20));
|
|
10945
|
+
const maxScan = Math.min(2e3, Math.max(1, parseInt(opts.maxScan, 10) || 500));
|
|
10946
|
+
const maxTopicPairs = Math.min(100, Math.max(1, parseInt(opts.maxTopicPairs, 10) || 20));
|
|
10947
|
+
const all = await loadMemoriesFromDir25(paths.memoriesDir);
|
|
10948
|
+
const lexical = findLexicalConflictPairs2(all, {
|
|
10949
|
+
sinceDays,
|
|
10950
|
+
types: parseTypes(opts.types),
|
|
10951
|
+
minJaccard,
|
|
10952
|
+
maxPairs,
|
|
10953
|
+
maxScan
|
|
10954
|
+
});
|
|
10955
|
+
const topicStatusPairs = findTopicStatusConflictPairs2(all, maxTopicPairs);
|
|
10956
|
+
console.log(
|
|
10957
|
+
JSON.stringify(
|
|
10958
|
+
{
|
|
10959
|
+
pairs: lexical.pairs,
|
|
10960
|
+
topic_status_pairs: topicStatusPairs,
|
|
10961
|
+
scanned: lexical.scanned,
|
|
10962
|
+
truncated: lexical.truncated
|
|
10963
|
+
},
|
|
10964
|
+
null,
|
|
10965
|
+
2
|
|
10966
|
+
)
|
|
10967
|
+
);
|
|
10968
|
+
});
|
|
10969
|
+
}
|
|
10970
|
+
|
|
10751
10971
|
// src/index.ts
|
|
10752
|
-
var program = new
|
|
10753
|
-
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.9.
|
|
10972
|
+
var program = new Command47();
|
|
10973
|
+
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.9.6");
|
|
10754
10974
|
registerInit(program);
|
|
10755
10975
|
registerWelcome(program);
|
|
10756
10976
|
registerResolveProject(program);
|
|
10977
|
+
registerRuntime(program);
|
|
10757
10978
|
registerMcp(program);
|
|
10758
10979
|
registerBriefing(program);
|
|
10759
10980
|
registerTui(program);
|
|
@@ -10785,6 +11006,8 @@ registerMemoryImportChangelog(memory);
|
|
|
10785
11006
|
registerMemoryDigest(memory);
|
|
10786
11007
|
registerMemorySuggest(memory);
|
|
10787
11008
|
registerMemorySuggestTopic(memory);
|
|
11009
|
+
registerMemoryTimeline(memory);
|
|
11010
|
+
registerMemoryConflictCandidates(memory);
|
|
10788
11011
|
registerMemoryArchive(memory);
|
|
10789
11012
|
registerMemoryLint(memory);
|
|
10790
11013
|
var session = program.command("session").description("Manage session lifecycle");
|