@ijfw/memory-server 1.5.3 → 1.5.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ijfw/memory-server",
3
- "version": "1.5.3",
3
+ "version": "1.5.4",
4
4
  "description": "Cross-platform persistent memory server for IJFW. 14 MCP tools (memory + admin/update + brain). Works with 15 platforms: 14 via MCP (Claude Code, Codex, Gemini CLI, Cursor, Windsurf, Copilot, Hermes, Wayland, OpenCode, QwenCode, Cline, KimiCode, OpenClaw, Antigravity) plus Aider via the rules-only tier.",
5
5
  "author": "Sean Donahoe",
6
6
  "license": "MIT",
@@ -129,7 +129,7 @@ function buildExtractionPrompt(chunk) {
129
129
  ].join('\n');
130
130
  }
131
131
 
132
- export async function defaultExtractFacts({ file, text, chunks, env, guard, callTieredFn }) {
132
+ export async function defaultExtractFacts({ file: _file, text, chunks, env, guard, callTieredFn }) {
133
133
  // No LLM configured -> graceful no-op (preserves prior behavior).
134
134
  if (!llmReachable(env)) return [];
135
135
  if (!text || typeof text !== 'string') return [];
@@ -18,7 +18,12 @@ import { resolveBrainPaths } from './paths.js';
18
18
  import { validateSafeRepoPath } from './path-guard.js';
19
19
 
20
20
  const WIKI_TYPES = ['concepts', 'entities', 'decisions', 'milestones'];
21
- const WIKILINK_RE = /\[\[([^\]\n|]+)(?:\|[^\]\n]*)?\]\]/g;
21
+ // Match the entire bracket-pair content as a single negated character class.
22
+ // The slug (left of optional `|`) is extracted in JS after the regex match
23
+ // instead of via a nested optional group -- safe-regex flagged the original
24
+ // pattern (`[^\]\n|]+(?:\|[^\]\n]*)?`) as potentially unsafe even though it
25
+ // can't backtrack catastrophically. This single-class form is provably linear.
26
+ const WIKILINK_RE = /\[\[([^\]\n]+)\]\]/g;
22
27
 
23
28
  function findPage(wikiDir, slug) {
24
29
  for (const t of WIKI_TYPES) {
@@ -32,7 +37,11 @@ function parseWikilinks(md) {
32
37
  if (!md) return [];
33
38
  const out = new Set();
34
39
  for (const m of md.matchAll(WIKILINK_RE)) {
35
- const target = m[1].trim();
40
+ // The capture group now includes the optional `|alias` suffix; the slug
41
+ // is the substring before the first `|` (matches the original semantics).
42
+ const inner = m[1];
43
+ const pipeIdx = inner.indexOf('|');
44
+ const target = (pipeIdx === -1 ? inner : inner.slice(0, pipeIdx)).trim();
36
45
  if (target) out.add(target);
37
46
  }
38
47
  return [...out];
@@ -297,7 +297,7 @@ function verbConflictResolve(db, repoRoot, args) {
297
297
  return { ok: true, resolved: true, winnerId: args.winnerId, supersededIds, validTo: chosenValidTo };
298
298
  }
299
299
 
300
- export async function handleIjfwBrain({ verb, args = {}, db, repoRoot, env, opts = {} } = {}) {
300
+ export async function handleIjfwBrain({ verb, args = {}, db, repoRoot, env: _env, opts = {} } = {}) {
301
301
  if (!verb || typeof verb !== 'string') return { ok: false, error: 'missing-verb' };
302
302
  switch (verb) {
303
303
  case 'think': return verbThink(db, repoRoot, args, opts);
@@ -149,23 +149,6 @@ function extractTypeFromFrontmatter(raw) {
149
149
  return null;
150
150
  }
151
151
 
152
- /**
153
- * Return true if any direct child entry name of `dir` satisfies `predicate`.
154
- * Best-effort: returns false on any readdir error.
155
- *
156
- * @param {string} dir
157
- * @param {(name: string) => boolean} predicate
158
- * @returns {boolean}
159
- */
160
- function hasDirEntryMatching(dir, predicate) {
161
- try {
162
- const entries = readdirSync(dir);
163
- return entries.some(predicate);
164
- } catch {
165
- return false;
166
- }
167
- }
168
-
169
152
  /**
170
153
  * Return true if `name` is a direct child of `repoRoot` that is a directory
171
154
  * AND contains at least one `.md` file. Avoids false-positive on plain files
package/src/server.js CHANGED
@@ -28,7 +28,7 @@ import { migrateFactsInternalOnce } from './brain/migrate-facts-internal-once.js
28
28
  // importing server.js.
29
29
  import { runLayoutMigrations } from './memory/layout-migrations/index.js';
30
30
  import { homedir } from 'os';
31
- import { fileURLToPath, pathToFileURL } from 'url';
31
+ import { fileURLToPath } from 'url';
32
32
  import { createHash, randomBytes } from 'crypto';
33
33
 
34
34
  // Read version dynamically from package.json so bumps don't require a code change.
@@ -351,7 +351,7 @@ const __isServerEntryPoint = (() => {
351
351
  })();
352
352
  // Back-compat values for the line-2349 re-export. New code MUST use paths().memoryDir / paths().sessionsDir.
353
353
  const MEMORY_DIR = join(IJFW_DIR, 'memory');
354
- const SESSIONS_DIR = join(IJFW_DIR, 'sessions');
354
+ // SESSIONS_DIR removed -- replaced by paths().sessionsDir via brainPaths() helper.
355
355
  const GLOBAL_DIR = join(homedir(), '.ijfw', 'memory');
356
356
  // Legacy single-file location (pre-Phase 2). Still read for backward compat
357
357
  // but new writes go to the faceted structure.