memorix 0.5.0 → 0.5.2
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 +8 -6
- package/dist/cli/index.js +333 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/app.js +921 -0
- package/dist/dashboard/static/index.html +85 -0
- package/dist/dashboard/static/logo.png +0 -0
- package/dist/dashboard/static/style.css +1048 -0
- package/dist/index.js +372 -91
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
> **
|
|
22
|
+
> **One project, six agents, zero context loss.**
|
|
23
23
|
>
|
|
24
|
-
> Memorix
|
|
24
|
+
> Memorix is a **cross-agent memory bridge** — it lets Cursor, Windsurf, Claude Code, Codex, Copilot, and Antigravity **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.
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -199,7 +199,8 @@ args = ["-y", "memorix@latest", "serve"]
|
|
|
199
199
|
| `memorix_search` | L1: Compact index search | ~50-100/result |
|
|
200
200
|
| `memorix_timeline` | L2: Chronological context | ~100-200/group |
|
|
201
201
|
| `memorix_detail` | L3: Full observation details | ~500-1000/result |
|
|
202
|
-
| `memorix_retention` | Memory decay & retention
|
|
202
|
+
| `memorix_retention` | Memory decay & retention status | — |
|
|
203
|
+
| `memorix_dashboard` | Launch visual web dashboard in browser | — |
|
|
203
204
|
| `memorix_rules_sync` | Scan/deduplicate/generate rules across agents | — |
|
|
204
205
|
| `memorix_workspace_sync` | Migrate MCP configs, workflows, skills | — |
|
|
205
206
|
|
|
@@ -266,7 +267,7 @@ Files: ["src/auth/jwt.ts", "src/config.ts"]
|
|
|
266
267
|
└────────────────────────┬─────────────────────────────────────┘
|
|
267
268
|
│ MCP Protocol (stdio)
|
|
268
269
|
┌────────────────────────▼─────────────────────────────────────┐
|
|
269
|
-
│ Memorix MCP Server (
|
|
270
|
+
│ Memorix MCP Server (17 tools) │
|
|
270
271
|
│ │
|
|
271
272
|
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
272
273
|
│ │ Memory │ │ Compact │ │ Workspace Sync │ │
|
|
@@ -340,7 +341,7 @@ npm run build # Production build
|
|
|
340
341
|
|
|
341
342
|
```
|
|
342
343
|
src/
|
|
343
|
-
├── server.ts # MCP Server entry (
|
|
344
|
+
├── server.ts # MCP Server entry (17 tools)
|
|
344
345
|
├── types.ts # All type definitions
|
|
345
346
|
├── memory/ # Graph, observations, retention, entity extraction
|
|
346
347
|
├── store/ # Orama search engine + disk persistence
|
|
@@ -349,8 +350,9 @@ src/
|
|
|
349
350
|
├── hooks/ # Auto-memory hooks (normalizer + pattern detector)
|
|
350
351
|
├── workspace/ # Cross-agent MCP/workflow/skills sync
|
|
351
352
|
├── rules/ # Cross-agent rules sync (6 adapters)
|
|
353
|
+
├── dashboard/ # Visual web dashboard (knowledge graph, stats)
|
|
352
354
|
├── project/ # Git-based project detection
|
|
353
|
-
└── cli/ # CLI commands (serve, hook, sync,
|
|
355
|
+
└── cli/ # CLI commands (serve, hook, sync, dashboard)
|
|
354
356
|
```
|
|
355
357
|
|
|
356
358
|
> 📚 Full documentation available in [`docs/`](./docs/) — architecture, modules, API reference, design decisions, and more.
|
package/dist/cli/index.js
CHANGED
|
@@ -2631,10 +2631,10 @@ var init_engine2 = __esm({
|
|
|
2631
2631
|
for (const [target, adapter] of this.adapters) {
|
|
2632
2632
|
const configPath = adapter.getConfigPath(this.projectRoot);
|
|
2633
2633
|
const globalPath = adapter.getConfigPath();
|
|
2634
|
-
for (const
|
|
2635
|
-
if (existsSync4(
|
|
2634
|
+
for (const path8 of [configPath, globalPath]) {
|
|
2635
|
+
if (existsSync4(path8)) {
|
|
2636
2636
|
try {
|
|
2637
|
-
const content = readFileSync2(
|
|
2637
|
+
const content = readFileSync2(path8, "utf-8");
|
|
2638
2638
|
const servers = adapter.parse(content);
|
|
2639
2639
|
if (servers.length > 0) {
|
|
2640
2640
|
mcpConfigs[target] = servers;
|
|
@@ -3376,9 +3376,202 @@ var init_retention = __esm({
|
|
|
3376
3376
|
}
|
|
3377
3377
|
});
|
|
3378
3378
|
|
|
3379
|
-
// src/server.ts
|
|
3379
|
+
// src/dashboard/server.ts
|
|
3380
3380
|
var server_exports = {};
|
|
3381
3381
|
__export(server_exports, {
|
|
3382
|
+
startDashboard: () => startDashboard
|
|
3383
|
+
});
|
|
3384
|
+
import { createServer } from "http";
|
|
3385
|
+
import { promises as fs4 } from "fs";
|
|
3386
|
+
import path6 from "path";
|
|
3387
|
+
import { exec } from "child_process";
|
|
3388
|
+
function sendJson(res, data, status = 200) {
|
|
3389
|
+
res.writeHead(status, {
|
|
3390
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
3391
|
+
"Access-Control-Allow-Origin": "*"
|
|
3392
|
+
});
|
|
3393
|
+
res.end(JSON.stringify(data));
|
|
3394
|
+
}
|
|
3395
|
+
function sendError(res, message, status = 500) {
|
|
3396
|
+
sendJson(res, { error: message }, status);
|
|
3397
|
+
}
|
|
3398
|
+
function filterByProject(items, projectId) {
|
|
3399
|
+
return items.filter((item) => item.projectId === projectId);
|
|
3400
|
+
}
|
|
3401
|
+
async function handleApi(req, res, dataDir, projectId, projectName) {
|
|
3402
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
3403
|
+
const apiPath = url.pathname.replace("/api", "");
|
|
3404
|
+
try {
|
|
3405
|
+
switch (apiPath) {
|
|
3406
|
+
case "/project": {
|
|
3407
|
+
sendJson(res, { id: projectId, name: projectName });
|
|
3408
|
+
break;
|
|
3409
|
+
}
|
|
3410
|
+
case "/graph": {
|
|
3411
|
+
const graph = await loadGraphJsonl(dataDir);
|
|
3412
|
+
sendJson(res, graph);
|
|
3413
|
+
break;
|
|
3414
|
+
}
|
|
3415
|
+
case "/observations": {
|
|
3416
|
+
const allObs = await loadObservationsJson(dataDir);
|
|
3417
|
+
const observations2 = filterByProject(allObs, projectId);
|
|
3418
|
+
sendJson(res, observations2);
|
|
3419
|
+
break;
|
|
3420
|
+
}
|
|
3421
|
+
case "/stats": {
|
|
3422
|
+
const graph = await loadGraphJsonl(dataDir);
|
|
3423
|
+
const allObs = await loadObservationsJson(dataDir);
|
|
3424
|
+
const observations2 = filterByProject(allObs, projectId);
|
|
3425
|
+
const nextId2 = await loadIdCounter(dataDir);
|
|
3426
|
+
const typeCounts = {};
|
|
3427
|
+
for (const obs of observations2) {
|
|
3428
|
+
const t = obs.type || "unknown";
|
|
3429
|
+
typeCounts[t] = (typeCounts[t] || 0) + 1;
|
|
3430
|
+
}
|
|
3431
|
+
const sorted = [...observations2].sort((a, b) => (b.id || 0) - (a.id || 0)).slice(0, 10);
|
|
3432
|
+
sendJson(res, {
|
|
3433
|
+
entities: graph.entities.length,
|
|
3434
|
+
relations: graph.relations.length,
|
|
3435
|
+
observations: observations2.length,
|
|
3436
|
+
nextId: nextId2,
|
|
3437
|
+
typeCounts,
|
|
3438
|
+
recentObservations: sorted
|
|
3439
|
+
});
|
|
3440
|
+
break;
|
|
3441
|
+
}
|
|
3442
|
+
case "/retention": {
|
|
3443
|
+
const allObs = await loadObservationsJson(dataDir);
|
|
3444
|
+
const observations2 = filterByProject(allObs, projectId);
|
|
3445
|
+
const now = Date.now();
|
|
3446
|
+
const scored = observations2.map((obs) => {
|
|
3447
|
+
const age = now - new Date(obs.createdAt || now).getTime();
|
|
3448
|
+
const ageHours = age / (1e3 * 60 * 60);
|
|
3449
|
+
const importance = obs.importance ?? 5;
|
|
3450
|
+
const accessCount = obs.accessCount ?? 0;
|
|
3451
|
+
const lambda = 0.01;
|
|
3452
|
+
const decayScore = importance * Math.exp(-lambda * ageHours);
|
|
3453
|
+
const accessBonus = Math.min(accessCount * 0.5, 3);
|
|
3454
|
+
const score = Math.min(decayScore + accessBonus, 10);
|
|
3455
|
+
const isImmune2 = importance >= 8 || obs.type === "gotcha" || obs.type === "decision";
|
|
3456
|
+
return {
|
|
3457
|
+
id: obs.id,
|
|
3458
|
+
title: obs.title,
|
|
3459
|
+
type: obs.type,
|
|
3460
|
+
entityName: obs.entityName,
|
|
3461
|
+
score: Math.round(score * 100) / 100,
|
|
3462
|
+
isImmune: isImmune2,
|
|
3463
|
+
ageHours: Math.round(ageHours * 10) / 10,
|
|
3464
|
+
accessCount
|
|
3465
|
+
};
|
|
3466
|
+
});
|
|
3467
|
+
scored.sort((a, b) => b.score - a.score);
|
|
3468
|
+
const activeCount = scored.filter((s) => s.score >= 3).length;
|
|
3469
|
+
const staleCount = scored.filter((s) => s.score < 3 && s.score >= 1).length;
|
|
3470
|
+
const archiveCount = scored.filter((s) => s.score < 1).length;
|
|
3471
|
+
const immuneCount = scored.filter((s) => s.isImmune).length;
|
|
3472
|
+
sendJson(res, {
|
|
3473
|
+
summary: { active: activeCount, stale: staleCount, archive: archiveCount, immune: immuneCount },
|
|
3474
|
+
items: scored
|
|
3475
|
+
});
|
|
3476
|
+
break;
|
|
3477
|
+
}
|
|
3478
|
+
default:
|
|
3479
|
+
sendError(res, "Not found", 404);
|
|
3480
|
+
}
|
|
3481
|
+
} catch (err) {
|
|
3482
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
3483
|
+
sendError(res, message);
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
async function serveStatic(req, res, staticDir) {
|
|
3487
|
+
let urlPath = new URL(req.url || "/", `http://${req.headers.host}`).pathname;
|
|
3488
|
+
if (urlPath === "/" || !urlPath.includes(".")) {
|
|
3489
|
+
urlPath = "/index.html";
|
|
3490
|
+
}
|
|
3491
|
+
const filePath = path6.join(staticDir, urlPath);
|
|
3492
|
+
if (!filePath.startsWith(staticDir)) {
|
|
3493
|
+
sendError(res, "Forbidden", 403);
|
|
3494
|
+
return;
|
|
3495
|
+
}
|
|
3496
|
+
try {
|
|
3497
|
+
const data = await fs4.readFile(filePath);
|
|
3498
|
+
const ext = path6.extname(filePath);
|
|
3499
|
+
res.writeHead(200, {
|
|
3500
|
+
"Content-Type": MIME_TYPES[ext] || "application/octet-stream",
|
|
3501
|
+
"Cache-Control": "no-cache"
|
|
3502
|
+
});
|
|
3503
|
+
res.end(data);
|
|
3504
|
+
} catch {
|
|
3505
|
+
try {
|
|
3506
|
+
const indexData = await fs4.readFile(path6.join(staticDir, "index.html"));
|
|
3507
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
3508
|
+
res.end(indexData);
|
|
3509
|
+
} catch {
|
|
3510
|
+
sendError(res, "Not found", 404);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
function openBrowser(url) {
|
|
3515
|
+
const cmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
3516
|
+
exec(cmd, () => {
|
|
3517
|
+
});
|
|
3518
|
+
}
|
|
3519
|
+
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true) {
|
|
3520
|
+
const resolvedStaticDir = staticDir;
|
|
3521
|
+
const server = createServer(async (req, res) => {
|
|
3522
|
+
const url = req.url || "/";
|
|
3523
|
+
if (url.startsWith("/api/")) {
|
|
3524
|
+
await handleApi(req, res, dataDir, projectId, projectName);
|
|
3525
|
+
} else {
|
|
3526
|
+
await serveStatic(req, res, resolvedStaticDir);
|
|
3527
|
+
}
|
|
3528
|
+
});
|
|
3529
|
+
return new Promise((resolve2, reject) => {
|
|
3530
|
+
server.on("error", (err) => {
|
|
3531
|
+
if (err.code === "EADDRINUSE") {
|
|
3532
|
+
console.error(`Port ${port} is already in use. Try: memorix dashboard --port ${port + 1}`);
|
|
3533
|
+
reject(err);
|
|
3534
|
+
} else {
|
|
3535
|
+
reject(err);
|
|
3536
|
+
}
|
|
3537
|
+
});
|
|
3538
|
+
server.listen(port, () => {
|
|
3539
|
+
const url = `http://localhost:${port}`;
|
|
3540
|
+
console.error(`
|
|
3541
|
+
Memorix Dashboard`);
|
|
3542
|
+
console.error(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
3543
|
+
console.error(` Project: ${projectName} (${projectId})`);
|
|
3544
|
+
console.error(` Local: ${url}`);
|
|
3545
|
+
console.error(` Data dir: ${dataDir}`);
|
|
3546
|
+
console.error(`
|
|
3547
|
+
Press Ctrl+C to stop
|
|
3548
|
+
`);
|
|
3549
|
+
if (autoOpen) openBrowser(url);
|
|
3550
|
+
resolve2();
|
|
3551
|
+
});
|
|
3552
|
+
});
|
|
3553
|
+
}
|
|
3554
|
+
var MIME_TYPES;
|
|
3555
|
+
var init_server = __esm({
|
|
3556
|
+
"src/dashboard/server.ts"() {
|
|
3557
|
+
"use strict";
|
|
3558
|
+
init_esm_shims();
|
|
3559
|
+
init_persistence();
|
|
3560
|
+
MIME_TYPES = {
|
|
3561
|
+
".html": "text/html; charset=utf-8",
|
|
3562
|
+
".css": "text/css; charset=utf-8",
|
|
3563
|
+
".js": "application/javascript; charset=utf-8",
|
|
3564
|
+
".json": "application/json; charset=utf-8",
|
|
3565
|
+
".svg": "image/svg+xml",
|
|
3566
|
+
".png": "image/png",
|
|
3567
|
+
".ico": "image/x-icon"
|
|
3568
|
+
};
|
|
3569
|
+
}
|
|
3570
|
+
});
|
|
3571
|
+
|
|
3572
|
+
// src/server.ts
|
|
3573
|
+
var server_exports2 = {};
|
|
3574
|
+
__export(server_exports2, {
|
|
3382
3575
|
createMemorixServer: () => createMemorixServer
|
|
3383
3576
|
});
|
|
3384
3577
|
import { watch } from "fs";
|
|
@@ -3996,10 +4189,89 @@ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${enrichment}`
|
|
|
3996
4189
|
};
|
|
3997
4190
|
}
|
|
3998
4191
|
);
|
|
4192
|
+
let dashboardRunning = false;
|
|
4193
|
+
server.registerTool(
|
|
4194
|
+
"memorix_dashboard",
|
|
4195
|
+
{
|
|
4196
|
+
title: "Launch Dashboard",
|
|
4197
|
+
description: "Launch the Memorix Web Dashboard in the browser. Shows knowledge graph, observations, retention scores, and project stats in a visual interface.",
|
|
4198
|
+
inputSchema: {
|
|
4199
|
+
port: z.number().optional().describe("Port to run the dashboard on (default: 3210)")
|
|
4200
|
+
}
|
|
4201
|
+
},
|
|
4202
|
+
async ({ port: dashboardPort }) => {
|
|
4203
|
+
const portNum = dashboardPort || 3210;
|
|
4204
|
+
const url = `http://localhost:${portNum}`;
|
|
4205
|
+
if (dashboardRunning) {
|
|
4206
|
+
const { exec: exec2 } = await import("child_process");
|
|
4207
|
+
const cmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
4208
|
+
exec2(cmd, () => {
|
|
4209
|
+
});
|
|
4210
|
+
return {
|
|
4211
|
+
content: [{ type: "text", text: `Dashboard is already running at ${url}. Opened in browser.` }]
|
|
4212
|
+
};
|
|
4213
|
+
}
|
|
4214
|
+
try {
|
|
4215
|
+
const pathMod = await import("path");
|
|
4216
|
+
const fsMod = await import("fs");
|
|
4217
|
+
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
4218
|
+
const { startDashboard: startDashboard2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
4219
|
+
const candidates = [
|
|
4220
|
+
pathMod.default.join(__dirname, "..", "dashboard", "static"),
|
|
4221
|
+
pathMod.default.join(__dirname, "dashboard", "static"),
|
|
4222
|
+
pathMod.default.join(pathMod.default.dirname(fileURLToPath3(import.meta.url)), "..", "dashboard", "static"),
|
|
4223
|
+
pathMod.default.join(pathMod.default.dirname(fileURLToPath3(import.meta.url)), "dashboard", "static")
|
|
4224
|
+
];
|
|
4225
|
+
for (const [i, c] of candidates.entries()) {
|
|
4226
|
+
const hasIndex = fsMod.existsSync(pathMod.default.join(c, "index.html"));
|
|
4227
|
+
console.error(`[memorix] candidate[${i}]: ${c} (has index.html: ${hasIndex})`);
|
|
4228
|
+
}
|
|
4229
|
+
let staticDir = candidates[0];
|
|
4230
|
+
for (const c of candidates) {
|
|
4231
|
+
if (fsMod.existsSync(pathMod.default.join(c, "index.html"))) {
|
|
4232
|
+
staticDir = c;
|
|
4233
|
+
break;
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
console.error(`[memorix] Dashboard staticDir: ${staticDir}`);
|
|
4237
|
+
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false).then(() => {
|
|
4238
|
+
dashboardRunning = true;
|
|
4239
|
+
}).catch((err) => {
|
|
4240
|
+
console.error("[memorix] Dashboard error:", err);
|
|
4241
|
+
dashboardRunning = false;
|
|
4242
|
+
});
|
|
4243
|
+
await new Promise((resolve2) => setTimeout(resolve2, 800));
|
|
4244
|
+
dashboardRunning = true;
|
|
4245
|
+
const { exec: execCmd } = await import("child_process");
|
|
4246
|
+
const openCmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
4247
|
+
execCmd(openCmd, () => {
|
|
4248
|
+
});
|
|
4249
|
+
return {
|
|
4250
|
+
content: [{
|
|
4251
|
+
type: "text",
|
|
4252
|
+
text: [
|
|
4253
|
+
`Memorix Dashboard started!`,
|
|
4254
|
+
``,
|
|
4255
|
+
`URL: ${url}`,
|
|
4256
|
+
`Project: ${project.name} (${project.id})`,
|
|
4257
|
+
`Static: ${staticDir}`,
|
|
4258
|
+
``,
|
|
4259
|
+
`The dashboard has been opened in your default browser.`,
|
|
4260
|
+
`It shows your knowledge graph, observations, retention scores, and project stats.`
|
|
4261
|
+
].join("\n")
|
|
4262
|
+
}]
|
|
4263
|
+
};
|
|
4264
|
+
} catch (err) {
|
|
4265
|
+
return {
|
|
4266
|
+
content: [{ type: "text", text: `Failed to start dashboard: ${err instanceof Error ? err.message : String(err)}` }]
|
|
4267
|
+
};
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
);
|
|
3999
4271
|
return { server, graphManager, projectId: project.id };
|
|
4000
4272
|
}
|
|
4001
4273
|
var OBSERVATION_TYPES;
|
|
4002
|
-
var
|
|
4274
|
+
var init_server2 = __esm({
|
|
4003
4275
|
"src/server.ts"() {
|
|
4004
4276
|
"use strict";
|
|
4005
4277
|
init_esm_shims();
|
|
@@ -4052,7 +4324,7 @@ var init_serve = __esm({
|
|
|
4052
4324
|
},
|
|
4053
4325
|
run: async ({ args }) => {
|
|
4054
4326
|
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
4055
|
-
const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (
|
|
4327
|
+
const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
|
|
4056
4328
|
const projectRoot = args.cwd || process.cwd();
|
|
4057
4329
|
const { server, projectId } = await createMemorixServer2(projectRoot);
|
|
4058
4330
|
const transport = new StdioServerTransport();
|
|
@@ -4164,8 +4436,8 @@ var init_sync = __esm({
|
|
|
4164
4436
|
run: async ({ args }) => {
|
|
4165
4437
|
const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
4166
4438
|
const { RulesSyncer: RulesSyncer2 } = await Promise.resolve().then(() => (init_syncer(), syncer_exports));
|
|
4167
|
-
const { promises:
|
|
4168
|
-
const
|
|
4439
|
+
const { promises: fs5 } = await import("fs");
|
|
4440
|
+
const path8 = await import("path");
|
|
4169
4441
|
p2.intro("memorix sync");
|
|
4170
4442
|
const project = detectProject2();
|
|
4171
4443
|
p2.log.info(`Project: ${project.name} (${project.id})`);
|
|
@@ -4233,9 +4505,9 @@ var init_sync = __esm({
|
|
|
4233
4505
|
process.exit(0);
|
|
4234
4506
|
}
|
|
4235
4507
|
for (const file of files) {
|
|
4236
|
-
const fullPath =
|
|
4237
|
-
await
|
|
4238
|
-
await
|
|
4508
|
+
const fullPath = path8.join(project.rootPath, file.filePath);
|
|
4509
|
+
await fs5.mkdir(path8.dirname(fullPath), { recursive: true });
|
|
4510
|
+
await fs5.writeFile(fullPath, file.content, "utf-8");
|
|
4239
4511
|
p2.log.success(`Written: ${file.filePath}`);
|
|
4240
4512
|
}
|
|
4241
4513
|
p2.outro(`Synced ${files.length} rule(s) to ${target} format`);
|
|
@@ -4960,13 +5232,58 @@ var init_hooks = __esm({
|
|
|
4960
5232
|
}
|
|
4961
5233
|
});
|
|
4962
5234
|
|
|
5235
|
+
// src/cli/commands/dashboard.ts
|
|
5236
|
+
var dashboard_exports = {};
|
|
5237
|
+
__export(dashboard_exports, {
|
|
5238
|
+
default: () => dashboard_default
|
|
5239
|
+
});
|
|
5240
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
5241
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5242
|
+
import path7 from "path";
|
|
5243
|
+
var dashboard_default;
|
|
5244
|
+
var init_dashboard = __esm({
|
|
5245
|
+
"src/cli/commands/dashboard.ts"() {
|
|
5246
|
+
"use strict";
|
|
5247
|
+
init_esm_shims();
|
|
5248
|
+
dashboard_default = defineCommand9({
|
|
5249
|
+
meta: {
|
|
5250
|
+
name: "dashboard",
|
|
5251
|
+
description: "Launch the Memorix Web Dashboard"
|
|
5252
|
+
},
|
|
5253
|
+
args: {
|
|
5254
|
+
port: {
|
|
5255
|
+
type: "string",
|
|
5256
|
+
description: "Port to run the dashboard on (default: 3210)",
|
|
5257
|
+
default: "3210"
|
|
5258
|
+
}
|
|
5259
|
+
},
|
|
5260
|
+
run: async ({ args }) => {
|
|
5261
|
+
const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
5262
|
+
const { getProjectDataDir: getProjectDataDir2 } = await Promise.resolve().then(() => (init_persistence(), persistence_exports));
|
|
5263
|
+
const { startDashboard: startDashboard2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
5264
|
+
const project = detectProject2();
|
|
5265
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
5266
|
+
const port = parseInt(args.port, 10) || 3210;
|
|
5267
|
+
const cliDir = path7.dirname(fileURLToPath2(import.meta.url));
|
|
5268
|
+
const staticDir = path7.join(cliDir, "..", "dashboard", "static");
|
|
5269
|
+
await startDashboard2(dataDir, port, staticDir, project.id, project.name);
|
|
5270
|
+
await new Promise(() => {
|
|
5271
|
+
});
|
|
5272
|
+
}
|
|
5273
|
+
});
|
|
5274
|
+
}
|
|
5275
|
+
});
|
|
5276
|
+
|
|
4963
5277
|
// src/cli/index.ts
|
|
4964
5278
|
init_esm_shims();
|
|
4965
|
-
import { defineCommand as
|
|
4966
|
-
|
|
5279
|
+
import { defineCommand as defineCommand10, runMain } from "citty";
|
|
5280
|
+
import { createRequire as createRequire2 } from "module";
|
|
5281
|
+
var require2 = createRequire2(import.meta.url);
|
|
5282
|
+
var pkg = require2("../../package.json");
|
|
5283
|
+
var main = defineCommand10({
|
|
4967
5284
|
meta: {
|
|
4968
5285
|
name: "memorix",
|
|
4969
|
-
version:
|
|
5286
|
+
version: pkg.version,
|
|
4970
5287
|
description: "Cross-Agent Memory Bridge \u2014 Universal memory layer for AI coding agents via MCP"
|
|
4971
5288
|
},
|
|
4972
5289
|
subCommands: {
|
|
@@ -4974,7 +5291,8 @@ var main = defineCommand9({
|
|
|
4974
5291
|
status: () => Promise.resolve().then(() => (init_status(), status_exports)).then((m) => m.default),
|
|
4975
5292
|
sync: () => Promise.resolve().then(() => (init_sync(), sync_exports)).then((m) => m.default),
|
|
4976
5293
|
hook: () => Promise.resolve().then(() => (init_hook(), hook_exports)).then((m) => m.default),
|
|
4977
|
-
hooks: () => Promise.resolve().then(() => (init_hooks(), hooks_exports)).then((m) => m.default)
|
|
5294
|
+
hooks: () => Promise.resolve().then(() => (init_hooks(), hooks_exports)).then((m) => m.default),
|
|
5295
|
+
dashboard: () => Promise.resolve().then(() => (init_dashboard(), dashboard_exports)).then((m) => m.default)
|
|
4978
5296
|
},
|
|
4979
5297
|
run() {
|
|
4980
5298
|
}
|