moflo 4.9.37 → 4.10.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/.claude/guidance/shipped/moflo-memory-protocol.md +5 -1
- package/.claude/guidance/shipped/moflo-memorydb-maintenance.md +22 -11
- package/.claude/guidance/shipped/moflo-root-cause-discipline.md +47 -0
- package/.claude/helpers/statusline.cjs +69 -33
- package/.claude/helpers/subagent-bootstrap.json +1 -1
- package/.claude/helpers/subagent-start.cjs +1 -1
- package/bin/build-embeddings.mjs +6 -20
- package/bin/cli.js +5 -0
- package/bin/generate-code-map.mjs +4 -24
- package/bin/hooks.mjs +3 -12
- package/bin/index-all.mjs +3 -13
- package/bin/index-guidance.mjs +36 -85
- package/bin/index-patterns.mjs +6 -24
- package/bin/index-tests.mjs +4 -23
- package/bin/lib/db-repair.mjs +4 -25
- package/bin/lib/get-backend.mjs +306 -0
- package/bin/lib/incremental-write.mjs +27 -7
- package/bin/lib/moflo-paths.mjs +64 -4
- package/bin/lib/suppress-sqlite-warning.mjs +57 -0
- package/bin/migrations/knowledge-purge.mjs +7 -8
- package/bin/migrations/knowledge-to-learnings.mjs +7 -9
- package/bin/migrations/purge-doc-entries.mjs +7 -8
- package/bin/migrations/strip-context-preambles.mjs +4 -6
- package/bin/run-migrations.mjs +1 -10
- package/bin/semantic-search.mjs +7 -18
- package/bin/session-start-launcher.mjs +102 -102
- package/bin/simplify-classify.cjs +38 -17
- package/dist/src/cli/commands/daemon.js +38 -11
- package/dist/src/cli/commands/doctor-checks-coverage-truth.js +136 -0
- package/dist/src/cli/commands/doctor-checks-memory-access.js +146 -86
- package/dist/src/cli/commands/doctor-checks-memory.js +13 -18
- package/dist/src/cli/commands/doctor-checks-version-skew.js +94 -0
- package/dist/src/cli/commands/doctor-checks-writers-audit.js +170 -0
- package/dist/src/cli/commands/doctor-embedding-hygiene.js +3 -15
- package/dist/src/cli/commands/doctor-fixes.js +30 -0
- package/dist/src/cli/commands/doctor-registry.js +14 -0
- package/dist/src/cli/commands/doctor.js +1 -1
- package/dist/src/cli/commands/embeddings.js +17 -22
- package/dist/src/cli/commands/memory.js +13 -23
- package/dist/src/cli/embeddings/persistent-cache.js +44 -83
- package/dist/src/cli/init/moflo-init.js +40 -0
- package/dist/src/cli/mcp-tools/memory-tools.js +10 -3
- package/dist/src/cli/memory/bridge-core.js +256 -30
- package/dist/src/cli/memory/bridge-entries.js +70 -6
- package/dist/src/cli/memory/controller-registry.js +7 -2
- package/dist/src/cli/memory/controllers/batch-operations.js +5 -1
- package/dist/src/cli/memory/controllers/hierarchical-memory.js +7 -2
- package/dist/src/cli/memory/controllers/mutation-guard.js +22 -2
- package/dist/src/cli/memory/daemon-backend.js +400 -0
- package/dist/src/cli/memory/daemon-write-client.js +192 -15
- package/dist/src/cli/memory/database-provider.js +57 -40
- package/dist/src/cli/memory/hnsw-persistence.js +6 -8
- package/dist/src/cli/memory/index.js +0 -1
- package/dist/src/cli/memory/memory-bridge.js +40 -8
- package/dist/src/cli/memory/memory-initializer.js +269 -209
- package/dist/src/cli/memory/rvf-migration.js +25 -11
- package/dist/src/cli/memory/sqlite-backend.js +573 -0
- package/dist/src/cli/memory/suppress-sqlite-warning.js +49 -0
- package/dist/src/cli/services/cherry-pick-learnings.js +32 -21
- package/dist/src/cli/services/daemon-dashboard.js +13 -1
- package/dist/src/cli/services/daemon-lock.js +58 -1
- package/dist/src/cli/services/daemon-memory-rpc.js +245 -10
- package/dist/src/cli/services/embeddings-migration.js +9 -12
- package/dist/src/cli/services/ephemeral-namespace-purge.js +6 -11
- package/dist/src/cli/services/learning-service.js +12 -20
- package/dist/src/cli/services/project-root.js +69 -9
- package/dist/src/cli/services/soft-delete-purge.js +6 -11
- package/dist/src/cli/services/sqljs-migration-store.js +4 -1
- package/dist/src/cli/services/subagent-bootstrap.js +1 -1
- package/dist/src/cli/shared/events/event-store.js +26 -55
- package/dist/src/cli/version.js +1 -1
- package/package.json +2 -4
- package/dist/src/cli/memory/sqljs-backend.js +0 -643
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Learning Service
|
|
3
3
|
*
|
|
4
|
-
* Persistent pattern learning with HNSW indexing and
|
|
4
|
+
* Persistent pattern learning with HNSW indexing and node:sqlite backend.
|
|
5
5
|
* Manages short-term and long-term pattern storage with automatic
|
|
6
6
|
* promotion, deduplication, and consolidation.
|
|
7
7
|
*
|
|
8
8
|
* Features:
|
|
9
|
-
* - Pattern storage/search with
|
|
9
|
+
* - Pattern storage/search with node:sqlite backend (.moflo/moflo.db)
|
|
10
10
|
* - Short-term -> long-term pattern promotion (promote after 3 uses)
|
|
11
11
|
* - Quality thresholds: minimum quality 0.6, dedup threshold 0.95
|
|
12
12
|
* - Consolidation: max 500 short-term, 2000 long-term, prune after 30 days
|
|
13
13
|
* - HNSW indexing for fast similarity search
|
|
14
14
|
*/
|
|
15
|
-
import { existsSync, mkdirSync
|
|
15
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
16
16
|
import { dirname } from 'path';
|
|
17
|
-
import { mofloImport } from './moflo-require.js';
|
|
18
|
-
import { atomicWriteFileSync } from './atomic-file-write.js';
|
|
19
17
|
import { memoryDbPath } from './moflo-paths.js';
|
|
18
|
+
import { openDaemonDatabase } from '../memory/daemon-backend.js';
|
|
20
19
|
import { createNeuralEmbeddingProvider, } from './neural-embedding-provider.js';
|
|
21
20
|
// ============================================================================
|
|
22
21
|
// Configuration
|
|
@@ -212,11 +211,6 @@ class HNSWIndex {
|
|
|
212
211
|
}
|
|
213
212
|
}
|
|
214
213
|
}
|
|
215
|
-
async function loadSqlJs() {
|
|
216
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
217
|
-
const initSqlJs = (await mofloImport('sql.js')).default;
|
|
218
|
-
return initSqlJs();
|
|
219
|
-
}
|
|
220
214
|
function dbAll(db, sql, params = []) {
|
|
221
215
|
const stmt = db.prepare(sql);
|
|
222
216
|
if (params.length)
|
|
@@ -283,14 +277,10 @@ export class LearningService {
|
|
|
283
277
|
if (!existsSync(dataDir)) {
|
|
284
278
|
mkdirSync(dataDir, { recursive: true });
|
|
285
279
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
this.db = new SQL.Database();
|
|
293
|
-
}
|
|
280
|
+
// node:sqlite via the unified factory (Phase 5 / #1084). The factory
|
|
281
|
+
// creates the file lazily and applies WAL pragma so every UPDATE below
|
|
282
|
+
// persists incrementally — no whole-file dumps via export().
|
|
283
|
+
this.db = openDaemonDatabase(this.dbPath);
|
|
294
284
|
this.ensureSchema();
|
|
295
285
|
this.loadIndexes();
|
|
296
286
|
}
|
|
@@ -485,12 +475,14 @@ export class LearningService {
|
|
|
485
475
|
}
|
|
486
476
|
}
|
|
487
477
|
/**
|
|
488
|
-
*
|
|
478
|
+
* Persist any in-memory changes. node:sqlite + WAL writes incrementally
|
|
479
|
+
* on every `db.run`, so this is just a state-clear — the actual data hit
|
|
480
|
+
* disk when the mutations ran. Phase 5 (#1084) removed the explicit
|
|
481
|
+
* `db.export()` + atomicWriteFileSync (sql.js whole-file dump).
|
|
489
482
|
*/
|
|
490
483
|
save() {
|
|
491
484
|
if (!this.db)
|
|
492
485
|
return;
|
|
493
|
-
atomicWriteFileSync(this.dbPath, this.db.export());
|
|
494
486
|
this.dirty = false;
|
|
495
487
|
}
|
|
496
488
|
// --------------------------------------------------------------------------
|
|
@@ -1,21 +1,81 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project Root Discovery
|
|
2
|
+
* Project Root Discovery — canonical resolver.
|
|
3
3
|
*
|
|
4
|
-
* Walks up from cwd to find the
|
|
5
|
-
*
|
|
4
|
+
* Walks up from cwd to find the project's anchor directory using the same
|
|
5
|
+
* algorithm as `src/cli/memory/bridge-core.ts:getProjectRoot()` and the pure-JS
|
|
6
|
+
* twin at `bin/lib/moflo-paths.mjs:findProjectRoot()`. Every writer that
|
|
7
|
+
* touches `.moflo/moflo.db` (bin scripts, MCP tools, healers, daemon) MUST
|
|
8
|
+
* resolve through this single algorithm or its JS twin — otherwise different
|
|
9
|
+
* writers land on different DBs and the bridge reads stale data.
|
|
10
|
+
*
|
|
11
|
+
* Algorithm (#1057) — two-pass walk so memory markers always win:
|
|
12
|
+
* 1. `process.env.CLAUDE_PROJECT_DIR`, if set (Claude Code / explicit override).
|
|
13
|
+
* 2. **High-priority pass.** Walk from `opts.cwd ?? process.cwd()` up to the
|
|
14
|
+
* filesystem root, looking at each level for (in order):
|
|
15
|
+
* a. `<dir>/.moflo/moflo.db` — canonical memory DB marker
|
|
16
|
+
* b. `<dir>/.swarm/memory.db` — legacy memory DB marker (pre-#727)
|
|
17
|
+
* c. `<dir>/CLAUDE.md` AND `<dir>/package.json` — project marker pair
|
|
18
|
+
* If anything matches, return that dir. `node_modules` segments are
|
|
19
|
+
* skipped (npx run can land cwd inside one).
|
|
20
|
+
* 3. **Low-priority pass.** Walk again from cwd up to root looking for:
|
|
21
|
+
* d. `<dir>/package.json` — generic project marker
|
|
22
|
+
* e. `<dir>/.git` — git repo marker
|
|
23
|
+
* Return the first match.
|
|
24
|
+
* 4. Fall back to `opts.cwd ?? process.cwd()`.
|
|
25
|
+
*
|
|
26
|
+
* Why two passes? An upstream `.moflo/moflo.db` MUST win over a nested
|
|
27
|
+
* `package.json` (monorepo sub-package case) — otherwise the writer lands on
|
|
28
|
+
* a different DB than the bridge. Doing it in a single pass with bare
|
|
29
|
+
* `package.json` as a per-level marker would short-circuit at the nearest
|
|
30
|
+
* package.json before ever seeing the upstream memory marker.
|
|
31
|
+
*
|
|
32
|
+
* Story #229 history: this function was first extracted from workflow-tools.ts;
|
|
33
|
+
* #1057 brought it into alignment with bridge-core.getProjectRoot().
|
|
6
34
|
*/
|
|
7
35
|
import { existsSync } from 'node:fs';
|
|
8
|
-
import { resolve, dirname } from 'node:path';
|
|
9
|
-
export function findProjectRoot() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
36
|
+
import { resolve, dirname, parse, join, basename } from 'node:path';
|
|
37
|
+
export function findProjectRoot(opts) {
|
|
38
|
+
const honorEnv = opts?.honorEnv !== false;
|
|
39
|
+
if (honorEnv && process.env.CLAUDE_PROJECT_DIR) {
|
|
40
|
+
return process.env.CLAUDE_PROJECT_DIR;
|
|
41
|
+
}
|
|
42
|
+
const startDir = opts?.cwd ?? process.cwd();
|
|
43
|
+
const start = resolve(startDir);
|
|
44
|
+
const fsRoot = parse(start).root;
|
|
45
|
+
// High-priority pass: memory markers + CLAUDE.md/package.json pair.
|
|
46
|
+
let dir = start;
|
|
47
|
+
while (dir !== fsRoot) {
|
|
48
|
+
if (basename(dir) === 'node_modules') {
|
|
49
|
+
dir = dirname(dir);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (existsSync(join(dir, '.moflo', 'moflo.db')))
|
|
53
|
+
return dir;
|
|
54
|
+
if (existsSync(join(dir, '.swarm', 'memory.db')))
|
|
55
|
+
return dir;
|
|
56
|
+
if (existsSync(join(dir, 'CLAUDE.md')) && existsSync(join(dir, 'package.json'))) {
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
const parent = dirname(dir);
|
|
60
|
+
if (parent === dir)
|
|
61
|
+
break;
|
|
62
|
+
dir = parent;
|
|
63
|
+
}
|
|
64
|
+
// Low-priority pass: bare package.json or .git.
|
|
65
|
+
dir = start;
|
|
66
|
+
while (dir !== fsRoot) {
|
|
67
|
+
if (basename(dir) === 'node_modules') {
|
|
68
|
+
dir = dirname(dir);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (existsSync(join(dir, 'package.json')) || existsSync(join(dir, '.git'))) {
|
|
13
72
|
return dir;
|
|
14
73
|
}
|
|
15
74
|
const parent = dirname(dir);
|
|
16
75
|
if (parent === dir)
|
|
17
|
-
|
|
76
|
+
break;
|
|
18
77
|
dir = parent;
|
|
19
78
|
}
|
|
79
|
+
return startDir;
|
|
20
80
|
}
|
|
21
81
|
//# sourceMappingURL=project-root.js.map
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
* @module cli/services/soft-delete-purge
|
|
18
18
|
*/
|
|
19
19
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
20
|
-
import { mofloImport } from './moflo-require.js';
|
|
21
|
-
import { atomicWriteFileSync } from './atomic-file-write.js';
|
|
22
20
|
import { memoryDbPath } from './moflo-paths.js';
|
|
21
|
+
import { openDaemonDatabase } from '../memory/daemon-backend.js';
|
|
23
22
|
/**
|
|
24
23
|
* Hard-delete all `status='deleted'` rows from the memory DB and VACUUM.
|
|
25
24
|
*
|
|
@@ -34,12 +33,9 @@ export async function purgeSoftDeletedEntries(options = {}) {
|
|
|
34
33
|
const dbPath = path.resolve(options.dbPath ?? memoryDbPath(process.cwd()));
|
|
35
34
|
if (!fs.existsSync(dbPath))
|
|
36
35
|
return { purged: 0 };
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const SQL = await initSqlJs();
|
|
41
|
-
const buffer = fs.readFileSync(dbPath);
|
|
42
|
-
const db = new SQL.Database(buffer);
|
|
36
|
+
// node:sqlite via the unified factory (Phase 5 / #1084). WAL persists each
|
|
37
|
+
// DELETE/VACUUM incrementally; no atomicWriteFileSync needed.
|
|
38
|
+
const db = openDaemonDatabase(dbPath);
|
|
43
39
|
try {
|
|
44
40
|
// Probe: schema must carry `memory_entries`. Older / non-moflo DBs are
|
|
45
41
|
// a no-op so we don't VACUUM unrelated SQLite files.
|
|
@@ -53,10 +49,9 @@ export async function purgeSoftDeletedEntries(options = {}) {
|
|
|
53
49
|
if (purged === 0)
|
|
54
50
|
return { purged: 0 };
|
|
55
51
|
db.run(`DELETE FROM memory_entries WHERE status = 'deleted'`);
|
|
56
|
-
// VACUUM has to run outside any open transaction; sql.js
|
|
57
|
-
// each `db.run`, so this is safe to chain.
|
|
52
|
+
// VACUUM has to run outside any open transaction; node:sqlite/sql.js
|
|
53
|
+
// both auto-commit each `db.run`, so this is safe to chain.
|
|
58
54
|
db.run('VACUUM');
|
|
59
|
-
atomicWriteFileSync(dbPath, db.export());
|
|
60
55
|
return { purged };
|
|
61
56
|
}
|
|
62
57
|
finally {
|
|
@@ -226,7 +226,10 @@ export class SqlJsMemoryEntriesStore {
|
|
|
226
226
|
async beginTransaction() {
|
|
227
227
|
if (this.inTransaction)
|
|
228
228
|
return;
|
|
229
|
-
|
|
229
|
+
// BEGIN IMMEDIATE — busy_handler engages on RESERVED acquisition under
|
|
230
|
+
// contention (#1099). Plain `BEGIN` (= deferred) would race the
|
|
231
|
+
// SHARED→RESERVED upgrade and fail fast against concurrent writers.
|
|
232
|
+
this.db.run('BEGIN IMMEDIATE');
|
|
230
233
|
this.inTransaction = true;
|
|
231
234
|
}
|
|
232
235
|
async commit() {
|
|
@@ -21,7 +21,7 @@ const BOOTSTRAP_JSON_REL = '.claude/helpers/subagent-bootstrap.json';
|
|
|
21
21
|
// Defense-in-depth copy of the canonical directive in subagent-bootstrap.json.
|
|
22
22
|
// Kept as a single-line literal so the parity test can verify it matches the
|
|
23
23
|
// JSON via plain substring containment.
|
|
24
|
-
const FALLBACK_DIRECTIVE = 'MANDATORY FIRST ACTION: Your very first tool call MUST be mcp__moflo__memory_search (any query, any namespace). The memory-first gate WILL BLOCK all Glob, Grep, and Read calls until you do this. After memory search, follow `.claude/guidance/moflo-subagents.md` protocol. When search
|
|
24
|
+
const FALLBACK_DIRECTIVE = 'MANDATORY FIRST ACTION: Your very first tool call MUST be mcp__moflo__memory_search (any query, any namespace). The memory-first gate WILL BLOCK all Glob, Grep, and Read calls until you do this. After memory search, follow `.claude/guidance/moflo-subagents.md` protocol. When a search hit carries `navigation`, you MUST call mcp__moflo__memory_get_neighbors to traverse — calling mcp__moflo__memory_retrieve on every hit is a protocol violation. See `.claude/guidance/moflo-memory-protocol.md`.';
|
|
25
25
|
function loadDirective() {
|
|
26
26
|
const jsonPath = locateMofloRootPath(BOOTSTRAP_JSON_REL);
|
|
27
27
|
if (!jsonPath) {
|
|
@@ -10,13 +10,17 @@
|
|
|
10
10
|
* - Event filtering and queries
|
|
11
11
|
* - Snapshot support for performance
|
|
12
12
|
* - Event replay for projections
|
|
13
|
-
* -
|
|
13
|
+
* - node:sqlite (Node 22+) via the unified openDaemonDatabase factory
|
|
14
|
+
*
|
|
15
|
+
* Phase 5 (#1084) migrated this from sql.js to node:sqlite. The sql.js
|
|
16
|
+
* whole-file-export persistence model was the structural failure mode that
|
|
17
|
+
* #1078 killed; node:sqlite writes through WAL so explicit `persist()` calls
|
|
18
|
+
* become no-ops and concurrent writers no longer clobber each other.
|
|
14
19
|
*
|
|
15
20
|
* @module v3/shared/events/event-store
|
|
16
21
|
*/
|
|
17
22
|
import { EventEmitter } from 'node:events';
|
|
18
|
-
import {
|
|
19
|
-
import initSqlJs from 'sql.js';
|
|
23
|
+
import { openDaemonDatabase } from '../../memory/daemon-backend.js';
|
|
20
24
|
const DEFAULT_CONFIG = {
|
|
21
25
|
databasePath: ':memory:',
|
|
22
26
|
verbose: false,
|
|
@@ -31,7 +35,6 @@ export class EventStore extends EventEmitter {
|
|
|
31
35
|
db = null;
|
|
32
36
|
initialized = false;
|
|
33
37
|
persistTimer = null;
|
|
34
|
-
SQL = null;
|
|
35
38
|
// Version tracking per aggregate
|
|
36
39
|
aggregateVersions = new Map();
|
|
37
40
|
constructor(config = {}) {
|
|
@@ -39,72 +42,41 @@ export class EventStore extends EventEmitter {
|
|
|
39
42
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
42
|
-
* Initialize the event store
|
|
45
|
+
* Initialize the event store.
|
|
46
|
+
*
|
|
47
|
+
* Phase 5 (#1084): swapped sql.js's WASM init + new SQL.Database round-trip
|
|
48
|
+
* for openDaemonDatabase(path). WAL persists each INSERT incrementally so
|
|
49
|
+
* the auto-persist timer is no longer needed (kept zeroed-out for callers
|
|
50
|
+
* that pass autoPersistInterval > 0).
|
|
43
51
|
*/
|
|
44
52
|
async initialize() {
|
|
45
53
|
if (this.initialized)
|
|
46
54
|
return;
|
|
47
|
-
|
|
48
|
-
this.
|
|
49
|
-
|
|
50
|
-
? () => this.config.wasmPath
|
|
51
|
-
: (file) => {
|
|
52
|
-
// Try to resolve from node_modules first (works in Node.js)
|
|
53
|
-
try {
|
|
54
|
-
const sqlJsDir = require.resolve('sql.js');
|
|
55
|
-
const { dirname, join } = require('node:path');
|
|
56
|
-
const localPath = join(dirname(sqlJsDir), file);
|
|
57
|
-
if (require('node:fs').existsSync(localPath))
|
|
58
|
-
return localPath;
|
|
59
|
-
}
|
|
60
|
-
catch { /* fallback below */ }
|
|
61
|
-
return `https://sql.js.org/dist/${file}`;
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
// Load existing database if exists
|
|
65
|
-
if (this.config.databasePath !== ':memory:' && existsSync(this.config.databasePath)) {
|
|
66
|
-
const buffer = readFileSync(this.config.databasePath);
|
|
67
|
-
this.db = new this.SQL.Database(new Uint8Array(buffer));
|
|
68
|
-
if (this.config.verbose) {
|
|
69
|
-
console.log(`[EventStore] Loaded database from ${this.config.databasePath}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
this.db = new this.SQL.Database();
|
|
74
|
-
if (this.config.verbose) {
|
|
75
|
-
console.log('[EventStore] Created new event store database');
|
|
76
|
-
}
|
|
55
|
+
this.db = openDaemonDatabase(this.config.databasePath);
|
|
56
|
+
if (this.config.verbose) {
|
|
57
|
+
console.log(`[EventStore] Opened database at ${this.config.databasePath}`);
|
|
77
58
|
}
|
|
78
59
|
// Create schema
|
|
79
60
|
this.createSchema();
|
|
80
61
|
// Load aggregate versions
|
|
81
62
|
this.loadAggregateVersions();
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.persist().catch((err) => {
|
|
86
|
-
this.emit('error', { operation: 'auto-persist', error: err });
|
|
87
|
-
});
|
|
88
|
-
}, this.config.autoPersistInterval);
|
|
89
|
-
}
|
|
63
|
+
// node:sqlite + WAL persists every write — explicit auto-persist would
|
|
64
|
+
// be a redundant no-op. The persistTimer field is retained so anything
|
|
65
|
+
// poking at .initialize() shape stays compatible.
|
|
90
66
|
this.initialized = true;
|
|
91
67
|
this.emit('initialized');
|
|
92
68
|
}
|
|
93
69
|
/**
|
|
94
|
-
* Shutdown the event store
|
|
70
|
+
* Shutdown the event store. node:sqlite + WAL persists writes immediately;
|
|
71
|
+
* the only thing close() owes us is releasing the file handle.
|
|
95
72
|
*/
|
|
96
73
|
async shutdown() {
|
|
97
74
|
if (!this.initialized || !this.db)
|
|
98
75
|
return;
|
|
99
|
-
// Stop auto-persist
|
|
100
76
|
if (this.persistTimer) {
|
|
101
77
|
clearInterval(this.persistTimer);
|
|
102
78
|
this.persistTimer = null;
|
|
103
79
|
}
|
|
104
|
-
// Final persist
|
|
105
|
-
if (this.config.databasePath !== ':memory:') {
|
|
106
|
-
await this.persist();
|
|
107
|
-
}
|
|
108
80
|
this.db.close();
|
|
109
81
|
this.db = null;
|
|
110
82
|
this.initialized = false;
|
|
@@ -343,19 +315,18 @@ export class EventStore extends EventEmitter {
|
|
|
343
315
|
};
|
|
344
316
|
}
|
|
345
317
|
/**
|
|
346
|
-
* Persist to disk
|
|
318
|
+
* Persist to disk. node:sqlite + WAL writes through on each `db.run`, so
|
|
319
|
+
* this is a no-op kept for API compatibility with the old sql.js shape.
|
|
320
|
+
* The `persisted` event still fires so callers driven off it keep working.
|
|
347
321
|
*/
|
|
348
322
|
async persist() {
|
|
349
323
|
if (!this.db || this.config.databasePath === ':memory:') {
|
|
350
324
|
return;
|
|
351
325
|
}
|
|
352
|
-
const data = this.db.export();
|
|
353
|
-
const buffer = Buffer.from(data);
|
|
354
|
-
writeFileSync(this.config.databasePath, buffer);
|
|
355
326
|
if (this.config.verbose) {
|
|
356
|
-
console.log(`[EventStore]
|
|
327
|
+
console.log(`[EventStore] persist() is a no-op under node:sqlite WAL (${this.config.databasePath})`);
|
|
357
328
|
}
|
|
358
|
-
this.emit('persisted', { size:
|
|
329
|
+
this.emit('persisted', { size: 0, path: this.config.databasePath });
|
|
359
330
|
}
|
|
360
331
|
// ===== Private Methods =====
|
|
361
332
|
createSchema() {
|
package/dist/src/cli/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.0",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.",
|
|
5
5
|
"main": "dist/src/cli/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -69,7 +69,6 @@
|
|
|
69
69
|
"lru-cache": "^11.3.5",
|
|
70
70
|
"onnxruntime-node": "^1.24.3",
|
|
71
71
|
"semver": "^7.7.4",
|
|
72
|
-
"sql.js": "^1.14.1",
|
|
73
72
|
"tar": "^7.5.11",
|
|
74
73
|
"valibot": "^1.3.1"
|
|
75
74
|
},
|
|
@@ -93,11 +92,10 @@
|
|
|
93
92
|
"devDependencies": {
|
|
94
93
|
"@types/js-yaml": "^4.0.9",
|
|
95
94
|
"@types/node": "^24.12.2",
|
|
96
|
-
"@types/sql.js": "^1.4.9",
|
|
97
95
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
98
96
|
"@typescript-eslint/parser": "^7.18.0",
|
|
99
97
|
"eslint": "^8.0.0",
|
|
100
|
-
"moflo": "^4.9.
|
|
98
|
+
"moflo": "^4.9.37",
|
|
101
99
|
"tsx": "^4.21.0",
|
|
102
100
|
"typescript": "^5.9.3",
|
|
103
101
|
"vitest": "^4.0.0"
|