memorix 1.9.6 → 1.9.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 +18 -0
- package/dist/cli/index.js +254 -87
- package/dist/index.js +254 -87
- package/dist/maintenance-runner.js +96 -84
- package/dist/media-audio-runner.js +96 -84
- package/dist/media-video-runner.js +96 -84
- package/dist/memcode-runtime/CHANGELOG.md +18 -0
- package/dist/sdk.js +253 -86
- package/dist/vector-backfill-runner.js +96 -84
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/KNOWN_ISSUES_AND_ROADMAP.md +1 -1
- package/docs/README.md +1 -1
- package/docs/SETUP.md +1 -1
- package/package.json +1 -1
- 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/hooks/installers/index.ts +160 -3
- package/src/store/orama-store.ts +16 -1
- package/src/store/sqlite-fts.ts +38 -16
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@ All notable changes to this project will be documented in this file.
|
|
|
6
6
|
|
|
7
7
|
No unreleased changes.
|
|
8
8
|
|
|
9
|
+
## [1.9.8] - 2026-10-02
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **OpenCode v2 plugin compatibility** -- generated plugins retain the v1
|
|
13
|
+
named export while also exposing the v2 default `id`/`setup` contract,
|
|
14
|
+
including event subscriptions, tool hooks, cleanup, and host session IDs.
|
|
15
|
+
|
|
16
|
+
## [1.9.7] - 2026-09-28
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **SQLite FTS5 startup resilience** -- transient `SQLITE_BUSY` contention during
|
|
20
|
+
lexical-index initialization is retried before FTS5 is marked unavailable.
|
|
21
|
+
- **Large-store search fallback** -- runtime embedding failure, provider
|
|
22
|
+
disappearance, and vector-dimension mismatch now all fall back to the durable
|
|
23
|
+
SQLite lexical index instead of returning a silent empty result.
|
|
24
|
+
- **Release metadata** -- synchronized the npm, MCP Registry, and packaged
|
|
25
|
+
integration metadata for the 1.9.7 patch release.
|
|
26
|
+
|
|
9
27
|
## [1.9.6] - 2026-09-22
|
|
10
28
|
|
|
11
29
|
### Added
|
package/dist/cli/index.js
CHANGED
|
@@ -3232,7 +3232,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
|
|
|
3232
3232
|
|
|
3233
3233
|
// src/cli/version.ts
|
|
3234
3234
|
function getCliVersion() {
|
|
3235
|
-
return true ? "1.9.
|
|
3235
|
+
return true ? "1.9.8" : pkg.version;
|
|
3236
3236
|
}
|
|
3237
3237
|
var init_version = __esm({
|
|
3238
3238
|
"src/cli/version.ts"() {
|
|
@@ -9349,6 +9349,74 @@ var init_launch_root = __esm({
|
|
|
9349
9349
|
}
|
|
9350
9350
|
});
|
|
9351
9351
|
|
|
9352
|
+
// src/store/sqlite-reliability.ts
|
|
9353
|
+
function isTransientSqliteError(error40) {
|
|
9354
|
+
const code = error40?.code;
|
|
9355
|
+
if (typeof code === "string") {
|
|
9356
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
9357
|
+
}
|
|
9358
|
+
return error40 instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error40.message);
|
|
9359
|
+
}
|
|
9360
|
+
function isSqliteUnavailableError(error40) {
|
|
9361
|
+
return error40 instanceof SqliteUnavailableError || error40 instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error40.message);
|
|
9362
|
+
}
|
|
9363
|
+
function degradedReadError(storeName) {
|
|
9364
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
9365
|
+
}
|
|
9366
|
+
function degradedWriteError(storeName) {
|
|
9367
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
9368
|
+
}
|
|
9369
|
+
function formatSqliteFailure(error40) {
|
|
9370
|
+
return error40 instanceof Error && error40.message ? error40.message : String(error40);
|
|
9371
|
+
}
|
|
9372
|
+
function delay(ms2) {
|
|
9373
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms2));
|
|
9374
|
+
}
|
|
9375
|
+
async function retrySqliteBusy(operation, label) {
|
|
9376
|
+
for (let attempt = 0; ; attempt++) {
|
|
9377
|
+
try {
|
|
9378
|
+
return await operation();
|
|
9379
|
+
} catch (error40) {
|
|
9380
|
+
if (!isTransientSqliteError(error40) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error40;
|
|
9381
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
9382
|
+
console.error(
|
|
9383
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
9384
|
+
);
|
|
9385
|
+
await delay(waitMs);
|
|
9386
|
+
}
|
|
9387
|
+
}
|
|
9388
|
+
}
|
|
9389
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
9390
|
+
try {
|
|
9391
|
+
loadBetterSqlite3();
|
|
9392
|
+
} catch (error40) {
|
|
9393
|
+
throw new SqliteUnavailableError(error40);
|
|
9394
|
+
}
|
|
9395
|
+
return retrySqliteBusy(async () => {
|
|
9396
|
+
const store2 = factory();
|
|
9397
|
+
await store2.init(dataDir);
|
|
9398
|
+
return store2;
|
|
9399
|
+
}, label);
|
|
9400
|
+
}
|
|
9401
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
9402
|
+
var init_sqlite_reliability = __esm({
|
|
9403
|
+
"src/store/sqlite-reliability.ts"() {
|
|
9404
|
+
"use strict";
|
|
9405
|
+
init_esm_shims();
|
|
9406
|
+
init_sqlite_db();
|
|
9407
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
9408
|
+
SqliteUnavailableError = class extends Error {
|
|
9409
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
9410
|
+
constructor(cause) {
|
|
9411
|
+
super(
|
|
9412
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
9413
|
+
);
|
|
9414
|
+
this.name = "SqliteUnavailableError";
|
|
9415
|
+
}
|
|
9416
|
+
};
|
|
9417
|
+
}
|
|
9418
|
+
});
|
|
9419
|
+
|
|
9352
9420
|
// src/store/sqlite-fts.ts
|
|
9353
9421
|
function normalizeFtsToken(token) {
|
|
9354
9422
|
return token.replace(/"/g, '""');
|
|
@@ -9362,22 +9430,27 @@ function buildFtsQuery(query) {
|
|
|
9362
9430
|
function initializeObservationLexicalIndex(db2) {
|
|
9363
9431
|
const known = ftsAvailability.get(db2);
|
|
9364
9432
|
if (known !== void 0) return known;
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
db2.
|
|
9433
|
+
let lastError;
|
|
9434
|
+
for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
|
|
9435
|
+
try {
|
|
9436
|
+
db2.exec(CREATE_OBSERVATION_FTS);
|
|
9437
|
+
const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
|
|
9438
|
+
const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
|
|
9439
|
+
if (observationCount !== indexedCount) {
|
|
9440
|
+
db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
|
|
9441
|
+
}
|
|
9442
|
+
ftsAvailability.set(db2, true);
|
|
9443
|
+
return true;
|
|
9444
|
+
} catch (error40) {
|
|
9445
|
+
lastError = error40;
|
|
9446
|
+
if (!isTransientSqliteError(error40) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
|
|
9371
9447
|
}
|
|
9372
|
-
ftsAvailability.set(db2, true);
|
|
9373
|
-
return true;
|
|
9374
|
-
} catch (error40) {
|
|
9375
|
-
ftsAvailability.set(db2, false);
|
|
9376
|
-
console.warn(
|
|
9377
|
-
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error40 instanceof Error ? error40.message : String(error40)}`
|
|
9378
|
-
);
|
|
9379
|
-
return false;
|
|
9380
9448
|
}
|
|
9449
|
+
ftsAvailability.set(db2, false);
|
|
9450
|
+
console.warn(
|
|
9451
|
+
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
9452
|
+
);
|
|
9453
|
+
return false;
|
|
9381
9454
|
}
|
|
9382
9455
|
function isObservationLexicalIndexEnabled(db2) {
|
|
9383
9456
|
return ftsAvailability.get(db2) === true;
|
|
@@ -9431,11 +9504,12 @@ function searchObservationLexically(db2, options) {
|
|
|
9431
9504
|
score: Math.max(0, Number(row.lexical_score ?? 0))
|
|
9432
9505
|
}));
|
|
9433
9506
|
}
|
|
9434
|
-
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
|
|
9507
|
+
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
|
|
9435
9508
|
var init_sqlite_fts = __esm({
|
|
9436
9509
|
"src/store/sqlite-fts.ts"() {
|
|
9437
9510
|
"use strict";
|
|
9438
9511
|
init_esm_shims();
|
|
9512
|
+
init_sqlite_reliability();
|
|
9439
9513
|
ftsAvailability = /* @__PURE__ */ new WeakMap();
|
|
9440
9514
|
FTS_TABLE = "observations_fts";
|
|
9441
9515
|
CREATE_OBSERVATION_FTS = `
|
|
@@ -9469,6 +9543,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
|
|
|
9469
9543
|
VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
|
|
9470
9544
|
END;
|
|
9471
9545
|
`;
|
|
9546
|
+
FTS_INIT_MAX_ATTEMPTS = 3;
|
|
9472
9547
|
}
|
|
9473
9548
|
});
|
|
9474
9549
|
|
|
@@ -10724,74 +10799,6 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
10724
10799
|
}
|
|
10725
10800
|
});
|
|
10726
10801
|
|
|
10727
|
-
// src/store/sqlite-reliability.ts
|
|
10728
|
-
function isTransientSqliteError(error40) {
|
|
10729
|
-
const code = error40?.code;
|
|
10730
|
-
if (typeof code === "string") {
|
|
10731
|
-
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
10732
|
-
}
|
|
10733
|
-
return error40 instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error40.message);
|
|
10734
|
-
}
|
|
10735
|
-
function isSqliteUnavailableError(error40) {
|
|
10736
|
-
return error40 instanceof SqliteUnavailableError || error40 instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error40.message);
|
|
10737
|
-
}
|
|
10738
|
-
function degradedReadError(storeName) {
|
|
10739
|
-
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
10740
|
-
}
|
|
10741
|
-
function degradedWriteError(storeName) {
|
|
10742
|
-
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
10743
|
-
}
|
|
10744
|
-
function formatSqliteFailure(error40) {
|
|
10745
|
-
return error40 instanceof Error && error40.message ? error40.message : String(error40);
|
|
10746
|
-
}
|
|
10747
|
-
function delay(ms2) {
|
|
10748
|
-
return new Promise((resolve9) => setTimeout(resolve9, ms2));
|
|
10749
|
-
}
|
|
10750
|
-
async function retrySqliteBusy(operation, label) {
|
|
10751
|
-
for (let attempt = 0; ; attempt++) {
|
|
10752
|
-
try {
|
|
10753
|
-
return await operation();
|
|
10754
|
-
} catch (error40) {
|
|
10755
|
-
if (!isTransientSqliteError(error40) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error40;
|
|
10756
|
-
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
10757
|
-
console.error(
|
|
10758
|
-
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
10759
|
-
);
|
|
10760
|
-
await delay(waitMs);
|
|
10761
|
-
}
|
|
10762
|
-
}
|
|
10763
|
-
}
|
|
10764
|
-
async function initializeSqliteStore(factory, dataDir, label) {
|
|
10765
|
-
try {
|
|
10766
|
-
loadBetterSqlite3();
|
|
10767
|
-
} catch (error40) {
|
|
10768
|
-
throw new SqliteUnavailableError(error40);
|
|
10769
|
-
}
|
|
10770
|
-
return retrySqliteBusy(async () => {
|
|
10771
|
-
const store2 = factory();
|
|
10772
|
-
await store2.init(dataDir);
|
|
10773
|
-
return store2;
|
|
10774
|
-
}, label);
|
|
10775
|
-
}
|
|
10776
|
-
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
10777
|
-
var init_sqlite_reliability = __esm({
|
|
10778
|
-
"src/store/sqlite-reliability.ts"() {
|
|
10779
|
-
"use strict";
|
|
10780
|
-
init_esm_shims();
|
|
10781
|
-
init_sqlite_db();
|
|
10782
|
-
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
10783
|
-
SqliteUnavailableError = class extends Error {
|
|
10784
|
-
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
10785
|
-
constructor(cause) {
|
|
10786
|
-
super(
|
|
10787
|
-
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
10788
|
-
);
|
|
10789
|
-
this.name = "SqliteUnavailableError";
|
|
10790
|
-
}
|
|
10791
|
-
};
|
|
10792
|
-
}
|
|
10793
|
-
});
|
|
10794
|
-
|
|
10795
10802
|
// src/store/file-lock.ts
|
|
10796
10803
|
import { promises as fs2 } from "fs";
|
|
10797
10804
|
import { randomUUID } from "crypto";
|
|
@@ -188224,6 +188231,7 @@ async function searchObservations(options) {
|
|
|
188224
188231
|
};
|
|
188225
188232
|
let queryVector = null;
|
|
188226
188233
|
let embeddingProviderForSearch = null;
|
|
188234
|
+
let embeddingUnavailable = false;
|
|
188227
188235
|
if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
|
|
188228
188236
|
try {
|
|
188229
188237
|
const provider2 = await getEmbeddingProvider();
|
|
@@ -188231,6 +188239,7 @@ async function searchObservations(options) {
|
|
|
188231
188239
|
embeddingProviderForSearch = provider2;
|
|
188232
188240
|
const activeVectorDimensions = getVectorDimensions();
|
|
188233
188241
|
if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
|
|
188242
|
+
embeddingUnavailable = true;
|
|
188234
188243
|
rememberSearchMode(
|
|
188235
188244
|
modeKey,
|
|
188236
188245
|
`fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
|
|
@@ -188270,8 +188279,11 @@ async function searchObservations(options) {
|
|
|
188270
188279
|
hybridWeights: isCJKHeavy ? { text: 0.2, vector: 0.8 } : { text: 0.6, vector: 0.4 }
|
|
188271
188280
|
};
|
|
188272
188281
|
}
|
|
188282
|
+
} else {
|
|
188283
|
+
embeddingUnavailable = true;
|
|
188273
188284
|
}
|
|
188274
188285
|
} catch (error40) {
|
|
188286
|
+
embeddingUnavailable = true;
|
|
188275
188287
|
rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
|
|
188276
188288
|
console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
|
|
188277
188289
|
}
|
|
@@ -188279,7 +188291,7 @@ async function searchObservations(options) {
|
|
|
188279
188291
|
mark("preSearch");
|
|
188280
188292
|
let results;
|
|
188281
188293
|
const persistentCorpusEligible = await shouldUsePersistentSearch(projectIds, options.projectId);
|
|
188282
|
-
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled);
|
|
188294
|
+
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled || embeddingUnavailable);
|
|
188283
188295
|
let persistent = persistentCorpusEligible && queryVector && embeddingProviderForSearch ? await searchPersistentSemantically(options, projectIds, requestLimit, queryVector, embeddingProviderForSearch) : canUsePersistentLexical ? await searchPersistentLexically(options, projectIds, requestLimit) : null;
|
|
188284
188296
|
const durableStore = getOptionalObservationStore();
|
|
188285
188297
|
if (!persistent && queryVector && durableStore?.hasLexicalIndex?.() && count2(database) === 0) {
|
|
@@ -195655,6 +195667,161 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
195655
195667
|
},
|
|
195656
195668
|
};
|
|
195657
195669
|
};
|
|
195670
|
+
|
|
195671
|
+
/**
|
|
195672
|
+
* OpenCode v2 compatibility layer. Keep this beside the v1 export so one
|
|
195673
|
+
* generated file can be loaded by both host generations during migration.
|
|
195674
|
+
*/
|
|
195675
|
+
const v2HookCommand = ${hookCommand};
|
|
195676
|
+
|
|
195677
|
+
function v2ReportHookFailure(eventName, detail) {
|
|
195678
|
+
if (process.env.MEMORIX_HOOK_DEBUG !== '1') return;
|
|
195679
|
+
console.error('[memorix-plugin] v2 hook delivery failed:', eventName, detail);
|
|
195680
|
+
}
|
|
195681
|
+
|
|
195682
|
+
function v2EventData(event) {
|
|
195683
|
+
return event && typeof event.data === 'object' && event.data !== null ? event.data : {};
|
|
195684
|
+
}
|
|
195685
|
+
|
|
195686
|
+
function v2SessionId(event) {
|
|
195687
|
+
const data = v2EventData(event);
|
|
195688
|
+
const value = data.sessionID ?? data.sessionId ?? data.session_id
|
|
195689
|
+
?? event?.sessionID ?? event?.sessionId;
|
|
195690
|
+
return typeof value === 'string' ? value : '';
|
|
195691
|
+
}
|
|
195692
|
+
|
|
195693
|
+
function v2RunHook(payload, directory, sessionId) {
|
|
195694
|
+
const nextPayload = { agent: 'opencode', cwd: directory, ...payload };
|
|
195695
|
+
if (sessionId) nextPayload.session_id = sessionId;
|
|
195696
|
+
const eventName = nextPayload.hook_event_name || 'unknown';
|
|
195697
|
+
try {
|
|
195698
|
+
const result = spawnSync(v2HookCommand, ['hook'], {
|
|
195699
|
+
input: JSON.stringify(nextPayload),
|
|
195700
|
+
timeout: 10_000,
|
|
195701
|
+
encoding: 'utf-8',
|
|
195702
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
195703
|
+
shell: process.platform === 'win32',
|
|
195704
|
+
windowsHide: true,
|
|
195705
|
+
});
|
|
195706
|
+
if (result.status !== 0) {
|
|
195707
|
+
v2ReportHookFailure(eventName, {
|
|
195708
|
+
exit: result.status,
|
|
195709
|
+
stderr: (result.stderr || '').slice(0, 200),
|
|
195710
|
+
error: result.error?.message,
|
|
195711
|
+
});
|
|
195712
|
+
}
|
|
195713
|
+
} catch (error) {
|
|
195714
|
+
v2ReportHookFailure(eventName, error?.message ?? error);
|
|
195715
|
+
}
|
|
195716
|
+
}
|
|
195717
|
+
|
|
195718
|
+
function v2SessionState(states, sessionId) {
|
|
195719
|
+
const key = sessionId || '__unknown__';
|
|
195720
|
+
let state = states.get(key);
|
|
195721
|
+
if (!state) {
|
|
195722
|
+
state = { pendingText: '', lastDeliveredKey: '' };
|
|
195723
|
+
states.set(key, state);
|
|
195724
|
+
}
|
|
195725
|
+
return state;
|
|
195726
|
+
}
|
|
195727
|
+
|
|
195728
|
+
function v2FlushAssistant(state, directory, sessionId) {
|
|
195729
|
+
const text = state.pendingText.trim();
|
|
195730
|
+
if (!text || text === state.lastDeliveredKey) return;
|
|
195731
|
+
v2RunHook({ hook_event_name: 'message.updated', ai_response: text }, directory, sessionId);
|
|
195732
|
+
state.lastDeliveredKey = text;
|
|
195733
|
+
state.pendingText = '';
|
|
195734
|
+
}
|
|
195735
|
+
|
|
195736
|
+
function v2FilePath(file) {
|
|
195737
|
+
if (typeof file === 'string') return file;
|
|
195738
|
+
if (!file || typeof file !== 'object') return '';
|
|
195739
|
+
return file.path ?? file.file ?? file.name ?? '';
|
|
195740
|
+
}
|
|
195741
|
+
|
|
195742
|
+
function v2HandleEvent(event, directory, states) {
|
|
195743
|
+
if (!event || typeof event !== 'object') return;
|
|
195744
|
+
const type = typeof event.type === 'string' ? event.type : '';
|
|
195745
|
+
const data = v2EventData(event);
|
|
195746
|
+
const sessionId = v2SessionId(event);
|
|
195747
|
+
const state = v2SessionState(states, sessionId);
|
|
195748
|
+
const run = (payload) => v2RunHook(payload, directory, sessionId);
|
|
195749
|
+
|
|
195750
|
+
switch (type) {
|
|
195751
|
+
case 'session.created':
|
|
195752
|
+
run({ hook_event_name: 'session.created' });
|
|
195753
|
+
break;
|
|
195754
|
+
case 'session.text.delta':
|
|
195755
|
+
state.pendingText += typeof data.delta === 'string' ? data.delta : (typeof data.text === 'string' ? data.text : '');
|
|
195756
|
+
break;
|
|
195757
|
+
case 'session.message.updated':
|
|
195758
|
+
case 'message.updated':
|
|
195759
|
+
if (data.role === 'assistant' && typeof data.text === 'string') state.pendingText = data.text;
|
|
195760
|
+
break;
|
|
195761
|
+
case 'session.step.ended': {
|
|
195762
|
+
const files = Array.isArray(data.files) ? data.files : [];
|
|
195763
|
+
for (const file of files) {
|
|
195764
|
+
const filePath = v2FilePath(file);
|
|
195765
|
+
if (filePath) run({ hook_event_name: 'file.edited', file_path: filePath });
|
|
195766
|
+
}
|
|
195767
|
+
if (typeof data.text === 'string') state.pendingText += data.text;
|
|
195768
|
+
break;
|
|
195769
|
+
}
|
|
195770
|
+
case 'session.idle':
|
|
195771
|
+
v2FlushAssistant(state, directory, sessionId);
|
|
195772
|
+
run({ hook_event_name: 'session.idle' });
|
|
195773
|
+
break;
|
|
195774
|
+
case 'session.compacted':
|
|
195775
|
+
run({ hook_event_name: 'session.compacted' });
|
|
195776
|
+
break;
|
|
195777
|
+
default:
|
|
195778
|
+
break;
|
|
195779
|
+
}
|
|
195780
|
+
}
|
|
195781
|
+
|
|
195782
|
+
function setup(ctx) {
|
|
195783
|
+
const directory = ctx?.location?.directory || ctx?.location?.worktree || process.cwd();
|
|
195784
|
+
const controller = new AbortController();
|
|
195785
|
+
const states = new Map();
|
|
195786
|
+
|
|
195787
|
+
if (ctx?.tool?.hook) {
|
|
195788
|
+
try {
|
|
195789
|
+
Promise.resolve(ctx.tool.hook('execute.after', async (event) => {
|
|
195790
|
+
const sessionId = v2SessionId(event);
|
|
195791
|
+
const data = event && typeof event.input === 'object' ? event.input : {};
|
|
195792
|
+
const tool = event?.tool ?? event?.name ?? '';
|
|
195793
|
+
v2RunHook({
|
|
195794
|
+
hook_event_name: 'tool.execute.after',
|
|
195795
|
+
tool_name: tool,
|
|
195796
|
+
tool_input: data,
|
|
195797
|
+
}, directory, sessionId);
|
|
195798
|
+
if (tool === 'shell') {
|
|
195799
|
+
v2RunHook({
|
|
195800
|
+
hook_event_name: 'command.executed',
|
|
195801
|
+
command: data.command ?? data.cmd ?? '',
|
|
195802
|
+
}, directory, sessionId);
|
|
195803
|
+
}
|
|
195804
|
+
})).catch((error) => v2ReportHookFailure('execute.after', error?.message ?? error));
|
|
195805
|
+
} catch (error) {
|
|
195806
|
+
v2ReportHookFailure('execute.after', error?.message ?? error);
|
|
195807
|
+
}
|
|
195808
|
+
}
|
|
195809
|
+
|
|
195810
|
+
if (ctx?.event?.subscribe) {
|
|
195811
|
+
void (async () => {
|
|
195812
|
+
try {
|
|
195813
|
+
const stream = ctx.event.subscribe({ signal: controller.signal });
|
|
195814
|
+
for await (const event of stream) v2HandleEvent(event, directory, states);
|
|
195815
|
+
} catch (error) {
|
|
195816
|
+
if (!controller.signal.aborted) v2ReportHookFailure('event.subscribe', error?.message ?? error);
|
|
195817
|
+
}
|
|
195818
|
+
})();
|
|
195819
|
+
}
|
|
195820
|
+
|
|
195821
|
+
return () => controller.abort();
|
|
195822
|
+
}
|
|
195823
|
+
|
|
195824
|
+
export default { id: 'memorix', setup };
|
|
195658
195825
|
`;
|
|
195659
195826
|
}
|
|
195660
195827
|
async function installOpenCodeSkills(projectRoot, global2 = false) {
|
|
@@ -196480,7 +196647,7 @@ var init_installers = __esm({
|
|
|
196480
196647
|
"use strict";
|
|
196481
196648
|
init_esm_shims();
|
|
196482
196649
|
init_official_skills();
|
|
196483
|
-
OPENCODE_PLUGIN_VERSION =
|
|
196650
|
+
OPENCODE_PLUGIN_VERSION = 8;
|
|
196484
196651
|
AGENT_SKILL_DIRS = {
|
|
196485
196652
|
cursor: { project: path31.join(".cursor", "skills"), global: path31.join(".cursor", "skills") },
|
|
196486
196653
|
windsurf: { project: path31.join(".windsurf", "skills"), global: path31.join(".windsurf", "skills") },
|
|
@@ -209007,7 +209174,7 @@ var init_tool_profile = __esm({
|
|
|
209007
209174
|
function getMcpServerInfo() {
|
|
209008
209175
|
return {
|
|
209009
209176
|
name: "memorix",
|
|
209010
|
-
version: true ? "1.9.
|
|
209177
|
+
version: true ? "1.9.8" : "1.0.1"
|
|
209011
209178
|
};
|
|
209012
209179
|
}
|
|
209013
209180
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|