memorix 1.2.9 → 1.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 +24 -0
- package/README.md +30 -4
- package/README.zh-CN.md +28 -2
- package/assets/star-history-dark.svg +30 -0
- package/assets/star-history-light.svg +30 -0
- package/assets/star-history.json +599 -0
- package/dist/cli/index.js +1945 -579
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1292 -267
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.js +97 -21
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +24 -0
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js +1294 -269
- package/dist/sdk.js.map +1 -1
- package/dist/types.d.ts +99 -1
- package/dist/types.js.map +1 -1
- package/dist/vector-backfill-runner.js +97 -21
- package/dist/vector-backfill-runner.js.map +1 -1
- package/docs/1.3-MEMORY-ARCHITECTURE.md +236 -0
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +5 -3
- package/docs/API_REFERENCE.md +20 -1
- package/docs/ARCHITECTURE.md +34 -1
- package/docs/DEVELOPMENT.md +10 -3
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/MODULES.md +27 -1
- package/docs/README.md +3 -3
- package/docs/SETUP.md +6 -4
- package/docs/dev-log/progress.txt +22 -0
- package/docs/hooks-architecture.md +1 -1
- package/llms-full.txt +5 -1
- package/llms.txt +2 -0
- package/package.json +7 -2
- package/plugins/antigravity/memorix/rules/memorix.md +2 -0
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/gemini/memorix/GEMINI.md +2 -0
- package/plugins/gemini/memorix/gemini-extension.json +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/plugins/pi/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/server.json +38 -0
- package/src/cli/command-guide.ts +9 -1
- package/src/cli/commands/agent-integrations.ts +12 -6
- package/src/cli/commands/codegraph.ts +1 -0
- package/src/cli/commands/memory.ts +217 -1
- package/src/cli/commands/setup.ts +200 -23
- package/src/codegraph/auto-context.ts +11 -0
- package/src/codegraph/context-pack.ts +3 -0
- package/src/embedding/api-provider.ts +23 -9
- package/src/embedding/provider.ts +21 -10
- package/src/hooks/installers/index.ts +2 -0
- package/src/knowledge/context-assembly.ts +2 -1
- package/src/knowledge/workset.ts +77 -4
- package/src/memory/long-term-store.ts +242 -0
- package/src/memory/long-term-types.ts +136 -0
- package/src/memory/long-term.ts +626 -0
- package/src/memory/owner.ts +75 -0
- package/src/server.ts +112 -30
- package/src/store/sqlite-db.ts +74 -0
- package/src/types.ts +20 -0
package/dist/cli/index.js
CHANGED
|
@@ -3212,7 +3212,7 @@ ${import_picocolors.default.gray(m3)} ${s2}
|
|
|
3212
3212
|
|
|
3213
3213
|
// src/cli/version.ts
|
|
3214
3214
|
function getCliVersion() {
|
|
3215
|
-
return true ? "1.
|
|
3215
|
+
return true ? "1.3.0" : pkg.version;
|
|
3216
3216
|
}
|
|
3217
3217
|
var init_version = __esm({
|
|
3218
3218
|
"src/cli/version.ts"() {
|
|
@@ -3529,15 +3529,15 @@ function getDocumentProperties(doc, paths) {
|
|
|
3529
3529
|
const properties = {};
|
|
3530
3530
|
const pathsLength = paths.length;
|
|
3531
3531
|
for (let i2 = 0; i2 < pathsLength; i2++) {
|
|
3532
|
-
const
|
|
3533
|
-
const pathTokens =
|
|
3532
|
+
const path38 = paths[i2];
|
|
3533
|
+
const pathTokens = path38.split(".");
|
|
3534
3534
|
let current = doc;
|
|
3535
3535
|
const pathTokensLength = pathTokens.length;
|
|
3536
3536
|
for (let j3 = 0; j3 < pathTokensLength; j3++) {
|
|
3537
3537
|
current = current[pathTokens[j3]];
|
|
3538
3538
|
if (typeof current === "object") {
|
|
3539
3539
|
if (current !== null && "lat" in current && "lon" in current && typeof current.lat === "number" && typeof current.lon === "number") {
|
|
3540
|
-
current = properties[
|
|
3540
|
+
current = properties[path38] = current;
|
|
3541
3541
|
break;
|
|
3542
3542
|
} else if (!Array.isArray(current) && current !== null && j3 === pathTokensLength - 1) {
|
|
3543
3543
|
current = void 0;
|
|
@@ -3549,14 +3549,14 @@ function getDocumentProperties(doc, paths) {
|
|
|
3549
3549
|
}
|
|
3550
3550
|
}
|
|
3551
3551
|
if (typeof current !== "undefined") {
|
|
3552
|
-
properties[
|
|
3552
|
+
properties[path38] = current;
|
|
3553
3553
|
}
|
|
3554
3554
|
}
|
|
3555
3555
|
return properties;
|
|
3556
3556
|
}
|
|
3557
|
-
function getNested(obj,
|
|
3558
|
-
const props = getDocumentProperties(obj, [
|
|
3559
|
-
return props[
|
|
3557
|
+
function getNested(obj, path38) {
|
|
3558
|
+
const props = getDocumentProperties(obj, [path38]);
|
|
3559
|
+
return props[path38];
|
|
3560
3560
|
}
|
|
3561
3561
|
function convertDistanceToMeters(distance, unit) {
|
|
3562
3562
|
const ratio = mapDistanceToMeters[unit];
|
|
@@ -3572,10 +3572,10 @@ function removeVectorsFromHits(searchResult, vectorProperties) {
|
|
|
3572
3572
|
...result.document,
|
|
3573
3573
|
// Remove embeddings from the result
|
|
3574
3574
|
...vectorProperties.reduce((acc, prop) => {
|
|
3575
|
-
const
|
|
3576
|
-
const lastKey =
|
|
3575
|
+
const path38 = prop.split(".");
|
|
3576
|
+
const lastKey = path38.pop();
|
|
3577
3577
|
let obj = acc;
|
|
3578
|
-
for (const key of
|
|
3578
|
+
for (const key of path38) {
|
|
3579
3579
|
obj[key] = obj[key] ?? {};
|
|
3580
3580
|
obj = obj[key];
|
|
3581
3581
|
}
|
|
@@ -4307,15 +4307,15 @@ var init_avl = __esm({
|
|
|
4307
4307
|
if (node === null) {
|
|
4308
4308
|
return new AVLNode(key, [value]);
|
|
4309
4309
|
}
|
|
4310
|
-
const
|
|
4310
|
+
const path38 = [];
|
|
4311
4311
|
let current = node;
|
|
4312
4312
|
let parent = null;
|
|
4313
4313
|
while (current !== null) {
|
|
4314
|
-
|
|
4314
|
+
path38.push({ parent, node: current });
|
|
4315
4315
|
if (key < current.k) {
|
|
4316
4316
|
if (current.l === null) {
|
|
4317
4317
|
current.l = new AVLNode(key, [value]);
|
|
4318
|
-
|
|
4318
|
+
path38.push({ parent: current, node: current.l });
|
|
4319
4319
|
break;
|
|
4320
4320
|
} else {
|
|
4321
4321
|
parent = current;
|
|
@@ -4324,7 +4324,7 @@ var init_avl = __esm({
|
|
|
4324
4324
|
} else if (key > current.k) {
|
|
4325
4325
|
if (current.r === null) {
|
|
4326
4326
|
current.r = new AVLNode(key, [value]);
|
|
4327
|
-
|
|
4327
|
+
path38.push({ parent: current, node: current.r });
|
|
4328
4328
|
break;
|
|
4329
4329
|
} else {
|
|
4330
4330
|
parent = current;
|
|
@@ -4339,8 +4339,8 @@ var init_avl = __esm({
|
|
|
4339
4339
|
if (this.insertCount++ % rebalanceThreshold === 0) {
|
|
4340
4340
|
needRebalance = true;
|
|
4341
4341
|
}
|
|
4342
|
-
for (let i2 =
|
|
4343
|
-
const { parent: parent2, node: currentNode } =
|
|
4342
|
+
for (let i2 = path38.length - 1; i2 >= 0; i2--) {
|
|
4343
|
+
const { parent: parent2, node: currentNode } = path38[i2];
|
|
4344
4344
|
currentNode.updateHeight();
|
|
4345
4345
|
if (needRebalance) {
|
|
4346
4346
|
const rebalancedNode = this.rebalanceNode(currentNode);
|
|
@@ -4446,10 +4446,10 @@ var init_avl = __esm({
|
|
|
4446
4446
|
removeNode(node, key) {
|
|
4447
4447
|
if (node === null)
|
|
4448
4448
|
return null;
|
|
4449
|
-
const
|
|
4449
|
+
const path38 = [];
|
|
4450
4450
|
let current = node;
|
|
4451
4451
|
while (current !== null && current.k !== key) {
|
|
4452
|
-
|
|
4452
|
+
path38.push(current);
|
|
4453
4453
|
if (key < current.k) {
|
|
4454
4454
|
current = current.l;
|
|
4455
4455
|
} else {
|
|
@@ -4461,10 +4461,10 @@ var init_avl = __esm({
|
|
|
4461
4461
|
}
|
|
4462
4462
|
if (current.l === null || current.r === null) {
|
|
4463
4463
|
const child = current.l ? current.l : current.r;
|
|
4464
|
-
if (
|
|
4464
|
+
if (path38.length === 0) {
|
|
4465
4465
|
node = child;
|
|
4466
4466
|
} else {
|
|
4467
|
-
const parent =
|
|
4467
|
+
const parent = path38[path38.length - 1];
|
|
4468
4468
|
if (parent.l === current) {
|
|
4469
4469
|
parent.l = child;
|
|
4470
4470
|
} else {
|
|
@@ -4487,13 +4487,13 @@ var init_avl = __esm({
|
|
|
4487
4487
|
}
|
|
4488
4488
|
current = successorParent;
|
|
4489
4489
|
}
|
|
4490
|
-
|
|
4491
|
-
for (let i2 =
|
|
4492
|
-
const currentNode =
|
|
4490
|
+
path38.push(current);
|
|
4491
|
+
for (let i2 = path38.length - 1; i2 >= 0; i2--) {
|
|
4492
|
+
const currentNode = path38[i2];
|
|
4493
4493
|
currentNode.updateHeight();
|
|
4494
4494
|
const rebalancedNode = this.rebalanceNode(currentNode);
|
|
4495
4495
|
if (i2 > 0) {
|
|
4496
|
-
const parent =
|
|
4496
|
+
const parent = path38[i2 - 1];
|
|
4497
4497
|
if (parent.l === currentNode) {
|
|
4498
4498
|
parent.l = rebalancedNode;
|
|
4499
4499
|
} else if (parent.r === currentNode) {
|
|
@@ -5660,15 +5660,15 @@ function create2(orama, sharedInternalDocumentStore, schema, index, prefix = "")
|
|
|
5660
5660
|
};
|
|
5661
5661
|
}
|
|
5662
5662
|
for (const [prop, type] of Object.entries(schema)) {
|
|
5663
|
-
const
|
|
5663
|
+
const path38 = `${prefix}${prefix ? "." : ""}${prop}`;
|
|
5664
5664
|
if (typeof type === "object" && !Array.isArray(type)) {
|
|
5665
|
-
create2(orama, sharedInternalDocumentStore, type, index,
|
|
5665
|
+
create2(orama, sharedInternalDocumentStore, type, index, path38);
|
|
5666
5666
|
continue;
|
|
5667
5667
|
}
|
|
5668
5668
|
if (isVectorType(type)) {
|
|
5669
|
-
index.searchableProperties.push(
|
|
5670
|
-
index.searchablePropertiesWithTypes[
|
|
5671
|
-
index.vectorIndexes[
|
|
5669
|
+
index.searchableProperties.push(path38);
|
|
5670
|
+
index.searchablePropertiesWithTypes[path38] = type;
|
|
5671
|
+
index.vectorIndexes[path38] = {
|
|
5672
5672
|
type: "Vector",
|
|
5673
5673
|
node: new VectorIndex(getVectorSize(type)),
|
|
5674
5674
|
isArray: false
|
|
@@ -5678,32 +5678,32 @@ function create2(orama, sharedInternalDocumentStore, schema, index, prefix = "")
|
|
|
5678
5678
|
switch (type) {
|
|
5679
5679
|
case "boolean":
|
|
5680
5680
|
case "boolean[]":
|
|
5681
|
-
index.indexes[
|
|
5681
|
+
index.indexes[path38] = { type: "Bool", node: new BoolNode(), isArray };
|
|
5682
5682
|
break;
|
|
5683
5683
|
case "number":
|
|
5684
5684
|
case "number[]":
|
|
5685
|
-
index.indexes[
|
|
5685
|
+
index.indexes[path38] = { type: "AVL", node: new AVLTree(0, []), isArray };
|
|
5686
5686
|
break;
|
|
5687
5687
|
case "string":
|
|
5688
5688
|
case "string[]":
|
|
5689
|
-
index.indexes[
|
|
5690
|
-
index.avgFieldLength[
|
|
5691
|
-
index.frequencies[
|
|
5692
|
-
index.tokenOccurrences[
|
|
5693
|
-
index.fieldLengths[
|
|
5689
|
+
index.indexes[path38] = { type: "Radix", node: new RadixTree(), isArray };
|
|
5690
|
+
index.avgFieldLength[path38] = 0;
|
|
5691
|
+
index.frequencies[path38] = {};
|
|
5692
|
+
index.tokenOccurrences[path38] = {};
|
|
5693
|
+
index.fieldLengths[path38] = {};
|
|
5694
5694
|
break;
|
|
5695
5695
|
case "enum":
|
|
5696
5696
|
case "enum[]":
|
|
5697
|
-
index.indexes[
|
|
5697
|
+
index.indexes[path38] = { type: "Flat", node: new FlatTree(), isArray };
|
|
5698
5698
|
break;
|
|
5699
5699
|
case "geopoint":
|
|
5700
|
-
index.indexes[
|
|
5700
|
+
index.indexes[path38] = { type: "BKD", node: new BKDTree(), isArray };
|
|
5701
5701
|
break;
|
|
5702
5702
|
default:
|
|
5703
|
-
throw createError("INVALID_SCHEMA_TYPE", Array.isArray(type) ? "array" : type,
|
|
5703
|
+
throw createError("INVALID_SCHEMA_TYPE", Array.isArray(type) ? "array" : type, path38);
|
|
5704
5704
|
}
|
|
5705
|
-
index.searchableProperties.push(
|
|
5706
|
-
index.searchablePropertiesWithTypes[
|
|
5705
|
+
index.searchableProperties.push(path38);
|
|
5706
|
+
index.searchablePropertiesWithTypes[path38] = type;
|
|
5707
5707
|
}
|
|
5708
5708
|
}
|
|
5709
5709
|
return index;
|
|
@@ -6274,12 +6274,12 @@ function innerCreate(orama, sharedInternalDocumentStore, schema, sortableDeniedP
|
|
|
6274
6274
|
sorts: {}
|
|
6275
6275
|
};
|
|
6276
6276
|
for (const [prop, type] of Object.entries(schema)) {
|
|
6277
|
-
const
|
|
6278
|
-
if (sortableDeniedProperties.includes(
|
|
6277
|
+
const path38 = `${prefix}${prefix ? "." : ""}${prop}`;
|
|
6278
|
+
if (sortableDeniedProperties.includes(path38)) {
|
|
6279
6279
|
continue;
|
|
6280
6280
|
}
|
|
6281
6281
|
if (typeof type === "object" && !Array.isArray(type)) {
|
|
6282
|
-
const ret = innerCreate(orama, sharedInternalDocumentStore, type, sortableDeniedProperties,
|
|
6282
|
+
const ret = innerCreate(orama, sharedInternalDocumentStore, type, sortableDeniedProperties, path38);
|
|
6283
6283
|
safeArrayPush(sorter.sortableProperties, ret.sortableProperties);
|
|
6284
6284
|
sorter.sorts = {
|
|
6285
6285
|
...sorter.sorts,
|
|
@@ -6296,9 +6296,9 @@ function innerCreate(orama, sharedInternalDocumentStore, schema, sortableDeniedP
|
|
|
6296
6296
|
case "boolean":
|
|
6297
6297
|
case "number":
|
|
6298
6298
|
case "string":
|
|
6299
|
-
sorter.sortableProperties.push(
|
|
6300
|
-
sorter.sortablePropertiesWithTypes[
|
|
6301
|
-
sorter.sorts[
|
|
6299
|
+
sorter.sortableProperties.push(path38);
|
|
6300
|
+
sorter.sortablePropertiesWithTypes[path38] = type;
|
|
6301
|
+
sorter.sorts[path38] = {
|
|
6302
6302
|
docs: /* @__PURE__ */ new Map(),
|
|
6303
6303
|
orderedDocsToRemove: /* @__PURE__ */ new Map(),
|
|
6304
6304
|
orderedDocs: [],
|
|
@@ -6314,7 +6314,7 @@ function innerCreate(orama, sharedInternalDocumentStore, schema, sortableDeniedP
|
|
|
6314
6314
|
case "string[]":
|
|
6315
6315
|
continue;
|
|
6316
6316
|
default:
|
|
6317
|
-
throw createError("INVALID_SORT_SCHEMA_TYPE", Array.isArray(type) ? "array" : type,
|
|
6317
|
+
throw createError("INVALID_SORT_SCHEMA_TYPE", Array.isArray(type) ? "array" : type, path38);
|
|
6318
6318
|
}
|
|
6319
6319
|
}
|
|
6320
6320
|
}
|
|
@@ -8159,8 +8159,8 @@ function innerFullTextSearch(orama, params, language) {
|
|
|
8159
8159
|
function escapeRegex(str2) {
|
|
8160
8160
|
return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8161
8161
|
}
|
|
8162
|
-
function getPropValue(obj,
|
|
8163
|
-
const keys =
|
|
8162
|
+
function getPropValue(obj, path38) {
|
|
8163
|
+
const keys = path38.split(".");
|
|
8164
8164
|
let value = obj;
|
|
8165
8165
|
for (const key of keys) {
|
|
8166
8166
|
if (value && typeof value === "object" && key in value) {
|
|
@@ -9219,15 +9219,15 @@ function loadSqlite() {
|
|
|
9219
9219
|
throw new Error("[memorix] SQLite is unavailable (better-sqlite3, node:sqlite, and bun:sqlite failed)");
|
|
9220
9220
|
}
|
|
9221
9221
|
}
|
|
9222
|
-
function createDatabase(
|
|
9222
|
+
function createDatabase(path38, options2) {
|
|
9223
9223
|
const Sqlite = loadSqlite();
|
|
9224
9224
|
try {
|
|
9225
|
-
return addCompatibility(instantiateDatabase(Sqlite,
|
|
9225
|
+
return addCompatibility(instantiateDatabase(Sqlite, path38, options2));
|
|
9226
9226
|
} catch (error2) {
|
|
9227
9227
|
if (driver !== "better-sqlite3" || !isNativeBindingFailure(error2)) throw error2;
|
|
9228
9228
|
Database = loadNodeSqlite();
|
|
9229
9229
|
driver = "node:sqlite";
|
|
9230
|
-
return addCompatibility(instantiateDatabase(Database,
|
|
9230
|
+
return addCompatibility(instantiateDatabase(Database, path38, options2));
|
|
9231
9231
|
}
|
|
9232
9232
|
}
|
|
9233
9233
|
var Database, driver, requireFromHere;
|
|
@@ -9354,7 +9354,7 @@ function closeAllDatabases() {
|
|
|
9354
9354
|
_dbCache.delete(key);
|
|
9355
9355
|
}
|
|
9356
9356
|
}
|
|
9357
|
-
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
9357
|
+
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
9358
9358
|
var init_sqlite_db = __esm({
|
|
9359
9359
|
"src/store/sqlite-db.ts"() {
|
|
9360
9360
|
"use strict";
|
|
@@ -9780,6 +9780,57 @@ CREATE TABLE IF NOT EXISTS knowledge_claim_events (
|
|
|
9780
9780
|
" FOREIGN KEY (workflowId) REFERENCES knowledge_workflows(id) ON DELETE CASCADE",
|
|
9781
9781
|
");"
|
|
9782
9782
|
].join("\n");
|
|
9783
|
+
CREATE_LONG_TERM_MEMORIES_TABLE = `
|
|
9784
|
+
CREATE TABLE IF NOT EXISTS long_term_memories (
|
|
9785
|
+
id TEXT PRIMARY KEY,
|
|
9786
|
+
originProjectId TEXT NOT NULL,
|
|
9787
|
+
ownerId TEXT NOT NULL,
|
|
9788
|
+
scope TEXT NOT NULL,
|
|
9789
|
+
kind TEXT NOT NULL,
|
|
9790
|
+
state TEXT NOT NULL,
|
|
9791
|
+
portability TEXT NOT NULL DEFAULT 'project-bound',
|
|
9792
|
+
title TEXT NOT NULL,
|
|
9793
|
+
content TEXT NOT NULL,
|
|
9794
|
+
factsJson TEXT NOT NULL DEFAULT '[]',
|
|
9795
|
+
tagsJson TEXT NOT NULL DEFAULT '[]',
|
|
9796
|
+
applicability TEXT,
|
|
9797
|
+
origin TEXT NOT NULL,
|
|
9798
|
+
createdAt TEXT NOT NULL,
|
|
9799
|
+
updatedAt TEXT NOT NULL,
|
|
9800
|
+
qualifiedAt TEXT,
|
|
9801
|
+
approvedAt TEXT,
|
|
9802
|
+
archivedAt TEXT,
|
|
9803
|
+
supersededBy TEXT,
|
|
9804
|
+
lastValidatedAt TEXT,
|
|
9805
|
+
accessCount INTEGER NOT NULL DEFAULT 0,
|
|
9806
|
+
lastAccessedAt TEXT
|
|
9807
|
+
);
|
|
9808
|
+
`;
|
|
9809
|
+
CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE = `
|
|
9810
|
+
CREATE TABLE IF NOT EXISTS long_term_memory_evidence (
|
|
9811
|
+
id TEXT PRIMARY KEY,
|
|
9812
|
+
memoryId TEXT NOT NULL,
|
|
9813
|
+
kind TEXT NOT NULL,
|
|
9814
|
+
referenceId TEXT NOT NULL,
|
|
9815
|
+
relation TEXT NOT NULL,
|
|
9816
|
+
locator TEXT,
|
|
9817
|
+
capturedHash TEXT,
|
|
9818
|
+
createdAt TEXT NOT NULL,
|
|
9819
|
+
FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
|
|
9820
|
+
);
|
|
9821
|
+
`;
|
|
9822
|
+
CREATE_LONG_TERM_MEMORY_EVENTS_TABLE = `
|
|
9823
|
+
CREATE TABLE IF NOT EXISTS long_term_memory_events (
|
|
9824
|
+
id TEXT PRIMARY KEY,
|
|
9825
|
+
memoryId TEXT NOT NULL,
|
|
9826
|
+
kind TEXT NOT NULL,
|
|
9827
|
+
fromState TEXT,
|
|
9828
|
+
toState TEXT,
|
|
9829
|
+
detail TEXT,
|
|
9830
|
+
createdAt TEXT NOT NULL,
|
|
9831
|
+
FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
|
|
9832
|
+
);
|
|
9833
|
+
`;
|
|
9783
9834
|
CREATE_MAINTENANCE_JOBS_TABLE = `
|
|
9784
9835
|
CREATE TABLE IF NOT EXISTS maintenance_jobs (
|
|
9785
9836
|
id TEXT PRIMARY KEY,
|
|
@@ -9875,6 +9926,11 @@ CREATE INDEX IF NOT EXISTS idx_knowledge_page_claims_claim ON knowledge_page_cla
|
|
|
9875
9926
|
CREATE INDEX IF NOT EXISTS idx_knowledge_proposals_workspace_status ON knowledge_proposals(workspaceId, status, createdAt DESC);
|
|
9876
9927
|
CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC);
|
|
9877
9928
|
CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC);
|
|
9929
|
+
CREATE INDEX IF NOT EXISTS idx_long_term_memories_owner_state ON long_term_memories(ownerId, state, updatedAt DESC);
|
|
9930
|
+
CREATE INDEX IF NOT EXISTS idx_long_term_memories_project_state ON long_term_memories(originProjectId, state, updatedAt DESC);
|
|
9931
|
+
CREATE INDEX IF NOT EXISTS idx_long_term_memories_scope_portability ON long_term_memories(scope, portability, state, updatedAt DESC);
|
|
9932
|
+
CREATE INDEX IF NOT EXISTS idx_long_term_memory_evidence_memory ON long_term_memory_evidence(memoryId, createdAt);
|
|
9933
|
+
CREATE INDEX IF NOT EXISTS idx_long_term_memory_events_memory ON long_term_memory_events(memoryId, createdAt);
|
|
9878
9934
|
CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);
|
|
9879
9935
|
CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);
|
|
9880
9936
|
CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);
|
|
@@ -9963,6 +10019,19 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
9963
10019
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC)");
|
|
9964
10020
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key)");
|
|
9965
10021
|
}
|
|
10022
|
+
},
|
|
10023
|
+
{
|
|
10024
|
+
id: "1.3-long-term-memory",
|
|
10025
|
+
apply: (db2) => {
|
|
10026
|
+
db2.exec(CREATE_LONG_TERM_MEMORIES_TABLE);
|
|
10027
|
+
db2.exec(CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE);
|
|
10028
|
+
db2.exec(CREATE_LONG_TERM_MEMORY_EVENTS_TABLE);
|
|
10029
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memories_owner_state ON long_term_memories(ownerId, state, updatedAt DESC)");
|
|
10030
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memories_project_state ON long_term_memories(originProjectId, state, updatedAt DESC)");
|
|
10031
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memories_scope_portability ON long_term_memories(scope, portability, state, updatedAt DESC)");
|
|
10032
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memory_evidence_memory ON long_term_memory_evidence(memoryId, createdAt)");
|
|
10033
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memory_events_memory ON long_term_memory_events(memoryId, createdAt)");
|
|
10034
|
+
}
|
|
9966
10035
|
}
|
|
9967
10036
|
];
|
|
9968
10037
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -13292,9 +13361,9 @@ function parseTomlConfig(content, filePath) {
|
|
|
13292
13361
|
}
|
|
13293
13362
|
return root;
|
|
13294
13363
|
}
|
|
13295
|
-
function ensureTable(root,
|
|
13364
|
+
function ensureTable(root, path38) {
|
|
13296
13365
|
let cursor = root;
|
|
13297
|
-
for (const part of
|
|
13366
|
+
for (const part of path38) {
|
|
13298
13367
|
const value = cursor[part];
|
|
13299
13368
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
13300
13369
|
cursor[part] = {};
|
|
@@ -13428,8 +13497,8 @@ var require_main = __commonJS({
|
|
|
13428
13497
|
"node_modules/dotenv/lib/main.js"(exports2, module2) {
|
|
13429
13498
|
"use strict";
|
|
13430
13499
|
init_esm_shims();
|
|
13431
|
-
var
|
|
13432
|
-
var
|
|
13500
|
+
var fs28 = __require("fs");
|
|
13501
|
+
var path38 = __require("path");
|
|
13433
13502
|
var os5 = __require("os");
|
|
13434
13503
|
var crypto3 = __require("crypto");
|
|
13435
13504
|
var packageJson = require_package();
|
|
@@ -13567,7 +13636,7 @@ var require_main = __commonJS({
|
|
|
13567
13636
|
if (options2 && options2.path && options2.path.length > 0) {
|
|
13568
13637
|
if (Array.isArray(options2.path)) {
|
|
13569
13638
|
for (const filepath of options2.path) {
|
|
13570
|
-
if (
|
|
13639
|
+
if (fs28.existsSync(filepath)) {
|
|
13571
13640
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
13572
13641
|
}
|
|
13573
13642
|
}
|
|
@@ -13575,15 +13644,15 @@ var require_main = __commonJS({
|
|
|
13575
13644
|
possibleVaultPath = options2.path.endsWith(".vault") ? options2.path : `${options2.path}.vault`;
|
|
13576
13645
|
}
|
|
13577
13646
|
} else {
|
|
13578
|
-
possibleVaultPath =
|
|
13647
|
+
possibleVaultPath = path38.resolve(process.cwd(), ".env.vault");
|
|
13579
13648
|
}
|
|
13580
|
-
if (
|
|
13649
|
+
if (fs28.existsSync(possibleVaultPath)) {
|
|
13581
13650
|
return possibleVaultPath;
|
|
13582
13651
|
}
|
|
13583
13652
|
return null;
|
|
13584
13653
|
}
|
|
13585
13654
|
function _resolveHome(envPath) {
|
|
13586
|
-
return envPath[0] === "~" ?
|
|
13655
|
+
return envPath[0] === "~" ? path38.join(os5.homedir(), envPath.slice(1)) : envPath;
|
|
13587
13656
|
}
|
|
13588
13657
|
function _configVault(options2) {
|
|
13589
13658
|
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options2 && options2.debug);
|
|
@@ -13600,7 +13669,7 @@ var require_main = __commonJS({
|
|
|
13600
13669
|
return { parsed };
|
|
13601
13670
|
}
|
|
13602
13671
|
function configDotenv(options2) {
|
|
13603
|
-
const dotenvPath =
|
|
13672
|
+
const dotenvPath = path38.resolve(process.cwd(), ".env");
|
|
13604
13673
|
let encoding = "utf8";
|
|
13605
13674
|
let processEnv = process.env;
|
|
13606
13675
|
if (options2 && options2.processEnv != null) {
|
|
@@ -13628,13 +13697,13 @@ var require_main = __commonJS({
|
|
|
13628
13697
|
}
|
|
13629
13698
|
let lastError;
|
|
13630
13699
|
const parsedAll = {};
|
|
13631
|
-
for (const
|
|
13700
|
+
for (const path39 of optionPaths) {
|
|
13632
13701
|
try {
|
|
13633
|
-
const parsed = DotenvModule.parse(
|
|
13702
|
+
const parsed = DotenvModule.parse(fs28.readFileSync(path39, { encoding }));
|
|
13634
13703
|
DotenvModule.populate(parsedAll, parsed, options2);
|
|
13635
13704
|
} catch (e3) {
|
|
13636
13705
|
if (debug) {
|
|
13637
|
-
_debug(`Failed to load ${
|
|
13706
|
+
_debug(`Failed to load ${path39} ${e3.message}`);
|
|
13638
13707
|
}
|
|
13639
13708
|
lastError = e3;
|
|
13640
13709
|
}
|
|
@@ -13647,7 +13716,7 @@ var require_main = __commonJS({
|
|
|
13647
13716
|
const shortPaths = [];
|
|
13648
13717
|
for (const filePath of optionPaths) {
|
|
13649
13718
|
try {
|
|
13650
|
-
const relative3 =
|
|
13719
|
+
const relative3 = path38.relative(process.cwd(), filePath);
|
|
13651
13720
|
shortPaths.push(relative3);
|
|
13652
13721
|
} catch (e3) {
|
|
13653
13722
|
if (debug) {
|
|
@@ -14566,9 +14635,10 @@ function parseBatchLimit(error2) {
|
|
|
14566
14635
|
}
|
|
14567
14636
|
return null;
|
|
14568
14637
|
}
|
|
14569
|
-
async function fetchWithRetry(url, apiKey, body, attempt = 0) {
|
|
14638
|
+
async function fetchWithRetry(url, apiKey, body, options2 = {}, attempt = 0) {
|
|
14570
14639
|
const controller = new AbortController();
|
|
14571
|
-
const
|
|
14640
|
+
const timeoutMs = typeof options2.timeoutMs === "number" && Number.isFinite(options2.timeoutMs) ? Math.max(100, Math.min(Math.floor(options2.timeoutMs), 6e4)) : 1e4;
|
|
14641
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
14572
14642
|
let response;
|
|
14573
14643
|
try {
|
|
14574
14644
|
response = await fetch(url, {
|
|
@@ -14583,7 +14653,7 @@ async function fetchWithRetry(url, apiKey, body, attempt = 0) {
|
|
|
14583
14653
|
} catch (err) {
|
|
14584
14654
|
clearTimeout(timeout);
|
|
14585
14655
|
if (err instanceof Error && err.name === "AbortError") {
|
|
14586
|
-
throw new Error(`Embedding API timeout after
|
|
14656
|
+
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
14587
14657
|
}
|
|
14588
14658
|
throw err;
|
|
14589
14659
|
}
|
|
@@ -14591,13 +14661,13 @@ async function fetchWithRetry(url, apiKey, body, attempt = 0) {
|
|
|
14591
14661
|
if (response.ok) {
|
|
14592
14662
|
return response.json();
|
|
14593
14663
|
}
|
|
14594
|
-
if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
14664
|
+
if (options2.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
14595
14665
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
14596
14666
|
const retryAfter = response.headers.get("retry-after");
|
|
14597
14667
|
const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1e3 : delay;
|
|
14598
14668
|
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
14599
14669
|
await new Promise((resolve6) => setTimeout(resolve6, waitMs));
|
|
14600
|
-
return fetchWithRetry(url, apiKey, body, attempt + 1);
|
|
14670
|
+
return fetchWithRetry(url, apiKey, body, options2, attempt + 1);
|
|
14601
14671
|
}
|
|
14602
14672
|
const errorText2 = await response.text().catch(() => "unknown error");
|
|
14603
14673
|
throw new Error(`Embedding API error (${response.status}): ${errorText2}`);
|
|
@@ -14653,7 +14723,10 @@ var init_api_provider = __esm({
|
|
|
14653
14723
|
}
|
|
14654
14724
|
} else {
|
|
14655
14725
|
if (!allowNetworkProbe) return null;
|
|
14656
|
-
probeDimensions = await _APIEmbeddingProvider.probeAPI(config2
|
|
14726
|
+
probeDimensions = await _APIEmbeddingProvider.probeAPI(config2, {
|
|
14727
|
+
timeoutMs: options2.requestTimeoutMs,
|
|
14728
|
+
retry: options2.retry
|
|
14729
|
+
});
|
|
14657
14730
|
console.error(`[memorix] API embedding: ${config2.model} @ ${config2.baseUrl} (${probeDimensions}d)`);
|
|
14658
14731
|
saveCachedDims(config2, probeDimensions).catch(() => {
|
|
14659
14732
|
});
|
|
@@ -14695,7 +14768,7 @@ var init_api_provider = __esm({
|
|
|
14695
14768
|
baseUrl = baseUrl.replace(/\/+$/, "");
|
|
14696
14769
|
return { apiKey, baseUrl, model, requestedDimensions };
|
|
14697
14770
|
}
|
|
14698
|
-
static async probeAPI(config2) {
|
|
14771
|
+
static async probeAPI(config2, options2) {
|
|
14699
14772
|
const body = {
|
|
14700
14773
|
model: config2.model,
|
|
14701
14774
|
input: "dimension probe"
|
|
@@ -14706,14 +14779,15 @@ var init_api_provider = __esm({
|
|
|
14706
14779
|
const response = await fetchWithRetry(
|
|
14707
14780
|
`${config2.baseUrl}/embeddings`,
|
|
14708
14781
|
config2.apiKey,
|
|
14709
|
-
body
|
|
14782
|
+
body,
|
|
14783
|
+
options2
|
|
14710
14784
|
);
|
|
14711
14785
|
if (response.data.length === 0 || !response.data[0].embedding) {
|
|
14712
14786
|
throw new Error("API probe returned no embeddings; check model name and API key");
|
|
14713
14787
|
}
|
|
14714
14788
|
return response.data[0].embedding.length;
|
|
14715
14789
|
}
|
|
14716
|
-
async embed(text) {
|
|
14790
|
+
async embed(text, options2) {
|
|
14717
14791
|
const normalized = normalizeText(text);
|
|
14718
14792
|
const hash4 = textHash2(normalized, this.cacheKeyNamespace);
|
|
14719
14793
|
if (diskCacheLoaded) {
|
|
@@ -14731,7 +14805,8 @@ var init_api_provider = __esm({
|
|
|
14731
14805
|
const response = await fetchWithRetry(
|
|
14732
14806
|
`${this.config.baseUrl}/embeddings`,
|
|
14733
14807
|
this.config.apiKey,
|
|
14734
|
-
body
|
|
14808
|
+
body,
|
|
14809
|
+
options2
|
|
14735
14810
|
);
|
|
14736
14811
|
const embedding2 = response.data[0].embedding;
|
|
14737
14812
|
if (embedding2.length !== this.dimensions) {
|
|
@@ -14765,7 +14840,7 @@ var init_api_provider = __esm({
|
|
|
14765
14840
|
scheduleDiskSave();
|
|
14766
14841
|
return embedding;
|
|
14767
14842
|
}
|
|
14768
|
-
async embedBatch(texts) {
|
|
14843
|
+
async embedBatch(texts, options2) {
|
|
14769
14844
|
await ensureDiskCacheLoaded();
|
|
14770
14845
|
const normalizedTexts = texts.map(normalizeText);
|
|
14771
14846
|
const results = new Array(texts.length);
|
|
@@ -14799,7 +14874,8 @@ var init_api_provider = __esm({
|
|
|
14799
14874
|
const response = await fetchWithRetry(
|
|
14800
14875
|
`${this.config.baseUrl}/embeddings`,
|
|
14801
14876
|
this.config.apiKey,
|
|
14802
|
-
body
|
|
14877
|
+
body,
|
|
14878
|
+
options2
|
|
14803
14879
|
);
|
|
14804
14880
|
this.trackUsage(response);
|
|
14805
14881
|
for (const item of response.data) {
|
|
@@ -14976,9 +15052,9 @@ function wrapProvider(candidate2) {
|
|
|
14976
15052
|
return {
|
|
14977
15053
|
name: candidate2.name,
|
|
14978
15054
|
dimensions: candidate2.dimensions,
|
|
14979
|
-
async embed(text) {
|
|
15055
|
+
async embed(text, options2) {
|
|
14980
15056
|
try {
|
|
14981
|
-
return await candidate2.embed(text);
|
|
15057
|
+
return await candidate2.embed(text, options2);
|
|
14982
15058
|
} catch (error2) {
|
|
14983
15059
|
if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error2)) {
|
|
14984
15060
|
warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
|
|
@@ -14986,7 +15062,7 @@ function wrapProvider(candidate2) {
|
|
|
14986
15062
|
if (fallback) {
|
|
14987
15063
|
provider = wrapProvider(fallback);
|
|
14988
15064
|
warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
|
|
14989
|
-
return provider.embed(text);
|
|
15065
|
+
return provider.embed(text, options2);
|
|
14990
15066
|
}
|
|
14991
15067
|
}
|
|
14992
15068
|
if (isTemporaryEmbeddingFailure(error2)) {
|
|
@@ -14995,9 +15071,9 @@ function wrapProvider(candidate2) {
|
|
|
14995
15071
|
throw error2;
|
|
14996
15072
|
}
|
|
14997
15073
|
},
|
|
14998
|
-
async embedBatch(texts) {
|
|
15074
|
+
async embedBatch(texts, options2) {
|
|
14999
15075
|
try {
|
|
15000
|
-
return await candidate2.embedBatch(texts);
|
|
15076
|
+
return await candidate2.embedBatch(texts, options2);
|
|
15001
15077
|
} catch (error2) {
|
|
15002
15078
|
if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error2)) {
|
|
15003
15079
|
warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
|
|
@@ -15005,7 +15081,7 @@ function wrapProvider(candidate2) {
|
|
|
15005
15081
|
if (fallback) {
|
|
15006
15082
|
provider = wrapProvider(fallback);
|
|
15007
15083
|
warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
|
|
15008
|
-
return provider.embedBatch(texts);
|
|
15084
|
+
return provider.embedBatch(texts, options2);
|
|
15009
15085
|
}
|
|
15010
15086
|
}
|
|
15011
15087
|
if (isTemporaryEmbeddingFailure(error2)) {
|
|
@@ -15061,14 +15137,14 @@ async function getEmbeddingProvider(options2 = {}) {
|
|
|
15061
15137
|
return provider;
|
|
15062
15138
|
}
|
|
15063
15139
|
if (mode === "api") {
|
|
15064
|
-
const initialized = await createAPIProvider();
|
|
15140
|
+
const initialized = await createAPIProvider(options2);
|
|
15065
15141
|
if (!initialized) return null;
|
|
15066
15142
|
provider = wrapProvider(initialized);
|
|
15067
15143
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
15068
15144
|
return provider;
|
|
15069
15145
|
}
|
|
15070
15146
|
if (hasAPIEmbeddingConfig()) {
|
|
15071
|
-
const initialized = await createAPIProvider();
|
|
15147
|
+
const initialized = await createAPIProvider(options2);
|
|
15072
15148
|
if (initialized) {
|
|
15073
15149
|
provider = wrapProvider(initialized);
|
|
15074
15150
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
@@ -18967,12 +19043,12 @@ import { createHash as createHash4 } from "crypto";
|
|
|
18967
19043
|
function digest(input) {
|
|
18968
19044
|
return createHash4("sha256").update(input).digest("hex").slice(0, 16);
|
|
18969
19045
|
}
|
|
18970
|
-
function normalizeCodePath(
|
|
18971
|
-
return
|
|
19046
|
+
function normalizeCodePath(path38) {
|
|
19047
|
+
return path38.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
18972
19048
|
}
|
|
18973
|
-
function makeCodeFileId(projectId,
|
|
19049
|
+
function makeCodeFileId(projectId, path38) {
|
|
18974
19050
|
return `file:${digest(`${projectId}
|
|
18975
|
-
${normalizeCodePath(
|
|
19051
|
+
${normalizeCodePath(path38)}`)}`;
|
|
18976
19052
|
}
|
|
18977
19053
|
function makeCodeSymbolId(input) {
|
|
18978
19054
|
return `symbol:${digest([
|
|
@@ -19446,8 +19522,8 @@ var init_store = __esm({
|
|
|
19446
19522
|
});
|
|
19447
19523
|
tx();
|
|
19448
19524
|
}
|
|
19449
|
-
getFile(projectId,
|
|
19450
|
-
const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(
|
|
19525
|
+
getFile(projectId, path38) {
|
|
19526
|
+
const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path38));
|
|
19451
19527
|
return row ? rowToFile(row) : null;
|
|
19452
19528
|
}
|
|
19453
19529
|
listFiles(projectId) {
|
|
@@ -19682,30 +19758,30 @@ function normalizeCodeGraphExcludePatterns(exclude) {
|
|
|
19682
19758
|
...(exclude ?? []).map((pattern) => pattern.trim()).filter(Boolean)
|
|
19683
19759
|
])];
|
|
19684
19760
|
}
|
|
19685
|
-
function isCodeGraphExcludedPath(
|
|
19686
|
-
const normalized = normalizeCodePath2(
|
|
19761
|
+
function isCodeGraphExcludedPath(path38, exclude) {
|
|
19762
|
+
const normalized = normalizeCodePath2(path38);
|
|
19687
19763
|
return normalizeCodeGraphExcludePatterns(exclude).some((pattern) => matchesPattern(normalized, normalizeCodePath2(pattern)));
|
|
19688
19764
|
}
|
|
19689
|
-
function normalizeCodePath2(
|
|
19690
|
-
return
|
|
19765
|
+
function normalizeCodePath2(path38) {
|
|
19766
|
+
return path38.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
19691
19767
|
}
|
|
19692
|
-
function matchesPattern(
|
|
19768
|
+
function matchesPattern(path38, pattern) {
|
|
19693
19769
|
if (pattern.endsWith("/**")) {
|
|
19694
19770
|
const base = pattern.slice(0, -3);
|
|
19695
19771
|
if (base.startsWith("**/")) {
|
|
19696
19772
|
const suffix = base.slice(3);
|
|
19697
|
-
return
|
|
19773
|
+
return path38 === suffix || path38.endsWith(`/${suffix}`) || path38.includes(`/${suffix}/`);
|
|
19698
19774
|
}
|
|
19699
19775
|
if (!base.includes("/")) {
|
|
19700
|
-
return
|
|
19776
|
+
return path38 === base || path38.startsWith(`${base}/`) || path38.includes(`/${base}/`);
|
|
19701
19777
|
}
|
|
19702
|
-
return
|
|
19778
|
+
return path38 === base || path38.startsWith(`${base}/`);
|
|
19703
19779
|
}
|
|
19704
19780
|
if (pattern.startsWith("**/")) {
|
|
19705
19781
|
const suffix = pattern.slice(3);
|
|
19706
|
-
return
|
|
19782
|
+
return path38 === suffix || path38.endsWith(`/${suffix}`);
|
|
19707
19783
|
}
|
|
19708
|
-
return
|
|
19784
|
+
return path38 === pattern || path38.startsWith(`${pattern}/`);
|
|
19709
19785
|
}
|
|
19710
19786
|
var DEFAULT_CODEGRAPH_EXCLUDES;
|
|
19711
19787
|
var init_exclude = __esm({
|
|
@@ -19750,12 +19826,12 @@ import { join as join5, relative } from "path";
|
|
|
19750
19826
|
function hashText(text) {
|
|
19751
19827
|
return createHash6("sha256").update(text).digest("hex");
|
|
19752
19828
|
}
|
|
19753
|
-
function extension(
|
|
19754
|
-
const index =
|
|
19755
|
-
return index === -1 ? "" :
|
|
19829
|
+
function extension(path38) {
|
|
19830
|
+
const index = path38.lastIndexOf(".");
|
|
19831
|
+
return index === -1 ? "" : path38.slice(index);
|
|
19756
19832
|
}
|
|
19757
|
-
function languageForPath(
|
|
19758
|
-
const ext = extension(
|
|
19833
|
+
function languageForPath(path38) {
|
|
19834
|
+
const ext = extension(path38);
|
|
19759
19835
|
return LANGUAGE_BY_EXTENSION.get(ext) ?? "unknown";
|
|
19760
19836
|
}
|
|
19761
19837
|
function resolveMaxFileBytes(value) {
|
|
@@ -20236,7 +20312,7 @@ function resolveObservationCodeRefs(obs, lookup) {
|
|
|
20236
20312
|
}
|
|
20237
20313
|
function createStoreLookup(store2, projectId) {
|
|
20238
20314
|
return {
|
|
20239
|
-
findFile: (
|
|
20315
|
+
findFile: (path38) => store2.getFile(projectId, path38) ?? void 0,
|
|
20240
20316
|
findSymbols: (names, hintedFileIds) => store2.findSymbolsByNames(projectId, names, hintedFileIds)
|
|
20241
20317
|
};
|
|
20242
20318
|
}
|
|
@@ -20249,7 +20325,7 @@ function createSnapshotLookup(files, symbols) {
|
|
|
20249
20325
|
symbolsByName.set(symbol.name, group);
|
|
20250
20326
|
}
|
|
20251
20327
|
return {
|
|
20252
|
-
findFile: (
|
|
20328
|
+
findFile: (path38) => filesByPath.get(normalizeCodePath(path38)),
|
|
20253
20329
|
findSymbols: (names, hintedFileIds) => {
|
|
20254
20330
|
const hinted = new Set(hintedFileIds);
|
|
20255
20331
|
const found = [];
|
|
@@ -24448,7 +24524,7 @@ var require_gray_matter = __commonJS({
|
|
|
24448
24524
|
"node_modules/gray-matter/index.js"(exports2, module2) {
|
|
24449
24525
|
"use strict";
|
|
24450
24526
|
init_esm_shims();
|
|
24451
|
-
var
|
|
24527
|
+
var fs28 = __require("fs");
|
|
24452
24528
|
var sections = require_section_matter();
|
|
24453
24529
|
var defaults = require_defaults();
|
|
24454
24530
|
var stringify = require_stringify();
|
|
@@ -24532,7 +24608,7 @@ var require_gray_matter = __commonJS({
|
|
|
24532
24608
|
return stringify(file, data, options2);
|
|
24533
24609
|
};
|
|
24534
24610
|
matter12.read = function(filepath, options2) {
|
|
24535
|
-
const str2 =
|
|
24611
|
+
const str2 = fs28.readFileSync(filepath, "utf8");
|
|
24536
24612
|
const file = matter12(str2, options2);
|
|
24537
24613
|
file.path = filepath;
|
|
24538
24614
|
return file;
|
|
@@ -25399,8 +25475,8 @@ __export(task_lens_exports, {
|
|
|
25399
25475
|
scoreLensSource: () => scoreLensSource,
|
|
25400
25476
|
shouldShowLensSource: () => shouldShowLensSource
|
|
25401
25477
|
});
|
|
25402
|
-
function normalizePath2(
|
|
25403
|
-
return
|
|
25478
|
+
function normalizePath2(path38) {
|
|
25479
|
+
return path38.replace(/\\/g, "/");
|
|
25404
25480
|
}
|
|
25405
25481
|
function tokenize3(text) {
|
|
25406
25482
|
return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
|
|
@@ -25462,8 +25538,8 @@ function isContinuationTask(task) {
|
|
|
25462
25538
|
(keyword) => containsTaskKeyword(normalized, keyword)
|
|
25463
25539
|
);
|
|
25464
25540
|
}
|
|
25465
|
-
function pathKindScore(
|
|
25466
|
-
const normalized = normalizePath2(
|
|
25541
|
+
function pathKindScore(path38, lens) {
|
|
25542
|
+
const normalized = normalizePath2(path38).toLowerCase();
|
|
25467
25543
|
const name = normalized.split("/").pop() ?? normalized;
|
|
25468
25544
|
const inDocs = normalized.startsWith("docs/") || name === "readme.md" || name.includes("readme");
|
|
25469
25545
|
const isTest = /(^|\/)(tests?|__tests__|spec|fixtures?)\//.test(normalized) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(normalized) || /\.(test|spec)\.py$/.test(normalized);
|
|
@@ -25511,8 +25587,8 @@ function sourceTaskMatchScore(source, task) {
|
|
|
25511
25587
|
if (matches === 1) return 24;
|
|
25512
25588
|
return 0;
|
|
25513
25589
|
}
|
|
25514
|
-
function fallbackPathRank(
|
|
25515
|
-
const normalized = normalizePath2(
|
|
25590
|
+
function fallbackPathRank(path38) {
|
|
25591
|
+
const normalized = normalizePath2(path38);
|
|
25516
25592
|
if (normalized.startsWith("src/")) return 0;
|
|
25517
25593
|
if (normalized.startsWith("tests/") || normalized.startsWith("test/")) return 1;
|
|
25518
25594
|
if (normalized.startsWith("packages/") && normalized.includes("/src/")) return 2;
|
|
@@ -25521,11 +25597,11 @@ function fallbackPathRank(path37) {
|
|
|
25521
25597
|
}
|
|
25522
25598
|
function rankLensPaths(paths, lens, task) {
|
|
25523
25599
|
const tokens = tokenize3(task ?? "");
|
|
25524
|
-
return [...new Set(paths.map(normalizePath2))].map((
|
|
25525
|
-
path:
|
|
25600
|
+
return [...new Set(paths.map(normalizePath2))].map((path38, index) => ({
|
|
25601
|
+
path: path38,
|
|
25526
25602
|
index,
|
|
25527
|
-
score: pathKindScore(
|
|
25528
|
-
fallback: fallbackPathRank(
|
|
25603
|
+
score: pathKindScore(path38, lens) + tokenScore(path38, tokens),
|
|
25604
|
+
fallback: fallbackPathRank(path38)
|
|
25529
25605
|
})).sort((a3, b3) => b3.score - a3.score || a3.fallback - b3.fallback || a3.index - b3.index || a3.path.localeCompare(b3.path)).map((item) => item.path);
|
|
25530
25606
|
}
|
|
25531
25607
|
function lensPathCandidates(lens) {
|
|
@@ -32139,6 +32215,827 @@ var init_operator_shared = __esm({
|
|
|
32139
32215
|
}
|
|
32140
32216
|
});
|
|
32141
32217
|
|
|
32218
|
+
// src/memory/owner.ts
|
|
32219
|
+
var owner_exports = {};
|
|
32220
|
+
__export(owner_exports, {
|
|
32221
|
+
resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
|
|
32222
|
+
});
|
|
32223
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
32224
|
+
import { promises as fs15 } from "fs";
|
|
32225
|
+
import path19 from "path";
|
|
32226
|
+
function ownerPath(dataDir) {
|
|
32227
|
+
const resolved = path19.resolve(dataDir);
|
|
32228
|
+
const home = path19.basename(resolved).toLocaleLowerCase("en-US") === "data" ? path19.dirname(resolved) : resolved;
|
|
32229
|
+
return path19.join(home, "memorix-user.json");
|
|
32230
|
+
}
|
|
32231
|
+
function normalizedOwnerId(value) {
|
|
32232
|
+
const trimmed = value?.trim();
|
|
32233
|
+
return trimmed && ID_PATTERN.test(trimmed) ? trimmed : void 0;
|
|
32234
|
+
}
|
|
32235
|
+
async function readOwnerFile(filePath) {
|
|
32236
|
+
try {
|
|
32237
|
+
const value = JSON.parse(await fs15.readFile(filePath, "utf8"));
|
|
32238
|
+
const id = typeof value.id === "string" ? normalizedOwnerId(value.id) : void 0;
|
|
32239
|
+
return id ? { id, source: "local-file" } : void 0;
|
|
32240
|
+
} catch {
|
|
32241
|
+
return void 0;
|
|
32242
|
+
}
|
|
32243
|
+
}
|
|
32244
|
+
async function resolveLocalMemoryOwner(dataDir, options2 = {}) {
|
|
32245
|
+
const configured = normalizedOwnerId(process.env.MEMORIX_USER_ID);
|
|
32246
|
+
if (configured) return { id: configured, source: "environment" };
|
|
32247
|
+
const filePath = ownerPath(dataDir);
|
|
32248
|
+
const existing = await readOwnerFile(filePath);
|
|
32249
|
+
if (existing || !options2.create) return existing;
|
|
32250
|
+
await fs15.mkdir(path19.dirname(filePath), { recursive: true });
|
|
32251
|
+
const created = {
|
|
32252
|
+
version: 1,
|
|
32253
|
+
id: "local-" + randomUUID9(),
|
|
32254
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
32255
|
+
};
|
|
32256
|
+
try {
|
|
32257
|
+
await fs15.writeFile(filePath, JSON.stringify(created, null, 2) + "\n", { encoding: "utf8", flag: "wx" });
|
|
32258
|
+
return { id: created.id, source: "local-file" };
|
|
32259
|
+
} catch (error2) {
|
|
32260
|
+
if (error2?.code !== "EEXIST") throw error2;
|
|
32261
|
+
const concurrent = await readOwnerFile(filePath);
|
|
32262
|
+
if (concurrent) return concurrent;
|
|
32263
|
+
throw new Error("Memorix could not establish a valid local memory owner identity.");
|
|
32264
|
+
}
|
|
32265
|
+
}
|
|
32266
|
+
var ID_PATTERN;
|
|
32267
|
+
var init_owner = __esm({
|
|
32268
|
+
"src/memory/owner.ts"() {
|
|
32269
|
+
"use strict";
|
|
32270
|
+
init_esm_shims();
|
|
32271
|
+
ID_PATTERN = /^[A-Za-z0-9:_-]{3,160}$/;
|
|
32272
|
+
}
|
|
32273
|
+
});
|
|
32274
|
+
|
|
32275
|
+
// src/memory/long-term-store.ts
|
|
32276
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
32277
|
+
function optionalText5(value) {
|
|
32278
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
32279
|
+
}
|
|
32280
|
+
function arrayValue2(value) {
|
|
32281
|
+
if (typeof value !== "string" || !value) return [];
|
|
32282
|
+
try {
|
|
32283
|
+
const parsed = JSON.parse(value);
|
|
32284
|
+
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
32285
|
+
} catch {
|
|
32286
|
+
return [];
|
|
32287
|
+
}
|
|
32288
|
+
}
|
|
32289
|
+
function rowToMemory(row) {
|
|
32290
|
+
return {
|
|
32291
|
+
id: row.id,
|
|
32292
|
+
originProjectId: row.originProjectId,
|
|
32293
|
+
ownerId: row.ownerId,
|
|
32294
|
+
scope: row.scope,
|
|
32295
|
+
kind: row.kind,
|
|
32296
|
+
state: row.state,
|
|
32297
|
+
portability: row.portability,
|
|
32298
|
+
title: row.title,
|
|
32299
|
+
content: row.content,
|
|
32300
|
+
facts: arrayValue2(row.factsJson),
|
|
32301
|
+
tags: arrayValue2(row.tagsJson),
|
|
32302
|
+
...optionalText5(row.applicability) ? { applicability: row.applicability } : {},
|
|
32303
|
+
origin: row.origin,
|
|
32304
|
+
createdAt: row.createdAt,
|
|
32305
|
+
updatedAt: row.updatedAt,
|
|
32306
|
+
...optionalText5(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
|
|
32307
|
+
...optionalText5(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
|
|
32308
|
+
...optionalText5(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
|
|
32309
|
+
...optionalText5(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
|
|
32310
|
+
...optionalText5(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
|
|
32311
|
+
accessCount: Number(row.accessCount ?? 0),
|
|
32312
|
+
...optionalText5(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
|
|
32313
|
+
};
|
|
32314
|
+
}
|
|
32315
|
+
function rowToEvidence2(row) {
|
|
32316
|
+
return {
|
|
32317
|
+
id: row.id,
|
|
32318
|
+
memoryId: row.memoryId,
|
|
32319
|
+
kind: row.kind,
|
|
32320
|
+
referenceId: row.referenceId,
|
|
32321
|
+
relation: row.relation,
|
|
32322
|
+
...optionalText5(row.locator) ? { locator: row.locator } : {},
|
|
32323
|
+
...optionalText5(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
|
|
32324
|
+
createdAt: row.createdAt
|
|
32325
|
+
};
|
|
32326
|
+
}
|
|
32327
|
+
function rowToEvent2(row) {
|
|
32328
|
+
return {
|
|
32329
|
+
id: row.id,
|
|
32330
|
+
memoryId: row.memoryId,
|
|
32331
|
+
kind: row.kind,
|
|
32332
|
+
...optionalText5(row.fromState) ? { fromState: row.fromState } : {},
|
|
32333
|
+
...optionalText5(row.toState) ? { toState: row.toState } : {},
|
|
32334
|
+
...optionalText5(row.detail) ? { detail: row.detail } : {},
|
|
32335
|
+
createdAt: row.createdAt
|
|
32336
|
+
};
|
|
32337
|
+
}
|
|
32338
|
+
var LongTermMemoryStore;
|
|
32339
|
+
var init_long_term_store = __esm({
|
|
32340
|
+
"src/memory/long-term-store.ts"() {
|
|
32341
|
+
"use strict";
|
|
32342
|
+
init_esm_shims();
|
|
32343
|
+
init_sqlite_db();
|
|
32344
|
+
LongTermMemoryStore = class {
|
|
32345
|
+
db = null;
|
|
32346
|
+
async init(dataDir) {
|
|
32347
|
+
this.db = getDatabase(dataDir);
|
|
32348
|
+
}
|
|
32349
|
+
transaction(fn) {
|
|
32350
|
+
return this.db.transaction(fn)();
|
|
32351
|
+
}
|
|
32352
|
+
get(id) {
|
|
32353
|
+
const row = this.db.prepare("SELECT * FROM long_term_memories WHERE id = ?").get(id);
|
|
32354
|
+
return row ? rowToMemory(row) : void 0;
|
|
32355
|
+
}
|
|
32356
|
+
list(options2 = {}) {
|
|
32357
|
+
const limit = Math.max(1, Math.min(1e3, Math.floor(options2.limit ?? 500)));
|
|
32358
|
+
const clauses = [];
|
|
32359
|
+
const params = [];
|
|
32360
|
+
if (options2.ownerId) {
|
|
32361
|
+
clauses.push("ownerId = ?");
|
|
32362
|
+
params.push(options2.ownerId);
|
|
32363
|
+
}
|
|
32364
|
+
if (options2.originProjectId) {
|
|
32365
|
+
clauses.push("originProjectId = ?");
|
|
32366
|
+
params.push(options2.originProjectId);
|
|
32367
|
+
}
|
|
32368
|
+
const where = clauses.length ? " WHERE " + clauses.join(" AND ") : "";
|
|
32369
|
+
const rows = this.db.prepare(
|
|
32370
|
+
"SELECT * FROM long_term_memories" + where + " ORDER BY updatedAt DESC, id LIMIT ?"
|
|
32371
|
+
).all(...params, limit);
|
|
32372
|
+
return rows.map(rowToMemory);
|
|
32373
|
+
}
|
|
32374
|
+
insert(memory) {
|
|
32375
|
+
this.db.prepare(`
|
|
32376
|
+
INSERT INTO long_term_memories (
|
|
32377
|
+
id, originProjectId, ownerId, scope, kind, state, portability,
|
|
32378
|
+
title, content, factsJson, tagsJson, applicability, origin,
|
|
32379
|
+
createdAt, updatedAt, qualifiedAt, approvedAt, archivedAt,
|
|
32380
|
+
supersededBy, lastValidatedAt, accessCount, lastAccessedAt
|
|
32381
|
+
) VALUES (
|
|
32382
|
+
@id, @originProjectId, @ownerId, @scope, @kind, @state, @portability,
|
|
32383
|
+
@title, @content, @factsJson, @tagsJson, @applicability, @origin,
|
|
32384
|
+
@createdAt, @updatedAt, @qualifiedAt, @approvedAt, @archivedAt,
|
|
32385
|
+
@supersededBy, @lastValidatedAt, @accessCount, @lastAccessedAt
|
|
32386
|
+
)
|
|
32387
|
+
`).run({
|
|
32388
|
+
...memory,
|
|
32389
|
+
factsJson: JSON.stringify(memory.facts),
|
|
32390
|
+
tagsJson: JSON.stringify(memory.tags),
|
|
32391
|
+
applicability: memory.applicability ?? null,
|
|
32392
|
+
qualifiedAt: memory.qualifiedAt ?? null,
|
|
32393
|
+
approvedAt: memory.approvedAt ?? null,
|
|
32394
|
+
archivedAt: memory.archivedAt ?? null,
|
|
32395
|
+
supersededBy: memory.supersededBy ?? null,
|
|
32396
|
+
lastValidatedAt: memory.lastValidatedAt ?? null,
|
|
32397
|
+
lastAccessedAt: memory.lastAccessedAt ?? null
|
|
32398
|
+
});
|
|
32399
|
+
}
|
|
32400
|
+
update(memory) {
|
|
32401
|
+
this.db.prepare(`
|
|
32402
|
+
UPDATE long_term_memories SET
|
|
32403
|
+
scope = @scope,
|
|
32404
|
+
kind = @kind,
|
|
32405
|
+
state = @state,
|
|
32406
|
+
portability = @portability,
|
|
32407
|
+
title = @title,
|
|
32408
|
+
content = @content,
|
|
32409
|
+
factsJson = @factsJson,
|
|
32410
|
+
tagsJson = @tagsJson,
|
|
32411
|
+
applicability = @applicability,
|
|
32412
|
+
updatedAt = @updatedAt,
|
|
32413
|
+
qualifiedAt = @qualifiedAt,
|
|
32414
|
+
approvedAt = @approvedAt,
|
|
32415
|
+
archivedAt = @archivedAt,
|
|
32416
|
+
supersededBy = @supersededBy,
|
|
32417
|
+
lastValidatedAt = @lastValidatedAt,
|
|
32418
|
+
accessCount = @accessCount,
|
|
32419
|
+
lastAccessedAt = @lastAccessedAt
|
|
32420
|
+
WHERE id = @id
|
|
32421
|
+
`).run({
|
|
32422
|
+
...memory,
|
|
32423
|
+
factsJson: JSON.stringify(memory.facts),
|
|
32424
|
+
tagsJson: JSON.stringify(memory.tags),
|
|
32425
|
+
applicability: memory.applicability ?? null,
|
|
32426
|
+
qualifiedAt: memory.qualifiedAt ?? null,
|
|
32427
|
+
approvedAt: memory.approvedAt ?? null,
|
|
32428
|
+
archivedAt: memory.archivedAt ?? null,
|
|
32429
|
+
supersededBy: memory.supersededBy ?? null,
|
|
32430
|
+
lastValidatedAt: memory.lastValidatedAt ?? null,
|
|
32431
|
+
lastAccessedAt: memory.lastAccessedAt ?? null
|
|
32432
|
+
});
|
|
32433
|
+
}
|
|
32434
|
+
insertEvidence(input) {
|
|
32435
|
+
const evidence = {
|
|
32436
|
+
id: randomUUID10(),
|
|
32437
|
+
...input,
|
|
32438
|
+
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
32439
|
+
};
|
|
32440
|
+
this.db.prepare(`
|
|
32441
|
+
INSERT INTO long_term_memory_evidence (
|
|
32442
|
+
id, memoryId, kind, referenceId, relation, locator, capturedHash, createdAt
|
|
32443
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
32444
|
+
`).run(
|
|
32445
|
+
evidence.id,
|
|
32446
|
+
evidence.memoryId,
|
|
32447
|
+
evidence.kind,
|
|
32448
|
+
evidence.referenceId,
|
|
32449
|
+
evidence.relation,
|
|
32450
|
+
evidence.locator ?? null,
|
|
32451
|
+
evidence.capturedHash ?? null,
|
|
32452
|
+
evidence.createdAt
|
|
32453
|
+
);
|
|
32454
|
+
return evidence;
|
|
32455
|
+
}
|
|
32456
|
+
listEvidence(memoryId) {
|
|
32457
|
+
return this.db.prepare(`
|
|
32458
|
+
SELECT * FROM long_term_memory_evidence WHERE memoryId = ? ORDER BY createdAt ASC, id
|
|
32459
|
+
`).all(memoryId).map(rowToEvidence2);
|
|
32460
|
+
}
|
|
32461
|
+
recordEvent(input) {
|
|
32462
|
+
const event = {
|
|
32463
|
+
id: randomUUID10(),
|
|
32464
|
+
...input,
|
|
32465
|
+
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
32466
|
+
};
|
|
32467
|
+
this.db.prepare(`
|
|
32468
|
+
INSERT INTO long_term_memory_events (id, memoryId, kind, fromState, toState, detail, createdAt)
|
|
32469
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
32470
|
+
`).run(
|
|
32471
|
+
event.id,
|
|
32472
|
+
event.memoryId,
|
|
32473
|
+
event.kind,
|
|
32474
|
+
event.fromState ?? null,
|
|
32475
|
+
event.toState ?? null,
|
|
32476
|
+
event.detail ?? null,
|
|
32477
|
+
event.createdAt
|
|
32478
|
+
);
|
|
32479
|
+
return event;
|
|
32480
|
+
}
|
|
32481
|
+
listEvents(memoryId) {
|
|
32482
|
+
return this.db.prepare(`
|
|
32483
|
+
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
32484
|
+
`).all(memoryId).map(rowToEvent2);
|
|
32485
|
+
}
|
|
32486
|
+
markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
32487
|
+
const unique3 = [...new Set(ids.filter(Boolean))];
|
|
32488
|
+
if (unique3.length === 0) return;
|
|
32489
|
+
const statement = this.db.prepare(`
|
|
32490
|
+
UPDATE long_term_memories
|
|
32491
|
+
SET accessCount = accessCount + 1, lastAccessedAt = ?
|
|
32492
|
+
WHERE id = ?
|
|
32493
|
+
`);
|
|
32494
|
+
this.db.transaction(() => {
|
|
32495
|
+
for (const id of unique3) statement.run(at, id);
|
|
32496
|
+
})();
|
|
32497
|
+
}
|
|
32498
|
+
};
|
|
32499
|
+
}
|
|
32500
|
+
});
|
|
32501
|
+
|
|
32502
|
+
// src/memory/long-term-types.ts
|
|
32503
|
+
var LONG_TERM_MEMORY_KINDS, LONG_TERM_MEMORY_SCOPES, LONG_TERM_MEMORY_PORTABILITIES, LONG_TERM_MEMORY_EVIDENCE_KINDS, LONG_TERM_MEMORY_EVIDENCE_RELATIONS;
|
|
32504
|
+
var init_long_term_types = __esm({
|
|
32505
|
+
"src/memory/long-term-types.ts"() {
|
|
32506
|
+
"use strict";
|
|
32507
|
+
init_esm_shims();
|
|
32508
|
+
LONG_TERM_MEMORY_KINDS = ["episodic", "semantic", "procedural"];
|
|
32509
|
+
LONG_TERM_MEMORY_SCOPES = ["project", "user", "team"];
|
|
32510
|
+
LONG_TERM_MEMORY_PORTABILITIES = ["project-bound", "portable"];
|
|
32511
|
+
LONG_TERM_MEMORY_EVIDENCE_KINDS = [
|
|
32512
|
+
"observation",
|
|
32513
|
+
"claim",
|
|
32514
|
+
"workflow",
|
|
32515
|
+
"session",
|
|
32516
|
+
"checkpoint",
|
|
32517
|
+
"git",
|
|
32518
|
+
"code",
|
|
32519
|
+
"test",
|
|
32520
|
+
"run",
|
|
32521
|
+
"document",
|
|
32522
|
+
"manual",
|
|
32523
|
+
"user"
|
|
32524
|
+
];
|
|
32525
|
+
LONG_TERM_MEMORY_EVIDENCE_RELATIONS = [
|
|
32526
|
+
"supports",
|
|
32527
|
+
"verifies",
|
|
32528
|
+
"derives",
|
|
32529
|
+
"user-confirmed"
|
|
32530
|
+
];
|
|
32531
|
+
}
|
|
32532
|
+
});
|
|
32533
|
+
|
|
32534
|
+
// src/memory/long-term.ts
|
|
32535
|
+
var long_term_exports = {};
|
|
32536
|
+
__export(long_term_exports, {
|
|
32537
|
+
approveLongTermMemory: () => approveLongTermMemory,
|
|
32538
|
+
archiveLongTermMemory: () => archiveLongTermMemory,
|
|
32539
|
+
canReadLongTermMemory: () => canReadLongTermMemory,
|
|
32540
|
+
createLongTermMemoryCandidate: () => createLongTermMemoryCandidate,
|
|
32541
|
+
createManualLongTermMemory: () => createManualLongTermMemory,
|
|
32542
|
+
getLongTermMemoryDetail: () => getLongTermMemoryDetail,
|
|
32543
|
+
isEligibleLongTermMemory: () => isEligibleLongTermMemory,
|
|
32544
|
+
listLongTermMemories: () => listLongTermMemories,
|
|
32545
|
+
promoteObservationToLongTermMemory: () => promoteObservationToLongTermMemory,
|
|
32546
|
+
qualifyLongTermMemory: () => qualifyLongTermMemory,
|
|
32547
|
+
renderLongTermMemorySummary: () => renderLongTermMemorySummary,
|
|
32548
|
+
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
32549
|
+
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
32550
|
+
});
|
|
32551
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
32552
|
+
function isOneOf(value, values) {
|
|
32553
|
+
return typeof value === "string" && values.includes(value);
|
|
32554
|
+
}
|
|
32555
|
+
function compactText2(value, field, max = MAX_TEXT_LENGTH) {
|
|
32556
|
+
if (typeof value !== "string") throw new Error("Long-term memory " + field + " must be text.");
|
|
32557
|
+
const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
|
|
32558
|
+
if (!safe) throw new Error("Long-term memory " + field + " is required.");
|
|
32559
|
+
if (safe.length > max) throw new Error("Long-term memory " + field + " is too long.");
|
|
32560
|
+
return safe;
|
|
32561
|
+
}
|
|
32562
|
+
function compactList(values, field) {
|
|
32563
|
+
if (!values) return [];
|
|
32564
|
+
if (!Array.isArray(values)) throw new Error("Long-term memory " + field + " must be an array.");
|
|
32565
|
+
return [...new Set(values.filter((value) => typeof value === "string").map((value) => compactText2(value, field, 500)))].slice(0, MAX_LIST_ITEMS);
|
|
32566
|
+
}
|
|
32567
|
+
function normalizeEvidence(input) {
|
|
32568
|
+
if (!Array.isArray(input) || input.length === 0) {
|
|
32569
|
+
throw new Error("A long-term memory requires at least one source evidence reference.");
|
|
32570
|
+
}
|
|
32571
|
+
return input.map((evidence) => {
|
|
32572
|
+
if (!evidence || !isOneOf(evidence.kind, LONG_TERM_MEMORY_EVIDENCE_KINDS)) {
|
|
32573
|
+
throw new Error("Long-term memory evidence kind is invalid.");
|
|
32574
|
+
}
|
|
32575
|
+
if (!isOneOf(evidence.relation, LONG_TERM_MEMORY_EVIDENCE_RELATIONS)) {
|
|
32576
|
+
throw new Error("Long-term memory evidence relation is invalid.");
|
|
32577
|
+
}
|
|
32578
|
+
return {
|
|
32579
|
+
kind: evidence.kind,
|
|
32580
|
+
referenceId: compactText2(evidence.referenceId, "evidence reference", 1e3),
|
|
32581
|
+
relation: evidence.relation,
|
|
32582
|
+
...evidence.locator ? { locator: compactText2(evidence.locator, "evidence locator", 1e3) } : {},
|
|
32583
|
+
...evidence.capturedHash ? { capturedHash: compactText2(evidence.capturedHash, "evidence hash", 1e3) } : {}
|
|
32584
|
+
};
|
|
32585
|
+
});
|
|
32586
|
+
}
|
|
32587
|
+
function assertScope(scope) {
|
|
32588
|
+
if (!isOneOf(scope, LONG_TERM_MEMORY_SCOPES)) throw new Error("Long-term memory scope is invalid.");
|
|
32589
|
+
}
|
|
32590
|
+
function assertKind(kind) {
|
|
32591
|
+
if (!isOneOf(kind, LONG_TERM_MEMORY_KINDS)) throw new Error("Long-term memory kind is invalid.");
|
|
32592
|
+
}
|
|
32593
|
+
function assertPortability(value) {
|
|
32594
|
+
if (!isOneOf(value, LONG_TERM_MEMORY_PORTABILITIES)) {
|
|
32595
|
+
throw new Error("Long-term memory portability is invalid.");
|
|
32596
|
+
}
|
|
32597
|
+
}
|
|
32598
|
+
function assertPortableEvidence(scope, portability, evidence) {
|
|
32599
|
+
if (portability !== "portable") return;
|
|
32600
|
+
if (scope !== "user") {
|
|
32601
|
+
throw new Error("Only user-scoped long-term memories may be portable across projects.");
|
|
32602
|
+
}
|
|
32603
|
+
if (evidence.some((item) => !PORTABLE_EVIDENCE_KINDS.has(item.kind))) {
|
|
32604
|
+
throw new Error("Portable user memory may only use manual or user-confirmed evidence; project code, Git, observation, test, session, claim, and workflow evidence must remain project-bound.");
|
|
32605
|
+
}
|
|
32606
|
+
}
|
|
32607
|
+
function requireTeamReader(scope, reader) {
|
|
32608
|
+
if (scope === "team" && reader?.isTeamMember !== true) {
|
|
32609
|
+
throw new Error("Team long-term memory requires an explicit active team identity for this project.");
|
|
32610
|
+
}
|
|
32611
|
+
}
|
|
32612
|
+
function matchesScope(memory, reader) {
|
|
32613
|
+
if (memory.scope === "project") return memory.originProjectId === reader.projectId;
|
|
32614
|
+
if (memory.scope === "team") {
|
|
32615
|
+
return memory.originProjectId === reader.projectId && reader.isTeamMember === true;
|
|
32616
|
+
}
|
|
32617
|
+
if (!reader.ownerId || memory.ownerId !== reader.ownerId) return false;
|
|
32618
|
+
return memory.portability === "portable" || memory.originProjectId === reader.projectId;
|
|
32619
|
+
}
|
|
32620
|
+
function canReadLongTermMemory(memory, reader) {
|
|
32621
|
+
return matchesScope(memory, reader);
|
|
32622
|
+
}
|
|
32623
|
+
function isEligibleLongTermMemory(memory) {
|
|
32624
|
+
return memory.state === "qualified" || memory.state === "approved";
|
|
32625
|
+
}
|
|
32626
|
+
function taskTerms(task) {
|
|
32627
|
+
const matches = task.toLocaleLowerCase("en-US").match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
|
|
32628
|
+
return [...new Set(matches.filter((term) => term.length > 1 && !STOP_TERMS.has(term)))].slice(0, 16);
|
|
32629
|
+
}
|
|
32630
|
+
function kindFitScore(kind, task) {
|
|
32631
|
+
const normalized = task.toLocaleLowerCase("en-US");
|
|
32632
|
+
const hints = {
|
|
32633
|
+
episodic: ["resume", "continue", "handoff", "previous", "session", "\u63A5\u624B", "\u7EE7\u7EED", "\u4EA4\u63A5", "\u4E0A\u6B21", "\u4F1A\u8BDD"],
|
|
32634
|
+
semantic: ["why", "what", "architecture", "design", "decision", "reason", "\u4E3A\u4EC0\u4E48", "\u662F\u4EC0\u4E48", "\u67B6\u6784", "\u8BBE\u8BA1", "\u51B3\u7B56", "\u539F\u56E0"],
|
|
32635
|
+
procedural: ["how", "steps", "procedure", "run", "release", "publish", "verify", "implement", "\u6D41\u7A0B", "\u6B65\u9AA4", "\u53D1\u5E03", "\u9A8C\u8BC1", "\u4FEE\u590D", "\u5B9E\u73B0"]
|
|
32636
|
+
};
|
|
32637
|
+
return hints[kind].some((hint) => normalized.includes(hint)) ? 1 : 0;
|
|
32638
|
+
}
|
|
32639
|
+
function validationFreshnessScore(memory) {
|
|
32640
|
+
const validatedAt = memory.lastValidatedAt ?? memory.approvedAt ?? memory.qualifiedAt;
|
|
32641
|
+
if (!validatedAt) return 0;
|
|
32642
|
+
const time3 = Date.parse(validatedAt);
|
|
32643
|
+
if (!Number.isFinite(time3)) return 0;
|
|
32644
|
+
const ageDays = Math.max(0, Date.now() - time3) / (24 * 60 * 60 * 1e3);
|
|
32645
|
+
if (ageDays <= 30) return 0.35;
|
|
32646
|
+
if (ageDays <= 90) return 0.15;
|
|
32647
|
+
return 0;
|
|
32648
|
+
}
|
|
32649
|
+
function scoreForTask(memory, task) {
|
|
32650
|
+
const terms = taskTerms(task);
|
|
32651
|
+
if (terms.length === 0) return void 0;
|
|
32652
|
+
const title = memory.title.toLocaleLowerCase("en-US");
|
|
32653
|
+
const content = memory.content.toLocaleLowerCase("en-US");
|
|
32654
|
+
const facts = memory.facts.join(" ").toLocaleLowerCase("en-US");
|
|
32655
|
+
const tags = memory.tags.join(" ").toLocaleLowerCase("en-US");
|
|
32656
|
+
const applicability = (memory.applicability ?? "").toLocaleLowerCase("en-US");
|
|
32657
|
+
let score = memory.state === "approved" ? 0.5 : 0;
|
|
32658
|
+
const matched = [];
|
|
32659
|
+
for (const term of terms) {
|
|
32660
|
+
let termScore = 0;
|
|
32661
|
+
if (title.includes(term)) termScore += 5;
|
|
32662
|
+
if (tags.includes(term)) termScore += 4;
|
|
32663
|
+
if (applicability.includes(term)) termScore += 3;
|
|
32664
|
+
if (facts.includes(term)) termScore += 2;
|
|
32665
|
+
if (content.includes(term)) termScore += 1;
|
|
32666
|
+
if (termScore > 0) {
|
|
32667
|
+
score += termScore;
|
|
32668
|
+
matched.push(term);
|
|
32669
|
+
}
|
|
32670
|
+
}
|
|
32671
|
+
if (matched.length === 0) return void 0;
|
|
32672
|
+
score += kindFitScore(memory.kind, task);
|
|
32673
|
+
score += validationFreshnessScore(memory);
|
|
32674
|
+
const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
|
|
32675
|
+
const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
|
|
32676
|
+
return { score, reason: kindLabel + " matches " + matched.slice(0, 3).join(", ") + freshness };
|
|
32677
|
+
}
|
|
32678
|
+
function semanticText(memory) {
|
|
32679
|
+
return sanitizeCredentials([
|
|
32680
|
+
memory.title,
|
|
32681
|
+
memory.applicability,
|
|
32682
|
+
memory.tags.join(" "),
|
|
32683
|
+
memory.facts.join(" "),
|
|
32684
|
+
memory.content
|
|
32685
|
+
].filter((value) => Boolean(value)).join("\n")).replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
|
|
32686
|
+
}
|
|
32687
|
+
function cosineSimilarity(left, right) {
|
|
32688
|
+
if (left.length === 0 || left.length !== right.length) return 0;
|
|
32689
|
+
let dot = 0;
|
|
32690
|
+
let leftMagnitude = 0;
|
|
32691
|
+
let rightMagnitude = 0;
|
|
32692
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
32693
|
+
const a3 = left[index];
|
|
32694
|
+
const b3 = right[index];
|
|
32695
|
+
if (!Number.isFinite(a3) || !Number.isFinite(b3)) return 0;
|
|
32696
|
+
dot += a3 * b3;
|
|
32697
|
+
leftMagnitude += a3 * a3;
|
|
32698
|
+
rightMagnitude += b3 * b3;
|
|
32699
|
+
}
|
|
32700
|
+
if (leftMagnitude === 0 || rightMagnitude === 0) return 0;
|
|
32701
|
+
return dot / Math.sqrt(leftMagnitude * rightMagnitude);
|
|
32702
|
+
}
|
|
32703
|
+
function semanticSelection(memory, similarity, task) {
|
|
32704
|
+
if (similarity < MIN_SEMANTIC_SIMILARITY) return void 0;
|
|
32705
|
+
const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
|
|
32706
|
+
const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
|
|
32707
|
+
return {
|
|
32708
|
+
score: similarity * 10 + (memory.state === "approved" ? 0.5 : 0) + kindFitScore(memory.kind, task) + validationFreshnessScore(memory),
|
|
32709
|
+
reason: kindLabel + " semantic match " + similarity.toFixed(2) + freshness
|
|
32710
|
+
};
|
|
32711
|
+
}
|
|
32712
|
+
async function resolveSemanticProvider(explicit) {
|
|
32713
|
+
if (explicit !== void 0) return explicit;
|
|
32714
|
+
try {
|
|
32715
|
+
const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
|
|
32716
|
+
return await withTimeout(
|
|
32717
|
+
getEmbeddingProvider2({ requestTimeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS, retry: false }),
|
|
32718
|
+
SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
32719
|
+
"Long-term semantic provider initialization"
|
|
32720
|
+
);
|
|
32721
|
+
} catch {
|
|
32722
|
+
return null;
|
|
32723
|
+
}
|
|
32724
|
+
}
|
|
32725
|
+
function createStore(dataDir) {
|
|
32726
|
+
const store2 = new LongTermMemoryStore();
|
|
32727
|
+
return store2.init(dataDir).then(() => store2);
|
|
32728
|
+
}
|
|
32729
|
+
async function createManualLongTermMemory(input) {
|
|
32730
|
+
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
32731
|
+
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
32732
|
+
assertScope(input.scope);
|
|
32733
|
+
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID11(), relation: "supports" }];
|
|
32734
|
+
return createLongTermMemoryWithDataDir({
|
|
32735
|
+
dataDir: input.dataDir,
|
|
32736
|
+
originProjectId: input.projectId,
|
|
32737
|
+
ownerId: owner.id,
|
|
32738
|
+
scope: input.scope,
|
|
32739
|
+
kind: input.kind,
|
|
32740
|
+
portability: input.portability,
|
|
32741
|
+
title: input.title,
|
|
32742
|
+
content: input.content,
|
|
32743
|
+
facts: input.facts,
|
|
32744
|
+
tags: input.tags,
|
|
32745
|
+
applicability: input.applicability,
|
|
32746
|
+
origin: "manual",
|
|
32747
|
+
evidence,
|
|
32748
|
+
reader: input.reader
|
|
32749
|
+
});
|
|
32750
|
+
}
|
|
32751
|
+
async function promoteObservationToLongTermMemory(input) {
|
|
32752
|
+
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
32753
|
+
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
32754
|
+
return createLongTermMemoryWithDataDir({
|
|
32755
|
+
dataDir: input.dataDir,
|
|
32756
|
+
originProjectId: input.observation.projectId,
|
|
32757
|
+
ownerId: owner.id,
|
|
32758
|
+
scope: input.scope,
|
|
32759
|
+
kind: input.kind,
|
|
32760
|
+
portability: "project-bound",
|
|
32761
|
+
title: input.observation.title,
|
|
32762
|
+
content: input.observation.narrative,
|
|
32763
|
+
facts: input.observation.facts,
|
|
32764
|
+
tags: input.tags ?? input.observation.concepts,
|
|
32765
|
+
applicability: input.applicability,
|
|
32766
|
+
origin: input.observation.source === "git" ? "git" : "agent",
|
|
32767
|
+
evidence: [{
|
|
32768
|
+
kind: "observation",
|
|
32769
|
+
referenceId: "obs:" + input.observation.projectId + ":" + input.observation.id,
|
|
32770
|
+
relation: "derives"
|
|
32771
|
+
}],
|
|
32772
|
+
reader: input.reader
|
|
32773
|
+
});
|
|
32774
|
+
}
|
|
32775
|
+
async function createLongTermMemoryCandidate(input) {
|
|
32776
|
+
return createLongTermMemoryWithDataDir(input);
|
|
32777
|
+
}
|
|
32778
|
+
async function createLongTermMemoryWithDataDir(input) {
|
|
32779
|
+
assertScope(input.scope);
|
|
32780
|
+
assertKind(input.kind);
|
|
32781
|
+
const portability = input.portability ?? "project-bound";
|
|
32782
|
+
assertPortability(portability);
|
|
32783
|
+
requireTeamReader(input.scope, input.reader);
|
|
32784
|
+
const evidenceInputs = normalizeEvidence(input.evidence);
|
|
32785
|
+
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
32786
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
32787
|
+
const memory = {
|
|
32788
|
+
id: randomUUID11(),
|
|
32789
|
+
originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
|
|
32790
|
+
ownerId: compactText2(input.ownerId, "owner id", 160),
|
|
32791
|
+
scope: input.scope,
|
|
32792
|
+
kind: input.kind,
|
|
32793
|
+
state: "candidate",
|
|
32794
|
+
portability,
|
|
32795
|
+
title: compactText2(input.title, "title", 500),
|
|
32796
|
+
content: compactText2(input.content, "content"),
|
|
32797
|
+
facts: compactList(input.facts, "facts"),
|
|
32798
|
+
tags: compactList(input.tags, "tags"),
|
|
32799
|
+
...input.applicability ? { applicability: compactText2(input.applicability, "applicability", 1e3) } : {},
|
|
32800
|
+
origin: input.origin ?? "manual",
|
|
32801
|
+
createdAt: now3,
|
|
32802
|
+
updatedAt: now3,
|
|
32803
|
+
accessCount: 0
|
|
32804
|
+
};
|
|
32805
|
+
const store2 = await createStore(input.dataDir);
|
|
32806
|
+
const evidence = store2.transaction(() => {
|
|
32807
|
+
store2.insert(memory);
|
|
32808
|
+
const written = evidenceInputs.map((item) => store2.insertEvidence({ memoryId: memory.id, ...item, createdAt: now3 }));
|
|
32809
|
+
store2.recordEvent({
|
|
32810
|
+
memoryId: memory.id,
|
|
32811
|
+
kind: "created",
|
|
32812
|
+
toState: "candidate",
|
|
32813
|
+
detail: "Created as a source-backed long-term memory candidate.",
|
|
32814
|
+
createdAt: now3
|
|
32815
|
+
});
|
|
32816
|
+
return written;
|
|
32817
|
+
});
|
|
32818
|
+
return { memory, evidence };
|
|
32819
|
+
}
|
|
32820
|
+
function transitionDetail(value) {
|
|
32821
|
+
return compactText2(value, "transition reason", 1e3);
|
|
32822
|
+
}
|
|
32823
|
+
async function transitionMemory(input) {
|
|
32824
|
+
const store2 = await createStore(input.dataDir);
|
|
32825
|
+
return store2.transaction(() => {
|
|
32826
|
+
const current = store2.get(input.id);
|
|
32827
|
+
if (!current) throw new Error("Long-term memory was not found.");
|
|
32828
|
+
if (current.state !== input.expected) {
|
|
32829
|
+
throw new Error("Long-term memory must be " + input.expected + " before it can be " + input.next + ".");
|
|
32830
|
+
}
|
|
32831
|
+
const evidence = store2.listEvidence(current.id);
|
|
32832
|
+
if (evidence.length === 0) throw new Error("Long-term memory cannot advance without source evidence.");
|
|
32833
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
32834
|
+
const next = {
|
|
32835
|
+
...current,
|
|
32836
|
+
state: input.next,
|
|
32837
|
+
updatedAt: now3,
|
|
32838
|
+
lastValidatedAt: now3,
|
|
32839
|
+
...input.next === "qualified" ? { qualifiedAt: now3 } : { approvedAt: now3 }
|
|
32840
|
+
};
|
|
32841
|
+
store2.update(next);
|
|
32842
|
+
store2.recordEvent({
|
|
32843
|
+
memoryId: next.id,
|
|
32844
|
+
kind: input.event,
|
|
32845
|
+
fromState: current.state,
|
|
32846
|
+
toState: next.state,
|
|
32847
|
+
detail: transitionDetail(input.reason),
|
|
32848
|
+
createdAt: now3
|
|
32849
|
+
});
|
|
32850
|
+
return next;
|
|
32851
|
+
});
|
|
32852
|
+
}
|
|
32853
|
+
async function qualifyLongTermMemory(input) {
|
|
32854
|
+
return transitionMemory({ ...input, expected: "candidate", next: "qualified", event: "qualified" });
|
|
32855
|
+
}
|
|
32856
|
+
async function approveLongTermMemory(input) {
|
|
32857
|
+
return transitionMemory({ ...input, expected: "qualified", next: "approved", event: "approved" });
|
|
32858
|
+
}
|
|
32859
|
+
async function archiveLongTermMemory(input) {
|
|
32860
|
+
const store2 = await createStore(input.dataDir);
|
|
32861
|
+
return store2.transaction(() => {
|
|
32862
|
+
const current = store2.get(input.id);
|
|
32863
|
+
if (!current) throw new Error("Long-term memory was not found.");
|
|
32864
|
+
if (current.state === "archived" || current.state === "superseded") {
|
|
32865
|
+
throw new Error("Long-term memory is already inactive.");
|
|
32866
|
+
}
|
|
32867
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
32868
|
+
const next = { ...current, state: "archived", archivedAt: now3, updatedAt: now3 };
|
|
32869
|
+
store2.update(next);
|
|
32870
|
+
store2.recordEvent({
|
|
32871
|
+
memoryId: next.id,
|
|
32872
|
+
kind: "archived",
|
|
32873
|
+
fromState: current.state,
|
|
32874
|
+
toState: "archived",
|
|
32875
|
+
detail: transitionDetail(input.reason),
|
|
32876
|
+
createdAt: now3
|
|
32877
|
+
});
|
|
32878
|
+
return next;
|
|
32879
|
+
});
|
|
32880
|
+
}
|
|
32881
|
+
async function supersedeLongTermMemory(input) {
|
|
32882
|
+
const store2 = await createStore(input.dataDir);
|
|
32883
|
+
return store2.transaction(() => {
|
|
32884
|
+
const current = store2.get(input.id);
|
|
32885
|
+
if (!current) throw new Error("Long-term memory was not found.");
|
|
32886
|
+
if (current.state === "archived" || current.state === "superseded") {
|
|
32887
|
+
throw new Error("Long-term memory is already inactive.");
|
|
32888
|
+
}
|
|
32889
|
+
if (current.id === input.supersededBy) {
|
|
32890
|
+
throw new Error("Long-term memory cannot supersede itself.");
|
|
32891
|
+
}
|
|
32892
|
+
const replacement = store2.get(input.supersededBy);
|
|
32893
|
+
if (!replacement || !isEligibleLongTermMemory(replacement)) {
|
|
32894
|
+
throw new Error("Replacement long-term memory must be qualified or approved.");
|
|
32895
|
+
}
|
|
32896
|
+
if (replacement.scope !== current.scope) {
|
|
32897
|
+
throw new Error("Replacement long-term memory must use the same scope.");
|
|
32898
|
+
}
|
|
32899
|
+
if (current.scope === "user" && replacement.ownerId !== current.ownerId) {
|
|
32900
|
+
throw new Error("User long-term memory may only be superseded by the same local owner.");
|
|
32901
|
+
}
|
|
32902
|
+
if (current.scope !== "user" && replacement.originProjectId !== current.originProjectId) {
|
|
32903
|
+
throw new Error("Project and team long-term memory may only be superseded within the same project.");
|
|
32904
|
+
}
|
|
32905
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
32906
|
+
const next = {
|
|
32907
|
+
...current,
|
|
32908
|
+
state: "superseded",
|
|
32909
|
+
supersededBy: replacement.id,
|
|
32910
|
+
updatedAt: now3
|
|
32911
|
+
};
|
|
32912
|
+
store2.update(next);
|
|
32913
|
+
store2.recordEvent({
|
|
32914
|
+
memoryId: next.id,
|
|
32915
|
+
kind: "superseded",
|
|
32916
|
+
fromState: current.state,
|
|
32917
|
+
toState: "superseded",
|
|
32918
|
+
detail: transitionDetail(input.reason),
|
|
32919
|
+
createdAt: now3
|
|
32920
|
+
});
|
|
32921
|
+
return next;
|
|
32922
|
+
});
|
|
32923
|
+
}
|
|
32924
|
+
async function listLongTermMemories(input) {
|
|
32925
|
+
const store2 = await createStore(input.dataDir);
|
|
32926
|
+
return store2.list({ limit: input.limit ?? 100 }).filter((memory) => canReadLongTermMemory(memory, input.reader)).filter((memory) => input.includeInactive || memory.state !== "archived" && memory.state !== "superseded").map((memory) => ({ memory, evidence: store2.listEvidence(memory.id) }));
|
|
32927
|
+
}
|
|
32928
|
+
async function getLongTermMemoryDetail(input) {
|
|
32929
|
+
const store2 = await createStore(input.dataDir);
|
|
32930
|
+
const memory = store2.get(input.id);
|
|
32931
|
+
if (!memory || !canReadLongTermMemory(memory, input.reader)) {
|
|
32932
|
+
throw new Error("Long-term memory was not found in the active scope.");
|
|
32933
|
+
}
|
|
32934
|
+
store2.markAccess([memory.id]);
|
|
32935
|
+
return { memory, evidence: store2.listEvidence(memory.id), events: store2.listEvents(memory.id) };
|
|
32936
|
+
}
|
|
32937
|
+
async function selectLongTermMemoriesForTask(input) {
|
|
32938
|
+
const task = input.task?.trim();
|
|
32939
|
+
if (!task) return [];
|
|
32940
|
+
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: false });
|
|
32941
|
+
const reader = {
|
|
32942
|
+
projectId: input.projectId,
|
|
32943
|
+
...owner ? { ownerId: owner.id } : {},
|
|
32944
|
+
...input.agentId ? { agentId: input.agentId } : {},
|
|
32945
|
+
...input.isTeamMember ? { isTeamMember: true } : {}
|
|
32946
|
+
};
|
|
32947
|
+
const store2 = await createStore(input.dataDir);
|
|
32948
|
+
const eligible = store2.list({ limit: 1e3 }).filter((memory) => isEligibleLongTermMemory(memory) && canReadLongTermMemory(memory, reader));
|
|
32949
|
+
let selected = eligible.map((memory) => {
|
|
32950
|
+
const ranked = scoreForTask(memory, task);
|
|
32951
|
+
return ranked ? {
|
|
32952
|
+
memory,
|
|
32953
|
+
evidence: store2.listEvidence(memory.id),
|
|
32954
|
+
score: ranked.score,
|
|
32955
|
+
reason: ranked.reason
|
|
32956
|
+
} : void 0;
|
|
32957
|
+
}).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
|
|
32958
|
+
if (selected.length === 0 && eligible.length > 0) {
|
|
32959
|
+
const provider2 = await resolveSemanticProvider(input.embeddingProvider);
|
|
32960
|
+
const candidates = eligible.slice(0, MAX_SEMANTIC_CANDIDATES);
|
|
32961
|
+
if (provider2 && candidates.length > 0) {
|
|
32962
|
+
try {
|
|
32963
|
+
const vectors = await withTimeout(
|
|
32964
|
+
provider2.embedBatch([task, ...candidates.map(semanticText)], {
|
|
32965
|
+
timeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
32966
|
+
retry: false
|
|
32967
|
+
}),
|
|
32968
|
+
SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
32969
|
+
"Long-term semantic retrieval"
|
|
32970
|
+
);
|
|
32971
|
+
const query = vectors[0];
|
|
32972
|
+
if (Array.isArray(query)) {
|
|
32973
|
+
selected = candidates.map((memory, index) => {
|
|
32974
|
+
const vector = vectors[index + 1];
|
|
32975
|
+
const ranked = Array.isArray(vector) ? semanticSelection(memory, cosineSimilarity(query, vector), task) : void 0;
|
|
32976
|
+
return ranked ? {
|
|
32977
|
+
memory,
|
|
32978
|
+
evidence: store2.listEvidence(memory.id),
|
|
32979
|
+
score: ranked.score,
|
|
32980
|
+
reason: ranked.reason
|
|
32981
|
+
} : void 0;
|
|
32982
|
+
}).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
|
|
32983
|
+
}
|
|
32984
|
+
} catch {
|
|
32985
|
+
}
|
|
32986
|
+
}
|
|
32987
|
+
}
|
|
32988
|
+
selected = selected.slice(0, Math.max(1, Math.min(input.limit ?? 3, 5)));
|
|
32989
|
+
store2.markAccess(selected.map((item) => item.memory.id));
|
|
32990
|
+
return selected;
|
|
32991
|
+
}
|
|
32992
|
+
function renderLongTermMemorySummary(memory, maxTokens = 22) {
|
|
32993
|
+
const source = [memory.title, memory.applicability, memory.content].filter(Boolean).join(": ");
|
|
32994
|
+
const safe = sanitizeCredentials(source).replace(/\s+/g, " ").trim();
|
|
32995
|
+
return countTextTokens(safe) <= maxTokens ? safe : truncateToTokenBudget(safe, maxTokens);
|
|
32996
|
+
}
|
|
32997
|
+
var MAX_TEXT_LENGTH, MAX_LIST_ITEMS, MAX_SEMANTIC_CANDIDATES, SEMANTIC_RETRIEVAL_TIMEOUT_MS, MIN_SEMANTIC_SIMILARITY, PORTABLE_EVIDENCE_KINDS, STOP_TERMS;
|
|
32998
|
+
var init_long_term = __esm({
|
|
32999
|
+
"src/memory/long-term.ts"() {
|
|
33000
|
+
"use strict";
|
|
33001
|
+
init_esm_shims();
|
|
33002
|
+
init_token_budget();
|
|
33003
|
+
init_timeout();
|
|
33004
|
+
init_secret_filter();
|
|
33005
|
+
init_owner();
|
|
33006
|
+
init_long_term_store();
|
|
33007
|
+
init_long_term_types();
|
|
33008
|
+
MAX_TEXT_LENGTH = 12e3;
|
|
33009
|
+
MAX_LIST_ITEMS = 40;
|
|
33010
|
+
MAX_SEMANTIC_CANDIDATES = 48;
|
|
33011
|
+
SEMANTIC_RETRIEVAL_TIMEOUT_MS = 1800;
|
|
33012
|
+
MIN_SEMANTIC_SIMILARITY = 0.58;
|
|
33013
|
+
PORTABLE_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["manual", "user"]);
|
|
33014
|
+
STOP_TERMS = /* @__PURE__ */ new Set([
|
|
33015
|
+
"the",
|
|
33016
|
+
"and",
|
|
33017
|
+
"for",
|
|
33018
|
+
"with",
|
|
33019
|
+
"from",
|
|
33020
|
+
"that",
|
|
33021
|
+
"this",
|
|
33022
|
+
"into",
|
|
33023
|
+
"when",
|
|
33024
|
+
"what",
|
|
33025
|
+
"\u5982\u4F55",
|
|
33026
|
+
"\u4EC0\u4E48",
|
|
33027
|
+
"\u8FD9\u4E2A",
|
|
33028
|
+
"\u90A3\u4E2A",
|
|
33029
|
+
"\u6211\u4EEC",
|
|
33030
|
+
"\u9879\u76EE",
|
|
33031
|
+
"\u8FDB\u884C",
|
|
33032
|
+
"\u9700\u8981",
|
|
33033
|
+
"\u7EE7\u7EED",
|
|
33034
|
+
"\u5904\u7406"
|
|
33035
|
+
]);
|
|
33036
|
+
}
|
|
33037
|
+
});
|
|
33038
|
+
|
|
32142
33039
|
// src/cli/commands/memory.ts
|
|
32143
33040
|
var memory_exports = {};
|
|
32144
33041
|
__export(memory_exports, {
|
|
@@ -32151,6 +33048,26 @@ function getStringArg(named, positional) {
|
|
|
32151
33048
|
function getIdArg(args, positional) {
|
|
32152
33049
|
return args.ids || args.id || positional.join(",");
|
|
32153
33050
|
}
|
|
33051
|
+
function longTermKind(value) {
|
|
33052
|
+
const normalized = (value ?? "semantic").trim().toLowerCase();
|
|
33053
|
+
if (normalized === "episodic" || normalized === "semantic" || normalized === "procedural") return normalized;
|
|
33054
|
+
throw new Error("long-term kind must be episodic, semantic, or procedural.");
|
|
33055
|
+
}
|
|
33056
|
+
function longTermScope(value) {
|
|
33057
|
+
const normalized = (value ?? "project").trim().toLowerCase();
|
|
33058
|
+
if (normalized === "project" || normalized === "user" || normalized === "team") return normalized;
|
|
33059
|
+
throw new Error("long-term scope must be project, user, or team.");
|
|
33060
|
+
}
|
|
33061
|
+
function longTermPortability(value) {
|
|
33062
|
+
const normalized = (value ?? "project-bound").trim().toLowerCase();
|
|
33063
|
+
if (normalized === "project-bound" || normalized === "portable") return normalized;
|
|
33064
|
+
throw new Error("long-term portability must be project-bound or portable.");
|
|
33065
|
+
}
|
|
33066
|
+
function requiredLongTermReason(value) {
|
|
33067
|
+
const reason = value?.trim();
|
|
33068
|
+
if (!reason) throw new Error("reason is required for this long-term memory transition.");
|
|
33069
|
+
return reason;
|
|
33070
|
+
}
|
|
32154
33071
|
var memory_default;
|
|
32155
33072
|
var init_memory = __esm({
|
|
32156
33073
|
"src/cli/commands/memory.ts"() {
|
|
@@ -32197,16 +33114,27 @@ var init_memory = __esm({
|
|
|
32197
33114
|
instruction: { type: "string", description: "Custom instruction for promoted mini-skills" },
|
|
32198
33115
|
tags: { type: "string", description: "Comma-separated extra tags for promoted mini-skills" },
|
|
32199
33116
|
skillId: { type: "string", description: "Mini-skill ID for list/delete actions" },
|
|
33117
|
+
kind: { type: "string", description: "Long-term memory kind: episodic, semantic, or procedural" },
|
|
33118
|
+
scope: { type: "string", description: "Long-term memory scope: project, user, or team" },
|
|
33119
|
+
portability: { type: "string", description: "Long-term memory portability: project-bound or portable" },
|
|
33120
|
+
applicability: { type: "string", description: "When a long-term memory applies" },
|
|
33121
|
+
fromObservation: { type: "string", description: "Observation ID to promote into long-term memory" },
|
|
33122
|
+
supersededBy: { type: "string", description: "Qualified or approved long-term memory that replaces the current record" },
|
|
33123
|
+
"superseded-by": { type: "string", description: "Kebab-case alias for --supersededBy" },
|
|
33124
|
+
reason: { type: "string", description: "Evidence review reason for qualify, approve, or archive" },
|
|
33125
|
+
all: { type: "boolean", description: "Include archived and superseded long-term memories in list output" },
|
|
32200
33126
|
json: { type: "boolean", description: "Emit machine-readable JSON output" }
|
|
32201
33127
|
},
|
|
32202
33128
|
run: async ({ args }) => {
|
|
32203
33129
|
const action = args._?.[0] || "";
|
|
32204
33130
|
const positional = (args._ ?? []).slice(1);
|
|
33131
|
+
const longTermAction = action === "long-term" ? (positional[0] || args.action || "list").trim().toLowerCase() : void 0;
|
|
32205
33132
|
const asJson = !!args.json;
|
|
32206
33133
|
try {
|
|
32207
33134
|
const readOnlyActions = /* @__PURE__ */ new Set(["", "search", "graph-context", "recent", "suggest-topic-key", "detail", "timeline"]);
|
|
32208
33135
|
const needsSearchIndex = action === "search" || action === "detail" || action === "timeline";
|
|
32209
|
-
const
|
|
33136
|
+
const longTermReadOnly = longTermAction === "list" || longTermAction === "show";
|
|
33137
|
+
const context = readOnlyActions.has(action) || longTermReadOnly ? await getCliReadContext({ searchIndex: needsSearchIndex }) : await getCliProjectContext({ searchIndex: true });
|
|
32210
33138
|
const { project, dataDir, reader, identity } = context;
|
|
32211
33139
|
switch (action) {
|
|
32212
33140
|
case "search": {
|
|
@@ -32518,6 +33446,160 @@ var init_memory = __esm({
|
|
|
32518
33446
|
);
|
|
32519
33447
|
return;
|
|
32520
33448
|
}
|
|
33449
|
+
case "long-term": {
|
|
33450
|
+
const resolvedLongTermAction = longTermAction ?? "list";
|
|
33451
|
+
const longTermPositional = positional.slice(1);
|
|
33452
|
+
const {
|
|
33453
|
+
archiveLongTermMemory: archiveLongTermMemory2,
|
|
33454
|
+
approveLongTermMemory: approveLongTermMemory2,
|
|
33455
|
+
createManualLongTermMemory: createManualLongTermMemory2,
|
|
33456
|
+
getLongTermMemoryDetail: getLongTermMemoryDetail2,
|
|
33457
|
+
listLongTermMemories: listLongTermMemories2,
|
|
33458
|
+
promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2,
|
|
33459
|
+
qualifyLongTermMemory: qualifyLongTermMemory2,
|
|
33460
|
+
supersedeLongTermMemory: supersedeLongTermMemory2
|
|
33461
|
+
} = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
|
|
33462
|
+
const { resolveLocalMemoryOwner: resolveLocalMemoryOwner2 } = await Promise.resolve().then(() => (init_owner(), owner_exports));
|
|
33463
|
+
const owner = await resolveLocalMemoryOwner2(dataDir, { create: false });
|
|
33464
|
+
const longTermReader = {
|
|
33465
|
+
projectId: project.id,
|
|
33466
|
+
...owner ? { ownerId: owner.id } : {},
|
|
33467
|
+
...reader.agentId ? { agentId: reader.agentId } : {},
|
|
33468
|
+
...reader.isTeamMember ? { isTeamMember: true } : {}
|
|
33469
|
+
};
|
|
33470
|
+
const memoryId = () => {
|
|
33471
|
+
const id = args.id?.trim() || args.fromObservation?.trim() || longTermPositional[0]?.trim();
|
|
33472
|
+
if (!id) throw new Error("long-term memory id is required.");
|
|
33473
|
+
return id;
|
|
33474
|
+
};
|
|
33475
|
+
const scope = () => longTermScope(args.scope);
|
|
33476
|
+
const kind = () => longTermKind(args.kind);
|
|
33477
|
+
const portability = () => longTermPortability(args.portability);
|
|
33478
|
+
const reason = () => requiredLongTermReason(args.reason);
|
|
33479
|
+
switch (resolvedLongTermAction) {
|
|
33480
|
+
case "list": {
|
|
33481
|
+
const memories = await listLongTermMemories2({
|
|
33482
|
+
dataDir,
|
|
33483
|
+
reader: longTermReader,
|
|
33484
|
+
includeInactive: !!args.all,
|
|
33485
|
+
limit: parsePositiveInt(args.limit, 50)
|
|
33486
|
+
});
|
|
33487
|
+
emitResult(
|
|
33488
|
+
{ project, memories },
|
|
33489
|
+
memories.length === 0 ? "No long-term memories are visible in the active scope." : memories.map((item) => `- ${item.memory.id} [${item.memory.state}/${item.memory.kind}/${item.memory.scope}] ${item.memory.title}`).join("\n"),
|
|
33490
|
+
asJson
|
|
33491
|
+
);
|
|
33492
|
+
return;
|
|
33493
|
+
}
|
|
33494
|
+
case "show": {
|
|
33495
|
+
const detail = await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
|
|
33496
|
+
emitResult(
|
|
33497
|
+
{ project, ...detail },
|
|
33498
|
+
[
|
|
33499
|
+
`${detail.memory.id} [${detail.memory.state}/${detail.memory.kind}/${detail.memory.scope}]`,
|
|
33500
|
+
detail.memory.title,
|
|
33501
|
+
detail.memory.content,
|
|
33502
|
+
`Evidence: ${detail.evidence.length}`,
|
|
33503
|
+
`Audit events: ${detail.events.length}`
|
|
33504
|
+
].join("\n"),
|
|
33505
|
+
asJson
|
|
33506
|
+
);
|
|
33507
|
+
return;
|
|
33508
|
+
}
|
|
33509
|
+
case "add": {
|
|
33510
|
+
const content = getStringArg(args.text, longTermPositional);
|
|
33511
|
+
if (!content) {
|
|
33512
|
+
emitError('text is required for "memorix memory long-term add"', asJson);
|
|
33513
|
+
return;
|
|
33514
|
+
}
|
|
33515
|
+
const result = await createManualLongTermMemory2({
|
|
33516
|
+
dataDir,
|
|
33517
|
+
projectId: project.id,
|
|
33518
|
+
scope: scope(),
|
|
33519
|
+
kind: kind(),
|
|
33520
|
+
title: args.title?.trim() || content.slice(0, 100),
|
|
33521
|
+
content,
|
|
33522
|
+
facts: parseCsvList(args.facts),
|
|
33523
|
+
tags: parseCsvList(args.tags),
|
|
33524
|
+
applicability: args.applicability?.trim(),
|
|
33525
|
+
portability: portability(),
|
|
33526
|
+
reader: longTermReader
|
|
33527
|
+
});
|
|
33528
|
+
emitResult(
|
|
33529
|
+
{ project, ...result },
|
|
33530
|
+
`Created long-term memory candidate ${result.memory.id}. Qualify it after checking its evidence.`,
|
|
33531
|
+
asJson
|
|
33532
|
+
);
|
|
33533
|
+
return;
|
|
33534
|
+
}
|
|
33535
|
+
case "promote": {
|
|
33536
|
+
const rawId = args.fromObservation?.trim() || args.id?.trim() || longTermPositional[0]?.trim();
|
|
33537
|
+
const observationId2 = Number.parseInt(rawId || "", 10);
|
|
33538
|
+
if (!Number.isFinite(observationId2)) {
|
|
33539
|
+
emitError('fromObservation or id must be an observation ID for "memorix memory long-term promote"', asJson);
|
|
33540
|
+
return;
|
|
33541
|
+
}
|
|
33542
|
+
const observation = getObservation(observationId2, project.id);
|
|
33543
|
+
if (!observation || !canManageObservation(observation, reader)) {
|
|
33544
|
+
emitError("Observation was not found or is outside the active write scope.", asJson);
|
|
33545
|
+
return;
|
|
33546
|
+
}
|
|
33547
|
+
const result = await promoteObservationToLongTermMemory2({
|
|
33548
|
+
dataDir,
|
|
33549
|
+
observation,
|
|
33550
|
+
scope: scope(),
|
|
33551
|
+
kind: kind(),
|
|
33552
|
+
tags: parseCsvList(args.tags),
|
|
33553
|
+
applicability: args.applicability?.trim(),
|
|
33554
|
+
reader: longTermReader
|
|
33555
|
+
});
|
|
33556
|
+
emitResult(
|
|
33557
|
+
{ project, sourceObservationId: observation.id, ...result },
|
|
33558
|
+
`Promoted observation #${observation.id} to long-term memory candidate ${result.memory.id}.`,
|
|
33559
|
+
asJson
|
|
33560
|
+
);
|
|
33561
|
+
return;
|
|
33562
|
+
}
|
|
33563
|
+
case "qualify": {
|
|
33564
|
+
await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
|
|
33565
|
+
const memory = await qualifyLongTermMemory2({ dataDir, id: memoryId(), reason: reason() });
|
|
33566
|
+
emitResult({ project, memory }, `Qualified long-term memory ${memory.id}.`, asJson);
|
|
33567
|
+
return;
|
|
33568
|
+
}
|
|
33569
|
+
case "approve": {
|
|
33570
|
+
await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
|
|
33571
|
+
const memory = await approveLongTermMemory2({ dataDir, id: memoryId(), reason: reason() });
|
|
33572
|
+
emitResult({ project, memory }, `Approved long-term memory ${memory.id}.`, asJson);
|
|
33573
|
+
return;
|
|
33574
|
+
}
|
|
33575
|
+
case "archive": {
|
|
33576
|
+
await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
|
|
33577
|
+
const memory = await archiveLongTermMemory2({ dataDir, id: memoryId(), reason: reason() });
|
|
33578
|
+
emitResult({ project, memory }, `Archived long-term memory ${memory.id}.`, asJson);
|
|
33579
|
+
return;
|
|
33580
|
+
}
|
|
33581
|
+
case "supersede": {
|
|
33582
|
+
const supersededBy = args.supersededBy?.trim() || args["superseded-by"]?.trim();
|
|
33583
|
+
if (!supersededBy) {
|
|
33584
|
+
emitError('supersededBy is required for "memorix memory long-term supersede"', asJson);
|
|
33585
|
+
return;
|
|
33586
|
+
}
|
|
33587
|
+
await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
|
|
33588
|
+
await getLongTermMemoryDetail2({ dataDir, id: supersededBy, reader: longTermReader });
|
|
33589
|
+
const memory = await supersedeLongTermMemory2({
|
|
33590
|
+
dataDir,
|
|
33591
|
+
id: memoryId(),
|
|
33592
|
+
supersededBy,
|
|
33593
|
+
reason: reason()
|
|
33594
|
+
});
|
|
33595
|
+
emitResult({ project, memory }, `Superseded long-term memory ${memory.id} with ${supersededBy}.`, asJson);
|
|
33596
|
+
return;
|
|
33597
|
+
}
|
|
33598
|
+
default:
|
|
33599
|
+
emitError("long-term action must be list, show, add, promote, qualify, approve, archive, or supersede.", asJson);
|
|
33600
|
+
}
|
|
33601
|
+
return;
|
|
33602
|
+
}
|
|
32521
33603
|
default:
|
|
32522
33604
|
console.log("Memorix Memory Commands");
|
|
32523
33605
|
console.log("");
|
|
@@ -32533,6 +33615,13 @@ var init_memory = __esm({
|
|
|
32533
33615
|
console.log(' memorix memory deduplicate [--query "..."] [--dryRun]');
|
|
32534
33616
|
console.log(" memorix memory consolidate [--action preview|execute] [--threshold 0.45]");
|
|
32535
33617
|
console.log(' memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]');
|
|
33618
|
+
console.log(" memorix memory long-term list [--all]");
|
|
33619
|
+
console.log(' memorix memory long-term add --kind semantic --scope user --portability portable --title "..." --text "..." [--tags "..."] [--applicability "..."]');
|
|
33620
|
+
console.log(" memorix memory long-term promote --fromObservation 42 --kind procedural --scope project");
|
|
33621
|
+
console.log(' memorix memory long-term qualify --id <id> --reason "verified against evidence"');
|
|
33622
|
+
console.log(' memorix memory long-term approve --id <id> --reason "reviewed by operator"');
|
|
33623
|
+
console.log(' memorix memory long-term archive --id <id> --reason "no longer current"');
|
|
33624
|
+
console.log(' memorix memory long-term supersede --id <old-id> --superseded-by <qualified-id> --reason "replaced"');
|
|
32536
33625
|
}
|
|
32537
33626
|
} catch (error2) {
|
|
32538
33627
|
emitError(error2 instanceof Error ? error2.message : String(error2), asJson);
|
|
@@ -32543,7 +33632,7 @@ var init_memory = __esm({
|
|
|
32543
33632
|
});
|
|
32544
33633
|
|
|
32545
33634
|
// src/cli/commands/init-shared.ts
|
|
32546
|
-
import
|
|
33635
|
+
import path20 from "path";
|
|
32547
33636
|
function resolveInitScope(args, selectedScope) {
|
|
32548
33637
|
if (args.global && args.project) {
|
|
32549
33638
|
throw new Error("Choose either --global or --project, not both.");
|
|
@@ -32557,7 +33646,7 @@ function resolveInitScope(args, selectedScope) {
|
|
|
32557
33646
|
return selectedScope ?? "global";
|
|
32558
33647
|
}
|
|
32559
33648
|
function getInitTargetDir(scope, cwd, homeDir) {
|
|
32560
|
-
return scope === "global" ?
|
|
33649
|
+
return scope === "global" ? path20.join(homeDir, ".memorix") : cwd;
|
|
32561
33650
|
}
|
|
32562
33651
|
function getInitScopeDescription(scope) {
|
|
32563
33652
|
return scope === "global" ? "Global defaults for all projects on this machine" : "Project-level overrides for the current repository";
|
|
@@ -32567,7 +33656,7 @@ function shouldOfferDotenv(scope) {
|
|
|
32567
33656
|
}
|
|
32568
33657
|
function getEnvTemplateTarget(targetDir, options2) {
|
|
32569
33658
|
const filename = options2.hasDotenvExample ? ".env.memorix-example" : ".env.example";
|
|
32570
|
-
return
|
|
33659
|
+
return path20.join(targetDir, filename);
|
|
32571
33660
|
}
|
|
32572
33661
|
function getInitConfigFilename() {
|
|
32573
33662
|
return "config.toml";
|
|
@@ -32590,7 +33679,7 @@ __export(init_exports, {
|
|
|
32590
33679
|
});
|
|
32591
33680
|
import { existsSync as existsSync11, mkdirSync, writeFileSync } from "fs";
|
|
32592
33681
|
import { homedir as homedir8 } from "os";
|
|
32593
|
-
import
|
|
33682
|
+
import path21 from "path";
|
|
32594
33683
|
function buildInitTomlConfig(options2) {
|
|
32595
33684
|
const isGlobal = options2.scope === "global";
|
|
32596
33685
|
const lines = [
|
|
@@ -32724,8 +33813,8 @@ var init_init = __esm({
|
|
|
32724
33813
|
}
|
|
32725
33814
|
const isGlobal = scope === "global";
|
|
32726
33815
|
const targetDir = getInitTargetDir(scope, process.cwd(), homedir8());
|
|
32727
|
-
const targetPath =
|
|
32728
|
-
const envPath =
|
|
33816
|
+
const targetPath = path21.join(targetDir, isGlobal ? getInitConfigFilename() : getInitProjectConfigFilename());
|
|
33817
|
+
const envPath = path21.join(targetDir, ".env");
|
|
32729
33818
|
v3.info(getInitScopeDescription(scope));
|
|
32730
33819
|
if (existsSync11(targetPath)) {
|
|
32731
33820
|
const overwrite = await me({
|
|
@@ -32829,7 +33918,7 @@ var init_init = __esm({
|
|
|
32829
33918
|
v3.success(`Created ${targetPath}`);
|
|
32830
33919
|
if (shouldOfferDotenv(scope)) {
|
|
32831
33920
|
const envExamplePath = getEnvTemplateTarget(targetDir, {
|
|
32832
|
-
hasDotenvExample: existsSync11(
|
|
33921
|
+
hasDotenvExample: existsSync11(path21.join(targetDir, ".env.example"))
|
|
32833
33922
|
});
|
|
32834
33923
|
const envContent = envLines.join("\n");
|
|
32835
33924
|
if (existsSync11(envExamplePath)) {
|
|
@@ -32845,7 +33934,7 @@ var init_init = __esm({
|
|
|
32845
33934
|
writeFileSync(envExamplePath, envContent, "utf-8");
|
|
32846
33935
|
v3.success(`Created ${envExamplePath}`);
|
|
32847
33936
|
const createEnv = !existsSync11(envPath) ? await me({
|
|
32848
|
-
message: `Create .env from ${
|
|
33937
|
+
message: `Create .env from ${path21.basename(envExamplePath)} now? (you can fill in keys later)`,
|
|
32849
33938
|
initialValue: true
|
|
32850
33939
|
}) : false;
|
|
32851
33940
|
if (!BD(createEnv) && createEnv) {
|
|
@@ -34286,15 +35375,15 @@ __export(audit_exports, {
|
|
|
34286
35375
|
removeFile: () => removeFile,
|
|
34287
35376
|
saveAudit: () => saveAudit
|
|
34288
35377
|
});
|
|
34289
|
-
import * as
|
|
34290
|
-
import * as
|
|
35378
|
+
import * as fs16 from "fs/promises";
|
|
35379
|
+
import * as path22 from "path";
|
|
34291
35380
|
import { homedir as homedir22 } from "os";
|
|
34292
35381
|
function getAuditFilePath() {
|
|
34293
|
-
return process.env.MEMORIX_AUDIT_FILE ||
|
|
35382
|
+
return process.env.MEMORIX_AUDIT_FILE || path22.join(homedir22(), ".memorix", "audit.json");
|
|
34294
35383
|
}
|
|
34295
35384
|
async function loadAudit() {
|
|
34296
35385
|
try {
|
|
34297
|
-
const content = await
|
|
35386
|
+
const content = await fs16.readFile(getAuditFilePath(), "utf-8");
|
|
34298
35387
|
return JSON.parse(content);
|
|
34299
35388
|
} catch {
|
|
34300
35389
|
return {
|
|
@@ -34305,9 +35394,9 @@ async function loadAudit() {
|
|
|
34305
35394
|
}
|
|
34306
35395
|
async function saveAudit(data) {
|
|
34307
35396
|
const auditFile = getAuditFilePath();
|
|
34308
|
-
const dir =
|
|
34309
|
-
await
|
|
34310
|
-
await
|
|
35397
|
+
const dir = path22.dirname(auditFile);
|
|
35398
|
+
await fs16.mkdir(dir, { recursive: true });
|
|
35399
|
+
await fs16.writeFile(auditFile, JSON.stringify(data, null, 2), "utf-8");
|
|
34311
35400
|
}
|
|
34312
35401
|
function getProjectId(projectRoot) {
|
|
34313
35402
|
try {
|
|
@@ -34389,8 +35478,8 @@ __export(installers_exports, {
|
|
|
34389
35478
|
resolveOpenCodeHookCommand: () => resolveOpenCodeHookCommand,
|
|
34390
35479
|
uninstallHooks: () => uninstallHooks
|
|
34391
35480
|
});
|
|
34392
|
-
import * as
|
|
34393
|
-
import * as
|
|
35481
|
+
import * as fs17 from "fs/promises";
|
|
35482
|
+
import * as path23 from "path";
|
|
34394
35483
|
import * as os3 from "os";
|
|
34395
35484
|
import { execSync as execSync2 } from "child_process";
|
|
34396
35485
|
function resolveHookCommand() {
|
|
@@ -34406,7 +35495,7 @@ function resolveWindowsMemorixShim() {
|
|
|
34406
35495
|
stdio: ["ignore", "pipe", "ignore"],
|
|
34407
35496
|
windowsHide: true
|
|
34408
35497
|
}));
|
|
34409
|
-
return output.split(/\r?\n/).map((candidate2) => candidate2.trim()).find((candidate2) =>
|
|
35498
|
+
return output.split(/\r?\n/).map((candidate2) => candidate2.trim()).find((candidate2) => path23.isAbsolute(candidate2)) ?? null;
|
|
34410
35499
|
} catch {
|
|
34411
35500
|
return null;
|
|
34412
35501
|
}
|
|
@@ -34601,9 +35690,9 @@ async function installOfficialSkillsForAgent(agent, projectRoot, global2 = false
|
|
|
34601
35690
|
const root = global2 ? os3.homedir() : projectRoot;
|
|
34602
35691
|
const skillPaths = [];
|
|
34603
35692
|
for (const skillEntry of OFFICIAL_MEMORIX_SKILLS) {
|
|
34604
|
-
const skillPath =
|
|
34605
|
-
await
|
|
34606
|
-
await
|
|
35693
|
+
const skillPath = path23.join(root, relativeDir, skillEntry.name, "SKILL.md");
|
|
35694
|
+
await fs17.mkdir(path23.dirname(skillPath), { recursive: true });
|
|
35695
|
+
await fs17.writeFile(skillPath, skillEntry.content, "utf-8");
|
|
34607
35696
|
skillPaths.push(skillPath);
|
|
34608
35697
|
try {
|
|
34609
35698
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
@@ -34816,124 +35905,124 @@ async function installOpenCodeSkills(projectRoot, global2 = false) {
|
|
|
34816
35905
|
function getProjectConfigPath(agent, projectRoot) {
|
|
34817
35906
|
switch (agent) {
|
|
34818
35907
|
case "claude":
|
|
34819
|
-
return
|
|
35908
|
+
return path23.join(projectRoot, ".claude", "settings.local.json");
|
|
34820
35909
|
case "copilot":
|
|
34821
|
-
return
|
|
35910
|
+
return path23.join(projectRoot, ".github", "hooks", "memorix.json");
|
|
34822
35911
|
case "windsurf":
|
|
34823
|
-
return
|
|
35912
|
+
return path23.join(projectRoot, ".windsurf", "hooks.json");
|
|
34824
35913
|
case "cursor":
|
|
34825
|
-
return
|
|
35914
|
+
return path23.join(projectRoot, ".cursor", "hooks.json");
|
|
34826
35915
|
case "kiro":
|
|
34827
|
-
return
|
|
35916
|
+
return path23.join(projectRoot, ".kiro", "hooks", "memorix-agent-stop.kiro.hook");
|
|
34828
35917
|
case "codex":
|
|
34829
|
-
return
|
|
35918
|
+
return path23.join(projectRoot, "AGENTS.md");
|
|
34830
35919
|
case "trae":
|
|
34831
|
-
return
|
|
35920
|
+
return path23.join(projectRoot, ".trae", "rules", "project_rules.md");
|
|
34832
35921
|
case "opencode":
|
|
34833
|
-
return
|
|
35922
|
+
return path23.join(projectRoot, ".opencode", "plugins", "memorix.js");
|
|
34834
35923
|
case "pi":
|
|
34835
|
-
return
|
|
35924
|
+
return path23.join(projectRoot, ".pi", "packages", "memorix", "extensions", "memorix.js");
|
|
34836
35925
|
case "openclaw":
|
|
34837
|
-
return
|
|
35926
|
+
return path23.join(os3.homedir(), ".openclaw", "extensions", "memorix", "hooks", "memorix", "HOOK.md");
|
|
34838
35927
|
case "hermes":
|
|
34839
|
-
return
|
|
35928
|
+
return path23.join(os3.homedir(), ".hermes", "plugins", "memorix", "plugin.yaml");
|
|
34840
35929
|
case "omp":
|
|
34841
|
-
return
|
|
35930
|
+
return path23.join(projectRoot, ".omp", "packages", "memorix", "extensions", "memorix.js");
|
|
34842
35931
|
case "antigravity":
|
|
34843
|
-
return
|
|
35932
|
+
return path23.join(projectRoot, ".agents", "hooks.json");
|
|
34844
35933
|
case "gemini-cli":
|
|
34845
|
-
return
|
|
35934
|
+
return path23.join(projectRoot, ".gemini", "settings.json");
|
|
34846
35935
|
default:
|
|
34847
|
-
return
|
|
35936
|
+
return path23.join(projectRoot, ".memorix", "hooks.json");
|
|
34848
35937
|
}
|
|
34849
35938
|
}
|
|
34850
35939
|
function getGlobalConfigPath(agent) {
|
|
34851
35940
|
const home = os3.homedir();
|
|
34852
35941
|
switch (agent) {
|
|
34853
35942
|
case "claude":
|
|
34854
|
-
return
|
|
35943
|
+
return path23.join(home, ".claude", "settings.json");
|
|
34855
35944
|
case "copilot":
|
|
34856
35945
|
return "";
|
|
34857
35946
|
case "windsurf":
|
|
34858
|
-
return
|
|
35947
|
+
return path23.join(home, ".codeium", "windsurf", "hooks.json");
|
|
34859
35948
|
case "cursor":
|
|
34860
|
-
return
|
|
35949
|
+
return path23.join(home, ".cursor", "hooks.json");
|
|
34861
35950
|
case "antigravity":
|
|
34862
|
-
return
|
|
35951
|
+
return path23.join(home, ".gemini", "config", "hooks.json");
|
|
34863
35952
|
case "gemini-cli":
|
|
34864
|
-
return
|
|
35953
|
+
return path23.join(home, ".gemini", "settings.json");
|
|
34865
35954
|
case "opencode":
|
|
34866
|
-
return
|
|
35955
|
+
return path23.join(home, ".config", "opencode", "plugins", "memorix.js");
|
|
34867
35956
|
case "pi":
|
|
34868
|
-
return
|
|
35957
|
+
return path23.join(home, ".pi", "agent", "packages", "memorix", "extensions", "memorix.js");
|
|
34869
35958
|
case "openclaw":
|
|
34870
|
-
return
|
|
35959
|
+
return path23.join(home, ".openclaw", "extensions", "memorix", "hooks", "memorix", "HOOK.md");
|
|
34871
35960
|
case "hermes":
|
|
34872
|
-
return
|
|
35961
|
+
return path23.join(home, ".hermes", "plugins", "memorix", "plugin.yaml");
|
|
34873
35962
|
case "omp":
|
|
34874
|
-
return
|
|
35963
|
+
return path23.join(home, ".omp", "agent", "packages", "memorix", "extensions", "memorix.js");
|
|
34875
35964
|
case "trae":
|
|
34876
|
-
return
|
|
35965
|
+
return path23.join(home, ".trae", "rules", "project_rules.md");
|
|
34877
35966
|
default:
|
|
34878
|
-
return
|
|
35967
|
+
return path23.join(home, ".memorix", "hooks.json");
|
|
34879
35968
|
}
|
|
34880
35969
|
}
|
|
34881
35970
|
function getAgentRulesPath(agent, root, global2 = false) {
|
|
34882
35971
|
if (global2) {
|
|
34883
35972
|
switch (agent) {
|
|
34884
35973
|
case "windsurf":
|
|
34885
|
-
return
|
|
35974
|
+
return path23.join(root, ".codeium", "windsurf", "rules", "memorix.md");
|
|
34886
35975
|
case "cursor":
|
|
34887
|
-
return
|
|
35976
|
+
return path23.join(root, ".cursor", "rules", "memorix.mdc");
|
|
34888
35977
|
case "claude":
|
|
34889
|
-
return
|
|
35978
|
+
return path23.join(root, ".claude", "CLAUDE.md");
|
|
34890
35979
|
case "codex":
|
|
34891
|
-
return
|
|
35980
|
+
return path23.join(root, ".codex", "AGENTS.md");
|
|
34892
35981
|
case "kiro":
|
|
34893
|
-
return
|
|
35982
|
+
return path23.join(root, ".kiro", "steering", "memorix.md");
|
|
34894
35983
|
case "opencode":
|
|
34895
|
-
return
|
|
35984
|
+
return path23.join(root, ".config", "opencode", "AGENTS.md");
|
|
34896
35985
|
case "antigravity":
|
|
34897
35986
|
case "gemini-cli":
|
|
34898
|
-
return
|
|
35987
|
+
return path23.join(root, ".gemini", "GEMINI.md");
|
|
34899
35988
|
case "trae":
|
|
34900
|
-
return
|
|
35989
|
+
return path23.join(root, ".trae", "rules", "project_rules.md");
|
|
34901
35990
|
default:
|
|
34902
|
-
return
|
|
35991
|
+
return path23.join(root, ".agent", "rules", "memorix.md");
|
|
34903
35992
|
}
|
|
34904
35993
|
}
|
|
34905
35994
|
switch (agent) {
|
|
34906
35995
|
case "windsurf":
|
|
34907
|
-
return
|
|
35996
|
+
return path23.join(root, ".windsurf", "rules", "memorix.md");
|
|
34908
35997
|
case "cursor":
|
|
34909
|
-
return
|
|
35998
|
+
return path23.join(root, ".cursor", "rules", "memorix.mdc");
|
|
34910
35999
|
case "claude":
|
|
34911
|
-
return
|
|
36000
|
+
return path23.join(root, "CLAUDE.md");
|
|
34912
36001
|
case "copilot":
|
|
34913
|
-
return
|
|
36002
|
+
return path23.join(root, ".github", "copilot-instructions.md");
|
|
34914
36003
|
case "codex":
|
|
34915
|
-
return
|
|
36004
|
+
return path23.join(root, "AGENTS.md");
|
|
34916
36005
|
case "kiro":
|
|
34917
|
-
return
|
|
36006
|
+
return path23.join(root, ".kiro", "steering", "memorix.md");
|
|
34918
36007
|
case "opencode":
|
|
34919
|
-
return
|
|
36008
|
+
return path23.join(root, "AGENTS.md");
|
|
34920
36009
|
case "antigravity":
|
|
34921
36010
|
case "gemini-cli":
|
|
34922
|
-
return
|
|
36011
|
+
return path23.join(root, "GEMINI.md");
|
|
34923
36012
|
case "trae":
|
|
34924
|
-
return
|
|
36013
|
+
return path23.join(root, ".trae", "rules", "project_rules.md");
|
|
34925
36014
|
default:
|
|
34926
|
-
return
|
|
36015
|
+
return path23.join(root, ".agent", "rules", "memorix.md");
|
|
34927
36016
|
}
|
|
34928
36017
|
}
|
|
34929
36018
|
async function detectCopilotExtension(home) {
|
|
34930
36019
|
const extDirs = [
|
|
34931
|
-
|
|
34932
|
-
|
|
36020
|
+
path23.join(home, ".vscode", "extensions"),
|
|
36021
|
+
path23.join(home, ".vscode-insiders", "extensions")
|
|
34933
36022
|
];
|
|
34934
36023
|
for (const extDir of extDirs) {
|
|
34935
36024
|
try {
|
|
34936
|
-
const entries = await
|
|
36025
|
+
const entries = await fs17.readdir(extDir);
|
|
34937
36026
|
if (entries.some((e3) => e3.startsWith("github.copilot-"))) {
|
|
34938
36027
|
return true;
|
|
34939
36028
|
}
|
|
@@ -34945,21 +36034,21 @@ async function detectCopilotExtension(home) {
|
|
|
34945
36034
|
async function detectInstalledAgents() {
|
|
34946
36035
|
const agents = [];
|
|
34947
36036
|
const home = os3.homedir();
|
|
34948
|
-
const claudeDir =
|
|
36037
|
+
const claudeDir = path23.join(home, ".claude");
|
|
34949
36038
|
try {
|
|
34950
|
-
await
|
|
36039
|
+
await fs17.access(claudeDir);
|
|
34951
36040
|
agents.push("claude");
|
|
34952
36041
|
} catch {
|
|
34953
36042
|
}
|
|
34954
|
-
const windsurfDir =
|
|
36043
|
+
const windsurfDir = path23.join(home, ".codeium", "windsurf");
|
|
34955
36044
|
try {
|
|
34956
|
-
await
|
|
36045
|
+
await fs17.access(windsurfDir);
|
|
34957
36046
|
agents.push("windsurf");
|
|
34958
36047
|
} catch {
|
|
34959
36048
|
}
|
|
34960
|
-
const cursorDir =
|
|
36049
|
+
const cursorDir = path23.join(home, ".cursor");
|
|
34961
36050
|
try {
|
|
34962
|
-
await
|
|
36051
|
+
await fs17.access(cursorDir);
|
|
34963
36052
|
agents.push("cursor");
|
|
34964
36053
|
} catch {
|
|
34965
36054
|
}
|
|
@@ -34967,21 +36056,21 @@ async function detectInstalledAgents() {
|
|
|
34967
36056
|
if (copilotDetected) {
|
|
34968
36057
|
agents.push("copilot");
|
|
34969
36058
|
}
|
|
34970
|
-
const kiroConfig =
|
|
36059
|
+
const kiroConfig = path23.join(home, ".kiro");
|
|
34971
36060
|
try {
|
|
34972
|
-
await
|
|
36061
|
+
await fs17.access(kiroConfig);
|
|
34973
36062
|
agents.push("kiro");
|
|
34974
36063
|
} catch {
|
|
34975
36064
|
}
|
|
34976
|
-
const codexDir =
|
|
36065
|
+
const codexDir = path23.join(home, ".codex");
|
|
34977
36066
|
try {
|
|
34978
|
-
await
|
|
36067
|
+
await fs17.access(codexDir);
|
|
34979
36068
|
agents.push("codex");
|
|
34980
36069
|
} catch {
|
|
34981
36070
|
}
|
|
34982
|
-
const antigravityDir =
|
|
36071
|
+
const antigravityDir = path23.join(home, ".gemini", "config");
|
|
34983
36072
|
try {
|
|
34984
|
-
await
|
|
36073
|
+
await fs17.access(antigravityDir);
|
|
34985
36074
|
agents.push("antigravity");
|
|
34986
36075
|
} catch {
|
|
34987
36076
|
}
|
|
@@ -34992,15 +36081,15 @@ async function detectInstalledAgents() {
|
|
|
34992
36081
|
agents.push("gemini-cli");
|
|
34993
36082
|
} catch {
|
|
34994
36083
|
}
|
|
34995
|
-
const opencodeDir =
|
|
36084
|
+
const opencodeDir = path23.join(home, ".config", "opencode");
|
|
34996
36085
|
try {
|
|
34997
|
-
await
|
|
36086
|
+
await fs17.access(opencodeDir);
|
|
34998
36087
|
agents.push("opencode");
|
|
34999
36088
|
} catch {
|
|
35000
36089
|
}
|
|
35001
|
-
const traeDir =
|
|
36090
|
+
const traeDir = path23.join(home, ".trae");
|
|
35002
36091
|
try {
|
|
35003
|
-
await
|
|
36092
|
+
await fs17.access(traeDir);
|
|
35004
36093
|
agents.push("trae");
|
|
35005
36094
|
} catch {
|
|
35006
36095
|
}
|
|
@@ -35034,7 +36123,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
|
|
|
35034
36123
|
try {
|
|
35035
36124
|
const { access: access3, unlink: unlink2 } = await import("fs/promises");
|
|
35036
36125
|
await access3(entry.path);
|
|
35037
|
-
const basename5 =
|
|
36126
|
+
const basename5 = path23.basename(entry.path);
|
|
35038
36127
|
if (basename5 === "AGENTS.md" || basename5 === "GEMINI.md" || basename5 === "CONTEXT.md") {
|
|
35039
36128
|
continue;
|
|
35040
36129
|
}
|
|
@@ -35089,8 +36178,8 @@ async function installHooks(agent, projectRoot, global2 = false) {
|
|
|
35089
36178
|
case "opencode": {
|
|
35090
36179
|
const pluginContent = generateOpenCodePlugin();
|
|
35091
36180
|
const pluginPath = global2 ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
|
|
35092
|
-
await
|
|
35093
|
-
await
|
|
36181
|
+
await fs17.mkdir(path23.dirname(pluginPath), { recursive: true });
|
|
36182
|
+
await fs17.writeFile(pluginPath, pluginContent, "utf-8");
|
|
35094
36183
|
try {
|
|
35095
36184
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
35096
36185
|
await recordFile2(projectRoot, "hook", pluginPath, agent);
|
|
@@ -35119,14 +36208,14 @@ async function installHooks(agent, projectRoot, global2 = false) {
|
|
|
35119
36208
|
default:
|
|
35120
36209
|
generated = generateClaudeConfig();
|
|
35121
36210
|
}
|
|
35122
|
-
await
|
|
36211
|
+
await fs17.mkdir(path23.dirname(configPath), { recursive: true });
|
|
35123
36212
|
if (agent === "kiro") {
|
|
35124
36213
|
const hookFiles = generateKiroHookFiles();
|
|
35125
|
-
const hooksDir =
|
|
35126
|
-
await
|
|
36214
|
+
const hooksDir = path23.join(path23.dirname(configPath));
|
|
36215
|
+
await fs17.mkdir(hooksDir, { recursive: true });
|
|
35127
36216
|
for (const hf of hookFiles) {
|
|
35128
|
-
const hookPath =
|
|
35129
|
-
await
|
|
36217
|
+
const hookPath = path23.join(hooksDir, hf.filename);
|
|
36218
|
+
await fs17.writeFile(hookPath, hf.content, "utf-8");
|
|
35130
36219
|
try {
|
|
35131
36220
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
35132
36221
|
await recordFile2(projectRoot, "hook", hookPath, agent);
|
|
@@ -35136,7 +36225,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
|
|
|
35136
36225
|
} else {
|
|
35137
36226
|
let existing = {};
|
|
35138
36227
|
try {
|
|
35139
|
-
const content = await
|
|
36228
|
+
const content = await fs17.readFile(configPath, "utf-8");
|
|
35140
36229
|
existing = JSON.parse(content);
|
|
35141
36230
|
} catch {
|
|
35142
36231
|
}
|
|
@@ -35171,7 +36260,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
|
|
|
35171
36260
|
const h3 = merged.hooks;
|
|
35172
36261
|
if (h3) delete h3.preToolUse;
|
|
35173
36262
|
}
|
|
35174
|
-
await
|
|
36263
|
+
await fs17.writeFile(configPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
35175
36264
|
try {
|
|
35176
36265
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
35177
36266
|
await recordFile2(projectRoot, "hook", configPath, agent);
|
|
@@ -35219,18 +36308,18 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
|
|
|
35219
36308
|
const rulesRoot = global2 ? os3.homedir() : projectRoot;
|
|
35220
36309
|
const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
|
|
35221
36310
|
try {
|
|
35222
|
-
await
|
|
36311
|
+
await fs17.mkdir(path23.dirname(rulesPath), { recursive: true });
|
|
35223
36312
|
if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli") {
|
|
35224
36313
|
try {
|
|
35225
|
-
const existing = await
|
|
35226
|
-
await
|
|
36314
|
+
const existing = await fs17.readFile(rulesPath, "utf-8");
|
|
36315
|
+
await fs17.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
|
|
35227
36316
|
try {
|
|
35228
36317
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
35229
36318
|
await recordFile2(projectRoot, "rule", rulesPath, agent);
|
|
35230
36319
|
} catch {
|
|
35231
36320
|
}
|
|
35232
36321
|
} catch {
|
|
35233
|
-
await
|
|
36322
|
+
await fs17.writeFile(rulesPath, rulesContent, "utf-8");
|
|
35234
36323
|
try {
|
|
35235
36324
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
35236
36325
|
await recordFile2(projectRoot, "rule", rulesPath, agent);
|
|
@@ -35239,9 +36328,9 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
|
|
|
35239
36328
|
}
|
|
35240
36329
|
} else {
|
|
35241
36330
|
try {
|
|
35242
|
-
await
|
|
36331
|
+
await fs17.access(rulesPath);
|
|
35243
36332
|
} catch {
|
|
35244
|
-
await
|
|
36333
|
+
await fs17.writeFile(rulesPath, rulesContent, "utf-8");
|
|
35245
36334
|
try {
|
|
35246
36335
|
const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
|
|
35247
36336
|
await recordFile2(projectRoot, "rule", rulesPath, agent);
|
|
@@ -35331,6 +36420,8 @@ alwaysApply: true
|
|
|
35331
36420
|
"- Include `filesModified` when relevant",
|
|
35332
36421
|
"- Use `topicKey` for topics that evolve over time (prevents duplicates)",
|
|
35333
36422
|
'- For "why" decisions, use `memorix_store_reasoning`',
|
|
36423
|
+
'- For a stable fact, reusable procedure, or completed episode that merits deliberate long-term review, include `longTerm` in `memorix_store` with the appropriate kind and normally `scope: "project"`. It creates a candidate only: do not use it for routine updates, do not make project-derived evidence portable user memory, and do not assume it enters context until an operator qualifies and approves it through `memorix memory long-term`.',
|
|
36424
|
+
"- A `user` + `portable` durable memory delivered in a task brief is intentionally available across projects. When it matches the task, use it as reusable background even if its origin differs; do not treat it as a current-project fact. Expand it only when needed with `memorix_detail` using its `durable:<id>` reference and a specific purpose.",
|
|
35334
36425
|
"",
|
|
35335
36426
|
"**Don't store:** greetings, simple file reads, trivial commands (ls, pwd, git status).",
|
|
35336
36427
|
"",
|
|
@@ -35367,16 +36458,16 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
|
|
|
35367
36458
|
let success = false;
|
|
35368
36459
|
try {
|
|
35369
36460
|
if (agent === "kiro" || agent === "opencode") {
|
|
35370
|
-
await
|
|
36461
|
+
await fs17.unlink(configPath);
|
|
35371
36462
|
success = true;
|
|
35372
36463
|
} else {
|
|
35373
|
-
const content = await
|
|
36464
|
+
const content = await fs17.readFile(configPath, "utf-8");
|
|
35374
36465
|
const config2 = JSON.parse(content);
|
|
35375
36466
|
delete config2.hooks;
|
|
35376
36467
|
if (Object.keys(config2).length === 0) {
|
|
35377
|
-
await
|
|
36468
|
+
await fs17.unlink(configPath);
|
|
35378
36469
|
} else {
|
|
35379
|
-
await
|
|
36470
|
+
await fs17.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
35380
36471
|
}
|
|
35381
36472
|
success = true;
|
|
35382
36473
|
}
|
|
@@ -35389,10 +36480,10 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
|
|
|
35389
36480
|
const agentFiles = prevFiles.filter((e3) => e3.agent === agent);
|
|
35390
36481
|
for (const entry of agentFiles) {
|
|
35391
36482
|
try {
|
|
35392
|
-
const basename5 =
|
|
36483
|
+
const basename5 = path23.basename(entry.path);
|
|
35393
36484
|
if (basename5 === "AGENTS.md" || basename5 === "GEMINI.md" || basename5 === "CONTEXT.md") {
|
|
35394
36485
|
try {
|
|
35395
|
-
const content = await
|
|
36486
|
+
const content = await fs17.readFile(entry.path, "utf-8");
|
|
35396
36487
|
const memorixStart = content.indexOf("# Memorix");
|
|
35397
36488
|
if (memorixStart >= 0) {
|
|
35398
36489
|
const afterMemorix = content.substring(memorixStart);
|
|
@@ -35404,9 +36495,9 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
|
|
|
35404
36495
|
}
|
|
35405
36496
|
const cleaned = (before + "\n" + after).trim();
|
|
35406
36497
|
if (cleaned.length === 0) {
|
|
35407
|
-
await
|
|
36498
|
+
await fs17.unlink(entry.path);
|
|
35408
36499
|
} else {
|
|
35409
|
-
await
|
|
36500
|
+
await fs17.writeFile(entry.path, cleaned + "\n", "utf-8");
|
|
35410
36501
|
}
|
|
35411
36502
|
}
|
|
35412
36503
|
} catch {
|
|
@@ -35415,7 +36506,7 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
|
|
|
35415
36506
|
auditCleaned = true;
|
|
35416
36507
|
continue;
|
|
35417
36508
|
}
|
|
35418
|
-
await
|
|
36509
|
+
await fs17.unlink(entry.path);
|
|
35419
36510
|
await removeFile2(projectRoot, entry.path);
|
|
35420
36511
|
auditCleaned = true;
|
|
35421
36512
|
} catch {
|
|
@@ -35427,14 +36518,14 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
|
|
|
35427
36518
|
if (success) {
|
|
35428
36519
|
try {
|
|
35429
36520
|
const { rm: rm2 } = await import("fs/promises");
|
|
35430
|
-
const dir =
|
|
36521
|
+
const dir = path23.dirname(configPath);
|
|
35431
36522
|
let current = dir;
|
|
35432
36523
|
for (let i2 = 0; i2 < 3; i2++) {
|
|
35433
36524
|
try {
|
|
35434
|
-
const entries = await
|
|
36525
|
+
const entries = await fs17.readdir(current);
|
|
35435
36526
|
if (entries.length === 0) {
|
|
35436
36527
|
await rm2(current, { recursive: true });
|
|
35437
|
-
current =
|
|
36528
|
+
current = path23.dirname(current);
|
|
35438
36529
|
} else {
|
|
35439
36530
|
break;
|
|
35440
36531
|
}
|
|
@@ -35458,12 +36549,12 @@ async function getHookStatus(projectRoot) {
|
|
|
35458
36549
|
let usedPath = projectPath;
|
|
35459
36550
|
const verifiedByDefault = agent !== "opencode" && agent !== "pi";
|
|
35460
36551
|
try {
|
|
35461
|
-
await
|
|
36552
|
+
await fs17.access(projectPath);
|
|
35462
36553
|
installed = true;
|
|
35463
36554
|
} catch {
|
|
35464
36555
|
if (globalPath) {
|
|
35465
36556
|
try {
|
|
35466
|
-
await
|
|
36557
|
+
await fs17.access(globalPath);
|
|
35467
36558
|
installed = true;
|
|
35468
36559
|
usedPath = globalPath;
|
|
35469
36560
|
} catch {
|
|
@@ -35472,7 +36563,7 @@ async function getHookStatus(projectRoot) {
|
|
|
35472
36563
|
}
|
|
35473
36564
|
if (installed && agent === "opencode") {
|
|
35474
36565
|
try {
|
|
35475
|
-
const content = await
|
|
36566
|
+
const content = await fs17.readFile(usedPath, "utf-8");
|
|
35476
36567
|
const match = content.match(/@generated-version\s+(\d+)/);
|
|
35477
36568
|
const installedVersion = match ? parseInt(match[1], 10) : 0;
|
|
35478
36569
|
outdated = installedVersion < OPENCODE_PLUGIN_VERSION;
|
|
@@ -35503,11 +36594,11 @@ var init_installers = __esm({
|
|
|
35503
36594
|
init_official_skills();
|
|
35504
36595
|
OPENCODE_PLUGIN_VERSION = 7;
|
|
35505
36596
|
AGENT_SKILL_DIRS = {
|
|
35506
|
-
cursor: { project:
|
|
35507
|
-
windsurf: { project:
|
|
35508
|
-
kiro: { project:
|
|
35509
|
-
opencode: { project:
|
|
35510
|
-
trae: { project:
|
|
36597
|
+
cursor: { project: path23.join(".cursor", "skills"), global: path23.join(".cursor", "skills") },
|
|
36598
|
+
windsurf: { project: path23.join(".windsurf", "skills"), global: path23.join(".windsurf", "skills") },
|
|
36599
|
+
kiro: { project: path23.join(".kiro", "skills"), global: path23.join(".kiro", "skills") },
|
|
36600
|
+
opencode: { project: path23.join(".opencode", "skills"), global: path23.join(".config", "opencode", "skills") },
|
|
36601
|
+
trae: { project: path23.join(".trae", "skills"), global: path23.join(".trae", "skills") }
|
|
35511
36602
|
};
|
|
35512
36603
|
PACKAGE_OWNED_HOOK_AGENTS = /* @__PURE__ */ new Set(["openclaw", "hermes", "omp"]);
|
|
35513
36604
|
}
|
|
@@ -35531,6 +36622,8 @@ __export(setup_exports, {
|
|
|
35531
36622
|
installOpenClawBundlePackage: () => installOpenClawBundlePackage,
|
|
35532
36623
|
installPiPackage: () => installPiPackage,
|
|
35533
36624
|
installPluginPackage: () => installPluginPackage,
|
|
36625
|
+
migrateLegacyCodexIntegration: () => migrateLegacyCodexIntegration,
|
|
36626
|
+
parseCodexPluginState: () => parseCodexPluginState,
|
|
35534
36627
|
removeLegacyCodexMemorixMcpConfig: () => removeLegacyCodexMemorixMcpConfig,
|
|
35535
36628
|
tryInstallCodexPlugin: () => tryInstallCodexPlugin
|
|
35536
36629
|
});
|
|
@@ -35539,7 +36632,7 @@ import { existsSync as existsSync12 } from "fs";
|
|
|
35539
36632
|
import { copyFile, mkdir as mkdir5, readFile as readFile5, readdir as readdir2, rm, writeFile as writeFile5 } from "fs/promises";
|
|
35540
36633
|
import { createRequire as createRequire5 } from "module";
|
|
35541
36634
|
import { homedir as homedir24 } from "os";
|
|
35542
|
-
import
|
|
36635
|
+
import path24 from "path";
|
|
35543
36636
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
35544
36637
|
function getSetupAgentTargets() {
|
|
35545
36638
|
return [...SUPPORTED_SETUP_AGENTS];
|
|
@@ -35576,13 +36669,13 @@ function buildSetupPlan(options2) {
|
|
|
35576
36669
|
if (!isPackageOwnedAgent && includeHooks) actions.push("hooks");
|
|
35577
36670
|
return { agent: options2.agent, mcp, actions, includeHooks, includeRules, includePlugin: wantsPlugin };
|
|
35578
36671
|
}
|
|
35579
|
-
function findPackageRoot(start =
|
|
36672
|
+
function findPackageRoot(start = path24.dirname(fileURLToPath5(import.meta.url))) {
|
|
35580
36673
|
let dir = start;
|
|
35581
36674
|
for (let i2 = 0; i2 < 8; i2++) {
|
|
35582
|
-
if (existsSync12(
|
|
36675
|
+
if (existsSync12(path24.join(dir, "package.json")) && existsSync12(path24.join(dir, "plugins"))) {
|
|
35583
36676
|
return dir;
|
|
35584
36677
|
}
|
|
35585
|
-
const parent =
|
|
36678
|
+
const parent = path24.dirname(dir);
|
|
35586
36679
|
if (parent === dir) break;
|
|
35587
36680
|
dir = parent;
|
|
35588
36681
|
}
|
|
@@ -35593,12 +36686,12 @@ async function copyDir(source, destination) {
|
|
|
35593
36686
|
await mkdir5(destination, { recursive: true });
|
|
35594
36687
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
35595
36688
|
for (const entry of entries) {
|
|
35596
|
-
const src2 =
|
|
35597
|
-
const dest =
|
|
36689
|
+
const src2 = path24.join(source, entry.name);
|
|
36690
|
+
const dest = path24.join(destination, entry.name);
|
|
35598
36691
|
if (entry.isDirectory()) {
|
|
35599
36692
|
await copyDir(src2, dest);
|
|
35600
36693
|
} else {
|
|
35601
|
-
await mkdir5(
|
|
36694
|
+
await mkdir5(path24.dirname(dest), { recursive: true });
|
|
35602
36695
|
await copyFile(src2, dest);
|
|
35603
36696
|
}
|
|
35604
36697
|
}
|
|
@@ -35606,16 +36699,16 @@ async function copyDir(source, destination) {
|
|
|
35606
36699
|
async function writeOfficialSkills(skillsRoot) {
|
|
35607
36700
|
const written = [];
|
|
35608
36701
|
for (const skill2 of OFFICIAL_MEMORIX_SKILLS) {
|
|
35609
|
-
const skillPath =
|
|
35610
|
-
await mkdir5(
|
|
36702
|
+
const skillPath = path24.join(skillsRoot, skill2.name, "SKILL.md");
|
|
36703
|
+
await mkdir5(path24.dirname(skillPath), { recursive: true });
|
|
35611
36704
|
await writeFile5(skillPath, skill2.content, "utf-8");
|
|
35612
36705
|
written.push(skillPath);
|
|
35613
36706
|
}
|
|
35614
36707
|
return written;
|
|
35615
36708
|
}
|
|
35616
36709
|
async function stripHookCaptureFromPlugin(pluginPath, agent) {
|
|
35617
|
-
await rm(
|
|
35618
|
-
const manifestPath = agent === "claude" ?
|
|
36710
|
+
await rm(path24.join(pluginPath, "hooks"), { recursive: true, force: true });
|
|
36711
|
+
const manifestPath = agent === "claude" ? path24.join(pluginPath, ".claude-plugin", "plugin.json") : agent === "codex" ? path24.join(pluginPath, ".codex-plugin", "plugin.json") : path24.join(pluginPath, "plugin.json");
|
|
35619
36712
|
try {
|
|
35620
36713
|
const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
|
|
35621
36714
|
delete manifest.hooks;
|
|
@@ -35631,7 +36724,7 @@ async function stripHookCaptureFromPlugin(pluginPath, agent) {
|
|
|
35631
36724
|
}
|
|
35632
36725
|
}
|
|
35633
36726
|
async function stampCodexPluginVersion(pluginPath) {
|
|
35634
|
-
const manifestPath =
|
|
36727
|
+
const manifestPath = path24.join(pluginPath, ".codex-plugin", "plugin.json");
|
|
35635
36728
|
const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
|
|
35636
36729
|
if (manifest.name !== "memorix") {
|
|
35637
36730
|
throw new Error(`Unexpected Codex plugin manifest at ${manifestPath}`);
|
|
@@ -35641,8 +36734,8 @@ async function stampCodexPluginVersion(pluginPath) {
|
|
|
35641
36734
|
`, "utf-8");
|
|
35642
36735
|
}
|
|
35643
36736
|
async function stripHookCaptureFromOpenClawBundle(bundlePath) {
|
|
35644
|
-
await rm(
|
|
35645
|
-
const manifestPath =
|
|
36737
|
+
await rm(path24.join(bundlePath, "hooks"), { recursive: true, force: true });
|
|
36738
|
+
const manifestPath = path24.join(bundlePath, ".codex-plugin", "plugin.json");
|
|
35646
36739
|
try {
|
|
35647
36740
|
const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
|
|
35648
36741
|
delete manifest.hooks;
|
|
@@ -35678,7 +36771,7 @@ function mergeHermesPluginEnabled(existingContent, pluginName) {
|
|
|
35678
36771
|
}, { lineWidth: -1 });
|
|
35679
36772
|
}
|
|
35680
36773
|
function relativePosix(from, to) {
|
|
35681
|
-
let rel =
|
|
36774
|
+
let rel = path24.relative(from, to).replace(/\\/g, "/");
|
|
35682
36775
|
if (!rel.startsWith("./") && !rel.startsWith("../")) rel = `./${rel}`;
|
|
35683
36776
|
return rel;
|
|
35684
36777
|
}
|
|
@@ -35779,6 +36872,21 @@ function mergeTomlMcpConfig(existingContent, generatedContent) {
|
|
|
35779
36872
|
return `${parts.join("\n\n")}
|
|
35780
36873
|
`;
|
|
35781
36874
|
}
|
|
36875
|
+
function getTomlSection(content, section) {
|
|
36876
|
+
const lines = content.split(/\r?\n/);
|
|
36877
|
+
const header = `[${section}]`;
|
|
36878
|
+
const start = lines.findIndex((line) => line.trim() === header);
|
|
36879
|
+
if (start < 0) return null;
|
|
36880
|
+
let end = lines.length;
|
|
36881
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
36882
|
+
const trimmed = lines[index].trim();
|
|
36883
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
36884
|
+
end = index;
|
|
36885
|
+
break;
|
|
36886
|
+
}
|
|
36887
|
+
}
|
|
36888
|
+
return lines.slice(start + 1, end).join("\n");
|
|
36889
|
+
}
|
|
35782
36890
|
function isLegacyCodexMemorixNodeServer(server) {
|
|
35783
36891
|
if (server.name !== "memorix" || server.command.trim().toLowerCase() !== "node") return false;
|
|
35784
36892
|
const startsMemorixStdio = server.args.some((arg) => arg.trim().toLowerCase() === "serve");
|
|
@@ -35788,22 +36896,102 @@ function isLegacyCodexMemorixNodeServer(server) {
|
|
|
35788
36896
|
});
|
|
35789
36897
|
return startsMemorixStdio && sourceEntry;
|
|
35790
36898
|
}
|
|
35791
|
-
|
|
36899
|
+
function isOwnedLegacyCodexMcp(content) {
|
|
36900
|
+
const section = getTomlSection(content, "mcp_servers.memorix");
|
|
36901
|
+
if (section === null || getTomlSection(content, "mcp_servers.memorix.env") !== null) return false;
|
|
36902
|
+
const allowedKeys = /* @__PURE__ */ new Set(["command", "args", "type", "startup_timeout_sec", "tool_timeout_sec", "enabled"]);
|
|
36903
|
+
for (const rawLine of section.split(/\r?\n/)) {
|
|
36904
|
+
const line = rawLine.trim();
|
|
36905
|
+
if (!line || line.startsWith("#")) continue;
|
|
36906
|
+
const key = line.match(/^([A-Za-z0-9_]+)\s*=/)?.[1];
|
|
36907
|
+
if (!key || !allowedKeys.has(key)) return false;
|
|
36908
|
+
}
|
|
36909
|
+
const server = new CodexMCPAdapter().parse(content).find((entry) => entry.name === "memorix");
|
|
36910
|
+
return Boolean(server && isLegacyCodexMemorixNodeServer(server));
|
|
36911
|
+
}
|
|
36912
|
+
async function removeLegacyCodexMemorixMcpConfig(configPath = path24.join(homedir24(), ".codex", "config.toml")) {
|
|
35792
36913
|
let existingContent;
|
|
35793
36914
|
try {
|
|
35794
36915
|
existingContent = await readFile5(configPath, "utf-8");
|
|
35795
36916
|
} catch {
|
|
35796
36917
|
return { configPath, removed: false };
|
|
35797
36918
|
}
|
|
35798
|
-
|
|
35799
|
-
const legacyServer = adapter.parse(existingContent).find(isLegacyCodexMemorixNodeServer);
|
|
35800
|
-
if (!legacyServer) return { configPath, removed: false };
|
|
36919
|
+
if (!isOwnedLegacyCodexMcp(existingContent)) return { configPath, removed: false };
|
|
35801
36920
|
let nextContent = removeTomlSection(existingContent, "mcp_servers.memorix.env");
|
|
35802
36921
|
nextContent = removeTomlSection(nextContent, "mcp_servers.memorix");
|
|
35803
36922
|
await writeFile5(configPath, nextContent ? `${nextContent}
|
|
35804
36923
|
` : "", "utf-8");
|
|
35805
36924
|
return { configPath, removed: true };
|
|
35806
36925
|
}
|
|
36926
|
+
function collectHookCommands(value, commands) {
|
|
36927
|
+
if (Array.isArray(value)) {
|
|
36928
|
+
for (const item of value) collectHookCommands(item, commands);
|
|
36929
|
+
return;
|
|
36930
|
+
}
|
|
36931
|
+
if (!value || typeof value !== "object") return;
|
|
36932
|
+
for (const [key, child] of Object.entries(value)) {
|
|
36933
|
+
if ((key === "command" || key === "commandWindows") && typeof child === "string") {
|
|
36934
|
+
commands.push(child);
|
|
36935
|
+
} else {
|
|
36936
|
+
collectHookCommands(child, commands);
|
|
36937
|
+
}
|
|
36938
|
+
}
|
|
36939
|
+
}
|
|
36940
|
+
function isOwnedLegacyCodexHooks(content) {
|
|
36941
|
+
try {
|
|
36942
|
+
const parsed = JSON.parse(content);
|
|
36943
|
+
if (!parsed.hooks || typeof parsed.hooks !== "object") return false;
|
|
36944
|
+
const commands = [];
|
|
36945
|
+
collectHookCommands(parsed.hooks, commands);
|
|
36946
|
+
return commands.length > 0 && commands.every((command) => /^memorix(?:\.cmd)?\s+hook(?:\s|$)/i.test(command.trim()));
|
|
36947
|
+
} catch {
|
|
36948
|
+
return false;
|
|
36949
|
+
}
|
|
36950
|
+
}
|
|
36951
|
+
async function removeOwnedLegacyCodexPluginFolder(homeDir) {
|
|
36952
|
+
const canonicalPath = path24.join(homeDir, "plugins", "memorix");
|
|
36953
|
+
const legacyPath = path24.join(homeDir, ".codex", "plugins", "memorix");
|
|
36954
|
+
if (!existsSync12(legacyPath)) return "missing";
|
|
36955
|
+
if (!existsSync12(canonicalPath)) return "preserved";
|
|
36956
|
+
try {
|
|
36957
|
+
const manifest = JSON.parse(await readFile5(path24.join(legacyPath, ".codex-plugin", "plugin.json"), "utf-8"));
|
|
36958
|
+
const repository = String(manifest.repository ?? "");
|
|
36959
|
+
if (manifest.name !== "memorix" || !repository.includes("github.com/AVIDS2/memorix")) return "preserved";
|
|
36960
|
+
await rm(legacyPath, { recursive: true, force: true });
|
|
36961
|
+
return "removed";
|
|
36962
|
+
} catch {
|
|
36963
|
+
return "preserved";
|
|
36964
|
+
}
|
|
36965
|
+
}
|
|
36966
|
+
async function migrateLegacyCodexIntegration(options2 = {}) {
|
|
36967
|
+
const homeDir = options2.homeDir ?? homedir24();
|
|
36968
|
+
const projectRoot = options2.projectRoot ?? process.cwd();
|
|
36969
|
+
const configPath = path24.join(homeDir, ".codex", "config.toml");
|
|
36970
|
+
let mcp = "missing";
|
|
36971
|
+
try {
|
|
36972
|
+
const content = await readFile5(configPath, "utf-8");
|
|
36973
|
+
if (getTomlSection(content, "mcp_servers.memorix") !== null) {
|
|
36974
|
+
mcp = (await removeLegacyCodexMemorixMcpConfig(configPath)).removed ? "removed" : "preserved";
|
|
36975
|
+
}
|
|
36976
|
+
} catch {
|
|
36977
|
+
mcp = "missing";
|
|
36978
|
+
}
|
|
36979
|
+
const hooksPath = path24.join(projectRoot, ".codex", "hooks.json");
|
|
36980
|
+
let projectHooks = "missing";
|
|
36981
|
+
try {
|
|
36982
|
+
const content = await readFile5(hooksPath, "utf-8");
|
|
36983
|
+
if (isOwnedLegacyCodexHooks(content)) {
|
|
36984
|
+
await rm(hooksPath, { force: true });
|
|
36985
|
+
projectHooks = "removed";
|
|
36986
|
+
} else {
|
|
36987
|
+
projectHooks = "preserved";
|
|
36988
|
+
}
|
|
36989
|
+
} catch {
|
|
36990
|
+
projectHooks = "missing";
|
|
36991
|
+
}
|
|
36992
|
+
const pluginFolder = await removeOwnedLegacyCodexPluginFolder(homeDir);
|
|
36993
|
+
return { mcp, projectHooks, pluginFolder };
|
|
36994
|
+
}
|
|
35807
36995
|
function mergeYamlMcpConfig(existingContent, generatedContent) {
|
|
35808
36996
|
let existing = {};
|
|
35809
36997
|
try {
|
|
@@ -35848,12 +37036,12 @@ async function installMcpConfig(options2) {
|
|
|
35848
37036
|
}
|
|
35849
37037
|
const generated = adapter.generate([server]);
|
|
35850
37038
|
const content = options2.agent === "codex" ? mergeTomlMcpConfig(existingContent, generated) : options2.agent === "hermes" ? mergeYamlMcpConfig(existingContent, generated) : mergeJsonMcpConfig(existingContent, generated);
|
|
35851
|
-
await mkdir5(
|
|
37039
|
+
await mkdir5(path24.dirname(configPath), { recursive: true });
|
|
35852
37040
|
await writeFile5(configPath, content, "utf-8");
|
|
35853
37041
|
return { agent: options2.agent, configPath, transport: options2.mcp };
|
|
35854
37042
|
}
|
|
35855
37043
|
async function upsertCodexMarketplace(marketplacePath, pluginPath) {
|
|
35856
|
-
await mkdir5(
|
|
37044
|
+
await mkdir5(path24.dirname(marketplacePath), { recursive: true });
|
|
35857
37045
|
let catalog;
|
|
35858
37046
|
try {
|
|
35859
37047
|
catalog = JSON.parse(await readFile5(marketplacePath, "utf-8"));
|
|
@@ -35866,9 +37054,9 @@ async function upsertCodexMarketplace(marketplacePath, pluginPath) {
|
|
|
35866
37054
|
plugins: []
|
|
35867
37055
|
};
|
|
35868
37056
|
}
|
|
35869
|
-
const marketplaceDir =
|
|
35870
|
-
const agentsDir =
|
|
35871
|
-
const marketplaceRoot =
|
|
37057
|
+
const marketplaceDir = path24.dirname(marketplacePath);
|
|
37058
|
+
const agentsDir = path24.dirname(marketplaceDir);
|
|
37059
|
+
const marketplaceRoot = path24.basename(agentsDir) === ".agents" ? path24.dirname(agentsDir) : marketplaceDir;
|
|
35872
37060
|
const sourcePath = relativePosix(marketplaceRoot, pluginPath);
|
|
35873
37061
|
const entry = {
|
|
35874
37062
|
name: "memorix",
|
|
@@ -35891,7 +37079,7 @@ async function upsertCodexMarketplace(marketplacePath, pluginPath) {
|
|
|
35891
37079
|
await writeFile5(marketplacePath, JSON.stringify(catalog, null, 2) + "\n", "utf-8");
|
|
35892
37080
|
}
|
|
35893
37081
|
async function writeClaudeMarketplace(marketplacePath) {
|
|
35894
|
-
await mkdir5(
|
|
37082
|
+
await mkdir5(path24.dirname(marketplacePath), { recursive: true });
|
|
35895
37083
|
const catalog = {
|
|
35896
37084
|
$schema: "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
35897
37085
|
name: "memorix-local",
|
|
@@ -35920,18 +37108,18 @@ async function writeClaudeMarketplace(marketplacePath) {
|
|
|
35920
37108
|
async function installPluginPackage(options2) {
|
|
35921
37109
|
const home = options2.homeDir ?? homedir24();
|
|
35922
37110
|
const packageRoot = findPackageRoot();
|
|
35923
|
-
const source =
|
|
37111
|
+
const source = path24.join(packageRoot, "plugins", options2.agent, "memorix");
|
|
35924
37112
|
const includeHooks = options2.includeHooks ?? true;
|
|
35925
37113
|
if (!existsSync12(source)) {
|
|
35926
37114
|
throw new Error(`Plugin package template not found: ${source}`);
|
|
35927
37115
|
}
|
|
35928
37116
|
if (options2.agent === "codex") {
|
|
35929
|
-
const pluginPath2 =
|
|
35930
|
-
const marketplacePath2 =
|
|
37117
|
+
const pluginPath2 = path24.join(home, "plugins", "memorix");
|
|
37118
|
+
const marketplacePath2 = path24.join(home, ".agents", "plugins", "marketplace.json");
|
|
35931
37119
|
await copyDir(source, pluginPath2);
|
|
35932
37120
|
await stampCodexPluginVersion(pluginPath2);
|
|
35933
37121
|
if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "codex");
|
|
35934
|
-
await writeOfficialSkills(
|
|
37122
|
+
await writeOfficialSkills(path24.join(pluginPath2, "skills"));
|
|
35935
37123
|
await upsertCodexMarketplace(marketplacePath2, pluginPath2);
|
|
35936
37124
|
return {
|
|
35937
37125
|
agent: "codex",
|
|
@@ -35941,22 +37129,22 @@ async function installPluginPackage(options2) {
|
|
|
35941
37129
|
};
|
|
35942
37130
|
}
|
|
35943
37131
|
if (options2.agent === "copilot") {
|
|
35944
|
-
const pluginPath2 =
|
|
37132
|
+
const pluginPath2 = path24.join(home, ".copilot", "plugins", "local", "memorix");
|
|
35945
37133
|
await copyDir(source, pluginPath2);
|
|
35946
37134
|
if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "copilot");
|
|
35947
|
-
await writeOfficialSkills(
|
|
37135
|
+
await writeOfficialSkills(path24.join(pluginPath2, "skills"));
|
|
35948
37136
|
return {
|
|
35949
37137
|
agent: "copilot",
|
|
35950
37138
|
pluginPath: pluginPath2,
|
|
35951
37139
|
installHint: "Run `copilot plugin install <path>` if automatic install is unavailable, then restart Copilot CLI."
|
|
35952
37140
|
};
|
|
35953
37141
|
}
|
|
35954
|
-
const marketplaceRoot =
|
|
35955
|
-
const marketplacePath =
|
|
35956
|
-
const pluginPath =
|
|
37142
|
+
const marketplaceRoot = path24.join(home, ".claude", "plugins", "marketplaces", "memorix-local");
|
|
37143
|
+
const marketplacePath = path24.join(marketplaceRoot, ".claude-plugin", "marketplace.json");
|
|
37144
|
+
const pluginPath = path24.join(marketplaceRoot, "plugins", "memorix");
|
|
35957
37145
|
await copyDir(source, pluginPath);
|
|
35958
37146
|
if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath, "claude");
|
|
35959
|
-
await writeOfficialSkills(
|
|
37147
|
+
await writeOfficialSkills(path24.join(pluginPath, "skills"));
|
|
35960
37148
|
await writeClaudeMarketplace(marketplacePath);
|
|
35961
37149
|
return {
|
|
35962
37150
|
agent: "claude",
|
|
@@ -35969,11 +37157,11 @@ async function installPluginPackage(options2) {
|
|
|
35969
37157
|
async function installGeminiExtensionPackage(options2 = {}) {
|
|
35970
37158
|
const home = options2.homeDir ?? homedir24();
|
|
35971
37159
|
const packageRoot = findPackageRoot();
|
|
35972
|
-
const source =
|
|
37160
|
+
const source = path24.join(packageRoot, "plugins", "gemini", "memorix");
|
|
35973
37161
|
if (!existsSync12(source)) {
|
|
35974
37162
|
throw new Error(`Gemini extension template not found: ${source}`);
|
|
35975
37163
|
}
|
|
35976
|
-
const extensionPath =
|
|
37164
|
+
const extensionPath = path24.join(home, ".gemini", "extensions", "memorix");
|
|
35977
37165
|
await copyDir(source, extensionPath);
|
|
35978
37166
|
return {
|
|
35979
37167
|
agent: "gemini-cli",
|
|
@@ -35983,16 +37171,16 @@ async function installGeminiExtensionPackage(options2 = {}) {
|
|
|
35983
37171
|
}
|
|
35984
37172
|
async function installAntigravityPluginPackage(options2 = {}) {
|
|
35985
37173
|
const packageRoot = findPackageRoot();
|
|
35986
|
-
const source =
|
|
37174
|
+
const source = path24.join(packageRoot, "plugins", "antigravity", "memorix");
|
|
35987
37175
|
if (!existsSync12(source)) {
|
|
35988
37176
|
throw new Error(`Antigravity plugin template not found: ${source}`);
|
|
35989
37177
|
}
|
|
35990
|
-
const pluginPath = options2.global === false ?
|
|
37178
|
+
const pluginPath = options2.global === false ? path24.join(options2.projectRoot ?? process.cwd(), ".agents", "plugins", "memorix") : path24.join(options2.homeDir ?? homedir24(), ".gemini", "config", "plugins", "memorix");
|
|
35991
37179
|
await copyDir(source, pluginPath);
|
|
35992
37180
|
if (options2.includeHooks === false) {
|
|
35993
|
-
await rm(
|
|
37181
|
+
await rm(path24.join(pluginPath, "hooks.json"), { force: true });
|
|
35994
37182
|
}
|
|
35995
|
-
await writeOfficialSkills(
|
|
37183
|
+
await writeOfficialSkills(path24.join(pluginPath, "skills"));
|
|
35996
37184
|
return {
|
|
35997
37185
|
agent: "antigravity",
|
|
35998
37186
|
pluginPath,
|
|
@@ -36001,14 +37189,14 @@ async function installAntigravityPluginPackage(options2 = {}) {
|
|
|
36001
37189
|
}
|
|
36002
37190
|
async function installPiPackage(options2 = {}) {
|
|
36003
37191
|
const packageRoot = findPackageRoot();
|
|
36004
|
-
const source =
|
|
37192
|
+
const source = path24.join(packageRoot, "plugins", "pi", "memorix");
|
|
36005
37193
|
if (!existsSync12(source)) {
|
|
36006
37194
|
throw new Error(`Pi package template not found: ${source}`);
|
|
36007
37195
|
}
|
|
36008
|
-
const defaultRoot = options2.global ?
|
|
36009
|
-
const packagePath = options2.packageDir ??
|
|
37196
|
+
const defaultRoot = options2.global ? path24.join(options2.homeDir ?? homedir24(), ".pi", "agent", "packages") : path24.join(process.cwd(), ".pi", "packages");
|
|
37197
|
+
const packagePath = options2.packageDir ?? path24.join(defaultRoot, "memorix");
|
|
36010
37198
|
await copyDir(source, packagePath);
|
|
36011
|
-
await writeOfficialSkills(
|
|
37199
|
+
await writeOfficialSkills(path24.join(packagePath, "skills"));
|
|
36012
37200
|
const installHint = options2.global ? `Setup runs \`pi install "${packagePath}" --approve\`. If Pi is unavailable, run that command after installing Pi.` : `Setup runs \`pi install "${packagePath}" -l --approve\`. If Pi is unavailable, run that command from the project root after installing Pi.`;
|
|
36013
37201
|
return {
|
|
36014
37202
|
agent: "pi",
|
|
@@ -36019,14 +37207,14 @@ async function installPiPackage(options2 = {}) {
|
|
|
36019
37207
|
async function installOpenClawBundlePackage(options2 = {}) {
|
|
36020
37208
|
const home = options2.homeDir ?? homedir24();
|
|
36021
37209
|
const packageRoot = findPackageRoot();
|
|
36022
|
-
const source =
|
|
37210
|
+
const source = path24.join(packageRoot, "plugins", "openclaw", "memorix");
|
|
36023
37211
|
if (!existsSync12(source)) {
|
|
36024
37212
|
throw new Error(`OpenClaw bundle template not found: ${source}`);
|
|
36025
37213
|
}
|
|
36026
|
-
const bundlePath =
|
|
37214
|
+
const bundlePath = path24.join(home, ".openclaw", "extensions", "memorix");
|
|
36027
37215
|
await copyDir(source, bundlePath);
|
|
36028
37216
|
if (options2.includeHooks === false) await stripHookCaptureFromOpenClawBundle(bundlePath);
|
|
36029
|
-
await writeOfficialSkills(
|
|
37217
|
+
await writeOfficialSkills(path24.join(bundlePath, "skills"));
|
|
36030
37218
|
return {
|
|
36031
37219
|
agent: "openclaw",
|
|
36032
37220
|
bundlePath,
|
|
@@ -36035,22 +37223,22 @@ async function installOpenClawBundlePackage(options2 = {}) {
|
|
|
36035
37223
|
}
|
|
36036
37224
|
async function installHermesPluginPackage(options2 = {}) {
|
|
36037
37225
|
const packageRoot = findPackageRoot();
|
|
36038
|
-
const source =
|
|
37226
|
+
const source = path24.join(packageRoot, "plugins", "hermes", "memorix");
|
|
36039
37227
|
if (!existsSync12(source)) {
|
|
36040
37228
|
throw new Error(`Hermes plugin template not found: ${source}`);
|
|
36041
37229
|
}
|
|
36042
37230
|
const hermesHome = resolveHermesHome(options2.homeDir);
|
|
36043
|
-
const pluginPath =
|
|
37231
|
+
const pluginPath = path24.join(hermesHome, "plugins", "memorix");
|
|
36044
37232
|
await copyDir(source, pluginPath);
|
|
36045
|
-
await writeOfficialSkills(
|
|
36046
|
-
const configPath =
|
|
37233
|
+
await writeOfficialSkills(path24.join(pluginPath, "skills"));
|
|
37234
|
+
const configPath = path24.join(hermesHome, "config.yaml");
|
|
36047
37235
|
let existingContent = null;
|
|
36048
37236
|
try {
|
|
36049
37237
|
existingContent = await readFile5(configPath, "utf-8");
|
|
36050
37238
|
} catch {
|
|
36051
37239
|
existingContent = null;
|
|
36052
37240
|
}
|
|
36053
|
-
await mkdir5(
|
|
37241
|
+
await mkdir5(path24.dirname(configPath), { recursive: true });
|
|
36054
37242
|
await writeFile5(configPath, mergeHermesPluginEnabled(existingContent, "memorix"), "utf-8");
|
|
36055
37243
|
return {
|
|
36056
37244
|
agent: "hermes",
|
|
@@ -36062,14 +37250,14 @@ async function installHermesPluginPackage(options2 = {}) {
|
|
|
36062
37250
|
}
|
|
36063
37251
|
async function installOmpPackage(options2 = {}) {
|
|
36064
37252
|
const packageRoot = findPackageRoot();
|
|
36065
|
-
const source =
|
|
37253
|
+
const source = path24.join(packageRoot, "plugins", "omp", "memorix");
|
|
36066
37254
|
if (!existsSync12(source)) {
|
|
36067
37255
|
throw new Error(`Oh-my-Pi package template not found: ${source}`);
|
|
36068
37256
|
}
|
|
36069
|
-
const defaultRoot = options2.global ?
|
|
36070
|
-
const packagePath = options2.packageDir ??
|
|
37257
|
+
const defaultRoot = options2.global ? path24.join(options2.homeDir ?? homedir24(), ".omp", "agent", "packages") : path24.join(process.cwd(), ".omp", "packages");
|
|
37258
|
+
const packagePath = options2.packageDir ?? path24.join(defaultRoot, "memorix");
|
|
36071
37259
|
await copyDir(source, packagePath);
|
|
36072
|
-
await writeOfficialSkills(
|
|
37260
|
+
await writeOfficialSkills(path24.join(packagePath, "skills"));
|
|
36073
37261
|
return {
|
|
36074
37262
|
agent: "omp",
|
|
36075
37263
|
packagePath,
|
|
@@ -36110,19 +37298,56 @@ ${install.stdout || ""}`.toLowerCase();
|
|
|
36110
37298
|
message: installDetail ? `claude: marketplace registered, but automatic plugin install did not finish: ${installDetail}` : "claude: marketplace registered. Run `claude plugin install memorix@memorix-local`."
|
|
36111
37299
|
};
|
|
36112
37300
|
}
|
|
37301
|
+
function parseCodexPluginState(content) {
|
|
37302
|
+
try {
|
|
37303
|
+
const start = content.indexOf("{");
|
|
37304
|
+
const end = content.lastIndexOf("}");
|
|
37305
|
+
if (start < 0 || end < start) return "unknown";
|
|
37306
|
+
const parsed = JSON.parse(content.slice(start, end + 1));
|
|
37307
|
+
if (!Array.isArray(parsed.installed)) return "unknown";
|
|
37308
|
+
const plugin = parsed.installed.find((entry) => Boolean(entry) && typeof entry === "object" && entry.pluginId === "memorix@personal");
|
|
37309
|
+
if (!plugin || plugin.installed !== true) return "missing";
|
|
37310
|
+
return plugin.enabled === true ? "ready" : "disabled";
|
|
37311
|
+
} catch {
|
|
37312
|
+
return "unknown";
|
|
37313
|
+
}
|
|
37314
|
+
}
|
|
37315
|
+
function getCodexPluginState() {
|
|
37316
|
+
const result = spawnSync("codex", ["plugin", "list", "--json"], {
|
|
37317
|
+
encoding: "utf-8",
|
|
37318
|
+
stdio: "pipe",
|
|
37319
|
+
shell: process.platform === "win32"
|
|
37320
|
+
});
|
|
37321
|
+
if (result.status !== 0) return "unknown";
|
|
37322
|
+
return parseCodexPluginState(result.stdout || "");
|
|
37323
|
+
}
|
|
36113
37324
|
function tryInstallCodexPlugin() {
|
|
36114
37325
|
const result = spawnSync("codex", ["plugin", "add", "memorix@personal", "--json"], {
|
|
36115
37326
|
encoding: "utf-8",
|
|
36116
37327
|
stdio: "pipe",
|
|
36117
37328
|
shell: process.platform === "win32"
|
|
36118
37329
|
});
|
|
36119
|
-
if (result.status === 0) {
|
|
36120
|
-
return { ok: true, message: "codex: plugin installed from Personal marketplace" };
|
|
36121
|
-
}
|
|
36122
37330
|
const output = `${result.stderr || ""}
|
|
36123
37331
|
${result.stdout || ""}`.toLowerCase();
|
|
36124
|
-
|
|
36125
|
-
|
|
37332
|
+
const addFinished = result.status === 0 || output.includes("already");
|
|
37333
|
+
if (addFinished) {
|
|
37334
|
+
const pluginState = getCodexPluginState();
|
|
37335
|
+
if (pluginState === "ready") {
|
|
37336
|
+
return {
|
|
37337
|
+
ok: true,
|
|
37338
|
+
message: result.status === 0 ? "codex: plugin installed and enabled from Personal marketplace" : "codex: plugin already installed and enabled from Personal marketplace"
|
|
37339
|
+
};
|
|
37340
|
+
}
|
|
37341
|
+
if (pluginState === "disabled") {
|
|
37342
|
+
return {
|
|
37343
|
+
ok: false,
|
|
37344
|
+
message: "codex: Memorix plugin is installed but disabled. Enable it in Codex Plugins before any legacy MCP or project hooks are removed."
|
|
37345
|
+
};
|
|
37346
|
+
}
|
|
37347
|
+
return {
|
|
37348
|
+
ok: false,
|
|
37349
|
+
message: "codex: plugin registration finished, but Codex did not confirm an enabled Memorix plugin. Legacy MCP and project hooks were kept unchanged."
|
|
37350
|
+
};
|
|
36126
37351
|
}
|
|
36127
37352
|
const detail = (result.stderr || result.stdout || result.error?.message || "").trim();
|
|
36128
37353
|
return {
|
|
@@ -36211,7 +37436,7 @@ ${hook.stdout || ""}`.toLowerCase();
|
|
|
36211
37436
|
}
|
|
36212
37437
|
function resolveHermesCommand(hermesHome) {
|
|
36213
37438
|
if (process.platform === "win32") {
|
|
36214
|
-
const localHermes =
|
|
37439
|
+
const localHermes = path24.join(hermesHome, "hermes-agent", "venv", "Scripts", "hermes.exe");
|
|
36215
37440
|
if (existsSync12(localHermes)) return localHermes;
|
|
36216
37441
|
}
|
|
36217
37442
|
return "hermes";
|
|
@@ -36268,14 +37493,14 @@ async function installAgentSetup(agent, plan, global2) {
|
|
|
36268
37493
|
const hasAntigravityPlugin = plan.actions.includes("antigravity-plugin") && agent === "antigravity";
|
|
36269
37494
|
const hasHermesPlugin = plan.actions.includes("hermes-plugin") && agent === "hermes";
|
|
36270
37495
|
const hasOmpPackage = plan.actions.includes("omp-package") && agent === "omp";
|
|
36271
|
-
const wantsMcpConfig = plan.mcp !== "none" && agent !== "pi";
|
|
37496
|
+
const wantsMcpConfig = plan.mcp !== "none" && agent !== "pi" && !(agent === "codex" && !global2);
|
|
36272
37497
|
if (PLUGIN_PACKAGE_AGENTS.has(agent) && plan.includePlugin && !global2) {
|
|
36273
37498
|
v3.info(`${agent}: project setup leaves user-level plugins untouched. Run \`memorix setup --agent ${agent} --global\` to install its plugin, skills, and lifecycle hooks.`);
|
|
36274
37499
|
}
|
|
36275
37500
|
if (hasPluginPackage) {
|
|
36276
37501
|
const result = await installPluginPackage({
|
|
36277
37502
|
agent,
|
|
36278
|
-
includeHooks: plan.
|
|
37503
|
+
includeHooks: plan.includeHooks
|
|
36279
37504
|
});
|
|
36280
37505
|
v3.success(`${agent}: plugin package -> ${result.pluginPath}`);
|
|
36281
37506
|
if (result.marketplacePath) {
|
|
@@ -36283,17 +37508,16 @@ async function installAgentSetup(agent, plan, global2) {
|
|
|
36283
37508
|
}
|
|
36284
37509
|
if (agent === "codex") {
|
|
36285
37510
|
const install = tryInstallCodexPlugin();
|
|
36286
|
-
if (install.ok) v3.success(install.message);
|
|
36287
|
-
else v3.warn(install.message);
|
|
36288
37511
|
if (install.ok) {
|
|
36289
|
-
|
|
36290
|
-
|
|
36291
|
-
|
|
36292
|
-
|
|
36293
|
-
|
|
36294
|
-
|
|
36295
|
-
|
|
36296
|
-
|
|
37512
|
+
v3.success(install.message);
|
|
37513
|
+
const migration = await migrateLegacyCodexIntegration({ projectRoot: process.cwd() });
|
|
37514
|
+
if (migration.mcp === "removed") v3.info("codex: removed the legacy source-path MCP block; the enabled plugin now owns MCP.");
|
|
37515
|
+
if (migration.mcp === "preserved") v3.warn("codex: kept a customized legacy Memorix MCP block; remove it manually only after confirming plugin MCP works.");
|
|
37516
|
+
if (migration.projectHooks === "removed") v3.info("codex: removed a legacy project-local Memorix hooks.json; plugin hooks now own lifecycle capture.");
|
|
37517
|
+
if (migration.projectHooks === "preserved") v3.warn("codex: kept a project .codex/hooks.json because it contains non-Memorix commands.");
|
|
37518
|
+
if (migration.pluginFolder === "removed") v3.info("codex: removed the migrated legacy plugin folder under ~/.codex/plugins.");
|
|
37519
|
+
} else {
|
|
37520
|
+
v3.warn(install.message);
|
|
36297
37521
|
}
|
|
36298
37522
|
} else if (agent === "claude" && result.marketplaceRoot) {
|
|
36299
37523
|
const install = tryInstallClaudePlugin(result.marketplaceRoot);
|
|
@@ -36371,6 +37595,8 @@ async function installAgentSetup(agent, plan, global2) {
|
|
|
36371
37595
|
const result = await installMcpConfig({ agent, projectRoot: targetRoot, global: global2, mcp });
|
|
36372
37596
|
v3.success(`${agent}: MCP config -> ${result.configPath}`);
|
|
36373
37597
|
}
|
|
37598
|
+
} else if (agent === "codex" && !global2 && plan.mcp !== "none") {
|
|
37599
|
+
v3.info("codex: project-local .codex config is intentionally untouched. Run `memorix setup --agent codex --global` to install the user-level plugin.");
|
|
36374
37600
|
}
|
|
36375
37601
|
if (hasPluginPackage) {
|
|
36376
37602
|
if (plan.actions.includes("project-guidance") && (agent === "claude" || agent === "codex")) {
|
|
@@ -36463,7 +37689,7 @@ var init_setup = __esm({
|
|
|
36463
37689
|
ANTIGRAVITY_PLUGIN_AGENTS = /* @__PURE__ */ new Set(["antigravity"]);
|
|
36464
37690
|
HERMES_PLUGIN_AGENTS = /* @__PURE__ */ new Set(["hermes"]);
|
|
36465
37691
|
OMP_PACKAGE_AGENTS = /* @__PURE__ */ new Set(["omp"]);
|
|
36466
|
-
PACKAGE_OWNED_INTEGRATION_AGENTS = /* @__PURE__ */ new Set(["antigravity", "openclaw", "hermes", "omp"]);
|
|
37692
|
+
PACKAGE_OWNED_INTEGRATION_AGENTS = /* @__PURE__ */ new Set(["codex", "antigravity", "openclaw", "hermes", "omp"]);
|
|
36467
37693
|
SUPPORTED_SETUP_AGENTS = [
|
|
36468
37694
|
"claude",
|
|
36469
37695
|
"codex",
|
|
@@ -37022,6 +38248,7 @@ function receiptOmissionKind(raw) {
|
|
|
37022
38248
|
if (raw.includes("state")) return "code-state";
|
|
37023
38249
|
if (raw.includes("semantic")) return "semantic-code";
|
|
37024
38250
|
if (raw.includes("start")) return "start-here";
|
|
38251
|
+
if (raw.includes("durable-memory")) return "durable-memory";
|
|
37025
38252
|
if (raw.includes("memory")) return "memory";
|
|
37026
38253
|
if (raw.includes("claim")) return "claim";
|
|
37027
38254
|
if (raw.includes("knowledge-page")) return "knowledge-page";
|
|
@@ -37280,6 +38507,26 @@ function renderTaskWorksetPrompt(input) {
|
|
|
37280
38507
|
});
|
|
37281
38508
|
}
|
|
37282
38509
|
}
|
|
38510
|
+
if (input.durableMemory.length > 0) {
|
|
38511
|
+
appendLine(lines, "", maxTokens, omitted, "durable-memory-heading");
|
|
38512
|
+
appendLine(lines, "Durable memory", maxTokens, omitted, "durable-memory-heading");
|
|
38513
|
+
for (const memory of input.durableMemory.slice(0, 3)) {
|
|
38514
|
+
appendLine(
|
|
38515
|
+
lines,
|
|
38516
|
+
"- " + memory.kind + " (" + memory.scope + ", " + memory.state + "; ref durable:" + memory.id + "): " + memory.summary,
|
|
38517
|
+
maxTokens,
|
|
38518
|
+
omitted,
|
|
38519
|
+
"durable-memory",
|
|
38520
|
+
selected,
|
|
38521
|
+
{
|
|
38522
|
+
kind: "durable-memory",
|
|
38523
|
+
id: "durable:" + memory.id,
|
|
38524
|
+
reason: memory.reason,
|
|
38525
|
+
trust: "source-backed"
|
|
38526
|
+
}
|
|
38527
|
+
);
|
|
38528
|
+
}
|
|
38529
|
+
}
|
|
37283
38530
|
if (input.workflows.length > 0) {
|
|
37284
38531
|
appendLine(lines, "", maxTokens, omitted, "workflow-heading");
|
|
37285
38532
|
appendLine(lines, "Project workflow", maxTokens, omitted, "workflow-heading");
|
|
@@ -37349,6 +38596,32 @@ async function buildTaskWorkset(input) {
|
|
|
37349
38596
|
evidenceRefs: evidenceByClaim.get(claim.id).map((item) => item.id),
|
|
37350
38597
|
reason: selection.reasons[claim.id] ?? "source-qualified task match"
|
|
37351
38598
|
}));
|
|
38599
|
+
let durableMemory = [];
|
|
38600
|
+
let durableEvidence = [];
|
|
38601
|
+
if (task) {
|
|
38602
|
+
try {
|
|
38603
|
+
const selected = await selectLongTermMemoriesForTask({
|
|
38604
|
+
dataDir: input.dataDir,
|
|
38605
|
+
projectId: input.projectId,
|
|
38606
|
+
task,
|
|
38607
|
+
...input.reader?.agentId ? { agentId: input.reader.agentId } : {},
|
|
38608
|
+
...input.reader?.isTeamMember ? { isTeamMember: true } : {},
|
|
38609
|
+
limit: 3
|
|
38610
|
+
});
|
|
38611
|
+
durableMemory = selected.map((item) => ({
|
|
38612
|
+
id: item.memory.id,
|
|
38613
|
+
kind: item.memory.kind,
|
|
38614
|
+
scope: item.memory.scope,
|
|
38615
|
+
state: item.memory.state,
|
|
38616
|
+
title: item.memory.title,
|
|
38617
|
+
summary: renderLongTermMemorySummary(item.memory, 20),
|
|
38618
|
+
evidenceRefs: item.evidence.map((evidence) => evidence.id),
|
|
38619
|
+
reason: item.reason
|
|
38620
|
+
}));
|
|
38621
|
+
durableEvidence = selected.flatMap((item) => item.evidence);
|
|
38622
|
+
} catch {
|
|
38623
|
+
}
|
|
38624
|
+
}
|
|
37352
38625
|
let workspace;
|
|
37353
38626
|
let pages = [];
|
|
37354
38627
|
let workflows = [];
|
|
@@ -37388,7 +38661,10 @@ async function buildTaskWorkset(input) {
|
|
|
37388
38661
|
const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
|
|
37389
38662
|
claim,
|
|
37390
38663
|
evidenceByClaim.get(claim.id) ?? []
|
|
37391
|
-
))
|
|
38664
|
+
)).concat(
|
|
38665
|
+
durableMemory.map((memory) => "durable:" + memory.id),
|
|
38666
|
+
durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
|
|
38667
|
+
));
|
|
37392
38668
|
const verification = unique([
|
|
37393
38669
|
...workflows.flatMap((workflow) => workflow.verificationGates),
|
|
37394
38670
|
...input.verificationHints
|
|
@@ -37414,7 +38690,7 @@ async function buildTaskWorkset(input) {
|
|
|
37414
38690
|
} : {}
|
|
37415
38691
|
} : void 0;
|
|
37416
38692
|
const base = {
|
|
37417
|
-
version: "1.
|
|
38693
|
+
version: "1.3",
|
|
37418
38694
|
task,
|
|
37419
38695
|
lens: input.lens,
|
|
37420
38696
|
currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
|
|
@@ -37427,6 +38703,7 @@ async function buildTaskWorkset(input) {
|
|
|
37427
38703
|
hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
|
|
37428
38704
|
claims,
|
|
37429
38705
|
pages,
|
|
38706
|
+
durableMemory,
|
|
37430
38707
|
workflows,
|
|
37431
38708
|
cautions: normalizedCautions,
|
|
37432
38709
|
verification,
|
|
@@ -37443,7 +38720,7 @@ async function buildTaskWorkset(input) {
|
|
|
37443
38720
|
budget: { maxTokens }
|
|
37444
38721
|
});
|
|
37445
38722
|
const receipt = {
|
|
37446
|
-
version: "1.
|
|
38723
|
+
version: "1.3",
|
|
37447
38724
|
target: input.deliveryTarget ?? "project-context",
|
|
37448
38725
|
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
37449
38726
|
budget: {
|
|
@@ -37478,6 +38755,7 @@ var init_workset = __esm({
|
|
|
37478
38755
|
init_workspace();
|
|
37479
38756
|
init_workflow_store();
|
|
37480
38757
|
init_workflows();
|
|
38758
|
+
init_long_term();
|
|
37481
38759
|
CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
|
|
37482
38760
|
}
|
|
37483
38761
|
});
|
|
@@ -37490,7 +38768,7 @@ __export(current_facts_exports, {
|
|
|
37490
38768
|
});
|
|
37491
38769
|
import { execFileSync } from "child_process";
|
|
37492
38770
|
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
|
|
37493
|
-
import
|
|
38771
|
+
import path25 from "path";
|
|
37494
38772
|
function readTextIfExists(filePath) {
|
|
37495
38773
|
try {
|
|
37496
38774
|
if (!existsSync13(filePath)) return null;
|
|
@@ -37500,7 +38778,7 @@ function readTextIfExists(filePath) {
|
|
|
37500
38778
|
}
|
|
37501
38779
|
}
|
|
37502
38780
|
function readPackageVersion(rootPath) {
|
|
37503
|
-
const text = readTextIfExists(
|
|
38781
|
+
const text = readTextIfExists(path25.join(rootPath, "package.json"));
|
|
37504
38782
|
if (!text) return void 0;
|
|
37505
38783
|
try {
|
|
37506
38784
|
const parsed = JSON.parse(text);
|
|
@@ -37510,7 +38788,7 @@ function readPackageVersion(rootPath) {
|
|
|
37510
38788
|
}
|
|
37511
38789
|
}
|
|
37512
38790
|
function readLatestChangelog(rootPath) {
|
|
37513
|
-
const text = readTextIfExists(
|
|
38791
|
+
const text = readTextIfExists(path25.join(rootPath, "CHANGELOG.md"));
|
|
37514
38792
|
if (!text) return void 0;
|
|
37515
38793
|
const match = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
|
|
37516
38794
|
if (!match) return void 0;
|
|
@@ -37580,7 +38858,7 @@ function detectStaleProgressNotes(input) {
|
|
|
37580
38858
|
];
|
|
37581
38859
|
const notes = [];
|
|
37582
38860
|
for (const relPath of candidates) {
|
|
37583
|
-
const content = readTextIfExists(
|
|
38861
|
+
const content = readTextIfExists(path25.join(input.rootPath, relPath));
|
|
37584
38862
|
if (!content) continue;
|
|
37585
38863
|
const parsed = parseProgressNote(content);
|
|
37586
38864
|
const olderThanChangelog = compareDateStrings(parsed.lastUpdated, input.latestChangelog?.date);
|
|
@@ -37831,9 +39109,9 @@ async function inspectExternalCodeGraph(input) {
|
|
|
37831
39109
|
return { health, quality: providerQuality({ mode, health }) };
|
|
37832
39110
|
}
|
|
37833
39111
|
function safeRelativePath(projectRoot, value, exclude) {
|
|
37834
|
-
const
|
|
37835
|
-
if (!
|
|
37836
|
-
const absolute = resolve3(projectRoot,
|
|
39112
|
+
const path38 = safeText(value, 1024);
|
|
39113
|
+
if (!path38 || isAbsolute2(path38)) return void 0;
|
|
39114
|
+
const absolute = resolve3(projectRoot, path38);
|
|
37837
39115
|
const fromRoot = relative2(projectRoot, absolute);
|
|
37838
39116
|
if (!fromRoot || fromRoot === ".." || fromRoot.startsWith("..\\") || fromRoot.startsWith("../") || isAbsolute2(fromRoot)) return void 0;
|
|
37839
39117
|
const normalized = normalizeCodePath(fromRoot);
|
|
@@ -38115,15 +39393,15 @@ function countLanguages(files) {
|
|
|
38115
39393
|
}
|
|
38116
39394
|
return [...counts.entries()].map(([language, files2]) => ({ language, files: files2 })).sort((a3, b3) => a3.language.localeCompare(b3.language));
|
|
38117
39395
|
}
|
|
38118
|
-
function suggestedReadRank(
|
|
38119
|
-
const normalized =
|
|
39396
|
+
function suggestedReadRank(path38) {
|
|
39397
|
+
const normalized = path38.replace(/\\/g, "/");
|
|
38120
39398
|
if (normalized.startsWith("src/")) return 0;
|
|
38121
39399
|
if (normalized.startsWith("tests/") || normalized.startsWith("test/")) return 0;
|
|
38122
39400
|
if (normalized.startsWith("packages/") && normalized.includes("/src/")) return 2;
|
|
38123
39401
|
return 3;
|
|
38124
39402
|
}
|
|
38125
39403
|
function compactSuggestedReads(paths, limit = 8, exclude) {
|
|
38126
|
-
return uniq(paths).filter((
|
|
39404
|
+
return uniq(paths).filter((path38) => !isCodeGraphExcludedPath(path38, exclude)).sort((a3, b3) => suggestedReadRank(a3) - suggestedReadRank(b3)).slice(0, limit);
|
|
38127
39405
|
}
|
|
38128
39406
|
function collectGraph(store2, projectId, observations2, exclude) {
|
|
38129
39407
|
const files = store2.listFiles(projectId);
|
|
@@ -38163,14 +39441,14 @@ function collectGraph(store2, projectId, observations2, exclude) {
|
|
|
38163
39441
|
}
|
|
38164
39442
|
if (files.length === 0) {
|
|
38165
39443
|
for (const observation of observations2) {
|
|
38166
|
-
for (const
|
|
38167
|
-
if (!
|
|
38168
|
-
suggestedReads.push(
|
|
39444
|
+
for (const path38 of observation.filesModified ?? []) {
|
|
39445
|
+
if (!path38 || isCodeGraphExcludedPath(path38, exclude)) continue;
|
|
39446
|
+
suggestedReads.push(path38);
|
|
38169
39447
|
sources.push({
|
|
38170
39448
|
observationId: observation.id,
|
|
38171
39449
|
title: observation.title,
|
|
38172
39450
|
type: observation.type,
|
|
38173
|
-
path:
|
|
39451
|
+
path: path38,
|
|
38174
39452
|
status: "unbound",
|
|
38175
39453
|
reason: "Recorded file hint; Code Memory refresh is pending."
|
|
38176
39454
|
});
|
|
@@ -38254,7 +39532,7 @@ function formatProjectContextOverview(overview) {
|
|
|
38254
39532
|
if (overview.suggestedReads.length === 0) {
|
|
38255
39533
|
lines.push("- none yet");
|
|
38256
39534
|
} else {
|
|
38257
|
-
overview.suggestedReads.slice(0, 8).forEach((
|
|
39535
|
+
overview.suggestedReads.slice(0, 8).forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
|
|
38258
39536
|
}
|
|
38259
39537
|
return lines.join("\n");
|
|
38260
39538
|
}
|
|
@@ -38295,8 +39573,8 @@ __export(graph_store_exports, {
|
|
|
38295
39573
|
initGraphStore: () => initGraphStore,
|
|
38296
39574
|
resetGraphStore: () => resetGraphStore
|
|
38297
39575
|
});
|
|
38298
|
-
import
|
|
38299
|
-
import
|
|
39576
|
+
import path26 from "path";
|
|
39577
|
+
import fs18 from "fs";
|
|
38300
39578
|
function safeJsonParse3(val, fallback) {
|
|
38301
39579
|
if (val == null || val === "") return fallback;
|
|
38302
39580
|
try {
|
|
@@ -38386,8 +39664,8 @@ var init_graph_store = __esm({
|
|
|
38386
39664
|
async migrateFromJsonlIfNeeded() {
|
|
38387
39665
|
const count3 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities`).get();
|
|
38388
39666
|
if (count3.cnt > 0) return;
|
|
38389
|
-
const jsonlPath =
|
|
38390
|
-
if (!
|
|
39667
|
+
const jsonlPath = path26.join(this.dataDir, "graph.jsonl");
|
|
39668
|
+
if (!fs18.existsSync(jsonlPath)) return;
|
|
38391
39669
|
try {
|
|
38392
39670
|
const data = await loadGraphJsonl(this.dataDir);
|
|
38393
39671
|
if (data.entities.length === 0 && data.relations.length === 0) return;
|
|
@@ -39129,8 +40407,8 @@ var compaction_checkpoint_store_exports = {};
|
|
|
39129
40407
|
__export(compaction_checkpoint_store_exports, {
|
|
39130
40408
|
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
39131
40409
|
});
|
|
39132
|
-
import { createHash as createHash12, randomUUID as
|
|
39133
|
-
function
|
|
40410
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
40411
|
+
function optionalText6(value) {
|
|
39134
40412
|
return typeof value === "string" && value ? value : void 0;
|
|
39135
40413
|
}
|
|
39136
40414
|
function optionalNumber2(value) {
|
|
@@ -39184,15 +40462,15 @@ function rowToCheckpoint(row) {
|
|
|
39184
40462
|
reason: row.reason,
|
|
39185
40463
|
sourceEvent: row.source_event,
|
|
39186
40464
|
sourceKey: row.source_key,
|
|
39187
|
-
...
|
|
40465
|
+
...optionalText6(row.summary) ? { summary: row.summary } : {},
|
|
39188
40466
|
...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
|
|
39189
|
-
...
|
|
40467
|
+
...optionalText6(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
|
|
39190
40468
|
...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
|
|
39191
40469
|
transcriptAvailable: Boolean(row.transcript_available),
|
|
39192
40470
|
status: row.status,
|
|
39193
40471
|
preCapturedAt: row.pre_captured_at,
|
|
39194
|
-
...
|
|
39195
|
-
...
|
|
40472
|
+
...optionalText6(row.completed_at) ? { completedAt: row.completed_at } : {},
|
|
40473
|
+
...optionalText6(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
|
|
39196
40474
|
deliveryCount: Number(row.delivery_count ?? 0),
|
|
39197
40475
|
createdAt: row.created_at,
|
|
39198
40476
|
updatedAt: row.updated_at
|
|
@@ -39230,7 +40508,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
39230
40508
|
if (pending) return rowToCheckpoint(pending);
|
|
39231
40509
|
const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
39232
40510
|
const checkpoint = {
|
|
39233
|
-
id:
|
|
40511
|
+
id: randomUUID12(),
|
|
39234
40512
|
projectId: input.projectId,
|
|
39235
40513
|
sessionId: input.sessionId,
|
|
39236
40514
|
agent: input.agent,
|
|
@@ -39238,7 +40516,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
39238
40516
|
captureKind: "preflight",
|
|
39239
40517
|
reason: safeReason(input.reason),
|
|
39240
40518
|
sourceEvent: input.sourceEvent,
|
|
39241
|
-
sourceKey: `pre:${
|
|
40519
|
+
sourceKey: `pre:${randomUUID12()}`,
|
|
39242
40520
|
transcriptAvailable: Boolean(input.transcriptAvailable),
|
|
39243
40521
|
status: "active",
|
|
39244
40522
|
preCapturedAt: now3,
|
|
@@ -39304,7 +40582,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
39304
40582
|
return this.get(checkpoint2.id);
|
|
39305
40583
|
}
|
|
39306
40584
|
const checkpoint = {
|
|
39307
|
-
id:
|
|
40585
|
+
id: randomUUID12(),
|
|
39308
40586
|
projectId: input.projectId,
|
|
39309
40587
|
sessionId: input.sessionId,
|
|
39310
40588
|
agent: input.agent,
|
|
@@ -39439,7 +40717,7 @@ __export(auto_context_exports, {
|
|
|
39439
40717
|
formatLegacyAutoProjectContextPrompt: () => formatLegacyAutoProjectContextPrompt
|
|
39440
40718
|
});
|
|
39441
40719
|
import { existsSync as existsSync15, statSync as statSync4 } from "fs";
|
|
39442
|
-
import
|
|
40720
|
+
import path27 from "path";
|
|
39443
40721
|
function activeProjectObservations(observations2, projectId) {
|
|
39444
40722
|
return observations2.filter((obs) => obs.projectId === projectId && (obs.status ?? "active") === "active");
|
|
39445
40723
|
}
|
|
@@ -39674,6 +40952,7 @@ async function buildAutoProjectContext(input) {
|
|
|
39674
40952
|
stale: overview.freshness.stale
|
|
39675
40953
|
},
|
|
39676
40954
|
runtimeCautions,
|
|
40955
|
+
...input.reader ? { reader: input.reader } : {},
|
|
39677
40956
|
...input.deliveryTarget ? { deliveryTarget: input.deliveryTarget } : {}
|
|
39678
40957
|
});
|
|
39679
40958
|
return {
|
|
@@ -39718,7 +40997,7 @@ function dedupeSourcesByObservation(sources) {
|
|
|
39718
40997
|
function existingLensCandidates(rootPath, lens) {
|
|
39719
40998
|
const out = [];
|
|
39720
40999
|
for (const candidate2 of lensPathCandidates(lens)) {
|
|
39721
|
-
const absolute =
|
|
41000
|
+
const absolute = path27.join(rootPath, candidate2);
|
|
39722
41001
|
try {
|
|
39723
41002
|
if (!existsSync15(absolute)) continue;
|
|
39724
41003
|
const stat = statSync4(absolute);
|
|
@@ -39828,7 +41107,7 @@ function formatAutoProjectContextSummary(context) {
|
|
|
39828
41107
|
"Start here"
|
|
39829
41108
|
].filter(Boolean);
|
|
39830
41109
|
if (startHere.length > 0) {
|
|
39831
|
-
startHere.forEach((
|
|
41110
|
+
startHere.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
|
|
39832
41111
|
} else {
|
|
39833
41112
|
lines.push("- no code-bound reads yet; inspect the task-relevant files directly");
|
|
39834
41113
|
}
|
|
@@ -39837,6 +41116,14 @@ function formatAutoProjectContextSummary(context) {
|
|
|
39837
41116
|
"Reliable memory",
|
|
39838
41117
|
reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
|
|
39839
41118
|
);
|
|
41119
|
+
if (context.workset.durableMemory.length > 0) {
|
|
41120
|
+
lines.push("", "Durable memory");
|
|
41121
|
+
for (const memory of context.workset.durableMemory.slice(0, 3)) {
|
|
41122
|
+
lines.push(
|
|
41123
|
+
"- " + memory.kind + " (" + memory.scope + ", " + memory.state + "): " + compactContinuationText(memory.summary, 28)
|
|
41124
|
+
);
|
|
41125
|
+
}
|
|
41126
|
+
}
|
|
39840
41127
|
const continuation = context.workset.continuation;
|
|
39841
41128
|
if (continuation?.previousSession || continuation?.memories.length || continuation?.compactCheckpoint) {
|
|
39842
41129
|
lines.push("", "Resume from prior work");
|
|
@@ -39886,7 +41173,7 @@ function formatLegacyAutoProjectContextPrompt(context) {
|
|
|
39886
41173
|
if (startHere.length === 0) {
|
|
39887
41174
|
lines.push("- no code-bound reads yet; inspect the task-relevant code directly");
|
|
39888
41175
|
} else {
|
|
39889
|
-
startHere.forEach((
|
|
41176
|
+
startHere.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
|
|
39890
41177
|
}
|
|
39891
41178
|
const { reliableSources, cautionSources, hiddenReliableCount, hiddenCautionCount } = lensSourceSets(context);
|
|
39892
41179
|
lines.push("", "Reliable memory");
|
|
@@ -40354,6 +41641,7 @@ async function attachTaskWorkset(input) {
|
|
|
40354
41641
|
stale: input.pack.warnings.filter((warning) => warning.status === "stale").length
|
|
40355
41642
|
},
|
|
40356
41643
|
runtimeCautions: input.runtimeCautions,
|
|
41644
|
+
...input.reader ? { reader: input.reader } : {},
|
|
40357
41645
|
deliveryTarget: "context-pack"
|
|
40358
41646
|
});
|
|
40359
41647
|
return { ...input.pack, workset };
|
|
@@ -40364,7 +41652,7 @@ function buildContextPackPrompt(pack) {
|
|
|
40364
41652
|
const unboundMemories = pack.memories.filter((memory) => memory.status === "unbound");
|
|
40365
41653
|
const lines = ["## Task", pack.task, "", "## Reliable Memories"];
|
|
40366
41654
|
const visibleCodeFacts = pack.codeFacts.filter((fact) => !isCodeGraphExcludedPath(fact.path)).slice(0, 5);
|
|
40367
|
-
const visibleSuggestedReads = pack.suggestedReads.filter((
|
|
41655
|
+
const visibleSuggestedReads = pack.suggestedReads.filter((path38) => !isCodeGraphExcludedPath(path38)).slice(0, 5);
|
|
40368
41656
|
if (reliableMemories.length === 0) lines.push("- none");
|
|
40369
41657
|
for (const memory of reliableMemories) {
|
|
40370
41658
|
lines.push(`- #${memory.id} ${memory.status}: [${memory.type}] ${memory.title} (${memory.reason})`);
|
|
@@ -40388,7 +41676,7 @@ function buildContextPackPrompt(pack) {
|
|
|
40388
41676
|
}
|
|
40389
41677
|
lines.push("", "## Suggested Next Reads");
|
|
40390
41678
|
if (visibleSuggestedReads.length === 0) lines.push("- none");
|
|
40391
|
-
visibleSuggestedReads.forEach((
|
|
41679
|
+
visibleSuggestedReads.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
|
|
40392
41680
|
lines.push("", "## Suggested Verification");
|
|
40393
41681
|
if (pack.suggestedVerification.length === 0) lines.push("- none");
|
|
40394
41682
|
for (const command of pack.suggestedVerification) lines.push(`- ${command}`);
|
|
@@ -40601,7 +41889,8 @@ ${formatUsageHint()}`;
|
|
|
40601
41889
|
} : {},
|
|
40602
41890
|
...external.outline ? { semanticCode: external.outline } : {},
|
|
40603
41891
|
providerQuality: external.quality,
|
|
40604
|
-
...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {}
|
|
41892
|
+
...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
|
|
41893
|
+
reader
|
|
40605
41894
|
});
|
|
40606
41895
|
emitResult({ project, pack, providerQuality: external.quality }, buildContextPackPrompt(pack), asJson);
|
|
40607
41896
|
return;
|
|
@@ -42787,8 +44076,8 @@ var transfer_exports = {};
|
|
|
42787
44076
|
__export(transfer_exports, {
|
|
42788
44077
|
default: () => transfer_default
|
|
42789
44078
|
});
|
|
42790
|
-
import { promises as
|
|
42791
|
-
import
|
|
44079
|
+
import { promises as fs19 } from "fs";
|
|
44080
|
+
import path28 from "path";
|
|
42792
44081
|
async function readStandardInput() {
|
|
42793
44082
|
return new Promise((resolve6, reject) => {
|
|
42794
44083
|
let content = "";
|
|
@@ -42809,13 +44098,13 @@ async function readImportPayload(args, projectRoot) {
|
|
|
42809
44098
|
throw new Error("Choose exactly one import source: --data <json>, --file <path>, or --stdin.");
|
|
42810
44099
|
}
|
|
42811
44100
|
if (readFromStdin) return readStandardInput();
|
|
42812
|
-
if (file) return
|
|
44101
|
+
if (file) return fs19.readFile(path28.resolve(projectRoot, file), "utf8");
|
|
42813
44102
|
return data;
|
|
42814
44103
|
}
|
|
42815
44104
|
async function writeExportPayload(projectRoot, output, payload) {
|
|
42816
|
-
const outputPath =
|
|
42817
|
-
await
|
|
42818
|
-
await
|
|
44105
|
+
const outputPath = path28.resolve(projectRoot, output);
|
|
44106
|
+
await fs19.mkdir(path28.dirname(outputPath), { recursive: true });
|
|
44107
|
+
await fs19.writeFile(outputPath, payload, "utf8");
|
|
42819
44108
|
return outputPath;
|
|
42820
44109
|
}
|
|
42821
44110
|
var transfer_default;
|
|
@@ -44389,8 +45678,8 @@ var init_parseUtil = __esm({
|
|
|
44389
45678
|
init_errors2();
|
|
44390
45679
|
init_en();
|
|
44391
45680
|
makeIssue = (params) => {
|
|
44392
|
-
const { data, path:
|
|
44393
|
-
const fullPath = [...
|
|
45681
|
+
const { data, path: path38, errorMaps, issueData } = params;
|
|
45682
|
+
const fullPath = [...path38, ...issueData.path || []];
|
|
44394
45683
|
const fullIssue = {
|
|
44395
45684
|
...issueData,
|
|
44396
45685
|
path: fullPath
|
|
@@ -44427,15 +45716,15 @@ var init_parseUtil = __esm({
|
|
|
44427
45716
|
this.value = "aborted";
|
|
44428
45717
|
}
|
|
44429
45718
|
static mergeArray(status, results) {
|
|
44430
|
-
const
|
|
45719
|
+
const arrayValue3 = [];
|
|
44431
45720
|
for (const s2 of results) {
|
|
44432
45721
|
if (s2.status === "aborted")
|
|
44433
45722
|
return INVALID;
|
|
44434
45723
|
if (s2.status === "dirty")
|
|
44435
45724
|
status.dirty();
|
|
44436
|
-
|
|
45725
|
+
arrayValue3.push(s2.value);
|
|
44437
45726
|
}
|
|
44438
|
-
return { status: status.value, value:
|
|
45727
|
+
return { status: status.value, value: arrayValue3 };
|
|
44439
45728
|
}
|
|
44440
45729
|
static async mergeObjectAsync(status, pairs) {
|
|
44441
45730
|
const syncPairs = [];
|
|
@@ -44704,11 +45993,11 @@ var init_types3 = __esm({
|
|
|
44704
45993
|
init_parseUtil();
|
|
44705
45994
|
init_util2();
|
|
44706
45995
|
ParseInputLazyPath = class {
|
|
44707
|
-
constructor(parent, value,
|
|
45996
|
+
constructor(parent, value, path38, key) {
|
|
44708
45997
|
this._cachedPath = [];
|
|
44709
45998
|
this.parent = parent;
|
|
44710
45999
|
this.data = value;
|
|
44711
|
-
this._path =
|
|
46000
|
+
this._path = path38;
|
|
44712
46001
|
this._key = key;
|
|
44713
46002
|
}
|
|
44714
46003
|
get path() {
|
|
@@ -48461,7 +49750,7 @@ function collectCodeMemory(opts) {
|
|
|
48461
49750
|
if (status.indexedAt) lines.push(`Last scan: ${status.indexedAt}`);
|
|
48462
49751
|
if (suggestedReads.length > 0) {
|
|
48463
49752
|
lines.push("Suggested reads:");
|
|
48464
|
-
suggestedReads.forEach((
|
|
49753
|
+
suggestedReads.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
|
|
48465
49754
|
}
|
|
48466
49755
|
return lines.join("\n");
|
|
48467
49756
|
} catch {
|
|
@@ -48486,7 +49775,7 @@ __export(planner_exports, {
|
|
|
48486
49775
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
48487
49776
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
48488
49777
|
});
|
|
48489
|
-
import { randomUUID as
|
|
49778
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
48490
49779
|
function isPlannerTask(metadata) {
|
|
48491
49780
|
if (!metadata) return null;
|
|
48492
49781
|
try {
|
|
@@ -48544,7 +49833,7 @@ function seedAutonomousPipeline(teamStore, projectId, config2, opts) {
|
|
|
48544
49833
|
const maxIterations = config2.maxIterations ?? 3;
|
|
48545
49834
|
const taskBudget = config2.taskBudget ?? 15;
|
|
48546
49835
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
48547
|
-
const pipelineId =
|
|
49836
|
+
const pipelineId = randomUUID13();
|
|
48548
49837
|
const meta = {
|
|
48549
49838
|
plannerType: "plan",
|
|
48550
49839
|
pipelineId,
|
|
@@ -49465,7 +50754,7 @@ __export(receipt_service_exports, {
|
|
|
49465
50754
|
});
|
|
49466
50755
|
import { createHash as createHash13 } from "crypto";
|
|
49467
50756
|
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
49468
|
-
import
|
|
50757
|
+
import path29 from "path";
|
|
49469
50758
|
function sha256(value) {
|
|
49470
50759
|
return `sha256:${createHash13("sha256").update(value).digest("hex")}`;
|
|
49471
50760
|
}
|
|
@@ -49494,7 +50783,7 @@ function safeJsonArray(value) {
|
|
|
49494
50783
|
}
|
|
49495
50784
|
}
|
|
49496
50785
|
async function loadReceiptObservations(dataDir, projectId) {
|
|
49497
|
-
const dbPath =
|
|
50786
|
+
const dbPath = path29.join(dataDir, "memorix.db");
|
|
49498
50787
|
if (existsSync18(dbPath)) {
|
|
49499
50788
|
try {
|
|
49500
50789
|
const DB = loadBetterSqlite3();
|
|
@@ -49511,7 +50800,7 @@ async function loadReceiptObservations(dataDir, projectId) {
|
|
|
49511
50800
|
} catch {
|
|
49512
50801
|
}
|
|
49513
50802
|
}
|
|
49514
|
-
const jsonPath =
|
|
50803
|
+
const jsonPath = path29.join(dataDir, "observations.json");
|
|
49515
50804
|
if (!existsSync18(jsonPath)) return [];
|
|
49516
50805
|
try {
|
|
49517
50806
|
const parsed = JSON.parse(readFileSync12(jsonPath, "utf-8"));
|
|
@@ -49932,10 +51221,10 @@ function assignProp(target, prop, value) {
|
|
|
49932
51221
|
configurable: true
|
|
49933
51222
|
});
|
|
49934
51223
|
}
|
|
49935
|
-
function getElementAtPath(obj,
|
|
49936
|
-
if (!
|
|
51224
|
+
function getElementAtPath(obj, path38) {
|
|
51225
|
+
if (!path38)
|
|
49937
51226
|
return obj;
|
|
49938
|
-
return
|
|
51227
|
+
return path38.reduce((acc, key) => acc?.[key], obj);
|
|
49939
51228
|
}
|
|
49940
51229
|
function promiseAllObject(promisesObj) {
|
|
49941
51230
|
const keys = Object.keys(promisesObj);
|
|
@@ -50184,11 +51473,11 @@ function aborted(x3, startIndex = 0) {
|
|
|
50184
51473
|
}
|
|
50185
51474
|
return false;
|
|
50186
51475
|
}
|
|
50187
|
-
function prefixIssues(
|
|
51476
|
+
function prefixIssues(path38, issues) {
|
|
50188
51477
|
return issues.map((iss) => {
|
|
50189
51478
|
var _a;
|
|
50190
51479
|
(_a = iss).path ?? (_a.path = []);
|
|
50191
|
-
iss.path.unshift(
|
|
51480
|
+
iss.path.unshift(path38);
|
|
50192
51481
|
return iss;
|
|
50193
51482
|
});
|
|
50194
51483
|
}
|
|
@@ -62494,8 +63783,8 @@ var require_utils2 = __commonJS({
|
|
|
62494
63783
|
}
|
|
62495
63784
|
return ind;
|
|
62496
63785
|
}
|
|
62497
|
-
function removeDotSegments(
|
|
62498
|
-
let input =
|
|
63786
|
+
function removeDotSegments(path38) {
|
|
63787
|
+
let input = path38;
|
|
62499
63788
|
const output = [];
|
|
62500
63789
|
let nextSlash = -1;
|
|
62501
63790
|
let len = 0;
|
|
@@ -62748,8 +64037,8 @@ var require_schemes = __commonJS({
|
|
|
62748
64037
|
wsComponent.secure = void 0;
|
|
62749
64038
|
}
|
|
62750
64039
|
if (wsComponent.resourceName) {
|
|
62751
|
-
const [
|
|
62752
|
-
wsComponent.path =
|
|
64040
|
+
const [path38, query] = wsComponent.resourceName.split("?");
|
|
64041
|
+
wsComponent.path = path38 && path38 !== "/" ? path38 : void 0;
|
|
62753
64042
|
wsComponent.query = query;
|
|
62754
64043
|
wsComponent.resourceName = void 0;
|
|
62755
64044
|
}
|
|
@@ -66188,12 +67477,12 @@ var require_dist = __commonJS({
|
|
|
66188
67477
|
throw new Error(`Unknown format "${name}"`);
|
|
66189
67478
|
return f4;
|
|
66190
67479
|
};
|
|
66191
|
-
function addFormats(ajv, list,
|
|
67480
|
+
function addFormats(ajv, list, fs28, exportName) {
|
|
66192
67481
|
var _a;
|
|
66193
67482
|
var _b;
|
|
66194
67483
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
66195
67484
|
for (const f4 of list)
|
|
66196
|
-
ajv.addFormat(f4,
|
|
67485
|
+
ajv.addFormat(f4, fs28[f4]);
|
|
66197
67486
|
}
|
|
66198
67487
|
module2.exports = exports2 = formatsPlugin;
|
|
66199
67488
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -68669,8 +69958,8 @@ var syncer_exports = {};
|
|
|
68669
69958
|
__export(syncer_exports, {
|
|
68670
69959
|
RulesSyncer: () => RulesSyncer
|
|
68671
69960
|
});
|
|
68672
|
-
import { promises as
|
|
68673
|
-
import
|
|
69961
|
+
import { promises as fs20 } from "fs";
|
|
69962
|
+
import path30 from "path";
|
|
68674
69963
|
var RulesSyncer;
|
|
68675
69964
|
var init_syncer = __esm({
|
|
68676
69965
|
"src/rules/syncer.ts"() {
|
|
@@ -68715,8 +70004,8 @@ var init_syncer = __esm({
|
|
|
68715
70004
|
const found = await this.findFiles(scanPath);
|
|
68716
70005
|
for (const filePath of found) {
|
|
68717
70006
|
try {
|
|
68718
|
-
const content = await
|
|
68719
|
-
const relativePath =
|
|
70007
|
+
const content = await fs20.readFile(filePath, "utf-8");
|
|
70008
|
+
const relativePath = path30.relative(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
68720
70009
|
const parsed = entry.adapter.parse(relativePath, content);
|
|
68721
70010
|
rules.push(...parsed);
|
|
68722
70011
|
} catch {
|
|
@@ -68784,7 +70073,7 @@ var init_syncer = __esm({
|
|
|
68784
70073
|
const entries = [];
|
|
68785
70074
|
for (const adapter of this.adapters.values()) {
|
|
68786
70075
|
const absolutePaths = adapter.filePatterns.map(
|
|
68787
|
-
(p2) =>
|
|
70076
|
+
(p2) => path30.join(this.projectRoot, p2)
|
|
68788
70077
|
);
|
|
68789
70078
|
entries.push({ adapter, paths: absolutePaths });
|
|
68790
70079
|
}
|
|
@@ -68792,13 +70081,13 @@ var init_syncer = __esm({
|
|
|
68792
70081
|
}
|
|
68793
70082
|
/** Find files matching a glob-like path (simple implementation) */
|
|
68794
70083
|
async findFiles(pattern) {
|
|
68795
|
-
const dir =
|
|
68796
|
-
const fileGlob =
|
|
70084
|
+
const dir = path30.dirname(pattern);
|
|
70085
|
+
const fileGlob = path30.basename(pattern);
|
|
68797
70086
|
try {
|
|
68798
|
-
const stat = await
|
|
70087
|
+
const stat = await fs20.stat(dir);
|
|
68799
70088
|
if (!stat.isDirectory()) {
|
|
68800
70089
|
try {
|
|
68801
|
-
await
|
|
70090
|
+
await fs20.access(pattern);
|
|
68802
70091
|
return [pattern];
|
|
68803
70092
|
} catch {
|
|
68804
70093
|
return [];
|
|
@@ -68806,7 +70095,7 @@ var init_syncer = __esm({
|
|
|
68806
70095
|
}
|
|
68807
70096
|
} catch {
|
|
68808
70097
|
try {
|
|
68809
|
-
await
|
|
70098
|
+
await fs20.access(pattern);
|
|
68810
70099
|
return [pattern];
|
|
68811
70100
|
} catch {
|
|
68812
70101
|
return [];
|
|
@@ -68814,16 +70103,16 @@ var init_syncer = __esm({
|
|
|
68814
70103
|
}
|
|
68815
70104
|
if (fileGlob.includes("*")) {
|
|
68816
70105
|
try {
|
|
68817
|
-
const files = await
|
|
70106
|
+
const files = await fs20.readdir(dir);
|
|
68818
70107
|
const ext = fileGlob.replace("*", "");
|
|
68819
|
-
return files.filter((f4) => ext ? f4.endsWith(ext) : true).map((f4) =>
|
|
70108
|
+
return files.filter((f4) => ext ? f4.endsWith(ext) : true).map((f4) => path30.join(dir, f4));
|
|
68820
70109
|
} catch {
|
|
68821
70110
|
return [];
|
|
68822
70111
|
}
|
|
68823
70112
|
}
|
|
68824
70113
|
try {
|
|
68825
|
-
await
|
|
68826
|
-
return [
|
|
70114
|
+
await fs20.access(path30.join(dir, fileGlob));
|
|
70115
|
+
return [path30.join(dir, fileGlob)];
|
|
68827
70116
|
} catch {
|
|
68828
70117
|
return [];
|
|
68829
70118
|
}
|
|
@@ -69058,10 +70347,10 @@ var init_engine3 = __esm({
|
|
|
69058
70347
|
pathsToCheck.push(join25(homedir29(), ".gemini", "antigravity", "mcp_config.json"));
|
|
69059
70348
|
}
|
|
69060
70349
|
const merged = /* @__PURE__ */ new Map();
|
|
69061
|
-
for (const
|
|
69062
|
-
if (existsSync20(
|
|
70350
|
+
for (const path38 of pathsToCheck) {
|
|
70351
|
+
if (existsSync20(path38)) {
|
|
69063
70352
|
try {
|
|
69064
|
-
const content = readFileSync13(
|
|
70353
|
+
const content = readFileSync13(path38, "utf-8");
|
|
69065
70354
|
const servers = adapter.parse(content);
|
|
69066
70355
|
for (const s2 of servers) {
|
|
69067
70356
|
if (!merged.has(s2.name)) merged.set(s2.name, s2);
|
|
@@ -70038,8 +71327,8 @@ __export(server_exports, {
|
|
|
70038
71327
|
startDashboard: () => startDashboard
|
|
70039
71328
|
});
|
|
70040
71329
|
import { createServer } from "http";
|
|
70041
|
-
import { promises as
|
|
70042
|
-
import
|
|
71330
|
+
import { promises as fs21 } from "fs";
|
|
71331
|
+
import path31 from "path";
|
|
70043
71332
|
import { exec } from "child_process";
|
|
70044
71333
|
function sendJson(res, data, status = 200) {
|
|
70045
71334
|
res.writeHead(status, {
|
|
@@ -70517,7 +71806,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
70517
71806
|
const aliasModule = await Promise.resolve().then(() => (init_aliases(), aliases_exports));
|
|
70518
71807
|
canonicalId = await aliasModule.getCanonicalId(effectiveProjectId);
|
|
70519
71808
|
const { promises: fsP } = await import("fs");
|
|
70520
|
-
const registryPath =
|
|
71809
|
+
const registryPath = path31.join(baseDir, ".project-aliases.json");
|
|
70521
71810
|
const raw = await fsP.readFile(registryPath, "utf-8");
|
|
70522
71811
|
const registry2 = JSON.parse(raw);
|
|
70523
71812
|
aliasGroups = registry2.groups || [];
|
|
@@ -70632,14 +71921,14 @@ async function serveStatic(req, res, staticDir) {
|
|
|
70632
71921
|
if (urlPath === "/" || !urlPath.includes(".")) {
|
|
70633
71922
|
urlPath = "/index.html";
|
|
70634
71923
|
}
|
|
70635
|
-
const filePath =
|
|
71924
|
+
const filePath = path31.join(staticDir, urlPath);
|
|
70636
71925
|
if (!filePath.startsWith(staticDir)) {
|
|
70637
71926
|
sendError(res, "Forbidden", 403);
|
|
70638
71927
|
return;
|
|
70639
71928
|
}
|
|
70640
71929
|
try {
|
|
70641
|
-
const data = await
|
|
70642
|
-
const ext =
|
|
71930
|
+
const data = await fs21.readFile(filePath);
|
|
71931
|
+
const ext = path31.extname(filePath);
|
|
70643
71932
|
res.writeHead(200, {
|
|
70644
71933
|
"Content-Type": MIME_TYPES[ext] || "application/octet-stream",
|
|
70645
71934
|
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
@@ -70649,7 +71938,7 @@ async function serveStatic(req, res, staticDir) {
|
|
|
70649
71938
|
res.end(data);
|
|
70650
71939
|
} catch {
|
|
70651
71940
|
try {
|
|
70652
|
-
const indexData = await
|
|
71941
|
+
const indexData = await fs21.readFile(path31.join(staticDir, "index.html"));
|
|
70653
71942
|
res.writeHead(200, {
|
|
70654
71943
|
"Content-Type": "text/html; charset=utf-8",
|
|
70655
71944
|
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
@@ -71090,9 +72379,9 @@ __export(hooks_path_exports, {
|
|
|
71090
72379
|
resolveHooksDir: () => resolveHooksDir
|
|
71091
72380
|
});
|
|
71092
72381
|
import { existsSync as existsSync22, readFileSync as readFileSync15, statSync as statSync5, mkdirSync as mkdirSync6 } from "fs";
|
|
71093
|
-
import
|
|
72382
|
+
import path32 from "path";
|
|
71094
72383
|
function resolveGitDir(projectRoot) {
|
|
71095
|
-
const dotGit =
|
|
72384
|
+
const dotGit = path32.join(projectRoot, ".git");
|
|
71096
72385
|
if (!existsSync22(dotGit)) return null;
|
|
71097
72386
|
const stat = statSync5(dotGit);
|
|
71098
72387
|
if (stat.isDirectory()) {
|
|
@@ -71104,7 +72393,7 @@ function resolveGitDir(projectRoot) {
|
|
|
71104
72393
|
const match = content.match(/^gitdir:\s*(.+)$/);
|
|
71105
72394
|
if (match) {
|
|
71106
72395
|
const gitdir = match[1].trim();
|
|
71107
|
-
const resolved =
|
|
72396
|
+
const resolved = path32.isAbsolute(gitdir) ? gitdir : path32.resolve(projectRoot, gitdir);
|
|
71108
72397
|
if (existsSync22(resolved)) {
|
|
71109
72398
|
return resolved;
|
|
71110
72399
|
}
|
|
@@ -71117,10 +72406,10 @@ function resolveGitDir(projectRoot) {
|
|
|
71117
72406
|
function resolveHooksDir(projectRoot) {
|
|
71118
72407
|
const gitDir = resolveGitDir(projectRoot);
|
|
71119
72408
|
if (!gitDir) return null;
|
|
71120
|
-
const hooksDir =
|
|
72409
|
+
const hooksDir = path32.join(gitDir, "hooks");
|
|
71121
72410
|
return {
|
|
71122
72411
|
hooksDir,
|
|
71123
|
-
hookPath:
|
|
72412
|
+
hookPath: path32.join(hooksDir, "post-commit")
|
|
71124
72413
|
};
|
|
71125
72414
|
}
|
|
71126
72415
|
function ensureHooksDir(projectRoot) {
|
|
@@ -71498,7 +72787,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
71498
72787
|
};
|
|
71499
72788
|
const server = existingServer ?? new McpServer({
|
|
71500
72789
|
name: "memorix",
|
|
71501
|
-
version: true ? "1.
|
|
72790
|
+
version: true ? "1.3.0" : "1.0.1"
|
|
71502
72791
|
});
|
|
71503
72792
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
71504
72793
|
server.registerTool = ((name, ...args) => {
|
|
@@ -71578,7 +72867,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
71578
72867
|
"memorix_store",
|
|
71579
72868
|
{
|
|
71580
72869
|
title: "Store Memory",
|
|
71581
|
-
description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity. For a read-only task, do not store unless the user explicitly asks to save a record.",
|
|
72870
|
+
description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity. Set longTerm only when the caller explicitly wants an additional source-backed long-term candidate; it is never injected until an operator records a review through the CLI. For a read-only task, do not store unless the user explicitly asks to save a record.",
|
|
71582
72871
|
inputSchema: {
|
|
71583
72872
|
entityName: external_exports.string().describe('The entity this observation belongs to (e.g., "auth-module", "port-config")'),
|
|
71584
72873
|
type: external_exports.enum(OBSERVATION_TYPES2).describe("Observation type for classification"),
|
|
@@ -71600,30 +72889,43 @@ The path should point to a directory containing a .git folder.`
|
|
|
71600
72889
|
visibility: external_exports.enum(["personal", "project", "team"]).optional().describe(
|
|
71601
72890
|
"Retrieval scope. Project is the normal shared default; personal/team require memorix_session_start with joinTeam=true."
|
|
71602
72891
|
),
|
|
72892
|
+
longTerm: external_exports.object({
|
|
72893
|
+
kind: external_exports.enum(["episodic", "semantic", "procedural"]).describe("Cognitive kind for an additional long-term candidate."),
|
|
72894
|
+
scope: external_exports.enum(["project", "user", "team"]).optional().default("project").describe("Long-term scope. User capture is private source evidence and needs a bound agent identity."),
|
|
72895
|
+
tags: external_exports.array(external_exports.string()).optional().describe("Small set of retrieval tags for the candidate."),
|
|
72896
|
+
applicability: external_exports.string().optional().describe("When this durable fact or procedure applies.")
|
|
72897
|
+
}).optional().describe("Optional explicit request to create a source-backed long-term candidate alongside this observation. Candidates are not automatically injected."),
|
|
71603
72898
|
overrideReadOnly: external_exports.boolean().optional().describe(
|
|
71604
72899
|
"Use only when the user explicitly asks to save memory during a read-only or no-modification task."
|
|
71605
72900
|
)
|
|
71606
72901
|
}
|
|
71607
72902
|
},
|
|
71608
|
-
async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities, visibility, overrideReadOnly }) => {
|
|
72903
|
+
async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities, visibility, longTerm, overrideReadOnly }) => {
|
|
71609
72904
|
const unresolved = requireResolvedProject("store memory in the current project");
|
|
71610
72905
|
if (unresolved) return unresolved;
|
|
71611
72906
|
const readOnlyBoundary = blockReadOnlyAutopilotWrite(overrideReadOnly);
|
|
71612
72907
|
if (readOnlyBoundary) return readOnlyBoundary;
|
|
71613
|
-
const requestedVisibility =
|
|
72908
|
+
const requestedVisibility = longTerm?.scope === "user" ? "personal" : longTerm?.scope === "team" ? "team" : visibility;
|
|
72909
|
+
const effectiveVisibility = requestedVisibility ?? "project";
|
|
71614
72910
|
const reader = getObservationReader();
|
|
71615
|
-
if (
|
|
72911
|
+
if (effectiveVisibility !== "project" && !currentAgentId) {
|
|
71616
72912
|
return {
|
|
71617
72913
|
content: [{ type: "text", text: "Personal or team memory requires memorix_session_start with joinTeam=true so Memorix can bind an owner." }],
|
|
71618
72914
|
isError: true
|
|
71619
72915
|
};
|
|
71620
72916
|
}
|
|
71621
|
-
if (
|
|
72917
|
+
if (effectiveVisibility === "team" && !reader.isTeamMember) {
|
|
71622
72918
|
return {
|
|
71623
72919
|
content: [{ type: "text", text: "Team memory requires an active coordination membership in the current project." }],
|
|
71624
72920
|
isError: true
|
|
71625
72921
|
};
|
|
71626
72922
|
}
|
|
72923
|
+
if (longTerm?.scope === "team" && !reader.isTeamMember) {
|
|
72924
|
+
return {
|
|
72925
|
+
content: [{ type: "text", text: "Team long-term memory requires an active coordination membership in the current project." }],
|
|
72926
|
+
isError: true
|
|
72927
|
+
};
|
|
72928
|
+
}
|
|
71627
72929
|
try {
|
|
71628
72930
|
return await withFreshIndex(async () => {
|
|
71629
72931
|
let entityName = rawEntityName;
|
|
@@ -71645,7 +72947,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
71645
72947
|
const useFormation = formationMode === "active";
|
|
71646
72948
|
let formationResult = null;
|
|
71647
72949
|
let formationNote = "";
|
|
71648
|
-
if (useFormation && !topicKey && !progress) {
|
|
72950
|
+
if (useFormation && !topicKey && !progress && !longTerm) {
|
|
71649
72951
|
let currentFormationStage = "setup";
|
|
71650
72952
|
const completedFormationStages = {};
|
|
71651
72953
|
const formationStartTime = Date.now();
|
|
@@ -71796,7 +73098,7 @@ ${modeIcon} Formation[active]: ${formationResult.evaluation.category} (${formati
|
|
|
71796
73098
|
}
|
|
71797
73099
|
let compactAction = "";
|
|
71798
73100
|
let compactMerged = false;
|
|
71799
|
-
if (!useFormation && !topicKey && !progress) {
|
|
73101
|
+
if (!useFormation && !topicKey && !progress && !longTerm) {
|
|
71800
73102
|
try {
|
|
71801
73103
|
const searchResult = await compactSearch({
|
|
71802
73104
|
query: `${title} ${narrative.substring(0, 200)}`,
|
|
@@ -71953,9 +73255,33 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
|
|
|
71953
73255
|
sourceDetail: "explicit",
|
|
71954
73256
|
valueCategory: formationResult?.evaluation.category,
|
|
71955
73257
|
createdByAgentId: currentAgentId,
|
|
71956
|
-
visibility,
|
|
73258
|
+
visibility: requestedVisibility,
|
|
71957
73259
|
visibilityReader: reader
|
|
71958
73260
|
});
|
|
73261
|
+
let longTermNote = "";
|
|
73262
|
+
if (longTerm) {
|
|
73263
|
+
try {
|
|
73264
|
+
const { promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
|
|
73265
|
+
const promoted = await promoteObservationToLongTermMemory2({
|
|
73266
|
+
dataDir: projectDir2,
|
|
73267
|
+
observation: obs,
|
|
73268
|
+
scope: longTerm.scope,
|
|
73269
|
+
kind: longTerm.kind,
|
|
73270
|
+
tags: longTerm.tags,
|
|
73271
|
+
applicability: longTerm.applicability,
|
|
73272
|
+
reader: {
|
|
73273
|
+
projectId: project.id,
|
|
73274
|
+
...reader.agentId ? { agentId: reader.agentId } : {},
|
|
73275
|
+
...reader.isTeamMember ? { isTeamMember: true } : {}
|
|
73276
|
+
}
|
|
73277
|
+
});
|
|
73278
|
+
longTermNote = `
|
|
73279
|
+
Long-term candidate: ${promoted.memory.id} (${promoted.memory.kind}/${promoted.memory.scope}). Review it with the CLI before it is delivered automatically.`;
|
|
73280
|
+
} catch (longTermError) {
|
|
73281
|
+
longTermNote = `
|
|
73282
|
+
[WARN] Observation stored, but long-term candidate was not created: ${longTermError instanceof Error ? longTermError.message : "unknown error"}`;
|
|
73283
|
+
}
|
|
73284
|
+
}
|
|
71959
73285
|
await graphManager.addObservations([
|
|
71960
73286
|
{ entityName, contents: [`[#${obs.id}] ${title}`] }
|
|
71961
73287
|
]);
|
|
@@ -71972,7 +73298,7 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
|
|
|
71972
73298
|
const enrichment = enrichmentParts.length > 0 ? `
|
|
71973
73299
|
Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
71974
73300
|
const action = upserted ? "[UPDATED] Updated" : "[OK] Stored";
|
|
71975
|
-
if (!useFormation && !topicKey && !progress) {
|
|
73301
|
+
if (!useFormation && !topicKey && !progress && !longTerm) {
|
|
71976
73302
|
const shadowFormation = async () => {
|
|
71977
73303
|
let oldCompactDecision = null;
|
|
71978
73304
|
try {
|
|
@@ -72062,7 +73388,7 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
72062
73388
|
{
|
|
72063
73389
|
type: "text",
|
|
72064
73390
|
text: `${action} observation #${obs.id} "${title}" (~${obs.tokens} tokens)
|
|
72065
|
-
Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ""}${compactAction}${compressionNote}${enrichment}${formationNote}${attributionWarning}`
|
|
73391
|
+
Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ""}${compactAction}${compressionNote}${enrichment}${formationNote}${attributionWarning}${longTermNote}`
|
|
72066
73392
|
}
|
|
72067
73393
|
]
|
|
72068
73394
|
};
|
|
@@ -72435,7 +73761,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
72435
73761
|
} : {},
|
|
72436
73762
|
...external.outline ? { semanticCode: external.outline } : {},
|
|
72437
73763
|
providerQuality: external.quality,
|
|
72438
|
-
...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {}
|
|
73764
|
+
...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
|
|
73765
|
+
reader: getObservationReader()
|
|
72439
73766
|
});
|
|
72440
73767
|
const text = buildContextPackPrompt2(pack);
|
|
72441
73768
|
return {
|
|
@@ -73109,7 +74436,7 @@ ${actions.join("\n")}`
|
|
|
73109
74436
|
"memorix_detail",
|
|
73110
74437
|
{
|
|
73111
74438
|
title: "Memory Details",
|
|
73112
|
-
description: 'Fetch full observation
|
|
74439
|
+
description: 'Fetch full observation, mini-skill, or curated durable-memory details \u2014 includes source kind (explicit memory / hook trace / git evidence), value category, and cross-references (~500-1000 tokens each). Do not re-fetch content already covered by a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Always use memorix_search first to find relevant IDs, then fetch only what you need. Accepts typed refs from search results (e.g. "obs:42", "skill:3") and durable refs from a project brief (e.g. "durable:<uuid>") via the typedRefs field, or legacy numeric ids / object refs for backward compatibility.',
|
|
73113
74440
|
inputSchema: {
|
|
73114
74441
|
ids: external_exports.array(external_exports.number()).optional().describe("Observation IDs to fetch (legacy, from memorix_search results)"),
|
|
73115
74442
|
refs: external_exports.array(
|
|
@@ -73118,7 +74445,7 @@ ${actions.join("\n")}`
|
|
|
73118
74445
|
projectId: external_exports.string().optional().describe("Project ID for global-search disambiguation")
|
|
73119
74446
|
})
|
|
73120
74447
|
).optional().describe("Explicit observation refs. Prefer this for global search results."),
|
|
73121
|
-
typedRefs: external_exports.array(external_exports.string()).optional().describe('Typed memory refs from search results, e.g. "obs:42", "skill:3", "obs:42@org/proj"'),
|
|
74448
|
+
typedRefs: external_exports.array(external_exports.string()).optional().describe('Typed memory refs from search results or a project brief, e.g. "obs:42", "skill:3", "durable:<uuid>", "obs:42@org/proj"'),
|
|
73122
74449
|
purpose: external_exports.string().optional().describe(
|
|
73123
74450
|
"Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
|
|
73124
74451
|
),
|
|
@@ -73131,14 +74458,19 @@ ${actions.join("\n")}`
|
|
|
73131
74458
|
const safeIds = coerceNumberArray(ids);
|
|
73132
74459
|
const safeRefs = coerceObservationRefs(refs);
|
|
73133
74460
|
const safeTypedRefs = coerceStringArray(typedRefs);
|
|
73134
|
-
const
|
|
74461
|
+
const durableIds = safeTypedRefs.flatMap((ref) => {
|
|
74462
|
+
const match = /^durable:([0-9a-f-]{36})$/i.exec(ref.trim());
|
|
74463
|
+
return match ? [match[1]] : [];
|
|
74464
|
+
});
|
|
74465
|
+
const observationTypedRefs = safeTypedRefs.filter((ref) => !/^durable:/i.test(ref.trim()));
|
|
74466
|
+
const hasCrossProjectRef = safeRefs.some((ref) => ref.projectId && ref.projectId !== project.id) || observationTypedRefs.some((ref) => ref.includes("@") && !ref.endsWith(`@${project.id}`));
|
|
73135
74467
|
if (!hasCrossProjectRef) {
|
|
73136
74468
|
const boundary = requireExplicitAutopilotExpansion("memorix_detail", purpose);
|
|
73137
74469
|
if (boundary) return boundary;
|
|
73138
74470
|
const requestedObservationIds = [
|
|
73139
74471
|
...safeIds,
|
|
73140
74472
|
...safeRefs.map((ref) => ref.id),
|
|
73141
|
-
...
|
|
74473
|
+
...observationTypedRefs.flatMap((ref) => {
|
|
73142
74474
|
const match = /^obs:(\d+)(?:@.+)?$/i.exec(ref.trim());
|
|
73143
74475
|
return match ? [Number(match[1])] : [];
|
|
73144
74476
|
})
|
|
@@ -73146,15 +74478,36 @@ ${actions.join("\n")}`
|
|
|
73146
74478
|
const duplicate = blockCoveredAutopilotEvidence("memorix_detail", requestedObservationIds, force);
|
|
73147
74479
|
if (duplicate) return duplicate;
|
|
73148
74480
|
}
|
|
73149
|
-
|
|
74481
|
+
const formatted = [];
|
|
73150
74482
|
try {
|
|
73151
|
-
|
|
73152
|
-
|
|
73153
|
-
|
|
73154
|
-
|
|
73155
|
-
|
|
73156
|
-
|
|
73157
|
-
|
|
74483
|
+
if (durableIds.length > 0) {
|
|
74484
|
+
const [{ getLongTermMemoryDetail: getLongTermMemoryDetail2 }, { resolveLocalMemoryOwner: resolveLocalMemoryOwner2 }] = await Promise.all([
|
|
74485
|
+
Promise.resolve().then(() => (init_long_term(), long_term_exports)),
|
|
74486
|
+
Promise.resolve().then(() => (init_owner(), owner_exports))
|
|
74487
|
+
]);
|
|
74488
|
+
const owner = await resolveLocalMemoryOwner2(projectDir2, { create: false });
|
|
74489
|
+
const observationReader = getObservationReader();
|
|
74490
|
+
const durableReader = {
|
|
74491
|
+
projectId: project.id,
|
|
74492
|
+
...owner ? { ownerId: owner.id } : {},
|
|
74493
|
+
...observationReader.agentId ? { agentId: observationReader.agentId } : {},
|
|
74494
|
+
...observationReader.isTeamMember ? { isTeamMember: true } : {}
|
|
74495
|
+
};
|
|
74496
|
+
const details = await Promise.all(durableIds.slice(0, 5).map(async (id) => {
|
|
74497
|
+
try {
|
|
74498
|
+
return await getLongTermMemoryDetail2({ dataDir: projectDir2, id, reader: durableReader });
|
|
74499
|
+
} catch (error2) {
|
|
74500
|
+
return { error: error2 instanceof Error ? error2.message : String(error2), id };
|
|
74501
|
+
}
|
|
74502
|
+
}));
|
|
74503
|
+
formatted.push(JSON.stringify({ durableMemory: details }, null, 2));
|
|
74504
|
+
}
|
|
74505
|
+
if (observationTypedRefs.length > 0 || safeRefs.length > 0 || safeIds.length > 0) {
|
|
74506
|
+
const reader = getObservationReader(hasCrossProjectRef ? "global" : "project");
|
|
74507
|
+
const result = observationTypedRefs.length > 0 ? await compactDetail(observationTypedRefs, { reader }) : safeRefs.length > 0 ? await compactDetail(safeRefs, { reader }) : await compactDetail(safeIds.map((id) => ({ id, projectId: project.id })), { reader });
|
|
74508
|
+
formatted.push(
|
|
74509
|
+
result.documents.length > 0 ? result.formatted : observationTypedRefs.length > 0 ? `No memories found for refs: ${observationTypedRefs.join(", ")}` : safeRefs.length > 0 ? `No memories found for refs: ${safeRefs.map((ref) => `${ref.projectId ?? "current"}#${ref.id}`).join(", ")}` : `No memories found for IDs: ${safeIds.join(", ")}`
|
|
74510
|
+
);
|
|
73158
74511
|
}
|
|
73159
74512
|
} catch (err) {
|
|
73160
74513
|
return { content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }], isError: true };
|
|
@@ -73163,7 +74516,7 @@ ${actions.join("\n")}`
|
|
|
73163
74516
|
content: [
|
|
73164
74517
|
{
|
|
73165
74518
|
type: "text",
|
|
73166
|
-
text:
|
|
74519
|
+
text: formatted.length > 0 ? formatted.join("\n\n") : safeTypedRefs.length > 0 ? `No memories found for refs: ${safeTypedRefs.join(", ")}` : safeRefs.length > 0 ? `No memories found for refs: ${safeRefs.map((ref) => `${ref.projectId ?? "current"}#${ref.id}`).join(", ")}` : `No memories found for IDs: ${safeIds.join(", ")}`
|
|
73167
74520
|
}
|
|
73168
74521
|
]
|
|
73169
74522
|
};
|
|
@@ -73883,9 +75236,9 @@ ${skill2.content}` }]
|
|
|
73883
75236
|
lines.push(`- **Description**: ${sk.description}`);
|
|
73884
75237
|
lines.push(`- **Observations**: ${sk.content.split("\n").length} lines of knowledge`);
|
|
73885
75238
|
if (write && target) {
|
|
73886
|
-
const
|
|
73887
|
-
if (
|
|
73888
|
-
lines.push(`- [OK] **Written**: \`${
|
|
75239
|
+
const path38 = engine.writeSkill(sk, target);
|
|
75240
|
+
if (path38) {
|
|
75241
|
+
lines.push(`- [OK] **Written**: \`${path38}\``);
|
|
73889
75242
|
} else {
|
|
73890
75243
|
lines.push(`- [ERROR] Failed to write`);
|
|
73891
75244
|
}
|
|
@@ -75717,8 +77070,8 @@ var init_serve = __esm({
|
|
|
75717
77070
|
safeCwd = homedir34();
|
|
75718
77071
|
}
|
|
75719
77072
|
const { existsSync: existsSync31, readFileSync: readFileSync23 } = await import("fs");
|
|
75720
|
-
const
|
|
75721
|
-
const lastRootFile =
|
|
77073
|
+
const path38 = await import("path");
|
|
77074
|
+
const lastRootFile = path38.join(homedir34(), ".memorix", "last-project-root");
|
|
75722
77075
|
let lastKnownProjectRoot;
|
|
75723
77076
|
if (existsSync31(lastRootFile)) {
|
|
75724
77077
|
try {
|
|
@@ -75753,9 +77106,9 @@ var init_serve = __esm({
|
|
|
75753
77106
|
if (detected) {
|
|
75754
77107
|
try {
|
|
75755
77108
|
const { writeFileSync: writeFileSync11, mkdirSync: mkdirSync11 } = await import("fs");
|
|
75756
|
-
const memorixDir =
|
|
77109
|
+
const memorixDir = path38.join(homedir34(), ".memorix");
|
|
75757
77110
|
mkdirSync11(memorixDir, { recursive: true });
|
|
75758
|
-
writeFileSync11(
|
|
77111
|
+
writeFileSync11(path38.join(memorixDir, "last-project-root"), detected.rootPath, "utf-8");
|
|
75759
77112
|
} catch {
|
|
75760
77113
|
}
|
|
75761
77114
|
}
|
|
@@ -77296,7 +78649,7 @@ var init_serve_http = __esm({
|
|
|
77296
78649
|
},
|
|
77297
78650
|
run: async ({ args }) => {
|
|
77298
78651
|
const { createServer: createServer2 } = await import("http");
|
|
77299
|
-
const { randomUUID:
|
|
78652
|
+
const { randomUUID: randomUUID14 } = await import("crypto");
|
|
77300
78653
|
const { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 } = await Promise.resolve().then(() => (init_streamableHttp(), streamableHttp_exports));
|
|
77301
78654
|
const { isInitializeRequest: isInitializeRequest2 } = await Promise.resolve().then(() => (init_types4(), types_exports));
|
|
77302
78655
|
const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
|
|
@@ -77480,7 +78833,7 @@ var init_serve_http = __esm({
|
|
|
77480
78833
|
if (!sessionId && isInitializeRequest2(body)) {
|
|
77481
78834
|
let createdState = null;
|
|
77482
78835
|
const transport = new StreamableHTTPServerTransport2({
|
|
77483
|
-
sessionIdGenerator: () =>
|
|
78836
|
+
sessionIdGenerator: () => randomUUID14(),
|
|
77484
78837
|
enableJsonResponse: true,
|
|
77485
78838
|
onsessioninitialized: (sid) => {
|
|
77486
78839
|
if (createdState) sessions.set(sid, createdState);
|
|
@@ -78847,8 +80200,8 @@ var init_sync = __esm({
|
|
|
78847
80200
|
}
|
|
78848
80201
|
const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
78849
80202
|
const { RulesSyncer: RulesSyncer2 } = await Promise.resolve().then(() => (init_syncer(), syncer_exports));
|
|
78850
|
-
const { promises:
|
|
78851
|
-
const
|
|
80203
|
+
const { promises: fs28 } = await import("fs");
|
|
80204
|
+
const path38 = await import("path");
|
|
78852
80205
|
we("memorix sync");
|
|
78853
80206
|
const project = detectProject2();
|
|
78854
80207
|
if (!project) {
|
|
@@ -78920,9 +80273,9 @@ var init_sync = __esm({
|
|
|
78920
80273
|
process.exit(0);
|
|
78921
80274
|
}
|
|
78922
80275
|
for (const file of files) {
|
|
78923
|
-
const fullPath =
|
|
78924
|
-
await
|
|
78925
|
-
await
|
|
80276
|
+
const fullPath = path38.join(project.rootPath, file.filePath);
|
|
80277
|
+
await fs28.mkdir(path38.dirname(fullPath), { recursive: true });
|
|
80278
|
+
await fs28.writeFile(fullPath, file.content, "utf-8");
|
|
78926
80279
|
v3.success(`Written: ${file.filePath}`);
|
|
78927
80280
|
}
|
|
78928
80281
|
fe2(`Synced ${files.length} rule(s) to ${target} format`);
|
|
@@ -80809,8 +82162,8 @@ var hooks_preview_exports = {};
|
|
|
80809
82162
|
__export(hooks_preview_exports, {
|
|
80810
82163
|
default: () => hooks_preview_default
|
|
80811
82164
|
});
|
|
80812
|
-
import * as
|
|
80813
|
-
import * as
|
|
82165
|
+
import * as fs22 from "fs/promises";
|
|
82166
|
+
import * as path33 from "path";
|
|
80814
82167
|
function estimateFileSize(agent, configPath) {
|
|
80815
82168
|
const sizes = {
|
|
80816
82169
|
claude: "~2KB",
|
|
@@ -80830,30 +82183,30 @@ function getRulesPath(agent, cwd, global2) {
|
|
|
80830
82183
|
if (global2) {
|
|
80831
82184
|
switch (agent) {
|
|
80832
82185
|
case "cursor":
|
|
80833
|
-
return
|
|
82186
|
+
return path33.join(home, ".cursor", "rules", "memorix.mdc");
|
|
80834
82187
|
case "codex":
|
|
80835
|
-
return
|
|
82188
|
+
return path33.join(home, ".codex", "AGENTS.md");
|
|
80836
82189
|
case "opencode":
|
|
80837
|
-
return
|
|
82190
|
+
return path33.join(home, ".config", "opencode", "AGENTS.md");
|
|
80838
82191
|
case "antigravity":
|
|
80839
|
-
return
|
|
82192
|
+
return path33.join(home, ".gemini", "GEMINI.md");
|
|
80840
82193
|
case "trae":
|
|
80841
|
-
return
|
|
82194
|
+
return path33.join(home, ".trae", "rules", "project_rules.md");
|
|
80842
82195
|
default:
|
|
80843
82196
|
return "";
|
|
80844
82197
|
}
|
|
80845
82198
|
} else {
|
|
80846
82199
|
switch (agent) {
|
|
80847
82200
|
case "cursor":
|
|
80848
|
-
return
|
|
82201
|
+
return path33.join(cwd, ".cursor", "rules", "memorix.mdc");
|
|
80849
82202
|
case "codex":
|
|
80850
|
-
return
|
|
82203
|
+
return path33.join(cwd, "AGENTS.md");
|
|
80851
82204
|
case "opencode":
|
|
80852
|
-
return
|
|
82205
|
+
return path33.join(cwd, "AGENTS.md");
|
|
80853
82206
|
case "antigravity":
|
|
80854
|
-
return
|
|
82207
|
+
return path33.join(cwd, "GEMINI.md");
|
|
80855
82208
|
case "trae":
|
|
80856
|
-
return
|
|
82209
|
+
return path33.join(cwd, ".trae", "rules", "project_rules.md");
|
|
80857
82210
|
default:
|
|
80858
82211
|
return "";
|
|
80859
82212
|
}
|
|
@@ -80910,7 +82263,7 @@ var init_hooks_preview = __esm({
|
|
|
80910
82263
|
const configPath = global2 ? getGlobalConfigPath2(agent) : getProjectConfigPath2(agent, cwd);
|
|
80911
82264
|
let action;
|
|
80912
82265
|
try {
|
|
80913
|
-
await
|
|
82266
|
+
await fs22.access(configPath);
|
|
80914
82267
|
action = "modify";
|
|
80915
82268
|
} catch {
|
|
80916
82269
|
action = "create";
|
|
@@ -80925,7 +82278,7 @@ var init_hooks_preview = __esm({
|
|
|
80925
82278
|
if (["cursor", "codex", "opencode", "antigravity", "trae"].includes(agent)) {
|
|
80926
82279
|
const rulesPath = getRulesPath(agent, cwd, global2);
|
|
80927
82280
|
try {
|
|
80928
|
-
await
|
|
82281
|
+
await fs22.access(rulesPath);
|
|
80929
82282
|
previewItems.push({
|
|
80930
82283
|
agent,
|
|
80931
82284
|
path: rulesPath,
|
|
@@ -80942,10 +82295,10 @@ var init_hooks_preview = __esm({
|
|
|
80942
82295
|
}
|
|
80943
82296
|
}
|
|
80944
82297
|
if (agent === "kiro") {
|
|
80945
|
-
const hooksDir =
|
|
82298
|
+
const hooksDir = path33.dirname(configPath);
|
|
80946
82299
|
previewItems.push({
|
|
80947
82300
|
agent,
|
|
80948
|
-
path:
|
|
82301
|
+
path: path33.join(hooksDir, "*.kiro.hook"),
|
|
80949
82302
|
action: "create",
|
|
80950
82303
|
size: "~500B each"
|
|
80951
82304
|
});
|
|
@@ -81716,9 +83069,9 @@ __export(ingest_image_exports, {
|
|
|
81716
83069
|
default: () => ingest_image_default
|
|
81717
83070
|
});
|
|
81718
83071
|
import { readFileSync as readFileSync16 } from "fs";
|
|
81719
|
-
import
|
|
83072
|
+
import path34 from "path";
|
|
81720
83073
|
function inferMimeType(filePath) {
|
|
81721
|
-
const ext =
|
|
83074
|
+
const ext = path34.extname(filePath).toLowerCase();
|
|
81722
83075
|
switch (ext) {
|
|
81723
83076
|
case ".jpg":
|
|
81724
83077
|
case ".jpeg":
|
|
@@ -81761,9 +83114,9 @@ var init_ingest_image = __esm({
|
|
|
81761
83114
|
return;
|
|
81762
83115
|
}
|
|
81763
83116
|
const { project, reader, identity } = await getCliProjectContext();
|
|
81764
|
-
const resolvedPath =
|
|
83117
|
+
const resolvedPath = path34.resolve(project.rootPath, imagePath);
|
|
81765
83118
|
const base642 = readFileSync16(resolvedPath).toString("base64");
|
|
81766
|
-
const filename =
|
|
83119
|
+
const filename = path34.basename(resolvedPath);
|
|
81767
83120
|
const analysis = await analyzeImage({
|
|
81768
83121
|
base64: base642,
|
|
81769
83122
|
filename,
|
|
@@ -82027,7 +83380,7 @@ __export(background_exports, {
|
|
|
82027
83380
|
doStart: () => doStart,
|
|
82028
83381
|
doStop: () => doStop
|
|
82029
83382
|
});
|
|
82030
|
-
import * as
|
|
83383
|
+
import * as fs23 from "fs";
|
|
82031
83384
|
import { spawn as spawn4, execSync as execSync5 } from "child_process";
|
|
82032
83385
|
import { randomBytes } from "crypto";
|
|
82033
83386
|
function getMemorixDir() {
|
|
@@ -82045,7 +83398,7 @@ function getLogFilePath() {
|
|
|
82045
83398
|
}
|
|
82046
83399
|
function loadState() {
|
|
82047
83400
|
try {
|
|
82048
|
-
const data =
|
|
83401
|
+
const data = fs23.readFileSync(getStateFilePath(), "utf-8");
|
|
82049
83402
|
return JSON.parse(data);
|
|
82050
83403
|
} catch {
|
|
82051
83404
|
return null;
|
|
@@ -82053,12 +83406,12 @@ function loadState() {
|
|
|
82053
83406
|
}
|
|
82054
83407
|
function saveState(state) {
|
|
82055
83408
|
const dir = getMemorixDir();
|
|
82056
|
-
if (!
|
|
82057
|
-
|
|
83409
|
+
if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
|
|
83410
|
+
fs23.writeFileSync(getStateFilePath(), JSON.stringify(state, null, 2));
|
|
82058
83411
|
}
|
|
82059
83412
|
function clearState() {
|
|
82060
83413
|
try {
|
|
82061
|
-
|
|
83414
|
+
fs23.unlinkSync(getStateFilePath());
|
|
82062
83415
|
} catch {
|
|
82063
83416
|
}
|
|
82064
83417
|
}
|
|
@@ -82125,7 +83478,7 @@ async function doStart(port) {
|
|
|
82125
83478
|
} else {
|
|
82126
83479
|
try {
|
|
82127
83480
|
const heartbeatPath = getMemorixDir() + "/background.heartbeat";
|
|
82128
|
-
const hbData =
|
|
83481
|
+
const hbData = fs23.readFileSync(heartbeatPath, "utf-8");
|
|
82129
83482
|
const hb = JSON.parse(hbData);
|
|
82130
83483
|
const age = Date.now() - hb.heartbeatAt;
|
|
82131
83484
|
if (age < 12e4) {
|
|
@@ -82133,7 +83486,7 @@ async function doStart(port) {
|
|
|
82133
83486
|
console.log(" The control plane likely crashed. Auto-restarting...");
|
|
82134
83487
|
}
|
|
82135
83488
|
try {
|
|
82136
|
-
|
|
83489
|
+
fs23.unlinkSync(heartbeatPath);
|
|
82137
83490
|
} catch {
|
|
82138
83491
|
}
|
|
82139
83492
|
} catch {
|
|
@@ -82154,19 +83507,19 @@ async function doStart(port) {
|
|
|
82154
83507
|
}
|
|
82155
83508
|
try {
|
|
82156
83509
|
const readyFile = getMemorixDir() + "/background.ready";
|
|
82157
|
-
if (
|
|
83510
|
+
if (fs23.existsSync(readyFile)) fs23.unlinkSync(readyFile);
|
|
82158
83511
|
} catch {
|
|
82159
83512
|
}
|
|
82160
83513
|
const logFile = getLogFilePath();
|
|
82161
83514
|
const dir = getMemorixDir();
|
|
82162
|
-
if (!
|
|
82163
|
-
if (
|
|
83515
|
+
if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
|
|
83516
|
+
if (fs23.existsSync(logFile)) {
|
|
82164
83517
|
try {
|
|
82165
|
-
|
|
83518
|
+
fs23.renameSync(logFile, logFile + ".prev");
|
|
82166
83519
|
} catch {
|
|
82167
83520
|
}
|
|
82168
83521
|
}
|
|
82169
|
-
const logFd =
|
|
83522
|
+
const logFd = fs23.openSync(logFile, "a");
|
|
82170
83523
|
const cliEntry = process.argv[1];
|
|
82171
83524
|
const child = spawn4(process.execPath, [cliEntry, "serve-http", "--port", String(port)], {
|
|
82172
83525
|
detached: true,
|
|
@@ -82176,7 +83529,7 @@ async function doStart(port) {
|
|
|
82176
83529
|
windowsHide: true
|
|
82177
83530
|
});
|
|
82178
83531
|
child.unref();
|
|
82179
|
-
|
|
83532
|
+
fs23.closeSync(logFd);
|
|
82180
83533
|
const pid = child.pid;
|
|
82181
83534
|
if (!pid) {
|
|
82182
83535
|
console.error("[ERROR] Failed to spawn background process");
|
|
@@ -82246,7 +83599,7 @@ async function doStop() {
|
|
|
82246
83599
|
console.log(`Background process (PID ${state.pid}) is not running. Cleaning up state.`);
|
|
82247
83600
|
clearState();
|
|
82248
83601
|
try {
|
|
82249
|
-
|
|
83602
|
+
fs23.unlinkSync(getMemorixDir() + "/background.ready");
|
|
82250
83603
|
} catch {
|
|
82251
83604
|
}
|
|
82252
83605
|
return;
|
|
@@ -82265,7 +83618,7 @@ async function doStop() {
|
|
|
82265
83618
|
}
|
|
82266
83619
|
clearState();
|
|
82267
83620
|
try {
|
|
82268
|
-
|
|
83621
|
+
fs23.unlinkSync(getMemorixDir() + "/background.ready");
|
|
82269
83622
|
} catch {
|
|
82270
83623
|
}
|
|
82271
83624
|
return;
|
|
@@ -82302,7 +83655,7 @@ async function doStop() {
|
|
|
82302
83655
|
}
|
|
82303
83656
|
clearState();
|
|
82304
83657
|
try {
|
|
82305
|
-
|
|
83658
|
+
fs23.unlinkSync(getMemorixDir() + "/background.ready");
|
|
82306
83659
|
} catch {
|
|
82307
83660
|
}
|
|
82308
83661
|
console.log("[OK] Control plane stopped.");
|
|
@@ -82378,7 +83731,7 @@ async function doStatus() {
|
|
|
82378
83731
|
console.log(" Process has exited. Cleaning up stale state...");
|
|
82379
83732
|
try {
|
|
82380
83733
|
const heartbeatPath = getMemorixDir() + "/background.heartbeat";
|
|
82381
|
-
const hbData =
|
|
83734
|
+
const hbData = fs23.readFileSync(heartbeatPath, "utf-8");
|
|
82382
83735
|
const hb = JSON.parse(hbData);
|
|
82383
83736
|
const age = Date.now() - hb.heartbeatAt;
|
|
82384
83737
|
if (age < 3e5) {
|
|
@@ -82419,26 +83772,26 @@ async function doEnsure(port) {
|
|
|
82419
83772
|
}
|
|
82420
83773
|
function doLogs(follow, lines) {
|
|
82421
83774
|
const logFile = getLogFilePath();
|
|
82422
|
-
if (!
|
|
83775
|
+
if (!fs23.existsSync(logFile)) {
|
|
82423
83776
|
console.log("No log file found. Start the background service first:");
|
|
82424
83777
|
console.log(" memorix background start");
|
|
82425
83778
|
return;
|
|
82426
83779
|
}
|
|
82427
83780
|
if (follow) {
|
|
82428
|
-
const content =
|
|
83781
|
+
const content = fs23.readFileSync(logFile, "utf-8");
|
|
82429
83782
|
const existingLines = content.split("\n");
|
|
82430
83783
|
const tail = existingLines.slice(-lines);
|
|
82431
83784
|
console.log(tail.join("\n"));
|
|
82432
83785
|
console.log("--- Following log (Ctrl+C to stop) ---");
|
|
82433
|
-
let position =
|
|
82434
|
-
const watcher =
|
|
83786
|
+
let position = fs23.statSync(logFile).size;
|
|
83787
|
+
const watcher = fs23.watch(logFile, () => {
|
|
82435
83788
|
try {
|
|
82436
|
-
const stat =
|
|
83789
|
+
const stat = fs23.statSync(logFile);
|
|
82437
83790
|
if (stat.size > position) {
|
|
82438
|
-
const fd =
|
|
83791
|
+
const fd = fs23.openSync(logFile, "r");
|
|
82439
83792
|
const buf = Buffer.alloc(stat.size - position);
|
|
82440
|
-
|
|
82441
|
-
|
|
83793
|
+
fs23.readSync(fd, buf, 0, buf.length, position);
|
|
83794
|
+
fs23.closeSync(fd);
|
|
82442
83795
|
process.stdout.write(buf.toString("utf-8"));
|
|
82443
83796
|
position = stat.size;
|
|
82444
83797
|
}
|
|
@@ -82448,7 +83801,7 @@ function doLogs(follow, lines) {
|
|
|
82448
83801
|
setInterval(() => {
|
|
82449
83802
|
}, 6e4);
|
|
82450
83803
|
} else {
|
|
82451
|
-
const content =
|
|
83804
|
+
const content = fs23.readFileSync(logFile, "utf-8");
|
|
82452
83805
|
const allLines = content.split("\n");
|
|
82453
83806
|
const tail = allLines.slice(-lines);
|
|
82454
83807
|
console.log(tail.join("\n"));
|
|
@@ -82633,7 +83986,7 @@ function asRecordArray(value) {
|
|
|
82633
83986
|
return Array.isArray(value) ? value.map(asRecord2).filter((entry) => entry !== null) : [];
|
|
82634
83987
|
}
|
|
82635
83988
|
function codexPluginPath() {
|
|
82636
|
-
return `${homedir32()}
|
|
83989
|
+
return `${homedir32()}/plugins/${CODEX_PLUGIN_NAME}`;
|
|
82637
83990
|
}
|
|
82638
83991
|
function codexPluginMcpPath() {
|
|
82639
83992
|
return `${codexPluginPath()}/.mcp.json`;
|
|
@@ -82652,7 +84005,10 @@ function isMemorixCodexPlugin(value) {
|
|
|
82652
84005
|
}
|
|
82653
84006
|
function parseCodexPluginList(output) {
|
|
82654
84007
|
try {
|
|
82655
|
-
const
|
|
84008
|
+
const start = output.indexOf("{");
|
|
84009
|
+
const end = output.lastIndexOf("}");
|
|
84010
|
+
if (start < 0 || end < start) return null;
|
|
84011
|
+
const parsed = asRecord2(JSON.parse(output.slice(start, end + 1)));
|
|
82656
84012
|
if (!parsed) return null;
|
|
82657
84013
|
const entries = [...asRecordArray(parsed.installed), ...asRecordArray(parsed.available)];
|
|
82658
84014
|
const plugin = entries.find(isMemorixCodexPlugin);
|
|
@@ -82795,7 +84151,7 @@ async function inspectCodexMarketplace() {
|
|
|
82795
84151
|
}
|
|
82796
84152
|
const source = asRecord2(entry.source);
|
|
82797
84153
|
const sourcePath = typeof source?.path === "string" ? source.path : "";
|
|
82798
|
-
const issues = source?.source === "local" && normalizeMarketplacePath(sourcePath) === "
|
|
84154
|
+
const issues = source?.source === "local" && normalizeMarketplacePath(sourcePath) === "plugins/memorix" ? [] : ["codex-marketplace-entry-stale"];
|
|
82799
84155
|
return {
|
|
82800
84156
|
scope: "global",
|
|
82801
84157
|
kind: "marketplace",
|
|
@@ -83362,9 +84718,11 @@ async function repairAgentIntegrations(options2 = {}) {
|
|
|
83362
84718
|
} else {
|
|
83363
84719
|
if (!options2.dry) {
|
|
83364
84720
|
await installPluginPackage({ agent: "codex" });
|
|
83365
|
-
|
|
83366
|
-
|
|
83367
|
-
|
|
84721
|
+
const install = tryInstallCodexPlugin();
|
|
84722
|
+
if (install.ok) {
|
|
84723
|
+
await migrateLegacyCodexIntegration({ projectRoot });
|
|
84724
|
+
} else {
|
|
84725
|
+
skipped.push("codex:plugin:global:install-pending");
|
|
83368
84726
|
}
|
|
83369
84727
|
}
|
|
83370
84728
|
changed.push("codex:plugin:global");
|
|
@@ -84023,7 +85381,7 @@ __export(dashboard_exports, {
|
|
|
84023
85381
|
default: () => dashboard_default
|
|
84024
85382
|
});
|
|
84025
85383
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
84026
|
-
import
|
|
85384
|
+
import path35 from "path";
|
|
84027
85385
|
var dashboard_default;
|
|
84028
85386
|
var init_dashboard = __esm({
|
|
84029
85387
|
"src/cli/commands/dashboard.ts"() {
|
|
@@ -84053,8 +85411,8 @@ var init_dashboard = __esm({
|
|
|
84053
85411
|
}
|
|
84054
85412
|
const dataDir = await getProjectDataDir2(project.id);
|
|
84055
85413
|
const port = parseInt(args.port, 10) || 3210;
|
|
84056
|
-
const cliDir =
|
|
84057
|
-
const staticDir =
|
|
85414
|
+
const cliDir = path35.dirname(fileURLToPath6(import.meta.url));
|
|
85415
|
+
const staticDir = path35.join(cliDir, "..", "dashboard", "static");
|
|
84058
85416
|
await startDashboard2(dataDir, port, staticDir, project.id, project.name, true, void 0, project.rootPath, true);
|
|
84059
85417
|
await new Promise(() => {
|
|
84060
85418
|
});
|
|
@@ -84310,12 +85668,12 @@ var uninstall_exports = {};
|
|
|
84310
85668
|
__export(uninstall_exports, {
|
|
84311
85669
|
default: () => uninstall_default
|
|
84312
85670
|
});
|
|
84313
|
-
import * as
|
|
84314
|
-
import * as
|
|
85671
|
+
import * as fs24 from "fs";
|
|
85672
|
+
import * as path36 from "path";
|
|
84315
85673
|
import * as os4 from "os";
|
|
84316
85674
|
function exists(p2) {
|
|
84317
85675
|
try {
|
|
84318
|
-
|
|
85676
|
+
fs24.accessSync(p2);
|
|
84319
85677
|
return true;
|
|
84320
85678
|
} catch {
|
|
84321
85679
|
return false;
|
|
@@ -84324,7 +85682,7 @@ function exists(p2) {
|
|
|
84324
85682
|
function checkJSON(p2) {
|
|
84325
85683
|
if (!exists(p2)) return false;
|
|
84326
85684
|
try {
|
|
84327
|
-
const content =
|
|
85685
|
+
const content = fs24.readFileSync(p2, "utf-8");
|
|
84328
85686
|
const cfg = JSON.parse(content);
|
|
84329
85687
|
const servers = cfg.mcpServers ?? cfg.mcp_servers ?? cfg.servers ?? {};
|
|
84330
85688
|
return Object.keys(servers).some((k5) => k5.toLowerCase().includes("memorix"));
|
|
@@ -84335,7 +85693,7 @@ function checkJSON(p2) {
|
|
|
84335
85693
|
function checkTOML(p2) {
|
|
84336
85694
|
if (!exists(p2)) return false;
|
|
84337
85695
|
try {
|
|
84338
|
-
const content =
|
|
85696
|
+
const content = fs24.readFileSync(p2, "utf-8");
|
|
84339
85697
|
return /\[mcp_servers\.(?:memorix|Memorix)\]/.test(content);
|
|
84340
85698
|
} catch {
|
|
84341
85699
|
return false;
|
|
@@ -84345,124 +85703,124 @@ function getMCPConfigEntries(home, cwd) {
|
|
|
84345
85703
|
const entries = [];
|
|
84346
85704
|
entries.push({
|
|
84347
85705
|
agent: "Claude Code",
|
|
84348
|
-
path:
|
|
85706
|
+
path: path36.join(home, ".claude.json"),
|
|
84349
85707
|
kind: "global",
|
|
84350
85708
|
format: "json",
|
|
84351
|
-
detected: checkJSON(
|
|
85709
|
+
detected: checkJSON(path36.join(home, ".claude.json")),
|
|
84352
85710
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84353
85711
|
});
|
|
84354
85712
|
entries.push({
|
|
84355
85713
|
agent: "Claude Code",
|
|
84356
|
-
path:
|
|
85714
|
+
path: path36.join(cwd, ".claude", "settings.json"),
|
|
84357
85715
|
kind: "project",
|
|
84358
85716
|
format: "json",
|
|
84359
|
-
detected: checkJSON(
|
|
85717
|
+
detected: checkJSON(path36.join(cwd, ".claude", "settings.json")),
|
|
84360
85718
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84361
85719
|
});
|
|
84362
85720
|
entries.push({
|
|
84363
85721
|
agent: "Cursor",
|
|
84364
|
-
path:
|
|
85722
|
+
path: path36.join(home, ".cursor", "mcp.json"),
|
|
84365
85723
|
kind: "global",
|
|
84366
85724
|
format: "json",
|
|
84367
|
-
detected: checkJSON(
|
|
85725
|
+
detected: checkJSON(path36.join(home, ".cursor", "mcp.json")),
|
|
84368
85726
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84369
85727
|
});
|
|
84370
85728
|
entries.push({
|
|
84371
85729
|
agent: "Cursor",
|
|
84372
|
-
path:
|
|
85730
|
+
path: path36.join(cwd, ".cursor", "mcp.json"),
|
|
84373
85731
|
kind: "project",
|
|
84374
85732
|
format: "json",
|
|
84375
|
-
detected: checkJSON(
|
|
85733
|
+
detected: checkJSON(path36.join(cwd, ".cursor", "mcp.json")),
|
|
84376
85734
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84377
85735
|
});
|
|
84378
85736
|
entries.push({
|
|
84379
85737
|
agent: "Windsurf",
|
|
84380
|
-
path:
|
|
85738
|
+
path: path36.join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
84381
85739
|
kind: "global",
|
|
84382
85740
|
format: "json",
|
|
84383
|
-
detected: checkJSON(
|
|
85741
|
+
detected: checkJSON(path36.join(home, ".codeium", "windsurf", "mcp_config.json")),
|
|
84384
85742
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84385
85743
|
});
|
|
84386
85744
|
entries.push({
|
|
84387
85745
|
agent: "Codex",
|
|
84388
|
-
path:
|
|
85746
|
+
path: path36.join(home, ".codex", "config.toml"),
|
|
84389
85747
|
kind: "global",
|
|
84390
85748
|
format: "toml",
|
|
84391
|
-
detected: checkTOML(
|
|
85749
|
+
detected: checkTOML(path36.join(home, ".codex", "config.toml")),
|
|
84392
85750
|
note: "Remove the [mcp_servers.memorix] section from this file."
|
|
84393
85751
|
});
|
|
84394
85752
|
entries.push({
|
|
84395
85753
|
agent: "VS Code / Copilot",
|
|
84396
|
-
path:
|
|
85754
|
+
path: path36.join(home, ".vscode", "mcp.json"),
|
|
84397
85755
|
kind: "global",
|
|
84398
85756
|
format: "json",
|
|
84399
|
-
detected: checkJSON(
|
|
85757
|
+
detected: checkJSON(path36.join(home, ".vscode", "mcp.json")),
|
|
84400
85758
|
note: 'Remove the "memorix" key from servers in this file.'
|
|
84401
85759
|
});
|
|
84402
85760
|
entries.push({
|
|
84403
85761
|
agent: "VS Code / Copilot",
|
|
84404
|
-
path:
|
|
85762
|
+
path: path36.join(cwd, ".vscode", "mcp.json"),
|
|
84405
85763
|
kind: "project",
|
|
84406
85764
|
format: "json",
|
|
84407
|
-
detected: checkJSON(
|
|
85765
|
+
detected: checkJSON(path36.join(cwd, ".vscode", "mcp.json")),
|
|
84408
85766
|
note: 'Remove the "memorix" key from servers in this file.'
|
|
84409
85767
|
});
|
|
84410
85768
|
entries.push({
|
|
84411
85769
|
agent: "Kiro",
|
|
84412
|
-
path:
|
|
85770
|
+
path: path36.join(home, ".kiro", "settings", "mcp.json"),
|
|
84413
85771
|
kind: "global",
|
|
84414
85772
|
format: "json",
|
|
84415
|
-
detected: checkJSON(
|
|
85773
|
+
detected: checkJSON(path36.join(home, ".kiro", "settings", "mcp.json")),
|
|
84416
85774
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84417
85775
|
});
|
|
84418
85776
|
entries.push({
|
|
84419
85777
|
agent: "Kiro",
|
|
84420
|
-
path:
|
|
85778
|
+
path: path36.join(cwd, ".kiro", "settings", "mcp.json"),
|
|
84421
85779
|
kind: "project",
|
|
84422
85780
|
format: "json",
|
|
84423
|
-
detected: checkJSON(
|
|
85781
|
+
detected: checkJSON(path36.join(cwd, ".kiro", "settings", "mcp.json")),
|
|
84424
85782
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84425
85783
|
});
|
|
84426
85784
|
entries.push({
|
|
84427
85785
|
agent: "Gemini CLI",
|
|
84428
|
-
path:
|
|
85786
|
+
path: path36.join(home, ".gemini", "settings.json"),
|
|
84429
85787
|
kind: "global",
|
|
84430
85788
|
format: "json",
|
|
84431
|
-
detected: checkJSON(
|
|
85789
|
+
detected: checkJSON(path36.join(home, ".gemini", "settings.json")),
|
|
84432
85790
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84433
85791
|
});
|
|
84434
85792
|
entries.push({
|
|
84435
85793
|
agent: "Antigravity",
|
|
84436
|
-
path:
|
|
85794
|
+
path: path36.join(home, ".gemini", "config", "mcp_config.json"),
|
|
84437
85795
|
kind: "global",
|
|
84438
85796
|
format: "json",
|
|
84439
|
-
detected: checkJSON(
|
|
85797
|
+
detected: checkJSON(path36.join(home, ".gemini", "config", "mcp_config.json")),
|
|
84440
85798
|
note: 'Remove the "memorix" key from mcpServers in this file.'
|
|
84441
85799
|
});
|
|
84442
85800
|
entries.push({
|
|
84443
85801
|
agent: "Antigravity",
|
|
84444
|
-
path:
|
|
85802
|
+
path: path36.join(home, ".gemini", "config", "hooks.json"),
|
|
84445
85803
|
kind: "global",
|
|
84446
85804
|
format: "json",
|
|
84447
|
-
detected: exists(
|
|
85805
|
+
detected: exists(path36.join(home, ".gemini", "config", "hooks.json")),
|
|
84448
85806
|
note: 'Remove the "memorix" hook group from this file.'
|
|
84449
85807
|
});
|
|
84450
85808
|
entries.push({
|
|
84451
85809
|
agent: "Antigravity",
|
|
84452
|
-
path:
|
|
85810
|
+
path: path36.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json"),
|
|
84453
85811
|
kind: "global",
|
|
84454
85812
|
format: "json",
|
|
84455
|
-
detected: exists(
|
|
85813
|
+
detected: exists(path36.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json")),
|
|
84456
85814
|
note: "Delete the containing ~/.gemini/config/plugins/memorix plugin directory if you want to remove the Antigravity plugin package."
|
|
84457
85815
|
});
|
|
84458
85816
|
const traeCfg = (() => {
|
|
84459
85817
|
if (process.platform === "win32") {
|
|
84460
|
-
return
|
|
85818
|
+
return path36.join(process.env.APPDATA || path36.join(home, "AppData", "Roaming"), "Trae", "User", "mcp.json");
|
|
84461
85819
|
}
|
|
84462
85820
|
if (process.platform === "darwin") {
|
|
84463
|
-
return
|
|
85821
|
+
return path36.join(home, "Library", "Application Support", "Trae", "User", "mcp.json");
|
|
84464
85822
|
}
|
|
84465
|
-
return
|
|
85823
|
+
return path36.join(home, ".config", "Trae", "User", "mcp.json");
|
|
84466
85824
|
})();
|
|
84467
85825
|
entries.push({
|
|
84468
85826
|
agent: "Trae",
|
|
@@ -84475,9 +85833,9 @@ function getMCPConfigEntries(home, cwd) {
|
|
|
84475
85833
|
return entries;
|
|
84476
85834
|
}
|
|
84477
85835
|
function checkBackground(home) {
|
|
84478
|
-
const statePath =
|
|
85836
|
+
const statePath = path36.join(home, ".memorix", "background.json");
|
|
84479
85837
|
try {
|
|
84480
|
-
const data =
|
|
85838
|
+
const data = fs24.readFileSync(statePath, "utf-8");
|
|
84481
85839
|
const state = JSON.parse(data);
|
|
84482
85840
|
try {
|
|
84483
85841
|
process.kill(state.pid, 0);
|
|
@@ -84616,7 +85974,7 @@ var init_uninstall = __esm({
|
|
|
84616
85974
|
},
|
|
84617
85975
|
async run({ args }) {
|
|
84618
85976
|
const home = os4.homedir();
|
|
84619
|
-
const memorixDir =
|
|
85977
|
+
const memorixDir = path36.join(home, ".memorix");
|
|
84620
85978
|
const dryRun = args["dry-run"];
|
|
84621
85979
|
const yes = args.yes;
|
|
84622
85980
|
const doHooks = args.hooks;
|
|
@@ -84744,7 +86102,7 @@ var init_uninstall = __esm({
|
|
|
84744
86102
|
if (exists(memorixDir)) {
|
|
84745
86103
|
console.log(`[DELETE] Removing ${memorixDir}...`);
|
|
84746
86104
|
try {
|
|
84747
|
-
|
|
86105
|
+
fs24.rmSync(memorixDir, { recursive: true, force: true });
|
|
84748
86106
|
console.log("[OK] Data directory deleted.");
|
|
84749
86107
|
changes++;
|
|
84750
86108
|
} catch (err) {
|
|
@@ -85115,24 +86473,24 @@ var init_claude_stream = __esm({
|
|
|
85115
86473
|
});
|
|
85116
86474
|
|
|
85117
86475
|
// src/orchestrate/adapters/claude.ts
|
|
85118
|
-
import * as
|
|
85119
|
-
import * as
|
|
86476
|
+
import * as fs25 from "fs";
|
|
86477
|
+
import * as path37 from "path";
|
|
85120
86478
|
function resolveMcpConfigPath(projectDir2) {
|
|
85121
|
-
const localPath =
|
|
86479
|
+
const localPath = path37.join(projectDir2, ".claude", "settings.local.json");
|
|
85122
86480
|
try {
|
|
85123
|
-
if (
|
|
86481
|
+
if (fs25.existsSync(localPath)) return localPath;
|
|
85124
86482
|
} catch {
|
|
85125
86483
|
}
|
|
85126
|
-
const settingsPath =
|
|
86484
|
+
const settingsPath = path37.join(projectDir2, ".claude", "settings.json");
|
|
85127
86485
|
try {
|
|
85128
|
-
if (
|
|
86486
|
+
if (fs25.existsSync(settingsPath)) return settingsPath;
|
|
85129
86487
|
} catch {
|
|
85130
86488
|
}
|
|
85131
86489
|
const mcpConfig = {
|
|
85132
86490
|
mcpServers: {
|
|
85133
86491
|
memorix: {
|
|
85134
86492
|
command: process.execPath,
|
|
85135
|
-
args: [
|
|
86493
|
+
args: [path37.resolve(path37.dirname(process.execPath), "..", "lib", "node_modules", "memorix", "dist", "index.js"), "serve", "--transport", "stdio"]
|
|
85136
86494
|
}
|
|
85137
86495
|
}
|
|
85138
86496
|
};
|
|
@@ -85142,10 +86500,10 @@ function resolveMcpConfigPath(projectDir2) {
|
|
|
85142
86500
|
args: ["serve", "--transport", "stdio"]
|
|
85143
86501
|
};
|
|
85144
86502
|
try {
|
|
85145
|
-
const claudeDir =
|
|
85146
|
-
|
|
85147
|
-
const tempPath =
|
|
85148
|
-
|
|
86503
|
+
const claudeDir = path37.join(projectDir2, ".claude");
|
|
86504
|
+
fs25.mkdirSync(claudeDir, { recursive: true });
|
|
86505
|
+
const tempPath = path37.join(claudeDir, "settings.local.json");
|
|
86506
|
+
fs25.writeFileSync(tempPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
85149
86507
|
return tempPath;
|
|
85150
86508
|
} catch {
|
|
85151
86509
|
return null;
|
|
@@ -86561,9 +87919,9 @@ function writePipelineSummary(projectDir2, summary) {
|
|
|
86561
87919
|
return null;
|
|
86562
87920
|
}
|
|
86563
87921
|
}
|
|
86564
|
-
function safeWrite(
|
|
87922
|
+
function safeWrite(path38, content) {
|
|
86565
87923
|
try {
|
|
86566
|
-
writeFileSync9(
|
|
87924
|
+
writeFileSync9(path38, content, "utf-8");
|
|
86567
87925
|
} catch {
|
|
86568
87926
|
}
|
|
86569
87927
|
}
|
|
@@ -88034,8 +89392,8 @@ var init_orchestrate = __esm({
|
|
|
88034
89392
|
const { getProjectDataDir: getProjectDataDir2 } = await Promise.resolve().then(() => (init_persistence(), persistence_exports));
|
|
88035
89393
|
const { resolveAdapters: resolveAdapters2, parseAgentQuotas: parseAgentQuotas2, buildQuotaMap: buildQuotaMap2 } = await Promise.resolve().then(() => (init_adapters(), adapters_exports));
|
|
88036
89394
|
const { runCoordinationLoop: runCoordinationLoop2 } = await Promise.resolve().then(() => (init_coordinator(), coordinator_exports));
|
|
88037
|
-
const
|
|
88038
|
-
const projectDir2 = args.project ?
|
|
89395
|
+
const path38 = await import("path");
|
|
89396
|
+
const projectDir2 = args.project ? path38.resolve(args.project) : process.cwd();
|
|
88039
89397
|
const proj = detectProject2(projectDir2);
|
|
88040
89398
|
if (!proj) {
|
|
88041
89399
|
console.error("[ERROR] Not a git repository. Run `git init` first.");
|
|
@@ -89145,7 +90503,7 @@ var init_Panels = __esm({
|
|
|
89145
90503
|
// src/cli/tui/ConfigureView.tsx
|
|
89146
90504
|
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
89147
90505
|
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
89148
|
-
import * as
|
|
90506
|
+
import * as fs26 from "fs";
|
|
89149
90507
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
89150
90508
|
function getConfigPath() {
|
|
89151
90509
|
return `${process.env.HOME || process.env.USERPROFILE}/.memorix/config.json`;
|
|
@@ -89153,15 +90511,15 @@ function getConfigPath() {
|
|
|
89153
90511
|
function loadConfig() {
|
|
89154
90512
|
try {
|
|
89155
90513
|
const p2 = getConfigPath();
|
|
89156
|
-
if (
|
|
90514
|
+
if (fs26.existsSync(p2)) return JSON.parse(fs26.readFileSync(p2, "utf-8"));
|
|
89157
90515
|
} catch {
|
|
89158
90516
|
}
|
|
89159
90517
|
return {};
|
|
89160
90518
|
}
|
|
89161
90519
|
function saveConfig(config2) {
|
|
89162
90520
|
const dir = `${process.env.HOME || process.env.USERPROFILE}/.memorix`;
|
|
89163
|
-
if (!
|
|
89164
|
-
|
|
90521
|
+
if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
|
|
90522
|
+
fs26.writeFileSync(getConfigPath(), JSON.stringify(config2, null, 2));
|
|
89165
90523
|
}
|
|
89166
90524
|
function separator2(w3 = 50) {
|
|
89167
90525
|
return SEP.thin.repeat(w3);
|
|
@@ -89874,7 +91232,7 @@ var init_session_service = __esm({
|
|
|
89874
91232
|
});
|
|
89875
91233
|
|
|
89876
91234
|
// src/cli/tui/data.ts
|
|
89877
|
-
import * as
|
|
91235
|
+
import * as fs27 from "fs";
|
|
89878
91236
|
function formatSearchModeLabel(mode) {
|
|
89879
91237
|
const normalized = (mode || "").toLowerCase();
|
|
89880
91238
|
if (!normalized) return "Unknown";
|
|
@@ -90081,7 +91439,7 @@ async function getBackgroundStatus() {
|
|
|
90081
91439
|
try {
|
|
90082
91440
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
90083
91441
|
const statePath = `${home.replace(/\\/g, "/")}/.memorix/background.json`;
|
|
90084
|
-
if (!
|
|
91442
|
+
if (!fs27.existsSync(statePath)) {
|
|
90085
91443
|
try {
|
|
90086
91444
|
const controller = new AbortController();
|
|
90087
91445
|
const timer = setTimeout(() => controller.abort(), 2e3);
|
|
@@ -90102,7 +91460,7 @@ async function getBackgroundStatus() {
|
|
|
90102
91460
|
}
|
|
90103
91461
|
return result;
|
|
90104
91462
|
}
|
|
90105
|
-
const state = JSON.parse(
|
|
91463
|
+
const state = JSON.parse(fs27.readFileSync(statePath, "utf-8"));
|
|
90106
91464
|
result.pid = state.pid;
|
|
90107
91465
|
result.port = state.port;
|
|
90108
91466
|
result.startedAt = state.startedAt;
|
|
@@ -90193,8 +91551,8 @@ function detectMode() {
|
|
|
90193
91551
|
try {
|
|
90194
91552
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
90195
91553
|
const statePath = `${home.replace(/\\/g, "/")}/.memorix/background.json`;
|
|
90196
|
-
if (
|
|
90197
|
-
const state = JSON.parse(
|
|
91554
|
+
if (fs27.existsSync(statePath)) {
|
|
91555
|
+
const state = JSON.parse(fs27.readFileSync(statePath, "utf-8"));
|
|
90198
91556
|
try {
|
|
90199
91557
|
process.kill(state.pid, 0);
|
|
90200
91558
|
return { mode: "Background", detail: `port ${state.port}` };
|
|
@@ -92735,9 +94093,17 @@ var GUIDES = {
|
|
|
92735
94093
|
"memorix memory recent [--limit 10]",
|
|
92736
94094
|
"memorix memory resolve --ids 42,43 [--status resolved|archived]",
|
|
92737
94095
|
"memorix memory consolidate --action preview|execute",
|
|
92738
|
-
'memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]'
|
|
94096
|
+
'memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]',
|
|
94097
|
+
"memorix memory long-term list [--all]",
|
|
94098
|
+
'memorix memory long-term add --kind semantic --scope user --portability portable --title "..." --text "..." [--tags "..."] [--applicability "..."]',
|
|
94099
|
+
"memorix memory long-term promote --from-observation 42 --kind procedural --scope project",
|
|
94100
|
+
'memorix memory long-term qualify|approve|archive --id <id> --reason "..."',
|
|
94101
|
+
'memorix memory long-term supersede --id <old-id> --superseded-by <qualified-id> --reason "..."'
|
|
92739
94102
|
],
|
|
92740
|
-
notes: [
|
|
94103
|
+
notes: [
|
|
94104
|
+
"Personal and team visibility require `memorix identity join` or `memorix identity use` first.",
|
|
94105
|
+
"Candidates never enter a task Workset. Only manual or user-confirmed `user + portable` memory may cross local projects."
|
|
94106
|
+
]
|
|
92741
94107
|
},
|
|
92742
94108
|
identity: {
|
|
92743
94109
|
summary: "Select the active local actor for private memory and coordination commands.",
|