@vortex-os/memory-extended 0.5.1
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 +244 -0
- package/dist/consolidate/index.d.ts +7 -0
- package/dist/consolidate/index.d.ts.map +1 -0
- package/dist/consolidate/index.js +4 -0
- package/dist/consolidate/index.js.map +1 -0
- package/dist/consolidate/proposer.d.ts +43 -0
- package/dist/consolidate/proposer.d.ts.map +1 -0
- package/dist/consolidate/proposer.js +276 -0
- package/dist/consolidate/proposer.js.map +1 -0
- package/dist/consolidate/query.d.ts +32 -0
- package/dist/consolidate/query.d.ts.map +1 -0
- package/dist/consolidate/query.js +40 -0
- package/dist/consolidate/query.js.map +1 -0
- package/dist/consolidate/store.d.ts +21 -0
- package/dist/consolidate/store.d.ts.map +1 -0
- package/dist/consolidate/store.js +91 -0
- package/dist/consolidate/store.js.map +1 -0
- package/dist/consolidate/types.d.ts +68 -0
- package/dist/consolidate/types.d.ts.map +1 -0
- package/dist/consolidate/types.js +2 -0
- package/dist/consolidate/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/frontmatter.d.ts +6 -0
- package/dist/internal/frontmatter.d.ts.map +1 -0
- package/dist/internal/frontmatter.js +38 -0
- package/dist/internal/frontmatter.js.map +1 -0
- package/dist/internal/proactive-curator-helpers.d.ts +171 -0
- package/dist/internal/proactive-curator-helpers.d.ts.map +1 -0
- package/dist/internal/proactive-curator-helpers.js +162 -0
- package/dist/internal/proactive-curator-helpers.js.map +1 -0
- package/dist/mcp/document-tools.d.ts +144 -0
- package/dist/mcp/document-tools.d.ts.map +1 -0
- package/dist/mcp/document-tools.js +319 -0
- package/dist/mcp/document-tools.js.map +1 -0
- package/dist/mcp/index.d.ts +34 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +29 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/install.d.ts +72 -0
- package/dist/mcp/install.d.ts.map +1 -0
- package/dist/mcp/install.js +92 -0
- package/dist/mcp/install.js.map +1 -0
- package/dist/mcp/memory-tools.d.ts +101 -0
- package/dist/mcp/memory-tools.d.ts.map +1 -0
- package/dist/mcp/memory-tools.js +105 -0
- package/dist/mcp/memory-tools.js.map +1 -0
- package/dist/mcp/recall-tool.d.ts +52 -0
- package/dist/mcp/recall-tool.d.ts.map +1 -0
- package/dist/mcp/recall-tool.js +60 -0
- package/dist/mcp/recall-tool.js.map +1 -0
- package/dist/mcp/server.d.ts +32 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +113 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/recall/engine.d.ts +38 -0
- package/dist/recall/engine.d.ts.map +1 -0
- package/dist/recall/engine.js +113 -0
- package/dist/recall/engine.js.map +1 -0
- package/dist/recall/index.d.ts +22 -0
- package/dist/recall/index.d.ts.map +1 -0
- package/dist/recall/index.js +20 -0
- package/dist/recall/index.js.map +1 -0
- package/dist/recall/intent.d.ts +24 -0
- package/dist/recall/intent.d.ts.map +1 -0
- package/dist/recall/intent.js +95 -0
- package/dist/recall/intent.js.map +1 -0
- package/dist/recall/render.d.ts +11 -0
- package/dist/recall/render.d.ts.map +1 -0
- package/dist/recall/render.js +23 -0
- package/dist/recall/render.js.map +1 -0
- package/dist/recall/types.d.ts +72 -0
- package/dist/recall/types.d.ts.map +1 -0
- package/dist/recall/types.js +2 -0
- package/dist/recall/types.js.map +1 -0
- package/dist/sessionArchive/adapters/claude-code.d.ts +3 -0
- package/dist/sessionArchive/adapters/claude-code.d.ts.map +1 -0
- package/dist/sessionArchive/adapters/claude-code.js +276 -0
- package/dist/sessionArchive/adapters/claude-code.js.map +1 -0
- package/dist/sessionArchive/adapters/claude-desktop.d.ts +3 -0
- package/dist/sessionArchive/adapters/claude-desktop.d.ts.map +1 -0
- package/dist/sessionArchive/adapters/claude-desktop.js +234 -0
- package/dist/sessionArchive/adapters/claude-desktop.js.map +1 -0
- package/dist/sessionArchive/adapters/codex.d.ts +3 -0
- package/dist/sessionArchive/adapters/codex.d.ts.map +1 -0
- package/dist/sessionArchive/adapters/codex.js +322 -0
- package/dist/sessionArchive/adapters/codex.js.map +1 -0
- package/dist/sessionArchive/adapters/gemini.d.ts +3 -0
- package/dist/sessionArchive/adapters/gemini.d.ts.map +1 -0
- package/dist/sessionArchive/adapters/gemini.js +248 -0
- package/dist/sessionArchive/adapters/gemini.js.map +1 -0
- package/dist/sessionArchive/adapters/index.d.ts +5 -0
- package/dist/sessionArchive/adapters/index.d.ts.map +1 -0
- package/dist/sessionArchive/adapters/index.js +5 -0
- package/dist/sessionArchive/adapters/index.js.map +1 -0
- package/dist/sessionArchive/index.d.ts +9 -0
- package/dist/sessionArchive/index.d.ts.map +1 -0
- package/dist/sessionArchive/index.js +6 -0
- package/dist/sessionArchive/index.js.map +1 -0
- package/dist/sessionArchive/ingest.d.ts +68 -0
- package/dist/sessionArchive/ingest.d.ts.map +1 -0
- package/dist/sessionArchive/ingest.js +134 -0
- package/dist/sessionArchive/ingest.js.map +1 -0
- package/dist/sessionArchive/normalize.d.ts +15 -0
- package/dist/sessionArchive/normalize.d.ts.map +1 -0
- package/dist/sessionArchive/normalize.js +40 -0
- package/dist/sessionArchive/normalize.js.map +1 -0
- package/dist/sessionArchive/store.d.ts +118 -0
- package/dist/sessionArchive/store.d.ts.map +1 -0
- package/dist/sessionArchive/store.js +491 -0
- package/dist/sessionArchive/store.js.map +1 -0
- package/dist/sessionArchive/types.d.ts +124 -0
- package/dist/sessionArchive/types.d.ts.map +1 -0
- package/dist/sessionArchive/types.js +24 -0
- package/dist/sessionArchive/types.js.map +1 -0
- package/dist/sqlite/drift.d.ts +22 -0
- package/dist/sqlite/drift.d.ts.map +1 -0
- package/dist/sqlite/drift.js +69 -0
- package/dist/sqlite/drift.js.map +1 -0
- package/dist/sqlite/index.d.ts +22 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +4 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite/rebuild.d.ts +32 -0
- package/dist/sqlite/rebuild.d.ts.map +1 -0
- package/dist/sqlite/rebuild.js +80 -0
- package/dist/sqlite/rebuild.js.map +1 -0
- package/dist/sqlite/schema.d.ts +15 -0
- package/dist/sqlite/schema.d.ts.map +1 -0
- package/dist/sqlite/schema.js +41 -0
- package/dist/sqlite/schema.js.map +1 -0
- package/dist/sqlite/store.d.ts +49 -0
- package/dist/sqlite/store.d.ts.map +1 -0
- package/dist/sqlite/store.js +179 -0
- package/dist/sqlite/store.js.map +1 -0
- package/dist/sqlite/types.d.ts +57 -0
- package/dist/sqlite/types.d.ts.map +1 -0
- package/dist/sqlite/types.js +2 -0
- package/dist/sqlite/types.js.map +1 -0
- package/dist/vector/backend-brute.d.ts +38 -0
- package/dist/vector/backend-brute.d.ts.map +1 -0
- package/dist/vector/backend-brute.js +112 -0
- package/dist/vector/backend-brute.js.map +1 -0
- package/dist/vector/embedder.d.ts +59 -0
- package/dist/vector/embedder.d.ts.map +1 -0
- package/dist/vector/embedder.js +47 -0
- package/dist/vector/embedder.js.map +1 -0
- package/dist/vector/index.d.ts +24 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/index.js +7 -0
- package/dist/vector/index.js.map +1 -0
- package/dist/vector/math.d.ts +21 -0
- package/dist/vector/math.d.ts.map +1 -0
- package/dist/vector/math.js +34 -0
- package/dist/vector/math.js.map +1 -0
- package/dist/vector/schema.d.ts +14 -0
- package/dist/vector/schema.d.ts.map +1 -0
- package/dist/vector/schema.js +24 -0
- package/dist/vector/schema.js.map +1 -0
- package/dist/vector/segment.d.ts +65 -0
- package/dist/vector/segment.d.ts.map +1 -0
- package/dist/vector/segment.js +72 -0
- package/dist/vector/segment.js.map +1 -0
- package/dist/vector/session.d.ts +90 -0
- package/dist/vector/session.d.ts.map +1 -0
- package/dist/vector/session.js +242 -0
- package/dist/vector/session.js.map +1 -0
- package/dist/vector/store.d.ts +69 -0
- package/dist/vector/store.d.ts.map +1 -0
- package/dist/vector/store.js +131 -0
- package/dist/vector/store.js.map +1 -0
- package/dist/vector/types.d.ts +109 -0
- package/dist/vector/types.d.ts.map +1 -0
- package/dist/vector/types.js +24 -0
- package/dist/vector/types.js.map +1 -0
- package/package.json +96 -0
- package/scripts/mcp-stdio.mjs +143 -0
- package/scripts/rebuild-memory-sqlite.mjs +39 -0
- package/scripts/rebuild-memory-vector.mjs +64 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
// ── (2) Decline store — verbatim from the curator's `decline-store.ts` ──────
|
|
5
|
+
//
|
|
6
|
+
// Persistence layer for declined and accepted proposals under
|
|
7
|
+
// `<cwd>/data/_proactive-curator/`:
|
|
8
|
+
// - `declined.json` — keyed by proposal kind + fingerprint; entries expire
|
|
9
|
+
// after `expiryDays` (default 30), filtered out at read time and purged at
|
|
10
|
+
// write time.
|
|
11
|
+
// - `accepted.log` — append-only JSON-lines audit trail.
|
|
12
|
+
// All operations are functional (no in-memory state); last-write-wins on the
|
|
13
|
+
// rare concurrent write.
|
|
14
|
+
const STORE_DIR = "data/_proactive-curator";
|
|
15
|
+
const DECLINED_FILE = "declined.json";
|
|
16
|
+
const ACCEPTED_LOG = "accepted.log";
|
|
17
|
+
const DEFAULT_EXPIRY_DAYS = 30;
|
|
18
|
+
/**
|
|
19
|
+
* Load the active (un-expired) declined fingerprints. Missing or corrupt store
|
|
20
|
+
* files return an empty set rather than throwing.
|
|
21
|
+
*/
|
|
22
|
+
export async function loadDeclinedFingerprints(cwd, now) {
|
|
23
|
+
const parsed = await readDeclinedFile(cwd);
|
|
24
|
+
if (!parsed)
|
|
25
|
+
return new Set();
|
|
26
|
+
const active = new Set();
|
|
27
|
+
const nowMs = now.getTime();
|
|
28
|
+
for (const kind of ["capture-insight", "create-hub", "mcp-document"]) {
|
|
29
|
+
const entries = parsed[kind] ?? {};
|
|
30
|
+
for (const [fp, entry] of Object.entries(entries)) {
|
|
31
|
+
if (isActive(entry, nowMs))
|
|
32
|
+
active.add(fp);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return active;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Persist a decline. Purges expired entries from disk in the same write so the
|
|
39
|
+
* store does not grow unbounded.
|
|
40
|
+
*/
|
|
41
|
+
export async function recordDecline(cwd, args) {
|
|
42
|
+
await ensureStoreDir(cwd);
|
|
43
|
+
const existing = (await readDeclinedFile(cwd)) ?? emptyDeclinedFile();
|
|
44
|
+
const expiryDays = args.expiryDays ?? DEFAULT_EXPIRY_DAYS;
|
|
45
|
+
const expiresAt = new Date(args.now.getTime() + expiryDays * 24 * 60 * 60 * 1000).toISOString();
|
|
46
|
+
const updated = {
|
|
47
|
+
"capture-insight": purgeExpired(existing["capture-insight"], args.now),
|
|
48
|
+
"create-hub": purgeExpired(existing["create-hub"], args.now),
|
|
49
|
+
"mcp-document": purgeExpired(existing["mcp-document"], args.now),
|
|
50
|
+
};
|
|
51
|
+
const entry = {
|
|
52
|
+
declinedAt: args.now.toISOString(),
|
|
53
|
+
topic: args.topic,
|
|
54
|
+
expiresAt,
|
|
55
|
+
actionKind: args.actionKind,
|
|
56
|
+
targetPath: args.targetPath,
|
|
57
|
+
...(args.sourceDocs ? { sourceDocs: args.sourceDocs } : {}),
|
|
58
|
+
};
|
|
59
|
+
updated[args.kind] = { ...updated[args.kind], [args.fingerprint]: entry };
|
|
60
|
+
await writeFile(join(cwd, STORE_DIR, DECLINED_FILE), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Append an acceptance record to the audit trail. Newline-delimited JSON so
|
|
64
|
+
* the file is grep-/tail-friendly without a parser.
|
|
65
|
+
*/
|
|
66
|
+
export async function recordAcceptance(cwd, args) {
|
|
67
|
+
await ensureStoreDir(cwd);
|
|
68
|
+
const line = JSON.stringify({
|
|
69
|
+
acceptedAt: args.now.toISOString(),
|
|
70
|
+
kind: args.kind,
|
|
71
|
+
fingerprint: args.fingerprint,
|
|
72
|
+
topic: args.topic,
|
|
73
|
+
actionKind: args.actionKind,
|
|
74
|
+
writtenPath: args.writtenPath,
|
|
75
|
+
});
|
|
76
|
+
await appendFile(join(cwd, STORE_DIR, ACCEPTED_LOG), line + "\n", "utf8");
|
|
77
|
+
}
|
|
78
|
+
function isActive(entry, nowMs) {
|
|
79
|
+
const expiresMs = new Date(entry.expiresAt).getTime();
|
|
80
|
+
return Number.isFinite(expiresMs) && expiresMs > nowMs;
|
|
81
|
+
}
|
|
82
|
+
// Fingerprints are file-derived keys parsed from JSON on disk; a crafted file
|
|
83
|
+
// could carry `__proto__`/`constructor`/`prototype` keys. Build the accumulator
|
|
84
|
+
// with a null prototype and skip those keys — belt-and-suspenders against
|
|
85
|
+
// prototype pollution when rebuilding the store.
|
|
86
|
+
const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
87
|
+
function purgeExpired(entries, now) {
|
|
88
|
+
if (!entries)
|
|
89
|
+
return {};
|
|
90
|
+
const out = Object.create(null);
|
|
91
|
+
const nowMs = now.getTime();
|
|
92
|
+
for (const [fp, entry] of Object.entries(entries)) {
|
|
93
|
+
if (DANGEROUS_KEYS.has(fp))
|
|
94
|
+
continue;
|
|
95
|
+
if (isActive(entry, nowMs))
|
|
96
|
+
out[fp] = entry;
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
async function readDeclinedFile(cwd) {
|
|
101
|
+
const file = join(cwd, STORE_DIR, DECLINED_FILE);
|
|
102
|
+
if (!existsSync(file))
|
|
103
|
+
return null;
|
|
104
|
+
try {
|
|
105
|
+
const raw = await readFile(file, "utf8");
|
|
106
|
+
const parsed = JSON.parse(raw);
|
|
107
|
+
// Backward compatible: an old declined.json predating the `mcp-document`
|
|
108
|
+
// kind simply lacks that key, so it defaults to an empty record.
|
|
109
|
+
return {
|
|
110
|
+
"capture-insight": parsed["capture-insight"] ?? {},
|
|
111
|
+
"create-hub": parsed["create-hub"] ?? {},
|
|
112
|
+
"mcp-document": parsed["mcp-document"] ?? {},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function emptyDeclinedFile() {
|
|
120
|
+
return { "capture-insight": {}, "create-hub": {}, "mcp-document": {} };
|
|
121
|
+
}
|
|
122
|
+
async function ensureStoreDir(cwd) {
|
|
123
|
+
await mkdir(join(cwd, STORE_DIR), { recursive: true });
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Reserved filename code points: path separators and the Windows-reserved set,
|
|
127
|
+
* listed by code so this source carries no literal separator/reserved bytes.
|
|
128
|
+
* The codes are 60,62,58,34,47,92,124,63,42 = the angle brackets, colon, double
|
|
129
|
+
* quote, both slashes, pipe, question mark, asterisk. The colon matters on NTFS,
|
|
130
|
+
* where a name containing it opens an alternate data stream instead of a plain
|
|
131
|
+
* file. Control characters (code points below 0x20) are rejected separately.
|
|
132
|
+
*/
|
|
133
|
+
const RESERVED_FILENAME_CODES = new Set([60, 62, 58, 34, 47, 92, 124, 63, 42]);
|
|
134
|
+
/**
|
|
135
|
+
* Assert that `name` is a safe plain basename: non-empty, not "." or "..", and
|
|
136
|
+
* free of path separators, control characters, and Windows-reserved characters.
|
|
137
|
+
*
|
|
138
|
+
* Used at write boundaries where the destination FOLDER is a trusted constant
|
|
139
|
+
* (e.g. consolidate's fixed `_memory/` dir, which the canonical path gate
|
|
140
|
+
* rejects as a system dir, so containment relies on the basename instead). A
|
|
141
|
+
* denylist, not an ASCII allowlist, so non-Latin names (e.g. Korean) still
|
|
142
|
+
* pass. Throws a clear Error. Inlined here to keep the add-on standalone — see
|
|
143
|
+
* the file header.
|
|
144
|
+
*/
|
|
145
|
+
export function assertSafeBasename(name) {
|
|
146
|
+
const trimmed = (name ?? "").trim();
|
|
147
|
+
let bad = trimmed.length === 0 || trimmed === "." || trimmed === "..";
|
|
148
|
+
if (!bad) {
|
|
149
|
+
for (let i = 0; i < name.length; i++) {
|
|
150
|
+
const code = name.charCodeAt(i);
|
|
151
|
+
if (code < 32 || RESERVED_FILENAME_CODES.has(code)) {
|
|
152
|
+
bad = true;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (bad) {
|
|
158
|
+
throw new Error("Unsafe filename " + JSON.stringify(name) +
|
|
159
|
+
": must be a plain basename (no path separators, traversal, control, or reserved characters such as the colon).");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=proactive-curator-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proactive-curator-helpers.js","sourceRoot":"","sources":["../../src/internal/proactive-curator-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export declare const SUGGEST_DOCUMENT_TOOL_NAME = "suggest_document";
|
|
2
|
+
export declare const WRITE_DOCUMENT_TOOL_NAME = "write_document";
|
|
3
|
+
export declare const DECLINE_DOCUMENT_TOOL_NAME = "decline_document";
|
|
4
|
+
export declare const suggestDocumentToolDefinition: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: "object";
|
|
9
|
+
properties: {
|
|
10
|
+
topic: {
|
|
11
|
+
type: string;
|
|
12
|
+
description: string;
|
|
13
|
+
};
|
|
14
|
+
name: {
|
|
15
|
+
type: string;
|
|
16
|
+
description: string;
|
|
17
|
+
};
|
|
18
|
+
title: {
|
|
19
|
+
type: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
content: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
description: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
tags: {
|
|
31
|
+
type: string;
|
|
32
|
+
items: {
|
|
33
|
+
type: string;
|
|
34
|
+
};
|
|
35
|
+
description: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
required: string[];
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export declare const writeDocumentToolDefinition: {
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object";
|
|
46
|
+
properties: {
|
|
47
|
+
topic: {
|
|
48
|
+
type: string;
|
|
49
|
+
description: string;
|
|
50
|
+
};
|
|
51
|
+
name: {
|
|
52
|
+
type: string;
|
|
53
|
+
description: string;
|
|
54
|
+
};
|
|
55
|
+
title: {
|
|
56
|
+
type: string;
|
|
57
|
+
description: string;
|
|
58
|
+
};
|
|
59
|
+
content: {
|
|
60
|
+
type: string;
|
|
61
|
+
description: string;
|
|
62
|
+
};
|
|
63
|
+
description: {
|
|
64
|
+
type: string;
|
|
65
|
+
description: string;
|
|
66
|
+
};
|
|
67
|
+
tags: {
|
|
68
|
+
type: string;
|
|
69
|
+
items: {
|
|
70
|
+
type: string;
|
|
71
|
+
};
|
|
72
|
+
description: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
required: string[];
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export declare const declineDocumentToolDefinition: {
|
|
79
|
+
name: string;
|
|
80
|
+
description: string;
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: "object";
|
|
83
|
+
properties: {
|
|
84
|
+
topic: {
|
|
85
|
+
type: string;
|
|
86
|
+
description: string;
|
|
87
|
+
};
|
|
88
|
+
name: {
|
|
89
|
+
type: string;
|
|
90
|
+
description: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
required: string[];
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
export interface DocumentArgs {
|
|
97
|
+
readonly topic: string;
|
|
98
|
+
readonly name: string;
|
|
99
|
+
readonly title?: string;
|
|
100
|
+
readonly content: string;
|
|
101
|
+
readonly description?: string;
|
|
102
|
+
readonly tags?: readonly string[];
|
|
103
|
+
}
|
|
104
|
+
export interface DocumentToolDeps {
|
|
105
|
+
/** Absolute path to the instance data dir (the parent of data/<topic>/). */
|
|
106
|
+
readonly cwd: string;
|
|
107
|
+
/** Inject the current date (tests pass a fixed Date; the bin passes new Date()). */
|
|
108
|
+
readonly now?: Date;
|
|
109
|
+
}
|
|
110
|
+
export interface SuggestResult {
|
|
111
|
+
readonly ok: boolean;
|
|
112
|
+
readonly error?: string;
|
|
113
|
+
readonly fingerprint?: string;
|
|
114
|
+
readonly targetPath?: string;
|
|
115
|
+
readonly relPath?: string;
|
|
116
|
+
readonly alreadyExists?: boolean;
|
|
117
|
+
readonly previouslyDeclined?: boolean;
|
|
118
|
+
readonly preview?: string;
|
|
119
|
+
}
|
|
120
|
+
export interface WriteResult {
|
|
121
|
+
readonly ok: boolean;
|
|
122
|
+
readonly error?: string;
|
|
123
|
+
readonly writtenPath?: string;
|
|
124
|
+
readonly relPath?: string;
|
|
125
|
+
}
|
|
126
|
+
export interface DeclineResult {
|
|
127
|
+
readonly ok: boolean;
|
|
128
|
+
readonly error?: string;
|
|
129
|
+
readonly fingerprint?: string;
|
|
130
|
+
}
|
|
131
|
+
export declare function renderDocumentBody(args: DocumentArgs, now: Date): string;
|
|
132
|
+
export declare function documentFingerprint(relPath: string, body: string): string;
|
|
133
|
+
export declare function declineFingerprint(relPath: string): string;
|
|
134
|
+
/** Build a proposal preview. Writes nothing. */
|
|
135
|
+
export declare function runSuggestDocument(args: DocumentArgs, deps: DocumentToolDeps): Promise<SuggestResult>;
|
|
136
|
+
/** Write the document (create-file; never overwrites) and record acceptance. */
|
|
137
|
+
export declare function runWriteDocument(args: DocumentArgs, deps: DocumentToolDeps): Promise<WriteResult>;
|
|
138
|
+
/** Record a decline so the same suggestion is suppressed for 30 days. */
|
|
139
|
+
export declare function runDeclineDocument(args: {
|
|
140
|
+
readonly topic: string;
|
|
141
|
+
readonly name: string;
|
|
142
|
+
readonly content?: string;
|
|
143
|
+
}, deps: DocumentToolDeps): Promise<DeclineResult>;
|
|
144
|
+
//# sourceMappingURL=document-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/document-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { mkdir, writeFile, access } from "node:fs/promises";
|
|
2
|
+
import { join, normalize, sep } from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
/**
|
|
5
|
+
* Slice 4 — document tools. A PROPOSE-then-write pair for saving content as a
|
|
6
|
+
* formal knowledge document under `data/<topic>/<name>.md`. This is the only
|
|
7
|
+
* write-ish MCP surface, and it is deliberately split in two so the boundary
|
|
8
|
+
* "writes only happen on explicit acceptance" is enforced by tool separation,
|
|
9
|
+
* not by a flag:
|
|
10
|
+
*
|
|
11
|
+
* - suggest_document: pure. Builds the target path + rendered body + a
|
|
12
|
+
* fingerprint, writes NOTHING. Flags if this fingerprint was already
|
|
13
|
+
* declined (so the host can avoid re-proposing).
|
|
14
|
+
* - write_document: the explicit second step. Writes the file (create-file
|
|
15
|
+
* semantics, never overwrites) and records the acceptance.
|
|
16
|
+
* - decline_document: records a decline so the same suggestion can be
|
|
17
|
+
* suppressed for a while (30-day expiry, via the shared decline store).
|
|
18
|
+
*
|
|
19
|
+
* Unlike consolidate/insight proposers, there is NO decision-LLM here: in an
|
|
20
|
+
* MCP setting the *host* model is the judge — it decides whether to call
|
|
21
|
+
* suggest, shows the preview to the user, and only calls write on a yes. So
|
|
22
|
+
* proposal generation is a pure render, not an LLM gate.
|
|
23
|
+
*
|
|
24
|
+
* The decline store reuse is intentional: the record/load functions are
|
|
25
|
+
* stateless and idempotent, so a one-shot MCP tool can call them directly.
|
|
26
|
+
* They were the proactive-curator decline store; they are now inlined in
|
|
27
|
+
* `internal/proactive-curator-helpers.ts` so this add-on stays self-contained
|
|
28
|
+
* (no dependency on a separately published `@vortex-os/proactive-curator`).
|
|
29
|
+
*/
|
|
30
|
+
import { assertSafeBasename, loadDeclinedFingerprints, recordDecline, recordAcceptance, } from "../internal/proactive-curator-helpers.js";
|
|
31
|
+
export const SUGGEST_DOCUMENT_TOOL_NAME = "suggest_document";
|
|
32
|
+
export const WRITE_DOCUMENT_TOOL_NAME = "write_document";
|
|
33
|
+
export const DECLINE_DOCUMENT_TOOL_NAME = "decline_document";
|
|
34
|
+
const PROPOSAL_KIND = "mcp-document";
|
|
35
|
+
export const suggestDocumentToolDefinition = {
|
|
36
|
+
name: SUGGEST_DOCUMENT_TOOL_NAME,
|
|
37
|
+
description: "Propose saving content as a formal knowledge document under data/<topic>/<name>.md. " +
|
|
38
|
+
"Writes NOTHING — returns a preview, the resolved target path, and a fingerprint. " +
|
|
39
|
+
"Show the preview to the user; only call write_document if they accept. Operational " +
|
|
40
|
+
"records (memories, decision-log, worklog) are auto-kept elsewhere — this tool is for " +
|
|
41
|
+
"curating prose into a durable, structured document the user chooses to keep.",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
topic: { type: "string", description: "Topic folder under data/ (e.g. 'notes', 'projects/acme')." },
|
|
46
|
+
name: { type: "string", description: "Document name / filename stem (no .md), e.g. 'onboarding-summary'." },
|
|
47
|
+
title: { type: "string", description: "Human title for the document (frontmatter + H1)." },
|
|
48
|
+
content: { type: "string", description: "Markdown body of the document." },
|
|
49
|
+
description: { type: "string", description: "One-line description for frontmatter." },
|
|
50
|
+
tags: { type: "array", items: { type: "string" }, description: "Optional frontmatter tags." },
|
|
51
|
+
},
|
|
52
|
+
required: ["topic", "name", "content"],
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export const writeDocumentToolDefinition = {
|
|
56
|
+
name: WRITE_DOCUMENT_TOOL_NAME,
|
|
57
|
+
description: "Write a document proposed by suggest_document, AFTER the user has explicitly accepted. " +
|
|
58
|
+
"Creates data/<topic>/<name>.md with frontmatter (never overwrites an existing file) and " +
|
|
59
|
+
"records the acceptance. Do not call this without a preceding suggest_document and a user yes.",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
topic: { type: "string", description: "Same topic passed to suggest_document." },
|
|
64
|
+
name: { type: "string", description: "Same name passed to suggest_document." },
|
|
65
|
+
title: { type: "string", description: "Same title." },
|
|
66
|
+
content: { type: "string", description: "Same markdown body." },
|
|
67
|
+
description: { type: "string", description: "Same one-line description." },
|
|
68
|
+
tags: { type: "array", items: { type: "string" }, description: "Same tags." },
|
|
69
|
+
},
|
|
70
|
+
required: ["topic", "name", "content"],
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
export const declineDocumentToolDefinition = {
|
|
74
|
+
name: DECLINE_DOCUMENT_TOOL_NAME,
|
|
75
|
+
description: "Record that the user declined a suggest_document proposal, so the same suggestion is " +
|
|
76
|
+
"suppressed for a while (30-day expiry). Pass the same topic + name.",
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
topic: { type: "string", description: "Same topic passed to suggest_document." },
|
|
81
|
+
name: { type: "string", description: "Same name passed to suggest_document." },
|
|
82
|
+
},
|
|
83
|
+
required: ["topic", "name"],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
// ── path safety ──────────────────────────────────────────────────────────────
|
|
87
|
+
// topic/name come from a model; refuse anything that could escape data/ or that
|
|
88
|
+
// contains path separators in the name. Returns an error string or null if ok.
|
|
89
|
+
//
|
|
90
|
+
// The underscore-meta guard checks the NORMALIZED path, not the raw first
|
|
91
|
+
// segment: a raw first-segment check (`topic.split('/')[0]`) is bypassable by a
|
|
92
|
+
// leading `.` (e.g. './_memory' has first segment '.', but join+normalize
|
|
93
|
+
// collapses it to '_memory/…', planting a file in the auto-managed memory SoT
|
|
94
|
+
// dir). Normalizing first closes every '.'/'.//' variant at once.
|
|
95
|
+
/** Non-underscore top-level dirs VortEX maintains structurally — never a doc target. */
|
|
96
|
+
const RESERVED_TOP_DIRS = new Set(["worklog", "decision-log", "runbooks", "hubs"]);
|
|
97
|
+
function validate(args) {
|
|
98
|
+
const topic = (args.topic ?? "").trim();
|
|
99
|
+
const name = (args.name ?? "").trim();
|
|
100
|
+
if (topic.length === 0)
|
|
101
|
+
return "topic is required";
|
|
102
|
+
if (name.length === 0)
|
|
103
|
+
return "name is required";
|
|
104
|
+
if ((args.content ?? "").trim().length === 0)
|
|
105
|
+
return "content is required";
|
|
106
|
+
// The filename must be a safe basename: no separators, control chars, or
|
|
107
|
+
// Windows-reserved characters (notably the colon, which on NTFS opens an
|
|
108
|
+
// alternate data stream). assertSafeBasename throws; surface its message.
|
|
109
|
+
try {
|
|
110
|
+
assertSafeBasename(name);
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
return e.message;
|
|
114
|
+
}
|
|
115
|
+
// No traversal, no absolute, no backslash/forward escapes.
|
|
116
|
+
const bad = /(^|[\\/])\.\.([\\/]|$)/;
|
|
117
|
+
if (bad.test(topic))
|
|
118
|
+
return `topic must not contain '..': ${topic}`;
|
|
119
|
+
if (name.includes("/") || name.includes("\\"))
|
|
120
|
+
return `name must not contain path separators: ${name}`;
|
|
121
|
+
if (topic.startsWith("/") || topic.startsWith("\\") || /^[a-zA-Z]:/.test(topic))
|
|
122
|
+
return `topic must be a relative path under data/: ${topic}`;
|
|
123
|
+
// topic must not reach into the underscore meta dirs (those are auto-managed).
|
|
124
|
+
// Normalize first so `./_memory`, `.//_memory`, `a/../_memory`, etc. all
|
|
125
|
+
// collapse to their real on-disk segments before the check.
|
|
126
|
+
const relNorm = normalize(topic).replace(/\\/g, "/");
|
|
127
|
+
if (relNorm.startsWith(".."))
|
|
128
|
+
return `topic must be a relative path under data/: ${topic}`;
|
|
129
|
+
const segs = relNorm.split("/").filter((s) => s.length > 0 && s !== ".");
|
|
130
|
+
if (segs.some((s) => s.startsWith("_")))
|
|
131
|
+
return `topic must not target an auto-managed _ directory: ${topic}`;
|
|
132
|
+
if (segs.length > 0 && RESERVED_TOP_DIRS.has(segs[0]))
|
|
133
|
+
return `topic must not target a reserved system directory (${segs[0]}): ${topic}`;
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
function ymd(d) {
|
|
137
|
+
const y = d.getFullYear();
|
|
138
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
139
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
140
|
+
return `${y}-${m}-${day}`;
|
|
141
|
+
}
|
|
142
|
+
function relTarget(topic, name) {
|
|
143
|
+
// Always forward-slash for the rel path we report/fingerprint, and normalize
|
|
144
|
+
// the topic first so the canonical on-disk path is what gets fingerprinted /
|
|
145
|
+
// decline-bookkept (e.g. './notes' and 'notes' resolve to the same rel path).
|
|
146
|
+
const canonical = normalize(topic.trim()).replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
147
|
+
return `data/${canonical}/${name}.md`;
|
|
148
|
+
}
|
|
149
|
+
function absTarget(cwd, topic, name) {
|
|
150
|
+
return join(cwd, "data", topic, `${name}.md`);
|
|
151
|
+
}
|
|
152
|
+
export function renderDocumentBody(args, now) {
|
|
153
|
+
const date = ymd(now);
|
|
154
|
+
const title = (args.title ?? args.name).trim();
|
|
155
|
+
const desc = (args.description ?? "").trim();
|
|
156
|
+
const tags = ["document", ...(args.tags ?? [])];
|
|
157
|
+
const fm = [
|
|
158
|
+
"---",
|
|
159
|
+
`title: ${title}`,
|
|
160
|
+
desc ? `description: ${desc}` : null,
|
|
161
|
+
"type: document",
|
|
162
|
+
`created: ${date}`,
|
|
163
|
+
`updated: ${date}`,
|
|
164
|
+
`tags: [${tags.join(", ")}]`,
|
|
165
|
+
"---",
|
|
166
|
+
]
|
|
167
|
+
.filter((l) => l !== null)
|
|
168
|
+
.join("\n");
|
|
169
|
+
return `${fm}\n\n# ${title}\n\n${args.content.trim()}\n`;
|
|
170
|
+
}
|
|
171
|
+
export function documentFingerprint(relPath, body) {
|
|
172
|
+
return createHash("sha256").update(`${relPath}\n${body}`).digest("hex").slice(0, 16);
|
|
173
|
+
}
|
|
174
|
+
// Coarser, path-level key for declines. A decline can't see the body (content
|
|
175
|
+
// may not be re-sent), so both the recorded decline and the suggest-side
|
|
176
|
+
// suppression check key off the rel path alone — they MUST stay identical, so
|
|
177
|
+
// they share this one helper.
|
|
178
|
+
export function declineFingerprint(relPath) {
|
|
179
|
+
return createHash("sha256").update(relPath).digest("hex").slice(0, 16);
|
|
180
|
+
}
|
|
181
|
+
async function exists(p) {
|
|
182
|
+
try {
|
|
183
|
+
await access(p);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// The shared decline store, inlined in `internal/proactive-curator-helpers.ts`.
|
|
191
|
+
// These functions are now always present (no separate package to resolve), so
|
|
192
|
+
// this returns them directly. The signature still returns the object (rather
|
|
193
|
+
// than the functions inline) so the call sites keep their best-effort try/catch
|
|
194
|
+
// wrappers unchanged — the propose/write flow never depends on the store, and a
|
|
195
|
+
// runtime fs error in decline-bookkeeping is still swallowed at the call site.
|
|
196
|
+
//
|
|
197
|
+
// `recordDecline` / `recordAcceptance` are called with `kind: "mcp-document"`,
|
|
198
|
+
// which is now a tracked `ProposalKind`. The loose `Record<string, unknown>`
|
|
199
|
+
// arg type still preserves the original call boundary (the prior lazy import
|
|
200
|
+
// cast to the same loose shape). As of FIX M3 the `mcp-document` decline IS
|
|
201
|
+
// read back by `loadDeclinedFingerprints` (it scans all three kinds), so a
|
|
202
|
+
// recorded decline actually suppresses a later matching suggest.
|
|
203
|
+
function loadDeclineStore() {
|
|
204
|
+
return {
|
|
205
|
+
loadDeclinedFingerprints,
|
|
206
|
+
recordDecline: recordDecline,
|
|
207
|
+
recordAcceptance: recordAcceptance,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/** Build a proposal preview. Writes nothing. */
|
|
211
|
+
export async function runSuggestDocument(args, deps) {
|
|
212
|
+
const err = validate(args);
|
|
213
|
+
if (err)
|
|
214
|
+
return { ok: false, error: err };
|
|
215
|
+
const now = deps.now ?? new Date();
|
|
216
|
+
const rel = relTarget(args.topic, args.name);
|
|
217
|
+
const body = renderDocumentBody(args, now);
|
|
218
|
+
const fingerprint = documentFingerprint(rel, body);
|
|
219
|
+
const abs = absTarget(deps.cwd, args.topic.trim(), args.name.trim());
|
|
220
|
+
// runDeclineDocument can't know the body (content may not be re-sent on a
|
|
221
|
+
// decline), so it records a rel-ONLY fingerprint. Match it on the suggest
|
|
222
|
+
// side with the SAME key so a prior decline suppresses this suggestion. We
|
|
223
|
+
// also keep the body-based fingerprint check (a decline made with the full
|
|
224
|
+
// rel+body fingerprint, were one ever recorded, still matches).
|
|
225
|
+
const declineKey = declineFingerprint(rel);
|
|
226
|
+
let previouslyDeclined = false;
|
|
227
|
+
const store = loadDeclineStore();
|
|
228
|
+
try {
|
|
229
|
+
const declined = await store.loadDeclinedFingerprints(deps.cwd, now);
|
|
230
|
+
previouslyDeclined = declined.has(fingerprint) || declined.has(declineKey);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
/* best-effort: a decline-store read error must not block the preview */
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
ok: true,
|
|
237
|
+
fingerprint,
|
|
238
|
+
targetPath: abs,
|
|
239
|
+
relPath: rel,
|
|
240
|
+
alreadyExists: await exists(abs),
|
|
241
|
+
previouslyDeclined,
|
|
242
|
+
preview: body,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** Write the document (create-file; never overwrites) and record acceptance. */
|
|
246
|
+
export async function runWriteDocument(args, deps) {
|
|
247
|
+
const err = validate(args);
|
|
248
|
+
if (err)
|
|
249
|
+
return { ok: false, error: err };
|
|
250
|
+
const now = deps.now ?? new Date();
|
|
251
|
+
const rel = relTarget(args.topic, args.name);
|
|
252
|
+
const body = renderDocumentBody(args, now);
|
|
253
|
+
const abs = absTarget(deps.cwd, args.topic.trim(), args.name.trim());
|
|
254
|
+
// Defense-in-depth: confirm the resolved absolute path stays under data/.
|
|
255
|
+
const dataRoot = normalize(join(deps.cwd, "data")) + sep;
|
|
256
|
+
if (!(normalize(abs) + sep).startsWith(dataRoot)) {
|
|
257
|
+
return { ok: false, error: `resolved path escapes data/: ${abs}` };
|
|
258
|
+
}
|
|
259
|
+
if (await exists(abs)) {
|
|
260
|
+
return { ok: false, error: `file already exists (refusing to overwrite): ${rel}` };
|
|
261
|
+
}
|
|
262
|
+
await mkdir(join(deps.cwd, "data", args.topic.trim()), { recursive: true });
|
|
263
|
+
// Exclusive create — close the check-then-write race (another writer could
|
|
264
|
+
// land between the exists() check above and here). EEXIST maps to the same
|
|
265
|
+
// clean "refusing to overwrite" result the pre-check returns.
|
|
266
|
+
try {
|
|
267
|
+
await writeFile(abs, body, { encoding: "utf8", flag: "wx" });
|
|
268
|
+
}
|
|
269
|
+
catch (e) {
|
|
270
|
+
if (e.code === "EEXIST") {
|
|
271
|
+
return { ok: false, error: `file already exists (refusing to overwrite): ${rel}` };
|
|
272
|
+
}
|
|
273
|
+
throw e;
|
|
274
|
+
}
|
|
275
|
+
const store = loadDeclineStore();
|
|
276
|
+
try {
|
|
277
|
+
await store.recordAcceptance(deps.cwd, {
|
|
278
|
+
kind: PROPOSAL_KIND,
|
|
279
|
+
fingerprint: documentFingerprint(rel, body),
|
|
280
|
+
topic: args.topic.trim(),
|
|
281
|
+
actionKind: "create-file",
|
|
282
|
+
writtenPath: abs,
|
|
283
|
+
now,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
/* acceptance log is best-effort */
|
|
288
|
+
}
|
|
289
|
+
return { ok: true, writtenPath: abs, relPath: rel };
|
|
290
|
+
}
|
|
291
|
+
/** Record a decline so the same suggestion is suppressed for 30 days. */
|
|
292
|
+
export async function runDeclineDocument(args, deps) {
|
|
293
|
+
const topic = (args.topic ?? "").trim();
|
|
294
|
+
const name = (args.name ?? "").trim();
|
|
295
|
+
if (topic.length === 0 || name.length === 0)
|
|
296
|
+
return { ok: false, error: "topic and name are required" };
|
|
297
|
+
const now = deps.now ?? new Date();
|
|
298
|
+
const rel = relTarget(topic, name);
|
|
299
|
+
// Fingerprint over rel path only here (content may not be re-sent on decline);
|
|
300
|
+
// suggest fingerprints over rel+body, so decline is a coarser path-level guard.
|
|
301
|
+
// Shared helper with the suggest-side check so the two keys never drift.
|
|
302
|
+
const fingerprint = declineFingerprint(rel);
|
|
303
|
+
const store = loadDeclineStore();
|
|
304
|
+
try {
|
|
305
|
+
await store.recordDecline(deps.cwd, {
|
|
306
|
+
kind: PROPOSAL_KIND,
|
|
307
|
+
fingerprint,
|
|
308
|
+
topic,
|
|
309
|
+
actionKind: "create-file",
|
|
310
|
+
targetPath: rel,
|
|
311
|
+
now,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
catch (e) {
|
|
315
|
+
return { ok: false, error: e.message };
|
|
316
|
+
}
|
|
317
|
+
return { ok: true, fingerprint };
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=document-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-tools.js","sourceRoot":"","sources":["../../src/mcp/document-tools.ts"],"names":[],"mappings":"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"}
|