@owrede/vault-memory 2.2.1 → 2.3.0
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 +34 -0
- package/README.md +4 -2
- package/dist/cli.js +188 -13
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
14
14
|
|
|
15
15
|
_Nothing yet._
|
|
16
16
|
|
|
17
|
+
## [2.3.0] — 2026-07-01
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Datacore/Dataview rendered indexing — foundation** (ADR-033). Phase 1 strips
|
|
22
|
+
Datacore/Dataview query source from indexed text so raw query blocks no longer
|
|
23
|
+
pollute search (`src/reader/datacore.ts`). Phase 2 adds migration 016
|
|
24
|
+
(`notes.rendered_source_hash`) as the schema foundation for indexing rendered
|
|
25
|
+
content supplied by the Obsidian plugin. _Note: later phases of ADR-033 are not
|
|
26
|
+
yet complete; this release ships the foundation only._
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **Incremental full-vault indexer now re-indexes changed notes** (#14). `indexVault`
|
|
31
|
+
in `incremental` mode decided whether to re-index from chunk count alone, so a note
|
|
32
|
+
whose body changed but already had chunks kept stale chunks/embeddings/sections/edges
|
|
33
|
+
while its `hash`/`content` were updated in place. The reindex decision now mirrors the
|
|
34
|
+
single-note indexer's three-way logic (hash-unchanged / frontmatter-only / body-changed),
|
|
35
|
+
and a latent foreign-key ordering bug (sections must be deleted before chunks) is fixed.
|
|
36
|
+
- **MCP server version is derived from `package.json`** (#14). `server.ts` hardcoded
|
|
37
|
+
`VERSION = "1.0.0"`, so the server advertised the wrong version and sink provisioning
|
|
38
|
+
stamped a stale sentinel. A new `src/version.ts` is the single source of truth.
|
|
39
|
+
- **Frontmatter long-string serialization** (#14). Long string values are written
|
|
40
|
+
single-line instead of being folded into a `>-` YAML block scalar that Obsidian's
|
|
41
|
+
Properties editor mishandles.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **`engines.node` narrowed to `>=22 <26`** (#14). Node 26+ has no `better-sqlite3`
|
|
46
|
+
prebuild for the new ABI and building from source currently fails. README prerequisites
|
|
47
|
+
updated accordingly.
|
|
48
|
+
- **Release versions reconciled to 2.3.0** across `package.json`, `plugin/package.json`,
|
|
49
|
+
`plugin/manifest.json`, and README (#14).
|
|
50
|
+
|
|
17
51
|
## [2.2.1] — 2026-06-29
|
|
18
52
|
|
|
19
53
|
### Fixed
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Local-first, source-agnostic-ready agentic knowledge layer over your Obsidian notes,
|
|
4
4
|
exposed to any MCP-aware agent.**
|
|
5
5
|
|
|
6
|
-
> See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v2.
|
|
6
|
+
> See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v2.3.0** — additive
|
|
7
7
|
> over v1.x; the 23 v1 tool names + input schemas are preserved byte-identical.
|
|
8
8
|
|
|
9
9
|
## 30-second example
|
|
@@ -198,7 +198,9 @@ vault-memory supports two engines, selectable **per vault**:
|
|
|
198
198
|
|
|
199
199
|
### Prerequisites
|
|
200
200
|
|
|
201
|
-
- **Node.js
|
|
201
|
+
- **Node.js 22–25** (`>=22 <26`) — runtime for the MCP server (`brew install node@22`).
|
|
202
|
+
Node 26+ is not yet supported: the native `better-sqlite3` dependency has no
|
|
203
|
+
prebuild for the new ABI and building from source currently fails.
|
|
202
204
|
- One or more Obsidian vaults; an MCP-aware client.
|
|
203
205
|
- **Ollama engine only:** [Ollama](https://ollama.com) on `localhost:11434`
|
|
204
206
|
(`brew install ollama && brew services start ollama`) + the `bge-m3` model
|
package/dist/cli.js
CHANGED
|
@@ -1697,6 +1697,12 @@ function runMigration015(db, _ctx) {
|
|
|
1697
1697
|
"DROP INDEX IF EXISTS sections_note_anchor; CREATE UNIQUE INDEX IF NOT EXISTS sections_note_headingpath_anchor ON sections(note_id, heading_path, anchor);"
|
|
1698
1698
|
);
|
|
1699
1699
|
}
|
|
1700
|
+
function runMigration016(db, _ctx) {
|
|
1701
|
+
const cols = db.prepare("PRAGMA table_info(notes)").all();
|
|
1702
|
+
if (!cols.some((c) => c.name === "rendered_source_hash")) {
|
|
1703
|
+
db.exec("ALTER TABLE notes ADD COLUMN rendered_source_hash TEXT");
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1700
1706
|
var INITIAL_SCHEMA, MIGRATION_002_ALIASES, MIGRATION_003_FIX_DELETE_FKS, MIGRATION_004_VARIABLE_DIMS, MIGRATION_006_BODY_HASH, MIGRATION_007_DOC_URI_ADD, MIGRATIONS;
|
|
1701
1707
|
var init_schema = __esm({
|
|
1702
1708
|
"src/db/schema.ts"() {
|
|
@@ -1977,6 +1983,11 @@ CREATE INDEX IF NOT EXISTS idx_notes_doc_uri ON notes(doc_uri);
|
|
|
1977
1983
|
version: 15,
|
|
1978
1984
|
description: "section identity = (note_id, heading_path, anchor) \u2014 context-aware, no longer collapse byte-identical siblings in different contexts (ADR-032 revised)",
|
|
1979
1985
|
run: runMigration015
|
|
1986
|
+
},
|
|
1987
|
+
{
|
|
1988
|
+
version: 16,
|
|
1989
|
+
description: "notes.rendered_source_hash \u2014 overlay marker for plugin-rendered Datacore content (ADR-033)",
|
|
1990
|
+
run: runMigration016
|
|
1980
1991
|
}
|
|
1981
1992
|
];
|
|
1982
1993
|
}
|
|
@@ -5892,6 +5903,73 @@ var init_wikilinks2 = __esm({
|
|
|
5892
5903
|
}
|
|
5893
5904
|
});
|
|
5894
5905
|
|
|
5906
|
+
// src/reader/datacore.ts
|
|
5907
|
+
function stripDynamicViewBlocks(body) {
|
|
5908
|
+
if (!body.includes("```") && !body.includes("~~~")) {
|
|
5909
|
+
return { content: body, replaced: 0 };
|
|
5910
|
+
}
|
|
5911
|
+
const lines = body.split("\n");
|
|
5912
|
+
const out = [];
|
|
5913
|
+
let replaced = 0;
|
|
5914
|
+
let i = 0;
|
|
5915
|
+
while (i < lines.length) {
|
|
5916
|
+
const line = lines[i];
|
|
5917
|
+
const open2 = FENCE_OPEN_RE.exec(line);
|
|
5918
|
+
if (open2) {
|
|
5919
|
+
const indent = open2[1] ?? "";
|
|
5920
|
+
const marker = open2[2] ?? "";
|
|
5921
|
+
const lang = (open2[3] ?? "").toLowerCase();
|
|
5922
|
+
const markerChar = marker[0];
|
|
5923
|
+
const isDynamic = DYNAMIC_VIEW_LANGS.has(lang);
|
|
5924
|
+
let j = i + 1;
|
|
5925
|
+
let closed = false;
|
|
5926
|
+
while (j < lines.length) {
|
|
5927
|
+
const close = FENCE_OPEN_RE.exec(lines[j]);
|
|
5928
|
+
if (close && (close[2] ?? "")[0] === markerChar && (close[2] ?? "").length >= marker.length && (close[3] ?? "") === "") {
|
|
5929
|
+
closed = true;
|
|
5930
|
+
break;
|
|
5931
|
+
}
|
|
5932
|
+
j++;
|
|
5933
|
+
}
|
|
5934
|
+
if (isDynamic) {
|
|
5935
|
+
out.push(`${indent}${DATACORE_PLACEHOLDER}`);
|
|
5936
|
+
replaced++;
|
|
5937
|
+
i = closed ? j + 1 : lines.length;
|
|
5938
|
+
} else {
|
|
5939
|
+
out.push(line);
|
|
5940
|
+
if (closed) {
|
|
5941
|
+
for (let k = i + 1; k <= j; k++) out.push(lines[k]);
|
|
5942
|
+
i = j + 1;
|
|
5943
|
+
} else {
|
|
5944
|
+
for (let k = i + 1; k < lines.length; k++) out.push(lines[k]);
|
|
5945
|
+
i = lines.length;
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5948
|
+
} else {
|
|
5949
|
+
out.push(line);
|
|
5950
|
+
i++;
|
|
5951
|
+
}
|
|
5952
|
+
}
|
|
5953
|
+
if (replaced === 0) return { content: body, replaced: 0 };
|
|
5954
|
+
return { content: out.join("\n"), replaced };
|
|
5955
|
+
}
|
|
5956
|
+
var DYNAMIC_VIEW_LANGS, DATACORE_PLACEHOLDER, FENCE_OPEN_RE;
|
|
5957
|
+
var init_datacore = __esm({
|
|
5958
|
+
"src/reader/datacore.ts"() {
|
|
5959
|
+
"use strict";
|
|
5960
|
+
init_esm_shims();
|
|
5961
|
+
DYNAMIC_VIEW_LANGS = /* @__PURE__ */ new Set([
|
|
5962
|
+
"datacore",
|
|
5963
|
+
"datacorejsx",
|
|
5964
|
+
"datacorejs",
|
|
5965
|
+
"dataview",
|
|
5966
|
+
"dataviewjs"
|
|
5967
|
+
]);
|
|
5968
|
+
DATACORE_PLACEHOLDER = "[Datacore view]";
|
|
5969
|
+
FENCE_OPEN_RE = /^(\s*)(`{3,}|~{3,})\s*([A-Za-z0-9_-]*)\s*$/;
|
|
5970
|
+
}
|
|
5971
|
+
});
|
|
5972
|
+
|
|
5895
5973
|
// src/adapters/source/obsidian-fs/hash.ts
|
|
5896
5974
|
import { createHash as createHash3 } from "crypto";
|
|
5897
5975
|
function sha256(input) {
|
|
@@ -5944,9 +6022,11 @@ async function parseNote(absolutePath, vaultRoot) {
|
|
|
5944
6022
|
const wikilinks = frontmatterLinks.length === 0 ? bodyLinks : mergeFrontmatterIntoBody(bodyLinks, frontmatterLinks);
|
|
5945
6023
|
const wordCount = countWords2(content);
|
|
5946
6024
|
const relativePath = toPosix2(path3.relative(path3.resolve(vaultRoot), path3.resolve(absolutePath)));
|
|
6025
|
+
const indexedContent = stripDynamicViewBlocks(content).content;
|
|
5947
6026
|
return {
|
|
5948
6027
|
relativePath,
|
|
5949
6028
|
content,
|
|
6029
|
+
indexedContent,
|
|
5950
6030
|
frontmatter,
|
|
5951
6031
|
title,
|
|
5952
6032
|
hash,
|
|
@@ -5990,6 +6070,7 @@ var init_parser = __esm({
|
|
|
5990
6070
|
"use strict";
|
|
5991
6071
|
init_esm_shims();
|
|
5992
6072
|
init_wikilinks2();
|
|
6073
|
+
init_datacore();
|
|
5993
6074
|
init_hash();
|
|
5994
6075
|
}
|
|
5995
6076
|
});
|
|
@@ -6833,6 +6914,9 @@ async function indexVault(vault, options) {
|
|
|
6833
6914
|
log(` skipped (parse error): ${rel} \u2014 ${msg}`);
|
|
6834
6915
|
continue;
|
|
6835
6916
|
}
|
|
6917
|
+
const previous = vault.db.notes.getByPath(parsed.relativePath);
|
|
6918
|
+
const hashUnchanged = previous != null && previous.hash === parsed.hash;
|
|
6919
|
+
const bodyUnchanged = previous != null && previous.body_hash != null && previous.body_hash === parsed.bodyHash;
|
|
6836
6920
|
const upsert = vault.db.notes.upsertByPath({
|
|
6837
6921
|
path: parsed.relativePath,
|
|
6838
6922
|
content: parsed.content,
|
|
@@ -6845,24 +6929,28 @@ async function indexVault(vault, options) {
|
|
|
6845
6929
|
});
|
|
6846
6930
|
vault.db.notes.setStatus(upsert.id, extractStatus(parsed.frontmatter));
|
|
6847
6931
|
vault.db.aliases.setForNote(upsert.id, extractAliases(parsed.frontmatter));
|
|
6848
|
-
const noteExisted = !upsert.isNew;
|
|
6849
|
-
const existing = noteExisted ? vault.db.notes.getById(upsert.id) : null;
|
|
6850
6932
|
const chunkCount = vault.db.chunks.getByNote(upsert.id).length;
|
|
6851
|
-
const
|
|
6933
|
+
const bodyChanged = !hashUnchanged && !bodyUnchanged;
|
|
6934
|
+
const needsReindex = mode === "full" || upsert.isNew || chunkCount === 0 || bodyChanged;
|
|
6935
|
+
const frontmatterOnly = !upsert.isNew && !needsReindex && !hashUnchanged;
|
|
6852
6936
|
if (upsert.isNew) notesIndexed++;
|
|
6853
|
-
else if (needsReindex) notesUpdated++;
|
|
6937
|
+
else if (needsReindex || frontmatterOnly) notesUpdated++;
|
|
6854
6938
|
if (needsReindex) {
|
|
6855
6939
|
parsedNotes.push({ parsed, noteId: upsert.id, needsReindex: true });
|
|
6940
|
+
} else if (frontmatterOnly) {
|
|
6941
|
+
vault.db.wikilinks.deleteByNote(upsert.id);
|
|
6942
|
+
vault.db.edges.deleteByNote(upsert.id);
|
|
6943
|
+
insertWikilinks(vault, upsert.id, parsed.wikilinks, firstPassResolver);
|
|
6944
|
+
writeAllEdges(vault, upsert.id, parsed, firstPassResolver);
|
|
6856
6945
|
}
|
|
6857
|
-
void existing;
|
|
6858
6946
|
}
|
|
6859
6947
|
log(`${parsedNotes.length} notes need (re-)indexing`);
|
|
6860
6948
|
for (const { parsed, noteId } of parsedNotes) {
|
|
6949
|
+
vault.db.sections.deleteByNote(noteId);
|
|
6861
6950
|
vault.db.chunks.deleteByNote(noteId);
|
|
6862
6951
|
vault.db.wikilinks.deleteByNote(noteId);
|
|
6863
6952
|
vault.db.edges.deleteByNote(noteId);
|
|
6864
|
-
|
|
6865
|
-
const chunks = chunkNote(parsed.content);
|
|
6953
|
+
const chunks = chunkNote(parsed.indexedContent);
|
|
6866
6954
|
if (chunks.length === 0) {
|
|
6867
6955
|
insertWikilinks(vault, noteId, parsed.wikilinks, firstPassResolver);
|
|
6868
6956
|
writeAllEdges(vault, noteId, parsed, firstPassResolver);
|
|
@@ -6879,7 +6967,7 @@ async function indexVault(vault, options) {
|
|
|
6879
6967
|
}));
|
|
6880
6968
|
const chunkIds = vault.db.chunks.insertBatch(noteId, chunkInputs);
|
|
6881
6969
|
try {
|
|
6882
|
-
buildSectionsForNote(vault, noteId, parsed.
|
|
6970
|
+
buildSectionsForNote(vault, noteId, parsed.indexedContent, chunkIds);
|
|
6883
6971
|
} catch (err) {
|
|
6884
6972
|
const message = err instanceof Error ? err.message : String(err);
|
|
6885
6973
|
console.error(
|
|
@@ -7216,7 +7304,7 @@ async function indexNote(options) {
|
|
|
7216
7304
|
vault.db.chunks.deleteByNote(upsert.id);
|
|
7217
7305
|
vault.db.wikilinks.deleteByNote(upsert.id);
|
|
7218
7306
|
vault.db.edges.deleteByNote(upsert.id);
|
|
7219
|
-
const chunks = chunkNote(parsed.
|
|
7307
|
+
const chunks = chunkNote(parsed.indexedContent);
|
|
7220
7308
|
if (chunks.length === 0) {
|
|
7221
7309
|
insertWikilinks2(vault, upsert.id, parsed.wikilinks);
|
|
7222
7310
|
writeAllEdges2(vault, upsert.id, parsed);
|
|
@@ -7243,7 +7331,7 @@ async function indexNote(options) {
|
|
|
7243
7331
|
}))
|
|
7244
7332
|
);
|
|
7245
7333
|
try {
|
|
7246
|
-
buildSectionsForNote(vault, upsert.id, parsed.
|
|
7334
|
+
buildSectionsForNote(vault, upsert.id, parsed.indexedContent, chunkIds);
|
|
7247
7335
|
} catch (err) {
|
|
7248
7336
|
const message = err instanceof Error ? err.message : String(err);
|
|
7249
7337
|
process.stderr.write(
|
|
@@ -7848,7 +7936,8 @@ async function writeNote(input) {
|
|
|
7848
7936
|
};
|
|
7849
7937
|
}
|
|
7850
7938
|
}
|
|
7851
|
-
const
|
|
7939
|
+
const yamlDumpOptions = { lineWidth: -1 };
|
|
7940
|
+
const fileText = frontmatter !== null && Object.keys(frontmatter).length > 0 ? matter2.stringify(content, frontmatter, yamlDumpOptions) : content;
|
|
7852
7941
|
input.onBeforeFsWrite?.();
|
|
7853
7942
|
await atomicWriteFile(absPath, fileText);
|
|
7854
7943
|
const written = await readExistingFile(absPath);
|
|
@@ -16138,6 +16227,92 @@ var init_contracts2 = __esm({
|
|
|
16138
16227
|
}
|
|
16139
16228
|
});
|
|
16140
16229
|
|
|
16230
|
+
// package.json
|
|
16231
|
+
var package_default;
|
|
16232
|
+
var init_package = __esm({
|
|
16233
|
+
"package.json"() {
|
|
16234
|
+
package_default = {
|
|
16235
|
+
name: "@owrede/vault-memory",
|
|
16236
|
+
version: "2.3.0",
|
|
16237
|
+
description: "Local-first semantic memory MCP server for Obsidian vaults",
|
|
16238
|
+
type: "module",
|
|
16239
|
+
license: "MIT",
|
|
16240
|
+
workspaces: [
|
|
16241
|
+
"plugin"
|
|
16242
|
+
],
|
|
16243
|
+
repository: {
|
|
16244
|
+
type: "git",
|
|
16245
|
+
url: "git+https://github.com/owrede/vault-memory.git"
|
|
16246
|
+
},
|
|
16247
|
+
bin: {
|
|
16248
|
+
"vault-memory": "dist/cli.js"
|
|
16249
|
+
},
|
|
16250
|
+
files: [
|
|
16251
|
+
"dist",
|
|
16252
|
+
"README.md",
|
|
16253
|
+
"LICENSE",
|
|
16254
|
+
"CHANGELOG.md"
|
|
16255
|
+
],
|
|
16256
|
+
engines: {
|
|
16257
|
+
node: ">=22 <26"
|
|
16258
|
+
},
|
|
16259
|
+
scripts: {
|
|
16260
|
+
build: "tsup",
|
|
16261
|
+
dev: "tsx watch src/cli.ts",
|
|
16262
|
+
start: "node dist/cli.js",
|
|
16263
|
+
test: "vitest run",
|
|
16264
|
+
"test:watch": "vitest",
|
|
16265
|
+
lint: "tsc --noEmit",
|
|
16266
|
+
"lint:adapters": "sh scripts/lint-adapters.sh",
|
|
16267
|
+
"lint:check": 'sh scripts/check-fixture-privacy.sh && sh scripts/lint-no-telemetry.sh && sh scripts/lint-adapters.sh && tsc --noEmit && prettier --check "src/**/*.ts"',
|
|
16268
|
+
format: 'prettier --write "src/**/*.ts"',
|
|
16269
|
+
"eval:baseline": "vitest run evals/v1-baseline/baseline.test.ts",
|
|
16270
|
+
"eval:snapshot": "node evals/v1-baseline/dump-tools.mjs > evals/v1-baseline/tools-list.snapshot.json && node evals/v1-baseline/dump-resources.mjs > evals/v1-baseline/resources-list.snapshot.json",
|
|
16271
|
+
"eval:smoketest": "npm run build && node scripts/smoketest-non-claude.mjs",
|
|
16272
|
+
release: "node scripts/release.mjs",
|
|
16273
|
+
"sync-marketplace": "node scripts/sync-marketplace.mjs"
|
|
16274
|
+
},
|
|
16275
|
+
dependencies: {
|
|
16276
|
+
"@huggingface/tokenizers": "^0.1.3",
|
|
16277
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
16278
|
+
"better-sqlite3": "^11.7.0",
|
|
16279
|
+
chokidar: "^4.0.1",
|
|
16280
|
+
"cross-spawn": "^7.0.6",
|
|
16281
|
+
graphology: "^0.26.0",
|
|
16282
|
+
"graphology-communities-louvain": "^2.0.2",
|
|
16283
|
+
"gray-matter": "^4.0.3",
|
|
16284
|
+
"onnxruntime-node": "^1.26.0",
|
|
16285
|
+
seedrandom: "^3.0.5",
|
|
16286
|
+
"smol-toml": "^1.3.1",
|
|
16287
|
+
"sqlite-vec": "^0.1.6",
|
|
16288
|
+
yaml: "^2.9.0",
|
|
16289
|
+
zod: "^4.4.3"
|
|
16290
|
+
},
|
|
16291
|
+
devDependencies: {
|
|
16292
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
16293
|
+
"@types/node": "^22.10.0",
|
|
16294
|
+
"@types/seedrandom": "^3.0.8",
|
|
16295
|
+
prettier: "^3.4.0",
|
|
16296
|
+
tsup: "^8.3.5",
|
|
16297
|
+
tsx: "^4.19.2",
|
|
16298
|
+
typescript: "^5.7.0",
|
|
16299
|
+
vitest: "^2.1.8"
|
|
16300
|
+
}
|
|
16301
|
+
};
|
|
16302
|
+
}
|
|
16303
|
+
});
|
|
16304
|
+
|
|
16305
|
+
// src/version.ts
|
|
16306
|
+
var VERSION;
|
|
16307
|
+
var init_version = __esm({
|
|
16308
|
+
"src/version.ts"() {
|
|
16309
|
+
"use strict";
|
|
16310
|
+
init_esm_shims();
|
|
16311
|
+
init_package();
|
|
16312
|
+
VERSION = package_default.version;
|
|
16313
|
+
}
|
|
16314
|
+
});
|
|
16315
|
+
|
|
16141
16316
|
// src/server.ts
|
|
16142
16317
|
var server_exports = {};
|
|
16143
16318
|
__export(server_exports, {
|
|
@@ -17219,7 +17394,7 @@ async function serve(options = {}) {
|
|
|
17219
17394
|
`);
|
|
17220
17395
|
});
|
|
17221
17396
|
}
|
|
17222
|
-
var
|
|
17397
|
+
var MEMORY_AUTO_DISCOVERY_FOLDER;
|
|
17223
17398
|
var init_server = __esm({
|
|
17224
17399
|
"src/server.ts"() {
|
|
17225
17400
|
"use strict";
|
|
@@ -17258,7 +17433,7 @@ var init_server = __esm({
|
|
|
17258
17433
|
init_brief2();
|
|
17259
17434
|
init_assembly2();
|
|
17260
17435
|
init_contracts2();
|
|
17261
|
-
|
|
17436
|
+
init_version();
|
|
17262
17437
|
MEMORY_AUTO_DISCOVERY_FOLDER = "_memory";
|
|
17263
17438
|
}
|
|
17264
17439
|
});
|