hoomanjs 1.28.1 → 1.28.3
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/README.md +10 -16
- package/dist/acp/sessions/config-options.js +2 -2
- package/dist/acp/sessions/config-options.js.map +1 -1
- package/dist/acp/utils/tool-kind.js +4 -4
- package/dist/chat/index.js +1 -1
- package/dist/chat/index.js.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/configure/app.js +5 -113
- package/dist/configure/app.js.map +1 -1
- package/dist/core/agent/index.d.ts +1 -1
- package/dist/core/agent/index.js +14 -2
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/config.d.ts +10 -36
- package/dist/core/config.js +13 -66
- package/dist/core/config.js.map +1 -1
- package/dist/core/memory/index.d.ts +1 -0
- package/dist/core/memory/index.js +1 -0
- package/dist/core/memory/index.js.map +1 -1
- package/dist/core/memory/ltm/llama-embed.d.ts +28 -0
- package/dist/core/memory/ltm/llama-embed.js +204 -0
- package/dist/core/memory/ltm/llama-embed.js.map +1 -0
- package/dist/core/memory/ltm/sqlite.d.ts +12 -0
- package/dist/core/memory/ltm/sqlite.js +101 -0
- package/dist/core/memory/ltm/sqlite.js.map +1 -0
- package/dist/core/memory/ltm/store.d.ts +13 -6
- package/dist/core/memory/ltm/store.js +192 -92
- package/dist/core/memory/ltm/store.js.map +1 -1
- package/dist/core/memory/ltm/tools.js +4 -4
- package/dist/core/memory/ltm/utils.d.ts +9 -11
- package/dist/core/memory/ltm/utils.js +14 -15
- package/dist/core/memory/ltm/utils.js.map +1 -1
- package/dist/core/memory/wiki/index.d.ts +4 -0
- package/dist/core/memory/wiki/index.js +4 -0
- package/dist/core/memory/wiki/index.js.map +1 -0
- package/dist/core/memory/wiki/store.d.ts +37 -0
- package/dist/core/memory/wiki/store.js +317 -0
- package/dist/core/memory/wiki/store.js.map +1 -0
- package/dist/core/memory/wiki/tools.d.ts +11 -0
- package/dist/core/memory/wiki/tools.js +291 -0
- package/dist/core/memory/wiki/tools.js.map +1 -0
- package/dist/core/memory/wiki/types.d.ts +25 -0
- package/dist/core/memory/wiki/types.js +2 -0
- package/dist/core/memory/wiki/types.js.map +1 -0
- package/dist/core/prompts/static/ltm.md +4 -4
- package/dist/core/prompts/static/wiki.md +2 -2
- package/dist/core/prompts/system.d.ts +4 -0
- package/dist/core/prompts/system.js +36 -4
- package/dist/core/prompts/system.js.map +1 -1
- package/dist/core/skills/built-in/hooman-config/SKILL.md +8 -30
- package/dist/core/state/tool-approvals.js +5 -5
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/plan.d.ts +2 -2
- package/dist/core/utils/paths.d.ts +7 -0
- package/dist/core/utils/paths.js +9 -0
- package/dist/core/utils/paths.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/package.json +18 -3
- package/dist/core/memory/ltm/embed.d.ts +0 -16
- package/dist/core/memory/ltm/embed.js +0 -49
- package/dist/core/memory/ltm/embed.js.map +0 -1
- package/dist/core/tools/wiki.d.ts +0 -11
- package/dist/core/tools/wiki.js +0 -566
- package/dist/core/tools/wiki.js.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type QMDStore } from "@tobilu/qmd";
|
|
2
|
+
import { type Config } from "../../config.js";
|
|
3
|
+
import type { PageRecord } from "./types.js";
|
|
4
|
+
export declare const PAGES_DIR = "pages";
|
|
5
|
+
export declare const INDEX_FILE = "index.md";
|
|
6
|
+
export declare const LOG_FILE = "log.md";
|
|
7
|
+
export declare const SCHEMA_FILE = "schema.md";
|
|
8
|
+
export declare const DEFAULT_SEARCH_LIMIT = 5;
|
|
9
|
+
export declare const MAX_SEARCH_LIMIT = 20;
|
|
10
|
+
/** QMD collection name for wiki pages (fixed; not user-configurable). */
|
|
11
|
+
export declare const QMD_COLLECTION = "wiki";
|
|
12
|
+
export declare class WikiStore {
|
|
13
|
+
readonly root: string;
|
|
14
|
+
private static readonly instances;
|
|
15
|
+
private qmdStorePromise;
|
|
16
|
+
private constructor();
|
|
17
|
+
/**
|
|
18
|
+
* Shared instance per wiki root so warmup and tools reuse the same QMD store promise.
|
|
19
|
+
*/
|
|
20
|
+
static forConfig(config: Config): WikiStore;
|
|
21
|
+
pageRelativePath(inputPath: string): string;
|
|
22
|
+
resolveWithin(relativePath: string): string;
|
|
23
|
+
pathExists(filePath: string): Promise<boolean>;
|
|
24
|
+
ensureLayout(): Promise<void>;
|
|
25
|
+
readPage(relativePath: string): Promise<PageRecord>;
|
|
26
|
+
private listPagePaths;
|
|
27
|
+
listPages(): Promise<PageRecord[]>;
|
|
28
|
+
writeIndex(pages: PageRecord[]): Promise<void>;
|
|
29
|
+
appendLog(operation: string, details: Record<string, string>): Promise<void>;
|
|
30
|
+
qmdStore(): Promise<QMDStore>;
|
|
31
|
+
/**
|
|
32
|
+
* Preload QMD models at startup (shared cache with LTM).
|
|
33
|
+
*/
|
|
34
|
+
warmup(): Promise<void>;
|
|
35
|
+
syncSearchIndex(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare function create(config: Config): WikiStore;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createStore } from "@tobilu/qmd";
|
|
4
|
+
import { resolveModelFile } from "node-llama-cpp";
|
|
5
|
+
import matter from "gray-matter";
|
|
6
|
+
import { DEFAULT_WIKI_EMBED_MODEL, DEFAULT_WIKI_GENERATE_MODEL, DEFAULT_WIKI_RERANK_MODEL, } from "../../config.js";
|
|
7
|
+
import { modelsCachePath, wikiDbPath, wikiPath } from "../../utils/paths.js";
|
|
8
|
+
export const PAGES_DIR = "pages";
|
|
9
|
+
export const INDEX_FILE = "index.md";
|
|
10
|
+
export const LOG_FILE = "log.md";
|
|
11
|
+
export const SCHEMA_FILE = "schema.md";
|
|
12
|
+
export const DEFAULT_SEARCH_LIMIT = 5;
|
|
13
|
+
export const MAX_SEARCH_LIMIT = 20;
|
|
14
|
+
/** QMD collection name for wiki pages (fixed; not user-configurable). */
|
|
15
|
+
export const QMD_COLLECTION = "wiki";
|
|
16
|
+
function stripLeadingSlashes(value) {
|
|
17
|
+
return value.replace(/^[/\\]+/, "");
|
|
18
|
+
}
|
|
19
|
+
function firstSentence(value, maxLength = 180) {
|
|
20
|
+
const clean = value.replace(/\s+/g, " ").trim();
|
|
21
|
+
if (!clean) {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
return clean.length > maxLength
|
|
25
|
+
? `${clean.slice(0, maxLength - 1).trimEnd()}…`
|
|
26
|
+
: clean;
|
|
27
|
+
}
|
|
28
|
+
function safeString(value) {
|
|
29
|
+
return typeof value === "string" && value.trim().length > 0
|
|
30
|
+
? value.trim()
|
|
31
|
+
: null;
|
|
32
|
+
}
|
|
33
|
+
function safeStringArray(value) {
|
|
34
|
+
if (!Array.isArray(value)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
return value
|
|
38
|
+
.filter((item) => typeof item === "string")
|
|
39
|
+
.map((item) => item.trim())
|
|
40
|
+
.filter((item) => item.length > 0);
|
|
41
|
+
}
|
|
42
|
+
function parseFrontmatter(content) {
|
|
43
|
+
const parsed = matter(content);
|
|
44
|
+
const data = parsed.data;
|
|
45
|
+
return {
|
|
46
|
+
frontmatter: {
|
|
47
|
+
title: safeString(data.title) ?? undefined,
|
|
48
|
+
summary: safeString(data.summary) ?? undefined,
|
|
49
|
+
tags: safeStringArray(data.tags),
|
|
50
|
+
related: safeStringArray(data.related),
|
|
51
|
+
type: safeString(data.type) ?? undefined,
|
|
52
|
+
created: safeString(data.created) ?? undefined,
|
|
53
|
+
updated: safeString(data.updated) ?? undefined,
|
|
54
|
+
},
|
|
55
|
+
body: parsed.content.trim(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function wordCount(content) {
|
|
59
|
+
const words = content.trim().match(/\S+/g);
|
|
60
|
+
return words ? words.length : 0;
|
|
61
|
+
}
|
|
62
|
+
function normalizeRelatedPath(value) {
|
|
63
|
+
let item = value.trim().replace(/\\/g, "/");
|
|
64
|
+
item = item.replace(/^\[\[|\]\]$/g, "");
|
|
65
|
+
item = stripLeadingSlashes(item);
|
|
66
|
+
if (!item.endsWith(".md")) {
|
|
67
|
+
item = `${item}.md`;
|
|
68
|
+
}
|
|
69
|
+
if (!item.startsWith(`${PAGES_DIR}/`)) {
|
|
70
|
+
item = `${PAGES_DIR}/${item}`;
|
|
71
|
+
}
|
|
72
|
+
return item;
|
|
73
|
+
}
|
|
74
|
+
function deriveTitle(relativePath, frontmatter) {
|
|
75
|
+
const fromFrontmatter = safeString(frontmatter.title);
|
|
76
|
+
if (fromFrontmatter) {
|
|
77
|
+
return fromFrontmatter;
|
|
78
|
+
}
|
|
79
|
+
return path.basename(relativePath, ".md").replace(/[-_]+/g, " ").trim();
|
|
80
|
+
}
|
|
81
|
+
function deriveSummary(frontmatter, body, fallback) {
|
|
82
|
+
const fromFrontmatter = safeString(frontmatter.summary);
|
|
83
|
+
if (fromFrontmatter) {
|
|
84
|
+
return firstSentence(fromFrontmatter);
|
|
85
|
+
}
|
|
86
|
+
const bodySummary = firstSentence(body);
|
|
87
|
+
return bodySummary || firstSentence(fallback) || "No summary available.";
|
|
88
|
+
}
|
|
89
|
+
function buildIndexMarkdown(pages) {
|
|
90
|
+
const sorted = [...pages].sort((a, b) => a.title.localeCompare(b.title));
|
|
91
|
+
const lines = [
|
|
92
|
+
"# Wiki Index",
|
|
93
|
+
"",
|
|
94
|
+
"<!-- Auto-generated by wiki_write_file. -->",
|
|
95
|
+
"",
|
|
96
|
+
`Updated: ${new Date().toISOString()}`,
|
|
97
|
+
"",
|
|
98
|
+
"## Pages",
|
|
99
|
+
];
|
|
100
|
+
if (sorted.length === 0) {
|
|
101
|
+
lines.push("- _No wiki pages yet._");
|
|
102
|
+
return `${lines.join("\n")}\n`;
|
|
103
|
+
}
|
|
104
|
+
for (const page of sorted) {
|
|
105
|
+
const tags = page.tags.length > 0 ? ` | tags: ${page.tags.join(", ")}` : "";
|
|
106
|
+
lines.push(`- [${page.title}](${page.path}): ${page.summary}${tags}`);
|
|
107
|
+
}
|
|
108
|
+
return `${lines.join("\n")}\n`;
|
|
109
|
+
}
|
|
110
|
+
function buildLogEntry(operation, details) {
|
|
111
|
+
const lines = [
|
|
112
|
+
`## [${new Date().toISOString()}] ${operation}`,
|
|
113
|
+
...Object.entries(details).map(([key, value]) => `- ${key}: ${value}`),
|
|
114
|
+
"",
|
|
115
|
+
];
|
|
116
|
+
return `${lines.join("\n")}\n`;
|
|
117
|
+
}
|
|
118
|
+
const DEFAULT_SCHEMA = `# Wiki Schema
|
|
119
|
+
|
|
120
|
+
This wiki is maintained by the agent through wiki tools.
|
|
121
|
+
|
|
122
|
+
## Structure
|
|
123
|
+
- \`pages/\`: markdown knowledge pages
|
|
124
|
+
- \`index.md\`: derived index (tool-managed)
|
|
125
|
+
- \`log.md\`: append-only activity log (tool-managed)
|
|
126
|
+
|
|
127
|
+
## Page conventions
|
|
128
|
+
- Use markdown files under \`pages/\`
|
|
129
|
+
- Prefer concise titles and summaries
|
|
130
|
+
- Add frontmatter when helpful (\`title\`, \`summary\`, \`tags\`, \`related\`, \`type\`)
|
|
131
|
+
- Use relative links to other pages when appropriate
|
|
132
|
+
`;
|
|
133
|
+
export class WikiStore {
|
|
134
|
+
root;
|
|
135
|
+
static instances = new Map();
|
|
136
|
+
qmdStorePromise = null;
|
|
137
|
+
constructor(_config, root) {
|
|
138
|
+
this.root = root;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Shared instance per wiki root so warmup and tools reuse the same QMD store promise.
|
|
142
|
+
*/
|
|
143
|
+
static forConfig(config) {
|
|
144
|
+
const root = wikiPath();
|
|
145
|
+
let inst = WikiStore.instances.get(root);
|
|
146
|
+
if (!inst) {
|
|
147
|
+
inst = new WikiStore(config, root);
|
|
148
|
+
WikiStore.instances.set(root, inst);
|
|
149
|
+
}
|
|
150
|
+
return inst;
|
|
151
|
+
}
|
|
152
|
+
pageRelativePath(inputPath) {
|
|
153
|
+
const normalized = stripLeadingSlashes(inputPath.trim().replace(/\\/g, "/"));
|
|
154
|
+
if (!normalized) {
|
|
155
|
+
throw new Error("Page path is required.");
|
|
156
|
+
}
|
|
157
|
+
const withPrefix = normalized.startsWith(`${PAGES_DIR}/`)
|
|
158
|
+
? normalized
|
|
159
|
+
: `${PAGES_DIR}/${normalized}`;
|
|
160
|
+
if (!withPrefix.toLowerCase().endsWith(".md")) {
|
|
161
|
+
throw new Error("Page paths must end with .md");
|
|
162
|
+
}
|
|
163
|
+
return withPrefix;
|
|
164
|
+
}
|
|
165
|
+
resolveWithin(relativePath) {
|
|
166
|
+
const abs = path.resolve(this.root, relativePath);
|
|
167
|
+
const normalizedRoot = path.resolve(this.root);
|
|
168
|
+
if (abs !== normalizedRoot &&
|
|
169
|
+
!abs.startsWith(`${normalizedRoot}${path.sep}`) &&
|
|
170
|
+
!(process.platform === "win32" &&
|
|
171
|
+
abs
|
|
172
|
+
.toLowerCase()
|
|
173
|
+
.startsWith(`${normalizedRoot.toLowerCase()}${path.sep}`))) {
|
|
174
|
+
throw new Error(`Path escapes wiki root: ${relativePath}`);
|
|
175
|
+
}
|
|
176
|
+
return abs;
|
|
177
|
+
}
|
|
178
|
+
async pathExists(filePath) {
|
|
179
|
+
try {
|
|
180
|
+
await fs.access(filePath);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async ensureLayout() {
|
|
188
|
+
const pagesRoot = this.resolveWithin(PAGES_DIR);
|
|
189
|
+
await fs.mkdir(pagesRoot, { recursive: true });
|
|
190
|
+
const indexPath = this.resolveWithin(INDEX_FILE);
|
|
191
|
+
const logPath = this.resolveWithin(LOG_FILE);
|
|
192
|
+
const schemaPath = this.resolveWithin(SCHEMA_FILE);
|
|
193
|
+
if (!(await this.pathExists(indexPath))) {
|
|
194
|
+
await fs.writeFile(indexPath, buildIndexMarkdown([]), "utf8");
|
|
195
|
+
}
|
|
196
|
+
if (!(await this.pathExists(logPath))) {
|
|
197
|
+
await fs.writeFile(logPath, "# Wiki Log\n\n", "utf8");
|
|
198
|
+
}
|
|
199
|
+
if (!(await this.pathExists(schemaPath))) {
|
|
200
|
+
await fs.writeFile(schemaPath, `${DEFAULT_SCHEMA}\n`, "utf8");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async readPage(relativePath) {
|
|
204
|
+
const absolutePath = this.resolveWithin(relativePath);
|
|
205
|
+
const content = await fs.readFile(absolutePath, "utf8");
|
|
206
|
+
const stat = await fs.stat(absolutePath);
|
|
207
|
+
const parsed = parseFrontmatter(content);
|
|
208
|
+
const title = deriveTitle(relativePath, parsed.frontmatter);
|
|
209
|
+
const summary = deriveSummary(parsed.frontmatter, parsed.body, title);
|
|
210
|
+
return {
|
|
211
|
+
path: relativePath.replace(/\\/g, "/"),
|
|
212
|
+
absolutePath,
|
|
213
|
+
title,
|
|
214
|
+
summary,
|
|
215
|
+
tags: parsed.frontmatter.tags ?? [],
|
|
216
|
+
related: (parsed.frontmatter.related ?? []).map(normalizeRelatedPath),
|
|
217
|
+
type: parsed.frontmatter.type ?? null,
|
|
218
|
+
created: parsed.frontmatter.created ?? null,
|
|
219
|
+
updated: parsed.frontmatter.updated ?? null,
|
|
220
|
+
wordCount: wordCount(parsed.body),
|
|
221
|
+
mtime: stat.mtime.toISOString(),
|
|
222
|
+
content,
|
|
223
|
+
body: parsed.body,
|
|
224
|
+
frontmatter: parsed.frontmatter,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
async listPagePaths() {
|
|
228
|
+
const pagesRoot = this.resolveWithin(PAGES_DIR);
|
|
229
|
+
const out = [];
|
|
230
|
+
const walk = async (dirPath) => {
|
|
231
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
232
|
+
for (const entry of entries) {
|
|
233
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
234
|
+
if (entry.isDirectory()) {
|
|
235
|
+
await walk(fullPath);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".md")) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const relFromRoot = path
|
|
242
|
+
.relative(this.root, fullPath)
|
|
243
|
+
.replace(/\\/g, "/");
|
|
244
|
+
out.push(relFromRoot);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
if (await this.pathExists(pagesRoot)) {
|
|
248
|
+
await walk(pagesRoot);
|
|
249
|
+
}
|
|
250
|
+
out.sort((a, b) => a.localeCompare(b));
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
async listPages() {
|
|
254
|
+
const paths = await this.listPagePaths();
|
|
255
|
+
return Promise.all(paths.map((relativePath) => this.readPage(relativePath)));
|
|
256
|
+
}
|
|
257
|
+
async writeIndex(pages) {
|
|
258
|
+
const indexPath = this.resolveWithin(INDEX_FILE);
|
|
259
|
+
await fs.writeFile(indexPath, buildIndexMarkdown(pages), "utf8");
|
|
260
|
+
}
|
|
261
|
+
async appendLog(operation, details) {
|
|
262
|
+
const logPath = this.resolveWithin(LOG_FILE);
|
|
263
|
+
await fs.appendFile(logPath, buildLogEntry(operation, details), "utf8");
|
|
264
|
+
}
|
|
265
|
+
async qmdStore() {
|
|
266
|
+
if (!this.qmdStorePromise) {
|
|
267
|
+
this.qmdStorePromise = (async () => {
|
|
268
|
+
await this.ensureLayout();
|
|
269
|
+
const dbPath = wikiDbPath();
|
|
270
|
+
await fs.mkdir(path.dirname(dbPath), { recursive: true });
|
|
271
|
+
const pagesRoot = this.resolveWithin(PAGES_DIR);
|
|
272
|
+
return createStore({
|
|
273
|
+
dbPath,
|
|
274
|
+
config: {
|
|
275
|
+
collections: {
|
|
276
|
+
[QMD_COLLECTION]: {
|
|
277
|
+
path: pagesRoot,
|
|
278
|
+
pattern: "**/*.md",
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
models: {
|
|
282
|
+
embed: DEFAULT_WIKI_EMBED_MODEL,
|
|
283
|
+
rerank: DEFAULT_WIKI_RERANK_MODEL,
|
|
284
|
+
generate: DEFAULT_WIKI_GENERATE_MODEL,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
})();
|
|
289
|
+
}
|
|
290
|
+
return this.qmdStorePromise;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Preload QMD models at startup (shared cache with LTM).
|
|
294
|
+
*/
|
|
295
|
+
async warmup() {
|
|
296
|
+
await this.ensureLayout();
|
|
297
|
+
const models = [
|
|
298
|
+
DEFAULT_WIKI_EMBED_MODEL,
|
|
299
|
+
DEFAULT_WIKI_RERANK_MODEL,
|
|
300
|
+
DEFAULT_WIKI_GENERATE_MODEL,
|
|
301
|
+
];
|
|
302
|
+
const cacheDir = modelsCachePath();
|
|
303
|
+
for (const model of new Set(models)) {
|
|
304
|
+
await resolveModelFile(model, cacheDir);
|
|
305
|
+
}
|
|
306
|
+
await this.qmdStore();
|
|
307
|
+
}
|
|
308
|
+
async syncSearchIndex() {
|
|
309
|
+
const store = await this.qmdStore();
|
|
310
|
+
await store.update({ collections: [QMD_COLLECTION] });
|
|
311
|
+
await store.embed({ force: false });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
export function create(config) {
|
|
315
|
+
return WikiStore.forConfig(config);
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/core/memory/wiki/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { JSONValue } from "@strands-agents/sdk";
|
|
2
|
+
import { WikiStore } from "./store.js";
|
|
3
|
+
export declare function createWikiTools(wiki: WikiStore): (import("@strands-agents/sdk").InvokableTool<{
|
|
4
|
+
type: "page";
|
|
5
|
+
}, JSONValue> | import("@strands-agents/sdk").InvokableTool<{
|
|
6
|
+
kind: "page" | "index" | "log" | "schema";
|
|
7
|
+
path?: string | undefined;
|
|
8
|
+
}, JSONValue> | import("@strands-agents/sdk").InvokableTool<Record<string, never>, JSONValue> | import("@strands-agents/sdk").InvokableTool<{
|
|
9
|
+
query: string;
|
|
10
|
+
k?: number | undefined;
|
|
11
|
+
}, JSONValue>)[];
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { tool } from "@strands-agents/sdk";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { DEFAULT_SEARCH_LIMIT, INDEX_FILE, LOG_FILE, MAX_SEARCH_LIMIT, QMD_COLLECTION, SCHEMA_FILE, } from "./store.js";
|
|
6
|
+
function toJsonValue(value) {
|
|
7
|
+
return JSON.parse(JSON.stringify(value));
|
|
8
|
+
}
|
|
9
|
+
function mapVectorChunkToMatch(row, root, index) {
|
|
10
|
+
const relPath = path.relative(root, row.filepath).replace(/\\/g, "/");
|
|
11
|
+
const distance = typeof row.score === "number" && Number.isFinite(row.score)
|
|
12
|
+
? Math.max(0, 1 - row.score)
|
|
13
|
+
: null;
|
|
14
|
+
const id = row.chunkPos != null
|
|
15
|
+
? `${row.docid}:${row.chunkPos}`
|
|
16
|
+
: `${row.docid}:${index}`;
|
|
17
|
+
return {
|
|
18
|
+
id,
|
|
19
|
+
path: relPath,
|
|
20
|
+
title: row.title,
|
|
21
|
+
summary: row.context,
|
|
22
|
+
tags: "",
|
|
23
|
+
distance,
|
|
24
|
+
score: row.score,
|
|
25
|
+
source: row.source,
|
|
26
|
+
chunk_pos: row.chunkPos ?? null,
|
|
27
|
+
content: row.body ?? "",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function createWikiTools(wiki) {
|
|
31
|
+
const { root } = wiki;
|
|
32
|
+
return [
|
|
33
|
+
tool({
|
|
34
|
+
name: "wiki_list_files",
|
|
35
|
+
description: "List wiki files by type. Supports `page` and returns frontmatter-aware summaries.",
|
|
36
|
+
inputSchema: z.object({
|
|
37
|
+
type: z.enum(["page"]).default("page"),
|
|
38
|
+
}),
|
|
39
|
+
callback: async () => {
|
|
40
|
+
await wiki.ensureLayout();
|
|
41
|
+
const pages = await wiki.listPages();
|
|
42
|
+
return toJsonValue({
|
|
43
|
+
root,
|
|
44
|
+
type: "page",
|
|
45
|
+
count: pages.length,
|
|
46
|
+
files: pages.map((page) => ({
|
|
47
|
+
path: page.path,
|
|
48
|
+
title: page.title,
|
|
49
|
+
summary: page.summary,
|
|
50
|
+
tags: page.tags,
|
|
51
|
+
related: page.related,
|
|
52
|
+
type: page.type,
|
|
53
|
+
created: page.created,
|
|
54
|
+
updated: page.updated,
|
|
55
|
+
word_count: page.wordCount,
|
|
56
|
+
modified_at: page.mtime,
|
|
57
|
+
})),
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
tool({
|
|
62
|
+
name: "wiki_read_file",
|
|
63
|
+
description: "Read wiki files. Kinds: index, log, schema, or a specific page.",
|
|
64
|
+
inputSchema: z.object({
|
|
65
|
+
kind: z.enum(["index", "log", "schema", "page"]),
|
|
66
|
+
path: z.string().optional(),
|
|
67
|
+
}),
|
|
68
|
+
callback: async (input) => {
|
|
69
|
+
await wiki.ensureLayout();
|
|
70
|
+
if (input.kind === "page") {
|
|
71
|
+
if (!input.path) {
|
|
72
|
+
throw new Error("`path` is required when kind is `page`.");
|
|
73
|
+
}
|
|
74
|
+
const relativePath = wiki.pageRelativePath(input.path);
|
|
75
|
+
const page = await wiki.readPage(relativePath);
|
|
76
|
+
return toJsonValue({
|
|
77
|
+
root,
|
|
78
|
+
kind: input.kind,
|
|
79
|
+
path: page.path,
|
|
80
|
+
frontmatter: page.frontmatter,
|
|
81
|
+
title: page.title,
|
|
82
|
+
summary: page.summary,
|
|
83
|
+
word_count: page.wordCount,
|
|
84
|
+
content: page.content,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (input.path) {
|
|
88
|
+
throw new Error("`path` is only valid when kind is `page` and should be omitted otherwise.");
|
|
89
|
+
}
|
|
90
|
+
const target = input.kind === "index"
|
|
91
|
+
? INDEX_FILE
|
|
92
|
+
: input.kind === "log"
|
|
93
|
+
? LOG_FILE
|
|
94
|
+
: SCHEMA_FILE;
|
|
95
|
+
const absolutePath = wiki.resolveWithin(target);
|
|
96
|
+
const content = await fs.readFile(absolutePath, "utf8");
|
|
97
|
+
return toJsonValue({
|
|
98
|
+
root,
|
|
99
|
+
kind: input.kind,
|
|
100
|
+
path: target,
|
|
101
|
+
content,
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
tool({
|
|
106
|
+
name: "wiki_write_file",
|
|
107
|
+
description: "Write wiki files. Page writes automatically maintain index, log, and search index.",
|
|
108
|
+
inputSchema: z.object({
|
|
109
|
+
kind: z.enum(["page", "schema"]),
|
|
110
|
+
path: z.string().optional(),
|
|
111
|
+
content: z.string().min(1),
|
|
112
|
+
}),
|
|
113
|
+
callback: async (input) => {
|
|
114
|
+
await wiki.ensureLayout();
|
|
115
|
+
const content = input.content;
|
|
116
|
+
if (input.kind === "schema") {
|
|
117
|
+
if (input.path) {
|
|
118
|
+
throw new Error("`path` is not valid when kind is `schema`.");
|
|
119
|
+
}
|
|
120
|
+
const schemaPath = wiki.resolveWithin(SCHEMA_FILE);
|
|
121
|
+
await fs.writeFile(schemaPath, content, "utf8");
|
|
122
|
+
await wiki.appendLog("schema_update", { path: SCHEMA_FILE });
|
|
123
|
+
return toJsonValue({
|
|
124
|
+
root,
|
|
125
|
+
kind: input.kind,
|
|
126
|
+
path: SCHEMA_FILE,
|
|
127
|
+
bytes_written: Buffer.byteLength(content, "utf8"),
|
|
128
|
+
index_updated: false,
|
|
129
|
+
log_updated: true,
|
|
130
|
+
search_index_updated: false,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (!input.path) {
|
|
134
|
+
throw new Error("`path` is required when kind is `page`.");
|
|
135
|
+
}
|
|
136
|
+
const relativePath = wiki.pageRelativePath(input.path);
|
|
137
|
+
const absolutePath = wiki.resolveWithin(relativePath);
|
|
138
|
+
const existed = await wiki.pathExists(absolutePath);
|
|
139
|
+
await fs.mkdir(path.dirname(absolutePath), { recursive: true });
|
|
140
|
+
await fs.writeFile(absolutePath, content, "utf8");
|
|
141
|
+
const page = await wiki.readPage(relativePath);
|
|
142
|
+
await wiki.syncSearchIndex();
|
|
143
|
+
const pages = await wiki.listPages();
|
|
144
|
+
await wiki.writeIndex(pages);
|
|
145
|
+
await wiki.appendLog(existed ? "page_update" : "page_create", {
|
|
146
|
+
path: page.path,
|
|
147
|
+
title: page.title,
|
|
148
|
+
});
|
|
149
|
+
return toJsonValue({
|
|
150
|
+
root,
|
|
151
|
+
kind: input.kind,
|
|
152
|
+
path: page.path,
|
|
153
|
+
title: page.title,
|
|
154
|
+
summary: page.summary,
|
|
155
|
+
bytes_written: Buffer.byteLength(content, "utf8"),
|
|
156
|
+
index_updated: true,
|
|
157
|
+
log_updated: true,
|
|
158
|
+
search_index_updated: true,
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
}),
|
|
162
|
+
tool({
|
|
163
|
+
name: "wiki_knowledge_graph",
|
|
164
|
+
description: "Build the wiki knowledge graph from page frontmatter links and shared tags.",
|
|
165
|
+
inputSchema: z.object({}),
|
|
166
|
+
callback: async () => {
|
|
167
|
+
await wiki.ensureLayout();
|
|
168
|
+
const pages = await wiki.listPages();
|
|
169
|
+
const nodes = pages.map((page) => ({
|
|
170
|
+
path: page.path,
|
|
171
|
+
title: page.title,
|
|
172
|
+
tags: page.tags,
|
|
173
|
+
type: page.type ?? "page",
|
|
174
|
+
word_count: page.wordCount,
|
|
175
|
+
}));
|
|
176
|
+
const edges = [];
|
|
177
|
+
const inbound = new Map();
|
|
178
|
+
const relatedOut = new Map();
|
|
179
|
+
for (const page of pages) {
|
|
180
|
+
relatedOut.set(page.path, page.related.length);
|
|
181
|
+
for (const related of page.related) {
|
|
182
|
+
edges.push({
|
|
183
|
+
source: page.path,
|
|
184
|
+
target: related,
|
|
185
|
+
type: "related",
|
|
186
|
+
});
|
|
187
|
+
inbound.set(related, (inbound.get(related) ?? 0) + 1);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const tagClusters = new Map();
|
|
191
|
+
for (const page of pages) {
|
|
192
|
+
for (const tag of page.tags) {
|
|
193
|
+
if (!tagClusters.has(tag)) {
|
|
194
|
+
tagClusters.set(tag, []);
|
|
195
|
+
}
|
|
196
|
+
tagClusters.get(tag).push(page.path);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const [tag, members] of tagClusters.entries()) {
|
|
200
|
+
if (members.length < 2) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
for (let i = 0; i < members.length; i += 1) {
|
|
204
|
+
for (let j = i + 1; j < members.length; j += 1) {
|
|
205
|
+
const source = members[i];
|
|
206
|
+
const target = members[j];
|
|
207
|
+
edges.push({ source, target, type: "shared-tag", tag });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const orphans = pages.filter((page) => {
|
|
212
|
+
const incoming = inbound.get(page.path) ?? 0;
|
|
213
|
+
const outgoing = relatedOut.get(page.path) ?? 0;
|
|
214
|
+
return incoming === 0 && outgoing === 0;
|
|
215
|
+
});
|
|
216
|
+
return toJsonValue({
|
|
217
|
+
nodes,
|
|
218
|
+
edges,
|
|
219
|
+
tag_clusters: Object.fromEntries(tagClusters.entries()),
|
|
220
|
+
stats: {
|
|
221
|
+
pages: pages.length,
|
|
222
|
+
links: edges.length,
|
|
223
|
+
orphans: orphans.length,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
228
|
+
tool({
|
|
229
|
+
name: "wiki_stats",
|
|
230
|
+
description: "Return wiki health and usage statistics for page content.",
|
|
231
|
+
inputSchema: z.object({}),
|
|
232
|
+
callback: async () => {
|
|
233
|
+
await wiki.ensureLayout();
|
|
234
|
+
const pages = await wiki.listPages();
|
|
235
|
+
const totalWords = pages.reduce((sum, page) => sum + page.wordCount, 0);
|
|
236
|
+
const tags = new Set();
|
|
237
|
+
const types = {};
|
|
238
|
+
const inbound = new Map();
|
|
239
|
+
for (const page of pages) {
|
|
240
|
+
for (const tag of page.tags) {
|
|
241
|
+
tags.add(tag);
|
|
242
|
+
}
|
|
243
|
+
const type = page.type ?? "page";
|
|
244
|
+
types[type] = (types[type] ?? 0) + 1;
|
|
245
|
+
for (const related of page.related) {
|
|
246
|
+
inbound.set(related, (inbound.get(related) ?? 0) + 1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const orphans = pages.filter((page) => (inbound.get(page.path) ?? 0) === 0 && page.related.length === 0);
|
|
250
|
+
const lastActivity = pages
|
|
251
|
+
.map((page) => page.mtime)
|
|
252
|
+
.sort()
|
|
253
|
+
.at(-1);
|
|
254
|
+
return toJsonValue({
|
|
255
|
+
pages: pages.length,
|
|
256
|
+
links: pages.reduce((sum, page) => sum + page.related.length, 0),
|
|
257
|
+
orphans: orphans.length,
|
|
258
|
+
total_words: totalWords,
|
|
259
|
+
avg_words_per_page: pages.length > 0 ? totalWords / pages.length : 0,
|
|
260
|
+
tags: tags.size,
|
|
261
|
+
types,
|
|
262
|
+
last_activity: lastActivity ?? null,
|
|
263
|
+
});
|
|
264
|
+
},
|
|
265
|
+
}),
|
|
266
|
+
tool({
|
|
267
|
+
name: "wiki_search",
|
|
268
|
+
description: "Semantic search over wiki chunks (QMD index under $HOOMAN_HOME/wiki/.qmd/index.sqlite). Returns matching snippets; use wiki_read_file on paths you need in full.",
|
|
269
|
+
inputSchema: z.object({
|
|
270
|
+
query: z.string().min(1),
|
|
271
|
+
k: z.number().int().min(1).max(MAX_SEARCH_LIMIT).optional(),
|
|
272
|
+
}),
|
|
273
|
+
callback: async (input) => {
|
|
274
|
+
await wiki.ensureLayout();
|
|
275
|
+
const store = await wiki.qmdStore();
|
|
276
|
+
const k = input.k ?? DEFAULT_SEARCH_LIMIT;
|
|
277
|
+
const rows = await store.searchVector(input.query, {
|
|
278
|
+
limit: k,
|
|
279
|
+
collection: QMD_COLLECTION,
|
|
280
|
+
});
|
|
281
|
+
const matches = rows.map((row, index) => mapVectorChunkToMatch(row, root, index));
|
|
282
|
+
return toJsonValue({
|
|
283
|
+
query: input.query,
|
|
284
|
+
count: matches.length,
|
|
285
|
+
matches,
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
}),
|
|
289
|
+
];
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=tools.js.map
|