memorix 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -34
- package/dist/cli/index.js +144 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/app.js +14 -0
- package/dist/index.js +74 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<a href="https://www.npmjs.com/package/memorix"><img src="https://img.shields.io/npm/dm/memorix.svg?style=flat-square&color=blue" alt="npm downloads"></a>
|
|
8
8
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-green.svg?style=flat-square" alt="License"></a>
|
|
9
9
|
<a href="https://github.com/AVIDS2/memorix"><img src="https://img.shields.io/github/stars/AVIDS2/memorix?style=flat-square&color=yellow" alt="GitHub stars"></a>
|
|
10
|
-
<img src="https://img.shields.io/badge/tests-
|
|
10
|
+
<img src="https://img.shields.io/badge/tests-405%20passed-brightgreen?style=flat-square" alt="Tests">
|
|
11
11
|
</p>
|
|
12
12
|
<p align="center">
|
|
13
13
|
<a href="#-quick-start">Quick Start</a> •
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
> **One project,
|
|
23
|
+
> **One project, seven agents, zero context loss.**
|
|
24
24
|
>
|
|
25
|
-
> Memorix is a **cross-agent memory bridge** — it lets Cursor, Windsurf, Claude Code, Codex, Copilot, and
|
|
25
|
+
> Memorix is a **cross-agent memory bridge** — it lets Cursor, Windsurf, Claude Code, Codex, Copilot, Antigravity, and **Kiro** **share the same project knowledge** in real-time. Architecture decisions made in one IDE are instantly available in another. Switch tools, open new windows, start fresh sessions — your context follows you everywhere via [MCP](https://modelcontextprotocol.io/). It also **syncs MCP configs, rules, skills, and workflows** across all your agents automatically.
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -46,7 +46,7 @@ Add Memorix to your agent's MCP config — **that's it**. No global install need
|
|
|
46
46
|
|
|
47
47
|
Restart your agent and Memorix is running! 🎉
|
|
48
48
|
|
|
49
|
-
> 💡 More agent configs: [Cursor](#cursor) • [Claude Code](#claude-code) • [Codex](#codex) • [VS Code Copilot](#vs-code-copilot) • [Antigravity](#antigravity)
|
|
49
|
+
> 💡 More agent configs: [Cursor](#cursor) • [Claude Code](#claude-code) • [Codex](#codex) • [VS Code Copilot](#vs-code-copilot) • [Antigravity](#antigravity) • [Kiro](#kiro)
|
|
50
50
|
|
|
51
51
|
### Or Install Globally
|
|
52
52
|
|
|
@@ -93,7 +93,7 @@ Then use `"command": "memorix"` instead of `"command": "npx"` in your config.
|
|
|
93
93
|
|
|
94
94
|
### 🔄 Cross-Agent Workspace Sync
|
|
95
95
|
|
|
96
|
-
- **
|
|
96
|
+
- **7 Agent Adapters** — Windsurf, Cursor, Claude Code, Codex, VS Code Copilot, Antigravity, **Kiro**
|
|
97
97
|
- **MCP Config Migration** — Detect and migrate MCP server configs (merges — never overwrites)
|
|
98
98
|
- **Rules Sync** — Scan → Deduplicate → Conflict detection → Cross-format generation
|
|
99
99
|
- **Skills & Workflows** — Copy skill folders and workflow files across agents
|
|
@@ -113,11 +113,13 @@ Then use `"command": "memorix"` instead of `"command": "npx"` in your config.
|
|
|
113
113
|
- **Project Switcher** — Dropdown to view any project's data without switching IDEs
|
|
114
114
|
- **Knowledge Graph** — Interactive visualization of entities and relations
|
|
115
115
|
- **Retention Scores** — Exponential decay scoring with immunity status
|
|
116
|
+
- **Observation Management** — Expand/collapse details, search, delete with confirmation, data export
|
|
116
117
|
- **Light/Dark Theme** — Premium glassmorphism design, bilingual (EN/中文)
|
|
117
118
|
|
|
118
119
|
### 🪝 Auto-Memory Hooks
|
|
119
120
|
|
|
120
121
|
- **Implicit Memory** — Auto-captures decisions, errors, gotchas from agent activity
|
|
122
|
+
- **Session Start Injection** — Intelligently loads recent high-value memories (gotchas, decisions, problem-solutions) and injects a concise summary into the agent's system prompt at session start
|
|
121
123
|
- **Multi-Language Pattern Detection** — English + Chinese keyword matching
|
|
122
124
|
- **Cooldown & Noise Filtering** — 30s cooldown, skips trivial commands (ls, cat, pwd)
|
|
123
125
|
- **One-Command Install** — `memorix hooks install` sets up hooks + rules for your agent
|
|
@@ -204,6 +206,20 @@ args = ["-y", "memorix@latest", "serve"]
|
|
|
204
206
|
}
|
|
205
207
|
```
|
|
206
208
|
|
|
209
|
+
### Kiro
|
|
210
|
+
|
|
211
|
+
`.kiro/settings/mcp.json`:
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"mcpServers": {
|
|
215
|
+
"memorix": {
|
|
216
|
+
"command": "npx",
|
|
217
|
+
"args": ["-y", "memorix@latest", "serve"]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
207
223
|
---
|
|
208
224
|
|
|
209
225
|
## 🛠 Available MCP Tools
|
|
@@ -278,33 +294,33 @@ Files: ["src/auth/jwt.ts", "src/config.ts"]
|
|
|
278
294
|
### Architecture
|
|
279
295
|
|
|
280
296
|
```
|
|
281
|
-
|
|
282
|
-
│
|
|
283
|
-
│ Windsurf │ Cursor │ Claude Code │ Codex │ Copilot │ Antigravity
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
│
|
|
288
|
-
│
|
|
289
|
-
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
|
|
290
|
-
│ │ Memory │ │ Compact │ │ Workspace Sync │
|
|
291
|
-
│ │ Layer │ │ Engine │ │ (
|
|
292
|
-
│ │ │ │ (3-layer) │ │ │
|
|
293
|
-
│ │ • Graph │ │ │ │ • MCP Configs │
|
|
294
|
-
│ │ • Retention │ │ │ │ • Rules │
|
|
295
|
-
│ │ • Entities │ │ │ │ • Skills │
|
|
296
|
-
│ │ • Relations │ │ │ │ • Workflows │
|
|
297
|
-
│ └──────┬──────┘ └──────┬───────┘ └──────────────────┘
|
|
298
|
-
│ │ │
|
|
299
|
-
│ ┌──────▼────────────────▼───────────────────────────────┐
|
|
300
|
-
│ │ Orama Store (BM25 + Vector) │ Persistence (JSONL) │
|
|
301
|
-
│ └───────────────────────────────────────────────────────┘
|
|
302
|
-
│
|
|
303
|
-
│ ┌───────────────────────────────────────────────────────┐
|
|
304
|
-
│ │ Hooks System: Normalizer → Pattern Detector → Store │
|
|
305
|
-
│ │ (Auto-captures decisions, bugs, gotchas from agents) │
|
|
306
|
-
│ └───────────────────────────────────────────────────────┘
|
|
307
|
-
|
|
297
|
+
┌───────────────────────────────────────────────────────────────────┐
|
|
298
|
+
│ AI Coding Agents │
|
|
299
|
+
│ Windsurf │ Cursor │ Claude Code │ Codex │ Copilot │ Antigravity │ Kiro
|
|
300
|
+
└───────────────────────────┬───────────────────────────────────────┘
|
|
301
|
+
│ MCP Protocol (stdio)
|
|
302
|
+
┌───────────────────────────▼───────────────────────────────────────┐
|
|
303
|
+
│ Memorix MCP Server (17 tools) │
|
|
304
|
+
│ │
|
|
305
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
306
|
+
│ │ Memory │ │ Compact │ │ Workspace Sync │ │
|
|
307
|
+
│ │ Layer │ │ Engine │ │ (7 adapters) │ │
|
|
308
|
+
│ │ │ │ (3-layer) │ │ │ │
|
|
309
|
+
│ │ • Graph │ │ │ │ • MCP Configs │ │
|
|
310
|
+
│ │ • Retention │ │ │ │ • Rules │ │
|
|
311
|
+
│ │ • Entities │ │ │ │ • Skills │ │
|
|
312
|
+
│ │ • Relations │ │ │ │ • Workflows │ │
|
|
313
|
+
│ └──────┬──────┘ └──────┬───────┘ └──────────────────┘ │
|
|
314
|
+
│ │ │ │
|
|
315
|
+
│ ┌──────▼────────────────▼───────────────────────────────┐ │
|
|
316
|
+
│ │ Orama Store (BM25 + Vector) │ Persistence (JSONL) │ │
|
|
317
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
318
|
+
│ │
|
|
319
|
+
│ ┌───────────────────────────────────────────────────────┐ │
|
|
320
|
+
│ │ Hooks System: Normalizer → Pattern Detector → Store │ │
|
|
321
|
+
│ │ (Auto-captures decisions, bugs, gotchas from agents) │ │
|
|
322
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
323
|
+
└───────────────────────────────────────────────────────────────────┘
|
|
308
324
|
```
|
|
309
325
|
|
|
310
326
|
---
|
|
@@ -349,7 +365,7 @@ cd memorix
|
|
|
349
365
|
npm install
|
|
350
366
|
|
|
351
367
|
npm run dev # tsup watch mode
|
|
352
|
-
npm test # vitest (
|
|
368
|
+
npm test # vitest (405 tests)
|
|
353
369
|
npm run lint # TypeScript type check
|
|
354
370
|
npm run build # Production build
|
|
355
371
|
```
|
|
@@ -366,7 +382,7 @@ src/
|
|
|
366
382
|
├── embedding/ # Optional fastembed vector provider
|
|
367
383
|
├── hooks/ # Auto-memory hooks (normalizer + pattern detector)
|
|
368
384
|
├── workspace/ # Cross-agent MCP/workflow/skills sync
|
|
369
|
-
├── rules/ # Cross-agent rules sync (
|
|
385
|
+
├── rules/ # Cross-agent rules sync (7 adapters)
|
|
370
386
|
├── dashboard/ # Visual web dashboard (knowledge graph, stats)
|
|
371
387
|
├── project/ # Git-based project detection
|
|
372
388
|
└── cli/ # CLI commands (serve, hook, sync, dashboard)
|
package/dist/cli/index.js
CHANGED
|
@@ -52,6 +52,9 @@ function sanitizeProjectId(projectId) {
|
|
|
52
52
|
return projectId.replace(/\//g, "--").replace(/[<>:"|?*\\]/g, "_");
|
|
53
53
|
}
|
|
54
54
|
async function getProjectDataDir(projectId, baseDir) {
|
|
55
|
+
if (projectId === "__invalid__") {
|
|
56
|
+
throw new Error("Cannot create data directory for invalid project");
|
|
57
|
+
}
|
|
55
58
|
const base = baseDir ?? DEFAULT_DATA_DIR;
|
|
56
59
|
const dirName = sanitizeProjectId(projectId);
|
|
57
60
|
const dataDir = path2.join(base, dirName);
|
|
@@ -1223,6 +1226,7 @@ __export(detector_exports, {
|
|
|
1223
1226
|
});
|
|
1224
1227
|
import { execSync } from "child_process";
|
|
1225
1228
|
import { existsSync } from "fs";
|
|
1229
|
+
import os2 from "os";
|
|
1226
1230
|
import path3 from "path";
|
|
1227
1231
|
function detectProject(cwd) {
|
|
1228
1232
|
const basePath = cwd ?? process.cwd();
|
|
@@ -1233,11 +1237,77 @@ function detectProject(cwd) {
|
|
|
1233
1237
|
const name2 = id2.split("/").pop() ?? path3.basename(rootPath);
|
|
1234
1238
|
return { id: id2, name: name2, gitRemote, rootPath };
|
|
1235
1239
|
}
|
|
1240
|
+
if (!isValidProjectRoot(rootPath)) {
|
|
1241
|
+
console.error(`[memorix] Skipped invalid project root: ${rootPath}`);
|
|
1242
|
+
return { id: "__invalid__", name: "unknown", rootPath };
|
|
1243
|
+
}
|
|
1236
1244
|
const name = path3.basename(rootPath);
|
|
1237
1245
|
const id = `local/${name}`;
|
|
1238
1246
|
console.error(`[memorix] Warning: no git remote found at ${rootPath}, using fallback projectId: ${id}`);
|
|
1239
1247
|
return { id, name, rootPath };
|
|
1240
1248
|
}
|
|
1249
|
+
function isValidProjectRoot(dirPath) {
|
|
1250
|
+
const resolved = path3.resolve(dirPath);
|
|
1251
|
+
const home = path3.resolve(os2.homedir());
|
|
1252
|
+
if (resolved === home) return false;
|
|
1253
|
+
if (resolved === path3.parse(resolved).root) return false;
|
|
1254
|
+
const basename2 = path3.basename(resolved).toLowerCase();
|
|
1255
|
+
const knownNonProjectDirs = /* @__PURE__ */ new Set([
|
|
1256
|
+
// IDE / editor config dirs
|
|
1257
|
+
".vscode",
|
|
1258
|
+
".cursor",
|
|
1259
|
+
".windsurf",
|
|
1260
|
+
".kiro",
|
|
1261
|
+
".codex",
|
|
1262
|
+
".gemini",
|
|
1263
|
+
".claude",
|
|
1264
|
+
".github",
|
|
1265
|
+
".git",
|
|
1266
|
+
// OS / system dirs
|
|
1267
|
+
"desktop",
|
|
1268
|
+
"documents",
|
|
1269
|
+
"downloads",
|
|
1270
|
+
"pictures",
|
|
1271
|
+
"videos",
|
|
1272
|
+
"music",
|
|
1273
|
+
"appdata",
|
|
1274
|
+
"application data",
|
|
1275
|
+
"library",
|
|
1276
|
+
// Package manager / tool dirs
|
|
1277
|
+
"node_modules",
|
|
1278
|
+
".npm",
|
|
1279
|
+
".yarn",
|
|
1280
|
+
".pnpm-store",
|
|
1281
|
+
".config",
|
|
1282
|
+
".local",
|
|
1283
|
+
".cache",
|
|
1284
|
+
".ssh",
|
|
1285
|
+
".memorix"
|
|
1286
|
+
]);
|
|
1287
|
+
if (knownNonProjectDirs.has(basename2)) {
|
|
1288
|
+
const parent = path3.resolve(path3.dirname(resolved));
|
|
1289
|
+
if (parent === home || parent === path3.parse(parent).root) {
|
|
1290
|
+
return false;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
const projectIndicators = [
|
|
1294
|
+
"package.json",
|
|
1295
|
+
"Cargo.toml",
|
|
1296
|
+
"go.mod",
|
|
1297
|
+
"pyproject.toml",
|
|
1298
|
+
"setup.py",
|
|
1299
|
+
"pom.xml",
|
|
1300
|
+
"build.gradle",
|
|
1301
|
+
"Makefile",
|
|
1302
|
+
"CMakeLists.txt",
|
|
1303
|
+
"composer.json",
|
|
1304
|
+
"Gemfile",
|
|
1305
|
+
".git",
|
|
1306
|
+
"README.md",
|
|
1307
|
+
"README"
|
|
1308
|
+
];
|
|
1309
|
+
return projectIndicators.some((f) => existsSync(path3.join(resolved, f)));
|
|
1310
|
+
}
|
|
1241
1311
|
function findPackageRoot(cwd) {
|
|
1242
1312
|
let dir = path3.resolve(cwd);
|
|
1243
1313
|
const root = path3.parse(dir).root;
|
|
@@ -3164,7 +3234,7 @@ __export(installers_exports, {
|
|
|
3164
3234
|
});
|
|
3165
3235
|
import * as fs3 from "fs/promises";
|
|
3166
3236
|
import * as path5 from "path";
|
|
3167
|
-
import * as
|
|
3237
|
+
import * as os3 from "os";
|
|
3168
3238
|
import { createRequire } from "module";
|
|
3169
3239
|
function resolveHookCommand() {
|
|
3170
3240
|
if (process.platform === "win32") {
|
|
@@ -3269,7 +3339,7 @@ function getProjectConfigPath(agent, projectRoot) {
|
|
|
3269
3339
|
}
|
|
3270
3340
|
}
|
|
3271
3341
|
function getGlobalConfigPath(agent) {
|
|
3272
|
-
const home =
|
|
3342
|
+
const home = os3.homedir();
|
|
3273
3343
|
switch (agent) {
|
|
3274
3344
|
case "claude":
|
|
3275
3345
|
case "copilot":
|
|
@@ -3284,7 +3354,7 @@ function getGlobalConfigPath(agent) {
|
|
|
3284
3354
|
}
|
|
3285
3355
|
async function detectInstalledAgents() {
|
|
3286
3356
|
const agents = [];
|
|
3287
|
-
const home =
|
|
3357
|
+
const home = os3.homedir();
|
|
3288
3358
|
const claudeDir = path5.join(home, ".claude");
|
|
3289
3359
|
try {
|
|
3290
3360
|
await fs3.access(claudeDir);
|
|
@@ -3409,7 +3479,7 @@ async function installAgentRules(agent, projectRoot) {
|
|
|
3409
3479
|
rulesPath = path5.join(projectRoot, "AGENTS.md");
|
|
3410
3480
|
break;
|
|
3411
3481
|
case "kiro":
|
|
3412
|
-
rulesPath = path5.join(projectRoot, ".kiro", "
|
|
3482
|
+
rulesPath = path5.join(projectRoot, ".kiro", "steering", "memorix.md");
|
|
3413
3483
|
break;
|
|
3414
3484
|
default:
|
|
3415
3485
|
rulesPath = path5.join(projectRoot, ".agent", "rules", "memorix.md");
|
|
@@ -4820,7 +4890,8 @@ var init_sync = __esm({
|
|
|
4820
4890
|
"claude-code": "Claude Code (CLAUDE.md, .claude/rules/*.md)",
|
|
4821
4891
|
codex: "Codex (SKILL.md, AGENTS.md)",
|
|
4822
4892
|
windsurf: "Windsurf (.windsurfrules, .windsurf/rules/*.md)",
|
|
4823
|
-
antigravity: "Antigravity (.agent/rules/*.md, GEMINI.md)"
|
|
4893
|
+
antigravity: "Antigravity (.agent/rules/*.md, GEMINI.md)",
|
|
4894
|
+
kiro: "Kiro (.kiro/steering/*.md, AGENTS.md)"
|
|
4824
4895
|
};
|
|
4825
4896
|
sync_default = defineCommand3({
|
|
4826
4897
|
meta: {
|
|
@@ -4830,7 +4901,7 @@ var init_sync = __esm({
|
|
|
4830
4901
|
args: {
|
|
4831
4902
|
target: {
|
|
4832
4903
|
type: "string",
|
|
4833
|
-
description: "Target agent format (cursor, claude-code, codex, windsurf, antigravity)",
|
|
4904
|
+
description: "Target agent format (cursor, claude-code, codex, windsurf, antigravity, kiro)",
|
|
4834
4905
|
required: false
|
|
4835
4906
|
},
|
|
4836
4907
|
dry: {
|
|
@@ -4873,11 +4944,11 @@ var init_sync = __esm({
|
|
|
4873
4944
|
}
|
|
4874
4945
|
let target = args.target;
|
|
4875
4946
|
if (!target) {
|
|
4876
|
-
const available = ["cursor", "claude-code", "codex", "windsurf", "antigravity"].filter(
|
|
4947
|
+
const available = ["cursor", "claude-code", "codex", "windsurf", "antigravity", "kiro"].filter(
|
|
4877
4948
|
(t) => !sources.includes(t)
|
|
4878
4949
|
);
|
|
4879
4950
|
if (available.length === 0) {
|
|
4880
|
-
available.push("cursor", "claude-code", "codex", "windsurf", "antigravity");
|
|
4951
|
+
available.push("cursor", "claude-code", "codex", "windsurf", "antigravity", "kiro");
|
|
4881
4952
|
}
|
|
4882
4953
|
const selected = await p2.select({
|
|
4883
4954
|
message: "Generate rules for which agent?",
|
|
@@ -5028,9 +5099,10 @@ function normalizeCursor(payload, event) {
|
|
|
5028
5099
|
return result;
|
|
5029
5100
|
}
|
|
5030
5101
|
function normalizeHookInput(payload) {
|
|
5102
|
+
const directEvent = typeof payload.event === "string" ? EVENT_MAP[payload.event] : void 0;
|
|
5031
5103
|
const agent = detectAgent(payload);
|
|
5032
5104
|
const rawEventName = extractEventName(payload, agent);
|
|
5033
|
-
const event = EVENT_MAP[rawEventName] ?? "post_tool";
|
|
5105
|
+
const event = directEvent ?? EVENT_MAP[rawEventName] ?? "post_tool";
|
|
5034
5106
|
const timestamp = payload.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
5035
5107
|
let agentSpecific = {};
|
|
5036
5108
|
switch (agent) {
|
|
@@ -5063,6 +5135,16 @@ var init_normalizer = __esm({
|
|
|
5063
5135
|
"use strict";
|
|
5064
5136
|
init_esm_shims();
|
|
5065
5137
|
EVENT_MAP = {
|
|
5138
|
+
// Identity mappings — already-normalized event names
|
|
5139
|
+
// This allows direct payloads like { event: 'session_start' } to work
|
|
5140
|
+
session_start: "session_start",
|
|
5141
|
+
user_prompt: "user_prompt",
|
|
5142
|
+
post_edit: "post_edit",
|
|
5143
|
+
post_command: "post_command",
|
|
5144
|
+
post_tool: "post_tool",
|
|
5145
|
+
pre_compact: "pre_compact",
|
|
5146
|
+
session_end: "session_end",
|
|
5147
|
+
post_response: "post_response",
|
|
5066
5148
|
// Claude Code / VS Code Copilot
|
|
5067
5149
|
SessionStart: "session_start",
|
|
5068
5150
|
UserPromptSubmit: "user_prompt",
|
|
@@ -5306,14 +5388,65 @@ async function handleHookEvent(input) {
|
|
|
5306
5388
|
return { observation: null, output: defaultOutput };
|
|
5307
5389
|
}
|
|
5308
5390
|
switch (input.event) {
|
|
5309
|
-
case "session_start":
|
|
5391
|
+
case "session_start": {
|
|
5392
|
+
let contextSummary = "";
|
|
5393
|
+
try {
|
|
5394
|
+
const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
5395
|
+
const { getProjectDataDir: getProjectDataDir2, loadObservationsJson: loadObservationsJson2 } = await Promise.resolve().then(() => (init_persistence(), persistence_exports));
|
|
5396
|
+
const project = await detectProject2(input.cwd || process.cwd());
|
|
5397
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
5398
|
+
const allObs = await loadObservationsJson2(dataDir);
|
|
5399
|
+
if (allObs.length > 0) {
|
|
5400
|
+
const PRIORITY_ORDER = {
|
|
5401
|
+
"gotcha": 6,
|
|
5402
|
+
"decision": 5,
|
|
5403
|
+
"problem-solution": 4,
|
|
5404
|
+
"trade-off": 3,
|
|
5405
|
+
"discovery": 2,
|
|
5406
|
+
"how-it-works": 1
|
|
5407
|
+
};
|
|
5408
|
+
const scored = allObs.map((obs, i) => ({
|
|
5409
|
+
obs,
|
|
5410
|
+
priority: PRIORITY_ORDER[obs.type ?? ""] ?? 0,
|
|
5411
|
+
recency: i
|
|
5412
|
+
// higher index = more recent
|
|
5413
|
+
})).sort((a, b) => {
|
|
5414
|
+
if (b.priority !== a.priority) return b.priority - a.priority;
|
|
5415
|
+
return b.recency - a.recency;
|
|
5416
|
+
});
|
|
5417
|
+
const top = scored.slice(0, 5);
|
|
5418
|
+
const TYPE_EMOJI = {
|
|
5419
|
+
"gotcha": "\u{1F534}",
|
|
5420
|
+
"decision": "\u{1F7E4}",
|
|
5421
|
+
"problem-solution": "\u{1F7E1}",
|
|
5422
|
+
"trade-off": "\u2696\uFE0F",
|
|
5423
|
+
"discovery": "\u{1F7E3}",
|
|
5424
|
+
"how-it-works": "\u{1F535}",
|
|
5425
|
+
"what-changed": "\u{1F7E2}",
|
|
5426
|
+
"why-it-exists": "\u{1F7E0}",
|
|
5427
|
+
"session-request": "\u{1F3AF}"
|
|
5428
|
+
};
|
|
5429
|
+
const lines = top.map(({ obs }) => {
|
|
5430
|
+
const emoji = TYPE_EMOJI[obs.type ?? ""] ?? "\u{1F4CC}";
|
|
5431
|
+
const title = obs.title ?? "(untitled)";
|
|
5432
|
+
const fact = obs.facts?.[0] ? ` \u2014 ${obs.facts[0]}` : "";
|
|
5433
|
+
return `${emoji} ${title}${fact}`;
|
|
5434
|
+
});
|
|
5435
|
+
contextSummary = `
|
|
5436
|
+
|
|
5437
|
+
Recent project memories (${project.name}):
|
|
5438
|
+
${lines.join("\n")}`;
|
|
5439
|
+
}
|
|
5440
|
+
} catch {
|
|
5441
|
+
}
|
|
5310
5442
|
return {
|
|
5311
5443
|
observation: null,
|
|
5312
5444
|
output: {
|
|
5313
5445
|
continue: true,
|
|
5314
|
-
systemMessage:
|
|
5446
|
+
systemMessage: `Memorix is active. Your memories from previous sessions are available via memorix_search.${contextSummary}`
|
|
5315
5447
|
}
|
|
5316
5448
|
};
|
|
5449
|
+
}
|
|
5317
5450
|
case "pre_compact":
|
|
5318
5451
|
return {
|
|
5319
5452
|
observation: buildObservation(input, extractContent(input)),
|