@lotargo/memory_plugin 1.6.6 → 1.6.8
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/CHANGELOG.md +148 -101
- package/README.md +436 -304
- package/mcp-server/cli/direct_commands.js +39 -0
- package/mcp-server/cli.js +16 -5
- package/mcp-server/cli_boot.js +4 -1
- package/mcp-server/client_cli.js +73 -0
- package/mcp-server/client_paths.js +44 -0
- package/mcp-server/client_registration.js +38 -0
- package/mcp-server/codex_config.js +86 -8
- package/mcp-server/db/database.js +14 -21
- package/mcp-server/db/migrations.js +66 -77
- package/mcp-server/db/rag_blob_transport.js +143 -0
- package/mcp-server/db/rag_sync.js +284 -0
- package/mcp-server/db/sync_queue.js +219 -307
- package/mcp-server/dev_link.js +142 -0
- package/mcp-server/fact_format.js +44 -12
- package/mcp-server/index.js +17 -7
- package/mcp-server/ingest/exporter.js +44 -38
- package/mcp-server/ingest/normalizer.js +1 -1
- package/mcp-server/ingest/pipeline.js +260 -248
- package/mcp-server/persona_migration.js +39 -0
- package/mcp-server/prompt_manager.js +162 -55
- package/mcp-server/retrieval/retriever.js +99 -64
- package/mcp-server/setup.js +150 -100
- package/mcp-server/storage/blob_store.js +53 -1
- package/mcp-server/tools/core/knowledge_read_core.js +163 -0
- package/mcp-server/tools/core/memory_core.js +24 -4
- package/mcp-server/tools/core/memory_routing.js +10 -0
- package/mcp-server/tools/core/note_core.js +53 -0
- package/mcp-server/tools/core/rag_query_core.js +169 -0
- package/mcp-server/tools/index.js +11 -9
- package/mcp-server/tools/memory_tools.js +4 -1
- package/mcp-server/tools/note_tools.js +35 -0
- package/mcp-server/tools/rag_tools.js +211 -364
- package/mcp-server/uninstall.js +627 -0
- package/opencode-plugin/index.js +80 -12
- package/opencode-plugin/main.js +136 -0
- package/package.json +25 -5
- package/skills/using-memory/SKILL.md +28 -19
- package/mcp-server/benchmarks/fetch_real_corpus.js +0 -351
- package/mcp-server/benchmarks/gpu_profile_benchmark.js +0 -170
- package/mcp-server/benchmarks/policy_dominance_test.js +0 -221
- package/mcp-server/benchmarks/quality_evaluator.js +0 -598
- package/mcp-server/benchmarks/raw_corpus_data.js +0 -613
- package/mcp-server/benchmarks/run_benchmarks.js +0 -366
- package/mcp-server/benchmarks/stress_ingestion.js +0 -195
- package/mcp-server/benchmarks/table_code_retrieval.js +0 -453
- package/mcp-server/benchmarks/test_dual_layer.js +0 -141
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { copyFile, cp, mkdir, readFile, readdir, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { resolveClientPaths } from "./client_paths.js";
|
|
7
|
+
|
|
8
|
+
export const PACKAGE_NAME = "@lotargo/memory_plugin";
|
|
9
|
+
export const REPO_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
10
|
+
export const DEV_PLUGIN_FILE = join(REPO_ROOT, "opencode-plugin", "main.js");
|
|
11
|
+
|
|
12
|
+
const LEGACY_PACKAGE_NAMES = new Set([
|
|
13
|
+
PACKAGE_NAME,
|
|
14
|
+
"opencode-memory-plugin",
|
|
15
|
+
"memory_plugin",
|
|
16
|
+
"memory-plugin",
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
function pluginSpec(entry) {
|
|
20
|
+
return Array.isArray(entry) ? entry[0] : entry;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isMemoryPluginSpec(spec, devPluginUrl = pathToFileURL(DEV_PLUGIN_FILE).href) {
|
|
24
|
+
if (typeof spec !== "string") return false;
|
|
25
|
+
if (LEGACY_PACKAGE_NAMES.has(spec)) return true;
|
|
26
|
+
if (/^@lotargo\/memory_plugin(?:@[^/]+)?$/i.test(spec)) return true;
|
|
27
|
+
if (/^(?:opencode-memory-plugin|memory_plugin|memory-plugin)(?:@[^/]+)?$/i.test(spec)) return true;
|
|
28
|
+
if (spec === devPluginUrl) return true;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function rewriteOpenCodePluginList(pluginList, devPluginUrl) {
|
|
33
|
+
const input = Array.isArray(pluginList) ? pluginList : [];
|
|
34
|
+
const output = [];
|
|
35
|
+
let inserted = false;
|
|
36
|
+
|
|
37
|
+
for (const entry of input) {
|
|
38
|
+
const spec = pluginSpec(entry);
|
|
39
|
+
if (!isMemoryPluginSpec(spec, devPluginUrl)) {
|
|
40
|
+
output.push(entry);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (inserted) continue;
|
|
44
|
+
output.push(Array.isArray(entry) ? [devPluginUrl, entry[1]] : devPluginUrl);
|
|
45
|
+
inserted = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!inserted) output.push(devPluginUrl);
|
|
49
|
+
return output;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function linkOpenCodeToRepository({
|
|
53
|
+
configDir = resolveClientPaths().opencodeDir,
|
|
54
|
+
pluginFile = DEV_PLUGIN_FILE,
|
|
55
|
+
} = {}) {
|
|
56
|
+
if (!existsSync(pluginFile)) throw new Error(`OpenCode plugin entry not found: ${pluginFile}`);
|
|
57
|
+
const configPath = join(configDir, "opencode.json");
|
|
58
|
+
const backupPath = `${configPath}.memory-dev-backup`;
|
|
59
|
+
await mkdir(configDir, { recursive: true });
|
|
60
|
+
|
|
61
|
+
let config = {};
|
|
62
|
+
if (existsSync(configPath)) {
|
|
63
|
+
const raw = await readFile(configPath, "utf-8");
|
|
64
|
+
config = raw.trim() ? JSON.parse(raw) : {};
|
|
65
|
+
if (!existsSync(backupPath)) await copyFile(configPath, backupPath);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const devPluginUrl = pathToFileURL(pluginFile).href;
|
|
69
|
+
config.plugin = rewriteOpenCodePluginList(config.plugin, devPluginUrl);
|
|
70
|
+
const content = `${JSON.stringify(config, null, 2)}\n`;
|
|
71
|
+
const tmpPath = `${configPath}.memory-dev-tmp-${process.pid}`;
|
|
72
|
+
await writeFile(tmpPath, content, "utf-8");
|
|
73
|
+
await rename(tmpPath, configPath);
|
|
74
|
+
|
|
75
|
+
return { configPath, backupPath, devPluginUrl };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function linkGlobalNpmPackage({ repoRoot = REPO_ROOT } = {}) {
|
|
79
|
+
const npmExecPath = process.env.npm_execpath;
|
|
80
|
+
const command = npmExecPath && existsSync(npmExecPath) ? process.execPath : "npm";
|
|
81
|
+
const args = npmExecPath && existsSync(npmExecPath) ? [npmExecPath, "link"] : ["link"];
|
|
82
|
+
const result = spawnSync(command, args, {
|
|
83
|
+
cwd: repoRoot,
|
|
84
|
+
stdio: "inherit",
|
|
85
|
+
// A direct npm-cli.js invocation is preferred. The shell fallback is only
|
|
86
|
+
// needed when dev-link is launched outside npm and no npm_execpath exists;
|
|
87
|
+
// the command and arguments are fixed, not user-provided.
|
|
88
|
+
shell: process.platform === "win32" && !npmExecPath,
|
|
89
|
+
});
|
|
90
|
+
if (result.error) throw result.error;
|
|
91
|
+
if (result.status !== 0) throw new Error(`npm link failed with exit code ${result.status}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function syncDevelopmentSkills({
|
|
95
|
+
skillsSource = join(REPO_ROOT, "skills"),
|
|
96
|
+
targets = null,
|
|
97
|
+
} = {}) {
|
|
98
|
+
if (!existsSync(skillsSource)) return [];
|
|
99
|
+
const { home, opencodeDir } = resolveClientPaths();
|
|
100
|
+
const destinations = targets || [
|
|
101
|
+
join(opencodeDir, "skills"),
|
|
102
|
+
join(home, ".codex", "skills"),
|
|
103
|
+
join(home, ".agents", "skills"),
|
|
104
|
+
join(home, ".claude", "skills"),
|
|
105
|
+
join(home, ".gemini", "config", "skills"),
|
|
106
|
+
];
|
|
107
|
+
const entries = await readdir(skillsSource, { withFileTypes: true });
|
|
108
|
+
for (const destination of destinations) {
|
|
109
|
+
await mkdir(destination, { recursive: true });
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
if (!entry.isDirectory()) continue;
|
|
112
|
+
await cp(join(skillsSource, entry.name), join(destination, entry.name), {
|
|
113
|
+
recursive: true,
|
|
114
|
+
force: true,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return destinations;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function runDevLink({ skipNpmLink = false } = {}) {
|
|
122
|
+
console.log(`\nLinking ${PACKAGE_NAME} to the working repository...\n`);
|
|
123
|
+
if (!skipNpmLink) {
|
|
124
|
+
linkGlobalNpmPackage();
|
|
125
|
+
console.log(` [OK] System CLI linked to ${REPO_ROOT}`);
|
|
126
|
+
}
|
|
127
|
+
const linked = await linkOpenCodeToRepository();
|
|
128
|
+
console.log(` [OK] OpenCode plugin source: ${linked.devPluginUrl}`);
|
|
129
|
+
console.log(` [OK] OpenCode config: ${linked.configPath}`);
|
|
130
|
+
console.log(` [OK] Original config backup: ${linked.backupPath}`);
|
|
131
|
+
const { enableGlobalPrompt } = await import("./prompt_manager.js");
|
|
132
|
+
const promptResults = await enableGlobalPrompt();
|
|
133
|
+
const promptFailures = promptResults.filter((result) => result.status === "failed");
|
|
134
|
+
if (promptFailures.length) {
|
|
135
|
+
throw new Error(`Failed to synchronize client prompts: ${promptFailures.map((item) => item.name).join(", ")}`);
|
|
136
|
+
}
|
|
137
|
+
console.log(" [OK] Codex, Claude Code, Gemini CLI, and Antigravity prompts synchronized");
|
|
138
|
+
const skillTargets = await syncDevelopmentSkills();
|
|
139
|
+
console.log(` [OK] Development skills synchronized to ${skillTargets.length} client location(s)`);
|
|
140
|
+
console.log("\nDevelopment link is active. After source edits, restart OpenCode; publishing and reinstalling are not required.\n");
|
|
141
|
+
return linked;
|
|
142
|
+
}
|
|
@@ -12,9 +12,25 @@
|
|
|
12
12
|
// keep "1" = protected fact: forget refuses to delete without force
|
|
13
13
|
// supersedes id (or number/text) this fact replaces
|
|
14
14
|
// supersededBy id of the fact that replaced this one
|
|
15
|
-
// tags comma-separated free-form tags for recall filtering
|
|
15
|
+
// tags comma-separated free-form tags for recall filtering
|
|
16
|
+
// kind "fact" = descriptive context, "directive" = active personalization/working instruction
|
|
16
17
|
|
|
17
|
-
const META_KEYS = ["id", "ttl", "keep", "supersededBy", "supersedes", "tags", "inject"];
|
|
18
|
+
const META_KEYS = ["id", "ttl", "keep", "supersededBy", "supersedes", "tags", "inject", "kind"];
|
|
19
|
+
|
|
20
|
+
const LEGACY_DIRECTIVE_TAGS = new Set([
|
|
21
|
+
"persona",
|
|
22
|
+
"behavior",
|
|
23
|
+
"behaviour",
|
|
24
|
+
"speech",
|
|
25
|
+
"style",
|
|
26
|
+
"tone",
|
|
27
|
+
"preference",
|
|
28
|
+
"preferences",
|
|
29
|
+
"pref",
|
|
30
|
+
"instruction",
|
|
31
|
+
"instructions",
|
|
32
|
+
"directive",
|
|
33
|
+
]);
|
|
18
34
|
|
|
19
35
|
const ENTRY_RE = /^- \[(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2})\]\s+(.*)$/;
|
|
20
36
|
|
|
@@ -125,9 +141,24 @@ export function isKeepFact(line) {
|
|
|
125
141
|
}
|
|
126
142
|
|
|
127
143
|
// True if the fact has been superseded by another fact.
|
|
128
|
-
export function isSuperseded(line) {
|
|
129
|
-
return Boolean(factMeta(line).supersededBy);
|
|
130
|
-
}
|
|
144
|
+
export function isSuperseded(line) {
|
|
145
|
+
return Boolean(factMeta(line).supersededBy);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Explicit kind metadata is authoritative. Legacy stores predate `kind`, so
|
|
149
|
+
// well-known personalization tags and inject:1 remain a compatibility bridge.
|
|
150
|
+
// kind:fact can explicitly opt a tagged item out of directive semantics.
|
|
151
|
+
export function isDirectiveFact(line) {
|
|
152
|
+
const meta = factMeta(line);
|
|
153
|
+
if (meta.kind === "directive") return true;
|
|
154
|
+
if (meta.kind === "fact") return false;
|
|
155
|
+
if (meta.inject === "1") return true;
|
|
156
|
+
const tags = String(meta.tags || "")
|
|
157
|
+
.split(",")
|
|
158
|
+
.map((tag) => tag.trim().toLowerCase())
|
|
159
|
+
.filter(Boolean);
|
|
160
|
+
return tags.some((tag) => LEGACY_DIRECTIVE_TAGS.has(tag));
|
|
161
|
+
}
|
|
131
162
|
|
|
132
163
|
// Keyword match: space-separated terms, all must be present (case-insensitive).
|
|
133
164
|
// Also matches against the fact's id and tags.
|
|
@@ -161,13 +192,14 @@ export function inDateRange(factLine, since, until) {
|
|
|
161
192
|
}
|
|
162
193
|
|
|
163
194
|
// Human-readable badges for a fact line, e.g. ["EXPIRED", "KEEP", "SUPERSEDED"].
|
|
164
|
-
export function metaBadges(factLine, now = Date.now()) {
|
|
165
|
-
const badges = [];
|
|
166
|
-
if (isExpiredLine(factLine, now)) badges.push("EXPIRED");
|
|
167
|
-
if (isKeepFact(factLine)) badges.push("KEEP");
|
|
168
|
-
if (isSuperseded(factLine)) badges.push("SUPERSEDED");
|
|
169
|
-
|
|
170
|
-
|
|
195
|
+
export function metaBadges(factLine, now = Date.now()) {
|
|
196
|
+
const badges = [];
|
|
197
|
+
if (isExpiredLine(factLine, now)) badges.push("EXPIRED");
|
|
198
|
+
if (isKeepFact(factLine)) badges.push("KEEP");
|
|
199
|
+
if (isSuperseded(factLine)) badges.push("SUPERSEDED");
|
|
200
|
+
if (isDirectiveFact(factLine)) badges.push("DIRECTIVE");
|
|
201
|
+
return badges;
|
|
202
|
+
}
|
|
171
203
|
|
|
172
204
|
// Display text of a fact line with badges appended, e.g.
|
|
173
205
|
// "user prefers TS [EXPIRED] [KEEP]"
|
package/mcp-server/index.js
CHANGED
|
@@ -45,15 +45,17 @@ function printUsage() {
|
|
|
45
45
|
|
|
46
46
|
Usage:
|
|
47
47
|
memory_plugin Start the MCP server on stdio (default)
|
|
48
|
-
memory_plugin setup [--opencode|--claude|--codex|--antigravity] [--mode <MODE>]
|
|
48
|
+
memory_plugin setup [--opencode|--claude|--codex|--gemini|--antigravity] [--mode <MODE>]
|
|
49
|
+
memory_plugin setup --uninstall [--purge] [--purge-cache] [--dry-run] [--yes]
|
|
50
|
+
memory_plugin uninstall [--purge] [--purge-cache] [--dry-run] [--yes] [--opencode|--claude|--codex|--gemini|--antigravity]
|
|
49
51
|
memory_plugin cli Interactive terminal UI
|
|
50
52
|
memory_plugin login [--from-env|--api-token|--db-url <URL>]
|
|
51
53
|
memory_plugin logout [--api-key]
|
|
52
54
|
memory_plugin auth-status
|
|
53
55
|
memory_plugin link|unlink|relink|identity [--dir <path>] [--remote <url>]
|
|
54
56
|
memory_plugin migrate_titles [--key <key>]
|
|
55
|
-
memory_plugin enable-prompt | disable-prompt
|
|
56
|
-
memory_plugin doctor --codex
|
|
57
|
+
memory_plugin enable-prompt | disable-prompt
|
|
58
|
+
memory_plugin doctor --codex
|
|
57
59
|
|
|
58
60
|
Options:
|
|
59
61
|
-h, --help Show this help text
|
|
@@ -62,9 +64,11 @@ Options:
|
|
|
62
64
|
Secrets: prefer TURSO_API_TOKEN / TURSO_DB_URL / TURSO_DB_TOKEN environment
|
|
63
65
|
variables over command-line flags — argv is visible to other local processes.
|
|
64
66
|
Data directory: ${MEMORY_DIR}`);
|
|
65
|
-
}
|
|
67
|
+
}
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
const isUninstallCommand = cliArgs.includes("uninstall") || cliArgs.includes("--uninstall");
|
|
70
|
+
|
|
71
|
+
if (!isUninstallCommand && (cliArgs.includes("--help") || cliArgs.includes("-h") || cliArgs[0] === "help")) {
|
|
68
72
|
printUsage();
|
|
69
73
|
process.exit(0);
|
|
70
74
|
}
|
|
@@ -74,8 +78,14 @@ if (cliArgs.includes("--version") || cliArgs.includes("-v")) {
|
|
|
74
78
|
process.exit(0);
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
if (
|
|
78
|
-
const {
|
|
81
|
+
if (isUninstallCommand) {
|
|
82
|
+
const { runUninstall } = await import("./uninstall.js");
|
|
83
|
+
await runUninstall();
|
|
84
|
+
process.exit(process.exitCode || 0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (cliArgs.includes("setup") || cliArgs.includes("install") || cliArgs.includes("--setup") || cliArgs.includes("-s")) {
|
|
88
|
+
const { runSetup } = await import("./setup.js");
|
|
79
89
|
await runSetup();
|
|
80
90
|
process.exit(0);
|
|
81
91
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getDatabase } from "../db/database.js";
|
|
2
2
|
import { writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { MEMORY_DIR } from "../memory.js";
|
|
5
|
-
import { toVectorBytes } from "../retrieval/retriever.js";
|
|
4
|
+
import { MEMORY_DIR } from "../memory.js";
|
|
5
|
+
import { toVectorBytes } from "../retrieval/retriever.js";
|
|
6
6
|
|
|
7
7
|
export const EXPORTS_DIR = join(MEMORY_DIR, "exports");
|
|
8
8
|
|
|
@@ -36,32 +36,38 @@ export async function exportDocumentData(docIdOrPath, customDb = null) {
|
|
|
36
36
|
|
|
37
37
|
const sections = await db.prepare("SELECT id, heading, breadcrumbs, content, token_count FROM sections WHERE doc_id = ?").all(doc.id);
|
|
38
38
|
const mediumChunks = await db.prepare("SELECT id, section_id, content, block_type, token_count, created_at FROM medium_chunks WHERE doc_id = ?").all(doc.id);
|
|
39
|
-
const rawMicroChunks = await db.prepare(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
SELECT
|
|
58
|
-
FROM
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
39
|
+
const rawMicroChunks = await db.prepare(`
|
|
40
|
+
SELECT m.id, m.medium_id, m.section_id, m.content, m.vector, m.token_count,
|
|
41
|
+
m.retrieval_policy, m.policy_source_id, s.breadcrumbs
|
|
42
|
+
FROM micro_chunks m
|
|
43
|
+
LEFT JOIN sections s ON s.id = m.section_id
|
|
44
|
+
WHERE m.doc_id = ?;
|
|
45
|
+
`).all(doc.id);
|
|
46
|
+
const microChunks = rawMicroChunks.map((chunk) => {
|
|
47
|
+
const bytes = toVectorBytes(chunk.vector);
|
|
48
|
+
return {
|
|
49
|
+
...chunk,
|
|
50
|
+
vector: bytes && bytes.byteLength
|
|
51
|
+
? Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64")
|
|
52
|
+
: "",
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
const ownedRows = await db.prepare(`
|
|
56
|
+
SELECT id FROM sections WHERE doc_id = ?
|
|
57
|
+
UNION SELECT id FROM medium_chunks WHERE doc_id = ?
|
|
58
|
+
UNION SELECT id FROM micro_chunks WHERE doc_id = ?;
|
|
59
|
+
`).all(doc.id, doc.id, doc.id);
|
|
60
|
+
const ownedIds = [doc.id, ...ownedRows.map((row) => row.id)];
|
|
61
|
+
const placeholders = ownedIds.map(() => "?").join(",");
|
|
62
|
+
const graphEdges = await db.prepare(`
|
|
63
|
+
SELECT source_id, target_id, relation_type, metadata_json, created_at
|
|
64
|
+
FROM graph_edges
|
|
65
|
+
WHERE source_id IN (${placeholders})
|
|
66
|
+
OR target_id IN (${placeholders})
|
|
67
|
+
OR target_id GLOB ?;
|
|
68
|
+
`).all(...ownedIds, ...ownedIds, `${doc.id}:L*`);
|
|
69
|
+
const knowledgeLinks = await db.prepare("SELECT * FROM knowledge_links WHERE doc_id = ?").all(doc.id);
|
|
70
|
+
const documentScopes = await db.prepare("SELECT scope_key, created_at FROM document_scopes WHERE doc_id = ?").all(doc.id);
|
|
65
71
|
|
|
66
72
|
return {
|
|
67
73
|
document: {
|
|
@@ -69,11 +75,11 @@ export async function exportDocumentData(docIdOrPath, customDb = null) {
|
|
|
69
75
|
path: doc.path,
|
|
70
76
|
title: doc.title,
|
|
71
77
|
blob_hash: doc.blob_hash,
|
|
72
|
-
checksum: doc.checksum,
|
|
73
|
-
toc_json: doc.toc_json,
|
|
74
|
-
metadata_json: doc.metadata_json,
|
|
75
|
-
toc,
|
|
76
|
-
metadata,
|
|
78
|
+
checksum: doc.checksum,
|
|
79
|
+
toc_json: doc.toc_json,
|
|
80
|
+
metadata_json: doc.metadata_json,
|
|
81
|
+
toc,
|
|
82
|
+
metadata,
|
|
77
83
|
created_at: doc.created_at,
|
|
78
84
|
updated_at: doc.updated_at,
|
|
79
85
|
},
|
|
@@ -86,11 +92,11 @@ export async function exportDocumentData(docIdOrPath, customDb = null) {
|
|
|
86
92
|
sections,
|
|
87
93
|
medium_chunks: mediumChunks,
|
|
88
94
|
micro_chunks: microChunks,
|
|
89
|
-
graph_edges: graphEdges,
|
|
90
|
-
knowledge_links: knowledgeLinks,
|
|
91
|
-
document_scopes: documentScopes,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
95
|
+
graph_edges: graphEdges,
|
|
96
|
+
knowledge_links: knowledgeLinks,
|
|
97
|
+
document_scopes: documentScopes,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
94
100
|
|
|
95
101
|
export async function exportDocumentToJsonString(docIdOrPath, customDb = null) {
|
|
96
102
|
const data = await exportDocumentData(docIdOrPath, customDb);
|
|
@@ -3,7 +3,7 @@ import { isIP } from "node:net";
|
|
|
3
3
|
import { lookup } from "node:dns/promises";
|
|
4
4
|
import { PDFParse } from "pdf-parse";
|
|
5
5
|
import mammoth from "mammoth";
|
|
6
|
-
import xlsx from "xlsx";
|
|
6
|
+
import * as xlsx from "xlsx";
|
|
7
7
|
|
|
8
8
|
export function cleanHtml(html) {
|
|
9
9
|
if (!html) return "";
|