memorix 1.9.1 → 1.9.3
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 +22 -0
- package/README.md +17 -4
- package/README.zh-CN.md +8 -4
- package/dist/cli/index.js +448 -243
- package/dist/index.js +302 -165
- package/dist/maintenance-runner.js +194 -98
- package/dist/media-audio-runner.js +196 -100
- package/dist/media-video-runner.js +194 -98
- package/dist/memcode-runtime/CHANGELOG.md +22 -0
- package/dist/sdk.js +301 -164
- package/dist/vector-backfill-runner.js +194 -98
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +15 -0
- package/docs/ARCHITECTURE.md +23 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/INTEGRATIONS.md +4 -0
- package/docs/PERFORMANCE.md +50 -0
- package/docs/README.md +1 -1
- package/docs/SETUP.md +5 -0
- package/package.json +1 -2
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/doctor.ts +78 -17
- package/src/cli/commands/memory.ts +2 -1
- package/src/cli/default-mode.ts +15 -0
- package/src/cli/index.ts +10 -1
- package/src/codegraph/lite-provider.ts +10 -1
- package/src/dashboard/maintenance.ts +11 -2
- package/src/memory/consolidation.ts +15 -6
- package/src/store/mini-skill-store.ts +31 -22
- package/src/store/obs-store.ts +46 -30
- package/src/store/session-store.ts +35 -21
- package/src/store/sqlite-db.ts +16 -7
- package/src/store/sqlite-reliability.ts +87 -0
- package/src/store/sqlite-store.ts +4 -1
- package/assets/star-history-dark.svg +0 -30
- package/assets/star-history-light.svg +0 -30
- package/assets/star-history.json +0 -712
|
@@ -580,70 +580,79 @@ function getDatabase(dataDir) {
|
|
|
580
580
|
loadBetterSqlite3();
|
|
581
581
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
582
582
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
583
|
-
|
|
584
|
-
db2.pragma("journal_mode = WAL");
|
|
585
|
-
db2.pragma("busy_timeout = 5000");
|
|
586
|
-
db2.pragma("foreign_keys = ON");
|
|
587
|
-
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
588
|
-
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
589
|
-
db2.exec(CREATE_SESSIONS_TABLE);
|
|
590
|
-
db2.exec(CREATE_META_TABLE);
|
|
591
|
-
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
592
|
-
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
593
|
-
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
594
|
-
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
595
|
-
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
596
|
-
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
597
|
-
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
598
|
-
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
599
|
-
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
600
|
-
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
601
|
-
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
602
|
-
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
603
|
-
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
604
|
-
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
605
|
-
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
606
|
-
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
583
|
+
let db2;
|
|
607
584
|
try {
|
|
608
|
-
db2
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
db2.exec(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
db2.exec(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
db2.exec(
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
db2.exec(
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
db2.exec(
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
585
|
+
db2 = createDatabase(dbPath);
|
|
586
|
+
db2.pragma("busy_timeout = 5000");
|
|
587
|
+
db2.pragma("journal_mode = WAL");
|
|
588
|
+
db2.pragma("foreign_keys = ON");
|
|
589
|
+
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
590
|
+
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
591
|
+
db2.exec(CREATE_SESSIONS_TABLE);
|
|
592
|
+
db2.exec(CREATE_META_TABLE);
|
|
593
|
+
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
594
|
+
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
595
|
+
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
596
|
+
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
597
|
+
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
598
|
+
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
599
|
+
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
600
|
+
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
601
|
+
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
602
|
+
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
603
|
+
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
604
|
+
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
605
|
+
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
606
|
+
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
607
|
+
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
608
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
609
|
+
try {
|
|
610
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
611
|
+
} catch {
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
|
|
615
|
+
} catch {
|
|
616
|
+
}
|
|
617
|
+
try {
|
|
618
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
|
|
619
|
+
} catch {
|
|
620
|
+
}
|
|
621
|
+
try {
|
|
622
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
|
|
623
|
+
} catch {
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
|
|
627
|
+
} catch {
|
|
628
|
+
}
|
|
629
|
+
try {
|
|
630
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
|
|
631
|
+
} catch {
|
|
632
|
+
}
|
|
633
|
+
try {
|
|
634
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
|
|
635
|
+
} catch {
|
|
636
|
+
}
|
|
637
|
+
try {
|
|
638
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
applySchemaMigrations(db2);
|
|
642
|
+
db2.exec(CREATE_INDEXES);
|
|
643
|
+
initializeObservationLexicalIndex(db2);
|
|
644
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
645
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
646
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
647
|
+
_dbCache.set(normalized, db2);
|
|
648
|
+
return db2;
|
|
649
|
+
} catch (error) {
|
|
650
|
+
try {
|
|
651
|
+
db2?.close();
|
|
652
|
+
} catch {
|
|
653
|
+
}
|
|
654
|
+
throw error;
|
|
638
655
|
}
|
|
639
|
-
applySchemaMigrations(db2);
|
|
640
|
-
db2.exec(CREATE_INDEXES);
|
|
641
|
-
initializeObservationLexicalIndex(db2);
|
|
642
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
643
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
644
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
645
|
-
_dbCache.set(normalized, db2);
|
|
646
|
-
return db2;
|
|
647
656
|
}
|
|
648
657
|
function closeAllDatabases() {
|
|
649
658
|
for (const [key, db2] of _dbCache) {
|
|
@@ -1633,6 +1642,74 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1633
1642
|
}
|
|
1634
1643
|
});
|
|
1635
1644
|
|
|
1645
|
+
// src/store/sqlite-reliability.ts
|
|
1646
|
+
function isTransientSqliteError(error) {
|
|
1647
|
+
const code = error?.code;
|
|
1648
|
+
if (typeof code === "string") {
|
|
1649
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
1650
|
+
}
|
|
1651
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
1652
|
+
}
|
|
1653
|
+
function isSqliteUnavailableError(error) {
|
|
1654
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
1655
|
+
}
|
|
1656
|
+
function degradedReadError(storeName) {
|
|
1657
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
1658
|
+
}
|
|
1659
|
+
function degradedWriteError(storeName) {
|
|
1660
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
1661
|
+
}
|
|
1662
|
+
function formatSqliteFailure(error) {
|
|
1663
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
1664
|
+
}
|
|
1665
|
+
function delay(ms) {
|
|
1666
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1667
|
+
}
|
|
1668
|
+
async function retrySqliteBusy(operation, label) {
|
|
1669
|
+
for (let attempt = 0; ; attempt++) {
|
|
1670
|
+
try {
|
|
1671
|
+
return await operation();
|
|
1672
|
+
} catch (error) {
|
|
1673
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
1674
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
1675
|
+
console.error(
|
|
1676
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
1677
|
+
);
|
|
1678
|
+
await delay(waitMs);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
1683
|
+
try {
|
|
1684
|
+
loadBetterSqlite3();
|
|
1685
|
+
} catch (error) {
|
|
1686
|
+
throw new SqliteUnavailableError(error);
|
|
1687
|
+
}
|
|
1688
|
+
return retrySqliteBusy(async () => {
|
|
1689
|
+
const store = factory();
|
|
1690
|
+
await store.init(dataDir);
|
|
1691
|
+
return store;
|
|
1692
|
+
}, label);
|
|
1693
|
+
}
|
|
1694
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
1695
|
+
var init_sqlite_reliability = __esm({
|
|
1696
|
+
"src/store/sqlite-reliability.ts"() {
|
|
1697
|
+
"use strict";
|
|
1698
|
+
init_esm_shims();
|
|
1699
|
+
init_sqlite_db();
|
|
1700
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
1701
|
+
SqliteUnavailableError = class extends Error {
|
|
1702
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
1703
|
+
constructor(cause) {
|
|
1704
|
+
super(
|
|
1705
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
1706
|
+
);
|
|
1707
|
+
this.name = "SqliteUnavailableError";
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1636
1713
|
// src/store/file-lock.ts
|
|
1637
1714
|
import { promises as fs2 } from "fs";
|
|
1638
1715
|
import { randomUUID } from "crypto";
|
|
@@ -3556,10 +3633,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
3556
3633
|
);
|
|
3557
3634
|
}
|
|
3558
3635
|
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
3559
|
-
const
|
|
3636
|
+
const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
3560
3637
|
const retryAfter = response.headers.get("retry-after");
|
|
3561
3638
|
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
3562
|
-
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter :
|
|
3639
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
|
|
3563
3640
|
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
3564
3641
|
await waitForRetry(waitMs, options.signal);
|
|
3565
3642
|
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
@@ -5591,6 +5668,7 @@ var init_sqlite_store = __esm({
|
|
|
5591
5668
|
"use strict";
|
|
5592
5669
|
init_esm_shims();
|
|
5593
5670
|
init_sqlite_db();
|
|
5671
|
+
init_sqlite_reliability();
|
|
5594
5672
|
init_sqlite_fts();
|
|
5595
5673
|
SqliteBackend = class {
|
|
5596
5674
|
db = null;
|
|
@@ -5868,7 +5946,9 @@ var init_sqlite_store = __esm({
|
|
|
5868
5946
|
// ── Compound atomic operation ────────────────────────────────────
|
|
5869
5947
|
async atomic(fn) {
|
|
5870
5948
|
const run = this._atomicQueue.catch(() => void 0).then(async () => {
|
|
5871
|
-
|
|
5949
|
+
await retrySqliteBusy(async () => {
|
|
5950
|
+
this.db.prepare("BEGIN IMMEDIATE").run();
|
|
5951
|
+
}, "Observation atomic write");
|
|
5872
5952
|
try {
|
|
5873
5953
|
const tx = {
|
|
5874
5954
|
loadAll: async () => this.rawLoadAll(),
|
|
@@ -5967,15 +6047,15 @@ function resetObservationStore() {
|
|
|
5967
6047
|
async function createObservationStore(dataDir) {
|
|
5968
6048
|
try {
|
|
5969
6049
|
const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
|
|
5970
|
-
|
|
5971
|
-
await store2.init(dataDir);
|
|
5972
|
-
return store2;
|
|
6050
|
+
return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
|
|
5973
6051
|
} catch (err) {
|
|
5974
|
-
|
|
6052
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
6053
|
+
const reason = formatSqliteFailure(err);
|
|
6054
|
+
console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
|
|
6055
|
+
const degraded = new DegradedBackend(reason);
|
|
6056
|
+
await degraded.init(dataDir);
|
|
6057
|
+
return degraded;
|
|
5975
6058
|
}
|
|
5976
|
-
const store = new DegradedBackend();
|
|
5977
|
-
await store.init(dataDir);
|
|
5978
|
-
return store;
|
|
5979
6059
|
}
|
|
5980
6060
|
async function initObservationStore(dataDir) {
|
|
5981
6061
|
if (_store2 && _storeDataDir === dataDir) {
|
|
@@ -5999,36 +6079,44 @@ var init_obs_store = __esm({
|
|
|
5999
6079
|
"src/store/obs-store.ts"() {
|
|
6000
6080
|
"use strict";
|
|
6001
6081
|
init_esm_shims();
|
|
6082
|
+
init_sqlite_reliability();
|
|
6002
6083
|
_store2 = null;
|
|
6003
6084
|
_storeDataDir = null;
|
|
6004
6085
|
DegradedBackend = class {
|
|
6086
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
6087
|
+
this.reason = reason;
|
|
6088
|
+
}
|
|
6089
|
+
reason;
|
|
6005
6090
|
dataDir = "";
|
|
6091
|
+
unavailableRead() {
|
|
6092
|
+
return degradedReadError("observations");
|
|
6093
|
+
}
|
|
6006
6094
|
async init(dataDir) {
|
|
6007
6095
|
this.dataDir = dataDir;
|
|
6008
6096
|
}
|
|
6009
6097
|
async loadAll() {
|
|
6010
|
-
|
|
6098
|
+
throw this.unavailableRead();
|
|
6011
6099
|
}
|
|
6012
6100
|
async loadByProject(_projectId, _options) {
|
|
6013
|
-
|
|
6101
|
+
throw this.unavailableRead();
|
|
6014
6102
|
}
|
|
6015
6103
|
async countByProject(_projectId, _options) {
|
|
6016
|
-
|
|
6104
|
+
throw this.unavailableRead();
|
|
6017
6105
|
}
|
|
6018
6106
|
async getById(_id) {
|
|
6019
|
-
|
|
6107
|
+
throw this.unavailableRead();
|
|
6020
6108
|
}
|
|
6021
6109
|
async loadIdCounter() {
|
|
6022
|
-
|
|
6110
|
+
throw this.unavailableRead();
|
|
6023
6111
|
}
|
|
6024
6112
|
async countAll() {
|
|
6025
|
-
|
|
6113
|
+
throw this.unavailableRead();
|
|
6026
6114
|
}
|
|
6027
6115
|
async listProjectIds() {
|
|
6028
|
-
|
|
6116
|
+
throw this.unavailableRead();
|
|
6029
6117
|
}
|
|
6030
6118
|
async searchLexical(_options) {
|
|
6031
|
-
|
|
6119
|
+
throw this.unavailableRead();
|
|
6032
6120
|
}
|
|
6033
6121
|
hasLexicalIndex() {
|
|
6034
6122
|
return false;
|
|
@@ -6037,25 +6125,25 @@ var init_obs_store = __esm({
|
|
|
6037
6125
|
return false;
|
|
6038
6126
|
}
|
|
6039
6127
|
async insert(_obs) {
|
|
6040
|
-
throw
|
|
6128
|
+
throw degradedWriteError("observations");
|
|
6041
6129
|
}
|
|
6042
6130
|
async update(_obs) {
|
|
6043
|
-
throw
|
|
6131
|
+
throw degradedWriteError("observations");
|
|
6044
6132
|
}
|
|
6045
6133
|
async remove(_id) {
|
|
6046
|
-
throw
|
|
6134
|
+
throw degradedWriteError("observations");
|
|
6047
6135
|
}
|
|
6048
6136
|
async bulkReplace(_obs) {
|
|
6049
|
-
throw
|
|
6137
|
+
throw degradedWriteError("observations");
|
|
6050
6138
|
}
|
|
6051
6139
|
async bulkRemoveByIds(_ids) {
|
|
6052
|
-
throw
|
|
6140
|
+
throw degradedWriteError("observations");
|
|
6053
6141
|
}
|
|
6054
6142
|
async saveIdCounter(_nextId) {
|
|
6055
|
-
throw
|
|
6143
|
+
throw degradedWriteError("observations");
|
|
6056
6144
|
}
|
|
6057
6145
|
async atomic(_fn) {
|
|
6058
|
-
throw
|
|
6146
|
+
throw degradedWriteError("observations");
|
|
6059
6147
|
}
|
|
6060
6148
|
async ensureFresh() {
|
|
6061
6149
|
return false;
|
|
@@ -6068,6 +6156,9 @@ var init_obs_store = __esm({
|
|
|
6068
6156
|
getBackendName() {
|
|
6069
6157
|
return "degraded";
|
|
6070
6158
|
}
|
|
6159
|
+
getBackendReason() {
|
|
6160
|
+
return this.reason;
|
|
6161
|
+
}
|
|
6071
6162
|
};
|
|
6072
6163
|
}
|
|
6073
6164
|
});
|
|
@@ -9388,7 +9479,8 @@ function clampCursor(afterId) {
|
|
|
9388
9479
|
}
|
|
9389
9480
|
async function loadConsolidationPage(projectId, options) {
|
|
9390
9481
|
const limit2 = clampBatchSize(options.limit);
|
|
9391
|
-
const
|
|
9482
|
+
const store = options.store ?? getObservationStore();
|
|
9483
|
+
const page = await store.loadByProject(projectId, {
|
|
9392
9484
|
status: "active",
|
|
9393
9485
|
afterId: clampCursor(options.afterId),
|
|
9394
9486
|
limit: limit2 + 1
|
|
@@ -9448,7 +9540,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
|
|
|
9448
9540
|
return findClusters(page.observations, threshold);
|
|
9449
9541
|
}
|
|
9450
9542
|
async function executeConsolidation(_projectDir, projectId, opts) {
|
|
9451
|
-
const store = getObservationStore();
|
|
9543
|
+
const store = opts?.store ?? getObservationStore();
|
|
9452
9544
|
const page = await loadConsolidationPage(projectId, opts ?? {});
|
|
9453
9545
|
const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
|
|
9454
9546
|
if (clusters.length === 0) {
|
|
@@ -55274,10 +55366,10 @@ var require_retry3 = __commonJS({
|
|
|
55274
55366
|
if (!await shouldRetryFn(err)) {
|
|
55275
55367
|
return { shouldRetry: false, config: err.config };
|
|
55276
55368
|
}
|
|
55277
|
-
const
|
|
55369
|
+
const delay3 = getNextRetryDelay(config);
|
|
55278
55370
|
err.config.retryConfig.currentRetryAttempt += 1;
|
|
55279
|
-
const backoff = config.retryBackoff ? config.retryBackoff(err,
|
|
55280
|
-
setTimeout(resolve2,
|
|
55371
|
+
const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve2) => {
|
|
55372
|
+
setTimeout(resolve2, delay3);
|
|
55281
55373
|
});
|
|
55282
55374
|
if (config.onRetryAttempt) {
|
|
55283
55375
|
await config.onRetryAttempt(err);
|
|
@@ -97063,7 +97155,7 @@ async function retryBackoff(fn, strategy) {
|
|
|
97063
97155
|
retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
|
|
97064
97156
|
}
|
|
97065
97157
|
const d = Math.min(retryInterval, maxInterval);
|
|
97066
|
-
await
|
|
97158
|
+
await delay2(d);
|
|
97067
97159
|
x2++;
|
|
97068
97160
|
}
|
|
97069
97161
|
}
|
|
@@ -97084,8 +97176,8 @@ function retryIntervalFromResponse(res) {
|
|
|
97084
97176
|
}
|
|
97085
97177
|
return 0;
|
|
97086
97178
|
}
|
|
97087
|
-
async function
|
|
97088
|
-
return new Promise((resolve2) => setTimeout(resolve2,
|
|
97179
|
+
async function delay2(delay3) {
|
|
97180
|
+
return new Promise((resolve2) => setTimeout(resolve2, delay3));
|
|
97089
97181
|
}
|
|
97090
97182
|
var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
|
|
97091
97183
|
var init_retries = __esm({
|
|
@@ -147074,7 +147166,7 @@ __export(lite_provider_exports, {
|
|
|
147074
147166
|
refreshProjectLite: () => refreshProjectLite
|
|
147075
147167
|
});
|
|
147076
147168
|
import { createHash as createHash10 } from "crypto";
|
|
147077
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147169
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147078
147170
|
import { join as join4, relative as relative2 } from "path";
|
|
147079
147171
|
function hashText2(text2) {
|
|
147080
147172
|
return createHash10("sha256").update(text2).digest("hex");
|
|
@@ -147091,6 +147183,9 @@ function resolveMaxFileBytes(value) {
|
|
|
147091
147183
|
if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
|
|
147092
147184
|
return Math.max(1, Math.floor(value));
|
|
147093
147185
|
}
|
|
147186
|
+
function isPythonVirtualenvDir(dir) {
|
|
147187
|
+
return existsSync11(join4(dir, "pyvenv.cfg"));
|
|
147188
|
+
}
|
|
147094
147189
|
function walk(root, exclude, maxFiles) {
|
|
147095
147190
|
const out = [];
|
|
147096
147191
|
const visit = (dir) => {
|
|
@@ -147108,6 +147203,7 @@ function walk(root, exclude, maxFiles) {
|
|
|
147108
147203
|
if (entry.isDirectory()) {
|
|
147109
147204
|
if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
|
|
147110
147205
|
if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
|
|
147206
|
+
if (isPythonVirtualenvDir(abs)) continue;
|
|
147111
147207
|
visit(abs);
|
|
147112
147208
|
if (out.length >= maxFiles) return;
|
|
147113
147209
|
continue;
|
|
@@ -150627,7 +150723,7 @@ __export(vector_backfill_runner_exports, {
|
|
|
150627
150723
|
import { spawn as spawn3 } from "child_process";
|
|
150628
150724
|
import {
|
|
150629
150725
|
closeSync,
|
|
150630
|
-
existsSync as
|
|
150726
|
+
existsSync as existsSync12,
|
|
150631
150727
|
mkdirSync as mkdirSync2,
|
|
150632
150728
|
openSync,
|
|
150633
150729
|
readFileSync as readFileSync9,
|
|
@@ -150755,7 +150851,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
|
|
|
150755
150851
|
}
|
|
150756
150852
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
150757
150853
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
150758
|
-
const exists = options.exists ??
|
|
150854
|
+
const exists = options.exists ?? existsSync12;
|
|
150759
150855
|
if (!exists(runnerPath)) return false;
|
|
150760
150856
|
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
150761
150857
|
if (!lock) return false;
|
|
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.9.3] - 2026-09-14
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **SQLite storage reliability** -- transient cross-process locks no longer
|
|
11
|
+
turn a process into a permanently empty read-only store. Observations,
|
|
12
|
+
sessions, and mini-skills share the same initialization and retry contract;
|
|
13
|
+
persistent runtime failures remain visible.
|
|
14
|
+
- **Storage diagnostics** -- `memorix doctor` reports the active backend,
|
|
15
|
+
distinguishes unavailable storage from an empty project, and returns a
|
|
16
|
+
failing exit status for storage failures.
|
|
17
|
+
|
|
18
|
+
## [1.9.2] - 2026-09-11
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **Non-interactive MCP startup** -- running the package without arguments
|
|
22
|
+
through piped stdio now starts the MCP server, while a real terminal keeps
|
|
23
|
+
opening the bundled memcode agent. This makes generic npm MCP launchers and
|
|
24
|
+
registry handshake checks use the correct protocol entry point.
|
|
25
|
+
- **Maintenance initialization** -- dashboard Consolidate uses its
|
|
26
|
+
request-scoped observation store, and CLI deduplication initializes the
|
|
27
|
+
project memory LLM before checking availability.
|
|
28
|
+
|
|
7
29
|
## [1.9.1] - 2026-09-08
|
|
8
30
|
|
|
9
31
|
### Changed
|