@hiveai/cli 0.2.4 → 0.2.5
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/Dashboard-SRPCHP7Z.js +194 -0
- package/dist/Dashboard-SRPCHP7Z.js.map +1 -0
- package/dist/index.js +67 -47
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/tui/Dashboard.tsx
|
|
4
|
+
import { useState, useEffect, useCallback } from "react";
|
|
5
|
+
import { Box, Text, useInput, useApp } from "ink";
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
import { writeFile } from "fs/promises";
|
|
8
|
+
import {
|
|
9
|
+
loadMemoriesFromDir,
|
|
10
|
+
resolveHaivePaths,
|
|
11
|
+
serializeMemory
|
|
12
|
+
} from "@hiveai/core";
|
|
13
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
var FILTERS = ["all", "draft", "proposed", "validated", "stale", "rejected"];
|
|
15
|
+
var LIST_H = 12;
|
|
16
|
+
function statusColor(status) {
|
|
17
|
+
if (status === "validated") return "green";
|
|
18
|
+
if (status === "proposed" || status === "stale") return "yellow";
|
|
19
|
+
if (status === "rejected") return "red";
|
|
20
|
+
return void 0;
|
|
21
|
+
}
|
|
22
|
+
function Dashboard({ root }) {
|
|
23
|
+
const { exit } = useApp();
|
|
24
|
+
const paths = resolveHaivePaths(root);
|
|
25
|
+
const [memories, setMemories] = useState([]);
|
|
26
|
+
const [loading, setLoading] = useState(true);
|
|
27
|
+
const [filterIdx, setFilterIdx] = useState(0);
|
|
28
|
+
const [cursor, setCursor] = useState(0);
|
|
29
|
+
const [flash, setFlash] = useState(null);
|
|
30
|
+
const filter = FILTERS[filterIdx] ?? "all";
|
|
31
|
+
const reload = useCallback(async () => {
|
|
32
|
+
if (!existsSync(paths.memoriesDir)) {
|
|
33
|
+
setLoading(false);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
setMemories(await loadMemoriesFromDir(paths.memoriesDir));
|
|
37
|
+
setLoading(false);
|
|
38
|
+
}, [paths.memoriesDir]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
void reload();
|
|
41
|
+
}, [reload]);
|
|
42
|
+
const filtered = memories.filter((m) => {
|
|
43
|
+
const s2 = m.memory.frontmatter.status;
|
|
44
|
+
if (filter === "all") return s2 !== "rejected";
|
|
45
|
+
return s2 === filter;
|
|
46
|
+
});
|
|
47
|
+
const selected = filtered[cursor];
|
|
48
|
+
const counts = memories.reduce((acc, m) => {
|
|
49
|
+
const s2 = m.memory.frontmatter.status;
|
|
50
|
+
acc[s2] = (acc[s2] ?? 0) + 1;
|
|
51
|
+
return acc;
|
|
52
|
+
}, {});
|
|
53
|
+
const flash_ = (text, color = "green") => {
|
|
54
|
+
setFlash({ text, color });
|
|
55
|
+
setTimeout(() => setFlash(null), 2e3);
|
|
56
|
+
};
|
|
57
|
+
const doApprove = useCallback(async () => {
|
|
58
|
+
if (!selected) return;
|
|
59
|
+
const fm = selected.memory.frontmatter;
|
|
60
|
+
if (fm.status === "validated") {
|
|
61
|
+
flash_("Already validated");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await writeFile(
|
|
65
|
+
selected.filePath,
|
|
66
|
+
serializeMemory({ frontmatter: { ...fm, status: "validated" }, body: selected.memory.body }),
|
|
67
|
+
"utf8"
|
|
68
|
+
);
|
|
69
|
+
flash_(`\u2713 Approved ${fm.id.slice(0, 32)}\u2026`);
|
|
70
|
+
const prev = cursor;
|
|
71
|
+
await reload();
|
|
72
|
+
setCursor(prev);
|
|
73
|
+
}, [selected, cursor, reload]);
|
|
74
|
+
const doReject = useCallback(async () => {
|
|
75
|
+
if (!selected) return;
|
|
76
|
+
const fm = selected.memory.frontmatter;
|
|
77
|
+
if (fm.status === "rejected") {
|
|
78
|
+
flash_("Already rejected", "red");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
await writeFile(
|
|
82
|
+
selected.filePath,
|
|
83
|
+
serializeMemory({ frontmatter: { ...fm, status: "rejected" }, body: selected.memory.body }),
|
|
84
|
+
"utf8"
|
|
85
|
+
);
|
|
86
|
+
flash_(`\u2717 Rejected ${fm.id.slice(0, 32)}\u2026`, "red");
|
|
87
|
+
await reload();
|
|
88
|
+
setCursor((c) => Math.min(c, Math.max(0, filtered.length - 2)));
|
|
89
|
+
}, [selected, filtered.length, reload]);
|
|
90
|
+
useInput((input, key) => {
|
|
91
|
+
if (input === "q") {
|
|
92
|
+
exit();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
|
|
96
|
+
if (key.downArrow) setCursor((c) => Math.min(filtered.length - 1, c + 1));
|
|
97
|
+
if (key.tab) {
|
|
98
|
+
setFilterIdx((i) => (i + 1) % FILTERS.length);
|
|
99
|
+
setCursor(0);
|
|
100
|
+
}
|
|
101
|
+
if (input === "a") void doApprove();
|
|
102
|
+
if (input === "r") void doReject();
|
|
103
|
+
});
|
|
104
|
+
if (loading) {
|
|
105
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading memories\u2026" });
|
|
106
|
+
}
|
|
107
|
+
if (!existsSync(paths.memoriesDir)) {
|
|
108
|
+
return /* @__PURE__ */ jsx(Text, { color: "red", children: "No .ai/memories found \u2014 run `haive init` first." });
|
|
109
|
+
}
|
|
110
|
+
const half = Math.floor(LIST_H / 2);
|
|
111
|
+
const start = Math.max(0, Math.min(cursor - half, Math.max(0, filtered.length - LIST_H)));
|
|
112
|
+
const visible = filtered.slice(start, start + LIST_H);
|
|
113
|
+
const v = counts["validated"] ?? 0;
|
|
114
|
+
const p = counts["proposed"] ?? 0;
|
|
115
|
+
const d = counts["draft"] ?? 0;
|
|
116
|
+
const s = counts["stale"] ?? 0;
|
|
117
|
+
const rej = counts["rejected"] ?? 0;
|
|
118
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
119
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "round", paddingX: 1, gap: 2, children: [
|
|
120
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "hAIve" }),
|
|
121
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: root }),
|
|
122
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
123
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
124
|
+
"\u2713 ",
|
|
125
|
+
v
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
|
|
128
|
+
/* @__PURE__ */ jsxs(Text, { color: p > 0 ? "yellow" : void 0, children: [
|
|
129
|
+
"~ ",
|
|
130
|
+
p
|
|
131
|
+
] }),
|
|
132
|
+
/* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
|
|
133
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
134
|
+
"\xB7 ",
|
|
135
|
+
d
|
|
136
|
+
] }),
|
|
137
|
+
s > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138
|
+
/* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
|
|
139
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
140
|
+
"\u26A0 ",
|
|
141
|
+
s
|
|
142
|
+
] })
|
|
143
|
+
] }),
|
|
144
|
+
rej > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
145
|
+
/* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
|
|
146
|
+
/* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
147
|
+
"\u2717 ",
|
|
148
|
+
rej
|
|
149
|
+
] })
|
|
150
|
+
] })
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 1, gap: 2, children: [
|
|
153
|
+
FILTERS.map((f) => /* @__PURE__ */ jsx(Text, { color: filter === f ? "cyan" : void 0, bold: filter === f, children: filter === f ? `[${f}]` : f }, f)),
|
|
154
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " tab\u2192cycle" })
|
|
155
|
+
] }),
|
|
156
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
157
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 64, borderStyle: "single", paddingX: 1, children: [
|
|
158
|
+
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: `MEMORIES ${filtered.length}/${memories.length}` }),
|
|
159
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (no memories)" }) : visible.map((m, vi) => {
|
|
160
|
+
const absIdx = start + vi;
|
|
161
|
+
const fm = m.memory.frontmatter;
|
|
162
|
+
const sel = absIdx === cursor;
|
|
163
|
+
const idShort = fm.id.length > 43 ? fm.id.slice(0, 40) + "\u2026" : fm.id;
|
|
164
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
165
|
+
/* @__PURE__ */ jsxs(Text, { color: sel ? "cyan" : void 0, bold: sel, children: [
|
|
166
|
+
sel ? "\u25B6 " : " ",
|
|
167
|
+
idShort.padEnd(43)
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(fm.status), children: fm.status.slice(0, 9) })
|
|
170
|
+
] }, fm.id);
|
|
171
|
+
})
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 36, borderStyle: "single", paddingX: 1, children: [
|
|
174
|
+
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "PREVIEW" }),
|
|
175
|
+
selected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
176
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
177
|
+
selected.memory.frontmatter.scope,
|
|
178
|
+
"/",
|
|
179
|
+
selected.memory.frontmatter.type
|
|
180
|
+
] }),
|
|
181
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(selected.memory.frontmatter.status), children: selected.memory.frontmatter.status }),
|
|
182
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
183
|
+
selected.memory.body.split("\n").slice(0, LIST_H - 1).map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: line || " " }, i))
|
|
184
|
+
] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "select a memory" })
|
|
185
|
+
] })
|
|
186
|
+
] }),
|
|
187
|
+
flash && /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: flash.color, children: flash.text }) }),
|
|
188
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate [tab] filter [a] approve [r] reject [q] quit" }) })
|
|
189
|
+
] });
|
|
190
|
+
}
|
|
191
|
+
export {
|
|
192
|
+
Dashboard
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=Dashboard-SRPCHP7Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tui/Dashboard.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { Box, Text, useInput, useApp } from \"ink\";\nimport { existsSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport {\n loadMemoriesFromDir,\n resolveHaivePaths,\n serializeMemory,\n type LoadedMemory,\n} from \"@hiveai/core\";\n\ntype FilterStatus = \"all\" | \"draft\" | \"proposed\" | \"validated\" | \"stale\" | \"rejected\";\nconst FILTERS: FilterStatus[] = [\"all\", \"draft\", \"proposed\", \"validated\", \"stale\", \"rejected\"];\nconst LIST_H = 12;\n\nfunction statusColor(status: string): \"green\" | \"yellow\" | \"red\" | undefined {\n if (status === \"validated\") return \"green\";\n if (status === \"proposed\" || status === \"stale\") return \"yellow\";\n if (status === \"rejected\") return \"red\";\n return undefined;\n}\n\ninterface Props {\n root: string;\n}\n\nexport function Dashboard({ root }: Props) {\n const { exit } = useApp();\n const paths = resolveHaivePaths(root);\n\n const [memories, setMemories] = useState<LoadedMemory[]>([]);\n const [loading, setLoading] = useState(true);\n const [filterIdx, setFilterIdx] = useState(0);\n const [cursor, setCursor] = useState(0);\n const [flash, setFlash] = useState<{ text: string; color: \"green\" | \"red\" } | null>(null);\n\n const filter: FilterStatus = FILTERS[filterIdx] ?? \"all\";\n\n const reload = useCallback(async () => {\n if (!existsSync(paths.memoriesDir)) {\n setLoading(false);\n return;\n }\n setMemories(await loadMemoriesFromDir(paths.memoriesDir));\n setLoading(false);\n }, [paths.memoriesDir]);\n\n useEffect(() => {\n void reload();\n }, [reload]);\n\n const filtered = memories.filter((m) => {\n const s = m.memory.frontmatter.status;\n if (filter === \"all\") return s !== \"rejected\";\n return s === filter;\n });\n\n const selected = filtered[cursor];\n\n const counts = memories.reduce<Record<string, number>>((acc, m) => {\n const s = m.memory.frontmatter.status;\n acc[s] = (acc[s] ?? 0) + 1;\n return acc;\n }, {});\n\n const flash_ = (text: string, color: \"green\" | \"red\" = \"green\") => {\n setFlash({ text, color });\n setTimeout(() => setFlash(null), 2000);\n };\n\n const doApprove = useCallback(async () => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n if (fm.status === \"validated\") { flash_(\"Already validated\"); return; }\n await writeFile(\n selected.filePath,\n serializeMemory({ frontmatter: { ...fm, status: \"validated\" as const }, body: selected.memory.body }),\n \"utf8\",\n );\n flash_(`✓ Approved ${fm.id.slice(0, 32)}…`);\n const prev = cursor;\n await reload();\n setCursor(prev);\n }, [selected, cursor, reload]);\n\n const doReject = useCallback(async () => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n if (fm.status === \"rejected\") { flash_(\"Already rejected\", \"red\"); return; }\n await writeFile(\n selected.filePath,\n serializeMemory({ frontmatter: { ...fm, status: \"rejected\" as const }, body: selected.memory.body }),\n \"utf8\",\n );\n flash_(`✗ Rejected ${fm.id.slice(0, 32)}…`, \"red\");\n await reload();\n setCursor((c) => Math.min(c, Math.max(0, filtered.length - 2)));\n }, [selected, filtered.length, reload]);\n\n useInput((input, key) => {\n if (input === \"q\") { exit(); return; }\n if (key.upArrow) setCursor((c) => Math.max(0, c - 1));\n if (key.downArrow) setCursor((c) => Math.min(filtered.length - 1, c + 1));\n if (key.tab) {\n setFilterIdx((i) => (i + 1) % FILTERS.length);\n setCursor(0);\n }\n if (input === \"a\") void doApprove();\n if (input === \"r\") void doReject();\n });\n\n if (loading) {\n return <Text dimColor>Loading memories…</Text>;\n }\n\n if (!existsSync(paths.memoriesDir)) {\n return <Text color=\"red\">No .ai/memories found — run `haive init` first.</Text>;\n }\n\n // Compute scrolling window\n const half = Math.floor(LIST_H / 2);\n const start = Math.max(0, Math.min(cursor - half, Math.max(0, filtered.length - LIST_H)));\n const visible = filtered.slice(start, start + LIST_H);\n\n const v = counts[\"validated\"] ?? 0;\n const p = counts[\"proposed\"] ?? 0;\n const d = counts[\"draft\"] ?? 0;\n const s = counts[\"stale\"] ?? 0;\n const rej = counts[\"rejected\"] ?? 0;\n\n return (\n <Box flexDirection=\"column\">\n\n {/* ── Header ── */}\n <Box borderStyle=\"round\" paddingX={1} gap={2}>\n <Text bold color=\"cyan\">hAIve</Text>\n <Text dimColor>{root}</Text>\n <Text> </Text>\n <Text color=\"green\">✓ {v}</Text>\n <Text> · </Text>\n <Text color={p > 0 ? \"yellow\" : undefined}>~ {p}</Text>\n <Text> · </Text>\n <Text dimColor>· {d}</Text>\n {s > 0 && <><Text> · </Text><Text color=\"yellow\">⚠ {s}</Text></>}\n {rej > 0 && <><Text> · </Text><Text color=\"red\">✗ {rej}</Text></>}\n </Box>\n\n {/* ── Filter bar ── */}\n <Box paddingX={1} gap={2}>\n {FILTERS.map((f) => (\n <Text key={f} color={filter === f ? \"cyan\" : undefined} bold={filter === f}>\n {filter === f ? `[${f}]` : f}\n </Text>\n ))}\n <Text dimColor> tab→cycle</Text>\n </Box>\n\n {/* ── List + Preview ── */}\n <Box>\n\n {/* List panel */}\n <Box flexDirection=\"column\" width={64} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>{`MEMORIES ${filtered.length}/${memories.length}`}</Text>\n {filtered.length === 0 ? (\n <Text dimColor> (no memories)</Text>\n ) : (\n visible.map((m, vi) => {\n const absIdx = start + vi;\n const fm = m.memory.frontmatter;\n const sel = absIdx === cursor;\n const idShort = fm.id.length > 43 ? fm.id.slice(0, 40) + \"…\" : fm.id;\n return (\n <Box key={fm.id}>\n <Text color={sel ? \"cyan\" : undefined} bold={sel}>\n {sel ? \"▶ \" : \" \"}\n {idShort.padEnd(43)}\n </Text>\n <Text color={statusColor(fm.status)}>{fm.status.slice(0, 9)}</Text>\n </Box>\n );\n })\n )}\n </Box>\n\n {/* Preview panel */}\n <Box flexDirection=\"column\" width={36} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>PREVIEW</Text>\n {selected ? (\n <>\n <Text color=\"cyan\">\n {selected.memory.frontmatter.scope}/{selected.memory.frontmatter.type}\n </Text>\n <Text color={statusColor(selected.memory.frontmatter.status)}>\n {selected.memory.frontmatter.status}\n </Text>\n <Text> </Text>\n {selected.memory.body\n .split(\"\\n\")\n .slice(0, LIST_H - 1)\n .map((line, i) => (\n <Text key={i} wrap=\"truncate-end\">\n {line || \" \"}\n </Text>\n ))}\n </>\n ) : (\n <Text dimColor>select a memory</Text>\n )}\n </Box>\n\n </Box>\n\n {/* ── Flash message ── */}\n {flash && (\n <Box paddingX={1}>\n <Text color={flash.color}>{flash.text}</Text>\n </Box>\n )}\n\n {/* ── Footer ── */}\n <Box paddingX={1}>\n <Text dimColor>\n ↑↓ navigate [tab] filter [a] approve [r] reject [q] quit\n </Text>\n </Box>\n\n </Box>\n );\n}\n"],"mappings":"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","names":["s"]}
|
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 Command25 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/briefing.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -122,15 +122,34 @@ function parseCsv(value) {
|
|
|
122
122
|
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
// src/commands/tui.ts
|
|
126
|
+
import "commander";
|
|
127
|
+
import { findProjectRoot as findProjectRoot2 } from "@hiveai/core";
|
|
128
|
+
function registerTui(program2) {
|
|
129
|
+
program2.command("tui").description("Interactive TUI dashboard \u2014 browse, filter, and manage memories in the terminal").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
130
|
+
if (!process.stdout.isTTY) {
|
|
131
|
+
console.error("haive tui requires an interactive terminal (TTY).");
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const root = findProjectRoot2(opts.dir);
|
|
136
|
+
const { render } = await import("ink");
|
|
137
|
+
const { createElement } = await import("react");
|
|
138
|
+
const { Dashboard } = await import("./Dashboard-SRPCHP7Z.js");
|
|
139
|
+
const { waitUntilExit } = render(createElement(Dashboard, { root }));
|
|
140
|
+
await waitUntilExit();
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
125
144
|
// src/commands/embeddings.ts
|
|
126
145
|
import { existsSync as existsSync2 } from "fs";
|
|
127
146
|
import path from "path";
|
|
128
147
|
import "commander";
|
|
129
|
-
import { findProjectRoot as
|
|
148
|
+
import { findProjectRoot as findProjectRoot3, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
|
|
130
149
|
function registerEmbeddings(program2) {
|
|
131
150
|
const embeddings = program2.command("embeddings").description("Manage local embeddings index for semantic search");
|
|
132
151
|
embeddings.command("index").description("Generate or refresh the embeddings index for all memories").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
133
|
-
const root =
|
|
152
|
+
const root = findProjectRoot3(opts.dir);
|
|
134
153
|
const paths = resolveHaivePaths2(root);
|
|
135
154
|
if (!existsSync2(paths.memoriesDir)) {
|
|
136
155
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -147,7 +166,7 @@ function registerEmbeddings(program2) {
|
|
|
147
166
|
);
|
|
148
167
|
});
|
|
149
168
|
embeddings.command("query <text>").description("Run a semantic search against the local embeddings index").option("-d, --dir <dir>", "project root").option("--limit <n>", "max results", "10").option("--min-score <n>", "minimum cosine similarity (0-1)", "0").action(async (text, opts) => {
|
|
150
|
-
const root =
|
|
169
|
+
const root = findProjectRoot3(opts.dir);
|
|
151
170
|
const paths = resolveHaivePaths2(root);
|
|
152
171
|
const { semanticSearch } = await loadEmbeddings();
|
|
153
172
|
const result = await semanticSearch(paths, text, {
|
|
@@ -170,7 +189,7 @@ function registerEmbeddings(program2) {
|
|
|
170
189
|
}
|
|
171
190
|
});
|
|
172
191
|
embeddings.command("status").description("Show the embeddings index status").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
173
|
-
const root =
|
|
192
|
+
const root = findProjectRoot3(opts.dir);
|
|
174
193
|
const paths = resolveHaivePaths2(root);
|
|
175
194
|
const { indexStat } = await loadEmbeddings();
|
|
176
195
|
const stat = await indexStat(paths);
|
|
@@ -201,7 +220,7 @@ import "commander";
|
|
|
201
220
|
import {
|
|
202
221
|
buildCodeMap,
|
|
203
222
|
codeMapPath,
|
|
204
|
-
findProjectRoot as
|
|
223
|
+
findProjectRoot as findProjectRoot4,
|
|
205
224
|
resolveHaivePaths as resolveHaivePaths3,
|
|
206
225
|
saveCodeMap
|
|
207
226
|
} from "@hiveai/core";
|
|
@@ -213,7 +232,7 @@ function registerIndexCode(program2) {
|
|
|
213
232
|
"extra directory names to skip (comma-separated)",
|
|
214
233
|
""
|
|
215
234
|
).action(async (opts) => {
|
|
216
|
-
const root =
|
|
235
|
+
const root = findProjectRoot4(opts.dir);
|
|
217
236
|
const paths = resolveHaivePaths3(root);
|
|
218
237
|
const extraExcludes = (opts.exclude ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
219
238
|
ui.info(`Indexing source files in ${root}\u2026`);
|
|
@@ -311,7 +330,7 @@ import { mkdir as mkdir2, writeFile as writeFile2, chmod, readFile as readFile2
|
|
|
311
330
|
import { existsSync as existsSync4 } from "fs";
|
|
312
331
|
import path4 from "path";
|
|
313
332
|
import "commander";
|
|
314
|
-
import { findProjectRoot as
|
|
333
|
+
import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
|
|
315
334
|
var HOOK_MARKER = "# hAIve auto-generated";
|
|
316
335
|
var HOOK_BODY = `#!/bin/sh
|
|
317
336
|
${HOOK_MARKER} \u2014 keep this block to allow upgrades. Hand-edit anything outside it.
|
|
@@ -327,7 +346,7 @@ fi
|
|
|
327
346
|
var HOOKS = ["post-merge", "post-rewrite"];
|
|
328
347
|
function registerInstallHooks(program2) {
|
|
329
348
|
program2.command("install-hooks").description("Install git hooks that run `haive sync` after pull/merge").option("-d, --dir <dir>", "project root").option("--force", "overwrite existing hooks").action(async (opts) => {
|
|
330
|
-
const root =
|
|
349
|
+
const root = findProjectRoot6(opts.dir);
|
|
331
350
|
const gitDir = path4.join(root, ".git");
|
|
332
351
|
if (!existsSync4(gitDir)) {
|
|
333
352
|
ui.error(`No .git directory at ${root}.`);
|
|
@@ -364,11 +383,11 @@ import { createRequire } from "module";
|
|
|
364
383
|
import path5 from "path";
|
|
365
384
|
import { fileURLToPath } from "url";
|
|
366
385
|
import "commander";
|
|
367
|
-
import { findProjectRoot as
|
|
386
|
+
import { findProjectRoot as findProjectRoot7 } from "@hiveai/core";
|
|
368
387
|
var require2 = createRequire(import.meta.url);
|
|
369
388
|
function registerMcp(program2) {
|
|
370
389
|
program2.command("mcp").description("Start the hAIve MCP server (stdio transport)").option("-d, --dir <dir>", "project root (defaults to nearest .ai/ or .git/)").action((opts) => {
|
|
371
|
-
const root =
|
|
390
|
+
const root = findProjectRoot7(opts.dir);
|
|
372
391
|
const bin = locateMcpBin();
|
|
373
392
|
if (!bin) {
|
|
374
393
|
ui.error(
|
|
@@ -405,7 +424,7 @@ import "path";
|
|
|
405
424
|
import "commander";
|
|
406
425
|
import {
|
|
407
426
|
DEFAULT_AUTO_PROMOTE_RULE,
|
|
408
|
-
findProjectRoot as
|
|
427
|
+
findProjectRoot as findProjectRoot8,
|
|
409
428
|
getUsage,
|
|
410
429
|
isAutoPromoteEligible,
|
|
411
430
|
loadMemoriesFromDir as loadMemoriesFromDir2,
|
|
@@ -419,7 +438,7 @@ function registerSync(program2) {
|
|
|
419
438
|
"--since <ref>",
|
|
420
439
|
"git ref/commit to compare against; report memories added/modified/removed since"
|
|
421
440
|
).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").action(async (opts) => {
|
|
422
|
-
const root =
|
|
441
|
+
const root = findProjectRoot8(opts.dir);
|
|
423
442
|
const paths = resolveHaivePaths5(root);
|
|
424
443
|
if (!existsSync6(paths.memoriesDir)) {
|
|
425
444
|
if (!opts.quiet) ui.warn(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -552,7 +571,7 @@ import path7 from "path";
|
|
|
552
571
|
import "commander";
|
|
553
572
|
import {
|
|
554
573
|
buildFrontmatter,
|
|
555
|
-
findProjectRoot as
|
|
574
|
+
findProjectRoot as findProjectRoot9,
|
|
556
575
|
inferModulesFromPaths,
|
|
557
576
|
memoryFilePath,
|
|
558
577
|
resolveHaivePaths as resolveHaivePaths6,
|
|
@@ -560,7 +579,7 @@ import {
|
|
|
560
579
|
} from "@hiveai/core";
|
|
561
580
|
function registerMemoryAdd(memory2) {
|
|
562
581
|
memory2.command("add").description("Add a new memory (defaults to personal scope)").requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary").requiredOption("--slug <slug>", "short 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", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor paths, comma-separated").option("--symbols <csv>", "anchor symbols, comma-separated").option("--commit <sha>", "anchor commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
563
|
-
const root =
|
|
582
|
+
const root = findProjectRoot9(opts.dir);
|
|
564
583
|
const paths = resolveHaivePaths6(root);
|
|
565
584
|
if (!existsSync7(paths.haiveDir)) {
|
|
566
585
|
ui.error(`No .ai/ found at ${root}. Run \`haive init\` first.`);
|
|
@@ -631,7 +650,7 @@ function parseCsv2(value) {
|
|
|
631
650
|
import { existsSync as existsSync8 } from "fs";
|
|
632
651
|
import path8 from "path";
|
|
633
652
|
import "commander";
|
|
634
|
-
import { findProjectRoot as
|
|
653
|
+
import { findProjectRoot as findProjectRoot10, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
|
|
635
654
|
|
|
636
655
|
// src/utils/fs.ts
|
|
637
656
|
import {
|
|
@@ -643,7 +662,7 @@ import {
|
|
|
643
662
|
// src/commands/memory-list.ts
|
|
644
663
|
function registerMemoryList(memory2) {
|
|
645
664
|
memory2.command("list").description("List memories with optional filters").option("--scope <scope>", "personal | team | module").option("--type <type>", "filter by type").option("--tag <tag>", "filter by tag").option("--module <name>", "filter by module name").option("--status <csv>", "filter by status (draft,proposed,validated,stale,rejected,deprecated)").option("--show-rejected", "include rejected memories (hidden by default)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
646
|
-
const root =
|
|
665
|
+
const root = findProjectRoot10(opts.dir);
|
|
647
666
|
const paths = resolveHaivePaths7(root);
|
|
648
667
|
if (!existsSync8(paths.memoriesDir)) {
|
|
649
668
|
ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
|
|
@@ -717,14 +736,14 @@ import { existsSync as existsSync9 } from "fs";
|
|
|
717
736
|
import path9 from "path";
|
|
718
737
|
import "commander";
|
|
719
738
|
import {
|
|
720
|
-
findProjectRoot as
|
|
739
|
+
findProjectRoot as findProjectRoot11,
|
|
721
740
|
memoryFilePath as memoryFilePath2,
|
|
722
741
|
resolveHaivePaths as resolveHaivePaths8,
|
|
723
742
|
serializeMemory as serializeMemory3
|
|
724
743
|
} from "@hiveai/core";
|
|
725
744
|
function registerMemoryPromote(memory2) {
|
|
726
745
|
memory2.command("promote <id>").description("Promote a personal memory to team scope (status -> proposed)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
727
|
-
const root =
|
|
746
|
+
const root = findProjectRoot11(opts.dir);
|
|
728
747
|
const paths = resolveHaivePaths8(root);
|
|
729
748
|
if (!existsSync9(paths.memoriesDir)) {
|
|
730
749
|
ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
|
|
@@ -776,13 +795,13 @@ import { writeFile as writeFile6 } from "fs/promises";
|
|
|
776
795
|
import path10 from "path";
|
|
777
796
|
import "commander";
|
|
778
797
|
import {
|
|
779
|
-
findProjectRoot as
|
|
798
|
+
findProjectRoot as findProjectRoot12,
|
|
780
799
|
resolveHaivePaths as resolveHaivePaths9,
|
|
781
800
|
serializeMemory as serializeMemory4
|
|
782
801
|
} from "@hiveai/core";
|
|
783
802
|
function registerMemoryApprove(memory2) {
|
|
784
803
|
memory2.command("approve [id]").description("Mark a memory as 'validated'. Use --all to bulk-approve all proposed/draft memories.").option("--all", "approve all proposed and draft memories at once").option("--pending", "approve all memories with status 'proposed'").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
785
|
-
const root =
|
|
804
|
+
const root = findProjectRoot12(opts.dir);
|
|
786
805
|
const paths = resolveHaivePaths9(root);
|
|
787
806
|
if (!existsSync10(paths.memoriesDir)) {
|
|
788
807
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -847,13 +866,13 @@ import { existsSync as existsSync11 } from "fs";
|
|
|
847
866
|
import path11 from "path";
|
|
848
867
|
import "commander";
|
|
849
868
|
import {
|
|
850
|
-
findProjectRoot as
|
|
869
|
+
findProjectRoot as findProjectRoot13,
|
|
851
870
|
resolveHaivePaths as resolveHaivePaths10,
|
|
852
871
|
serializeMemory as serializeMemory5
|
|
853
872
|
} from "@hiveai/core";
|
|
854
873
|
function registerMemoryUpdate(memory2) {
|
|
855
874
|
memory2.command("update <id>").description("Update body, tags, or anchor of an existing memory (preserves id and usage history)").option("--title <text>", "new title \u2014 replaces the first heading of the body").option("--body <text>", "new Markdown body \u2014 replaces the existing body").option("--tags <csv>", "new tags, comma-separated \u2014 fully replaces existing tags").option("--paths <csv>", "new anchor paths, comma-separated").option("--symbols <csv>", "new anchor symbols, comma-separated").option("--commit <sha>", "new anchor commit SHA").option("--domain <domain>", "new domain label").option("--author <author>", "new author handle or email").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
856
|
-
const root =
|
|
875
|
+
const root = findProjectRoot13(opts.dir);
|
|
857
876
|
const paths = resolveHaivePaths10(root);
|
|
858
877
|
if (!existsSync11(paths.memoriesDir)) {
|
|
859
878
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -932,7 +951,7 @@ import path12 from "path";
|
|
|
932
951
|
import "commander";
|
|
933
952
|
import {
|
|
934
953
|
DEFAULT_AUTO_PROMOTE_RULE as DEFAULT_AUTO_PROMOTE_RULE2,
|
|
935
|
-
findProjectRoot as
|
|
954
|
+
findProjectRoot as findProjectRoot14,
|
|
936
955
|
getUsage as getUsage2,
|
|
937
956
|
isAutoPromoteEligible as isAutoPromoteEligible2,
|
|
938
957
|
loadUsageIndex as loadUsageIndex2,
|
|
@@ -945,7 +964,7 @@ function registerMemoryAutoPromote(memory2) {
|
|
|
945
964
|
"memories with more rejections than this are skipped",
|
|
946
965
|
String(DEFAULT_AUTO_PROMOTE_RULE2.maxRejections)
|
|
947
966
|
).option("--apply", "actually write status=validated to disk (default: dry-run)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
948
|
-
const root =
|
|
967
|
+
const root = findProjectRoot14(opts.dir);
|
|
949
968
|
const paths = resolveHaivePaths11(root);
|
|
950
969
|
if (!existsSync12(paths.memoriesDir)) {
|
|
951
970
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -995,13 +1014,13 @@ import { readFile as readFile3 } from "fs/promises";
|
|
|
995
1014
|
import path13 from "path";
|
|
996
1015
|
import "commander";
|
|
997
1016
|
import {
|
|
998
|
-
findProjectRoot as
|
|
1017
|
+
findProjectRoot as findProjectRoot15,
|
|
999
1018
|
parseMemory,
|
|
1000
1019
|
resolveHaivePaths as resolveHaivePaths12
|
|
1001
1020
|
} from "@hiveai/core";
|
|
1002
1021
|
function registerMemoryEdit(memory2) {
|
|
1003
1022
|
memory2.command("edit <id>").description("Open a memory in $EDITOR and re-validate when you save").option("-e, --editor <cmd>", "editor command (defaults to $EDITOR or 'vi')").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1004
|
-
const root =
|
|
1023
|
+
const root = findProjectRoot15(opts.dir);
|
|
1005
1024
|
const paths = resolveHaivePaths12(root);
|
|
1006
1025
|
if (!existsSync13(paths.memoriesDir)) {
|
|
1007
1026
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1048,7 +1067,7 @@ import path14 from "path";
|
|
|
1048
1067
|
import "commander";
|
|
1049
1068
|
import {
|
|
1050
1069
|
deriveConfidence,
|
|
1051
|
-
findProjectRoot as
|
|
1070
|
+
findProjectRoot as findProjectRoot16,
|
|
1052
1071
|
getUsage as getUsage3,
|
|
1053
1072
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
1054
1073
|
loadUsageIndex as loadUsageIndex3,
|
|
@@ -1057,7 +1076,7 @@ import {
|
|
|
1057
1076
|
} from "@hiveai/core";
|
|
1058
1077
|
function registerMemoryForFiles(memory2) {
|
|
1059
1078
|
memory2.command("for-files <files...>").description("Show memories relevant to the given files (anchor overlap, module, domain)").option("-d, --dir <dir>", "project root").action(async (files, opts) => {
|
|
1060
|
-
const root =
|
|
1079
|
+
const root = findProjectRoot16(opts.dir);
|
|
1061
1080
|
const paths = resolveHaivePaths13(root);
|
|
1062
1081
|
if (!existsSync14(paths.memoriesDir)) {
|
|
1063
1082
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1121,14 +1140,14 @@ import { existsSync as existsSync15 } from "fs";
|
|
|
1121
1140
|
import path15 from "path";
|
|
1122
1141
|
import "commander";
|
|
1123
1142
|
import {
|
|
1124
|
-
findProjectRoot as
|
|
1143
|
+
findProjectRoot as findProjectRoot17,
|
|
1125
1144
|
getUsage as getUsage4,
|
|
1126
1145
|
loadUsageIndex as loadUsageIndex4,
|
|
1127
1146
|
resolveHaivePaths as resolveHaivePaths14
|
|
1128
1147
|
} from "@hiveai/core";
|
|
1129
1148
|
function registerMemoryHot(memory2) {
|
|
1130
1149
|
memory2.command("hot").description("List memories actively used but not yet validated (good promotion candidates)").option("--threshold <n>", "minimum read_count to qualify", "3").option("--status <status>", "limit to one status (default: draft + proposed)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1131
|
-
const root =
|
|
1150
|
+
const root = findProjectRoot17(opts.dir);
|
|
1132
1151
|
const paths = resolveHaivePaths14(root);
|
|
1133
1152
|
if (!existsSync15(paths.memoriesDir)) {
|
|
1134
1153
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1171,14 +1190,14 @@ import { existsSync as existsSync16 } from "fs";
|
|
|
1171
1190
|
import path16 from "path";
|
|
1172
1191
|
import "commander";
|
|
1173
1192
|
import {
|
|
1174
|
-
findProjectRoot as
|
|
1193
|
+
findProjectRoot as findProjectRoot18,
|
|
1175
1194
|
getUsage as getUsage5,
|
|
1176
1195
|
loadUsageIndex as loadUsageIndex5,
|
|
1177
1196
|
resolveHaivePaths as resolveHaivePaths15
|
|
1178
1197
|
} from "@hiveai/core";
|
|
1179
1198
|
function registerMemoryPending(memory2) {
|
|
1180
1199
|
memory2.command("pending").description("List 'proposed' memories awaiting review (sorted by reads desc)").option("--scope <scope>", "filter by scope (personal | team | module)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1181
|
-
const root =
|
|
1200
|
+
const root = findProjectRoot18(opts.dir);
|
|
1182
1201
|
const paths = resolveHaivePaths15(root);
|
|
1183
1202
|
if (!existsSync16(paths.memoriesDir)) {
|
|
1184
1203
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1220,7 +1239,7 @@ import path17 from "path";
|
|
|
1220
1239
|
import "commander";
|
|
1221
1240
|
import {
|
|
1222
1241
|
extractSnippet,
|
|
1223
|
-
findProjectRoot as
|
|
1242
|
+
findProjectRoot as findProjectRoot19,
|
|
1224
1243
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
1225
1244
|
pickSnippetNeedle,
|
|
1226
1245
|
resolveHaivePaths as resolveHaivePaths16,
|
|
@@ -1228,7 +1247,7 @@ import {
|
|
|
1228
1247
|
} from "@hiveai/core";
|
|
1229
1248
|
function registerMemoryQuery(memory2) {
|
|
1230
1249
|
memory2.command("query <text>").description("Search memories by id, tag, or substring (multi-word AND)").option("-d, --dir <dir>", "project root").option("--limit <n>", "max results", "20").option("--scope <scope>", "personal | team | module").option("--status <csv>", "filter by status (draft,proposed,validated,stale,rejected)").option("--show-rejected", "include rejected memories (hidden by default)").action(async (text, opts) => {
|
|
1231
|
-
const root =
|
|
1250
|
+
const root = findProjectRoot19(opts.dir);
|
|
1232
1251
|
const paths = resolveHaivePaths16(root);
|
|
1233
1252
|
if (!existsSync17(paths.memoriesDir)) {
|
|
1234
1253
|
ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
|
|
@@ -1272,7 +1291,7 @@ import { writeFile as writeFile9 } from "fs/promises";
|
|
|
1272
1291
|
import { existsSync as existsSync18 } from "fs";
|
|
1273
1292
|
import "commander";
|
|
1274
1293
|
import {
|
|
1275
|
-
findProjectRoot as
|
|
1294
|
+
findProjectRoot as findProjectRoot20,
|
|
1276
1295
|
loadUsageIndex as loadUsageIndex6,
|
|
1277
1296
|
recordRejection,
|
|
1278
1297
|
resolveHaivePaths as resolveHaivePaths17,
|
|
@@ -1281,7 +1300,7 @@ import {
|
|
|
1281
1300
|
} from "@hiveai/core";
|
|
1282
1301
|
function registerMemoryReject(memory2) {
|
|
1283
1302
|
memory2.command("reject <id>").description("Record a rejection (blocks auto-promotion and lowers confidence)").option("-r, --reason <reason>", "why this memory is being rejected").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1284
|
-
const root =
|
|
1303
|
+
const root = findProjectRoot20(opts.dir);
|
|
1285
1304
|
const paths = resolveHaivePaths17(root);
|
|
1286
1305
|
if (!existsSync18(paths.memoriesDir)) {
|
|
1287
1306
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1325,14 +1344,14 @@ import path18 from "path";
|
|
|
1325
1344
|
import { createInterface } from "readline/promises";
|
|
1326
1345
|
import "commander";
|
|
1327
1346
|
import {
|
|
1328
|
-
findProjectRoot as
|
|
1347
|
+
findProjectRoot as findProjectRoot21,
|
|
1329
1348
|
loadUsageIndex as loadUsageIndex7,
|
|
1330
1349
|
resolveHaivePaths as resolveHaivePaths18,
|
|
1331
1350
|
saveUsageIndex as saveUsageIndex2
|
|
1332
1351
|
} from "@hiveai/core";
|
|
1333
1352
|
function registerMemoryRm(memory2) {
|
|
1334
1353
|
memory2.command("rm <id>").description("Delete a memory file (and its usage entry by default)").option("-y, --yes", "skip the confirmation prompt").option("--keep-usage", "do not remove the usage.json entry").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1335
|
-
const root =
|
|
1354
|
+
const root = findProjectRoot21(opts.dir);
|
|
1336
1355
|
const paths = resolveHaivePaths18(root);
|
|
1337
1356
|
if (!existsSync19(paths.memoriesDir)) {
|
|
1338
1357
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1376,14 +1395,14 @@ import path19 from "path";
|
|
|
1376
1395
|
import "commander";
|
|
1377
1396
|
import {
|
|
1378
1397
|
deriveConfidence as deriveConfidence2,
|
|
1379
|
-
findProjectRoot as
|
|
1398
|
+
findProjectRoot as findProjectRoot22,
|
|
1380
1399
|
getUsage as getUsage6,
|
|
1381
1400
|
loadUsageIndex as loadUsageIndex8,
|
|
1382
1401
|
resolveHaivePaths as resolveHaivePaths19
|
|
1383
1402
|
} from "@hiveai/core";
|
|
1384
1403
|
function registerMemoryShow(memory2) {
|
|
1385
1404
|
memory2.command("show <id>").description("Print a memory's frontmatter, body, and confidence/usage").option("--raw", "print the raw file contents instead of a summary").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1386
|
-
const root =
|
|
1405
|
+
const root = findProjectRoot22(opts.dir);
|
|
1387
1406
|
const paths = resolveHaivePaths19(root);
|
|
1388
1407
|
if (!existsSync20(paths.memoriesDir)) {
|
|
1389
1408
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1434,14 +1453,14 @@ import path20 from "path";
|
|
|
1434
1453
|
import "commander";
|
|
1435
1454
|
import {
|
|
1436
1455
|
deriveConfidence as deriveConfidence3,
|
|
1437
|
-
findProjectRoot as
|
|
1456
|
+
findProjectRoot as findProjectRoot23,
|
|
1438
1457
|
getUsage as getUsage7,
|
|
1439
1458
|
loadUsageIndex as loadUsageIndex9,
|
|
1440
1459
|
resolveHaivePaths as resolveHaivePaths20
|
|
1441
1460
|
} from "@hiveai/core";
|
|
1442
1461
|
function registerMemoryStats(memory2) {
|
|
1443
1462
|
memory2.command("stats").description("Show usage stats and confidence levels per memory").option("--id <id>", "show stats for a single memory id").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1444
|
-
const root =
|
|
1463
|
+
const root = findProjectRoot23(opts.dir);
|
|
1445
1464
|
const paths = resolveHaivePaths20(root);
|
|
1446
1465
|
if (!existsSync21(paths.memoriesDir)) {
|
|
1447
1466
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -1479,14 +1498,14 @@ import { existsSync as existsSync22 } from "fs";
|
|
|
1479
1498
|
import path21 from "path";
|
|
1480
1499
|
import "commander";
|
|
1481
1500
|
import {
|
|
1482
|
-
findProjectRoot as
|
|
1501
|
+
findProjectRoot as findProjectRoot24,
|
|
1483
1502
|
resolveHaivePaths as resolveHaivePaths21,
|
|
1484
1503
|
serializeMemory as serializeMemory8,
|
|
1485
1504
|
verifyAnchor as verifyAnchor2
|
|
1486
1505
|
} from "@hiveai/core";
|
|
1487
1506
|
function registerMemoryVerify(memory2) {
|
|
1488
1507
|
memory2.command("verify").description("Check memory anchors against current code, optionally marking stale ones").option("--id <id>", "verify a single memory by id").option("--all", "verify every memory (default if --id is omitted)").option("--update", "write status=stale (or status=validated for re-freshed) back to disk").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1489
|
-
const root =
|
|
1508
|
+
const root = findProjectRoot24(opts.dir);
|
|
1490
1509
|
const paths = resolveHaivePaths21(root);
|
|
1491
1510
|
if (!existsSync22(paths.memoriesDir)) {
|
|
1492
1511
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -1562,11 +1581,12 @@ function applyVerification(mem, result) {
|
|
|
1562
1581
|
}
|
|
1563
1582
|
|
|
1564
1583
|
// src/index.ts
|
|
1565
|
-
var program = new
|
|
1566
|
-
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.
|
|
1584
|
+
var program = new Command25();
|
|
1585
|
+
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.5");
|
|
1567
1586
|
registerInit(program);
|
|
1568
1587
|
registerMcp(program);
|
|
1569
1588
|
registerBriefing(program);
|
|
1589
|
+
registerTui(program);
|
|
1570
1590
|
registerEmbeddings(program);
|
|
1571
1591
|
registerSync(program);
|
|
1572
1592
|
registerInstallHooks(program);
|