memorix 0.1.5 → 0.2.1
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/dist/cli/index.js +957 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -722,6 +722,15 @@ var init_entity_extractor = __esm({
|
|
|
722
722
|
});
|
|
723
723
|
|
|
724
724
|
// src/memory/observations.ts
|
|
725
|
+
var observations_exports = {};
|
|
726
|
+
__export(observations_exports, {
|
|
727
|
+
getObservation: () => getObservation,
|
|
728
|
+
getObservationCount: () => getObservationCount2,
|
|
729
|
+
getProjectObservations: () => getProjectObservations,
|
|
730
|
+
initObservations: () => initObservations,
|
|
731
|
+
reindexObservations: () => reindexObservations,
|
|
732
|
+
storeObservation: () => storeObservation
|
|
733
|
+
});
|
|
725
734
|
async function initObservations(dir) {
|
|
726
735
|
projectDir = dir;
|
|
727
736
|
const loaded = await loadObservationsJson(dir);
|
|
@@ -793,6 +802,12 @@ async function storeObservation(input) {
|
|
|
793
802
|
function getObservation(id) {
|
|
794
803
|
return observations.find((o) => o.id === id);
|
|
795
804
|
}
|
|
805
|
+
function getProjectObservations(projectId) {
|
|
806
|
+
return observations.filter((o) => o.projectId === projectId);
|
|
807
|
+
}
|
|
808
|
+
function getObservationCount2() {
|
|
809
|
+
return observations.length;
|
|
810
|
+
}
|
|
796
811
|
async function reindexObservations() {
|
|
797
812
|
let count2 = 0;
|
|
798
813
|
for (const obs of observations) {
|
|
@@ -2264,10 +2279,10 @@ var init_engine2 = __esm({
|
|
|
2264
2279
|
for (const [target, adapter] of this.adapters) {
|
|
2265
2280
|
const configPath = adapter.getConfigPath(this.projectRoot);
|
|
2266
2281
|
const globalPath = adapter.getConfigPath();
|
|
2267
|
-
for (const
|
|
2268
|
-
if (existsSync3(
|
|
2282
|
+
for (const path6 of [configPath, globalPath]) {
|
|
2283
|
+
if (existsSync3(path6)) {
|
|
2269
2284
|
try {
|
|
2270
|
-
const content = readFileSync(
|
|
2285
|
+
const content = readFileSync(path6, "utf-8");
|
|
2271
2286
|
const servers = adapter.parse(content);
|
|
2272
2287
|
if (servers.length > 0) {
|
|
2273
2288
|
mcpConfigs[target] = servers;
|
|
@@ -2532,6 +2547,7 @@ var server_exports = {};
|
|
|
2532
2547
|
__export(server_exports, {
|
|
2533
2548
|
createMemorixServer: () => createMemorixServer
|
|
2534
2549
|
});
|
|
2550
|
+
import { watch } from "fs";
|
|
2535
2551
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2536
2552
|
import { z } from "zod";
|
|
2537
2553
|
async function createMemorixServer(cwd) {
|
|
@@ -2546,6 +2562,26 @@ async function createMemorixServer(cwd) {
|
|
|
2546
2562
|
}
|
|
2547
2563
|
console.error(`[memorix] Project: ${project.id} (${project.name})`);
|
|
2548
2564
|
console.error(`[memorix] Data dir: ${projectDir2}`);
|
|
2565
|
+
const observationsFile = projectDir2 + "/observations.json";
|
|
2566
|
+
let reloadDebounce = null;
|
|
2567
|
+
try {
|
|
2568
|
+
watch(observationsFile, () => {
|
|
2569
|
+
if (reloadDebounce) clearTimeout(reloadDebounce);
|
|
2570
|
+
reloadDebounce = setTimeout(async () => {
|
|
2571
|
+
try {
|
|
2572
|
+
await initObservations(projectDir2);
|
|
2573
|
+
const count2 = await reindexObservations();
|
|
2574
|
+
if (count2 > 0) {
|
|
2575
|
+
console.error(`[memorix] Hot-reloaded ${count2} observations (external write detected)`);
|
|
2576
|
+
}
|
|
2577
|
+
} catch {
|
|
2578
|
+
}
|
|
2579
|
+
}, 500);
|
|
2580
|
+
});
|
|
2581
|
+
console.error(`[memorix] Watching for external writes (hooks hot-reload enabled)`);
|
|
2582
|
+
} catch {
|
|
2583
|
+
console.error(`[memorix] Warning: could not watch observations file for hot-reload`);
|
|
2584
|
+
}
|
|
2549
2585
|
const server = new McpServer({
|
|
2550
2586
|
name: "memorix",
|
|
2551
2587
|
version: "0.1.0"
|
|
@@ -3204,8 +3240,8 @@ var init_sync = __esm({
|
|
|
3204
3240
|
run: async ({ args }) => {
|
|
3205
3241
|
const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
3206
3242
|
const { RulesSyncer: RulesSyncer2 } = await Promise.resolve().then(() => (init_syncer(), syncer_exports));
|
|
3207
|
-
const { promises:
|
|
3208
|
-
const
|
|
3243
|
+
const { promises: fs4 } = await import("fs");
|
|
3244
|
+
const path6 = await import("path");
|
|
3209
3245
|
p2.intro("memorix sync");
|
|
3210
3246
|
const project = detectProject2();
|
|
3211
3247
|
p2.log.info(`Project: ${project.name} (${project.id})`);
|
|
@@ -3273,9 +3309,9 @@ var init_sync = __esm({
|
|
|
3273
3309
|
process.exit(0);
|
|
3274
3310
|
}
|
|
3275
3311
|
for (const file of files) {
|
|
3276
|
-
const fullPath =
|
|
3277
|
-
await
|
|
3278
|
-
await
|
|
3312
|
+
const fullPath = path6.join(project.rootPath, file.filePath);
|
|
3313
|
+
await fs4.mkdir(path6.dirname(fullPath), { recursive: true });
|
|
3314
|
+
await fs4.writeFile(fullPath, file.content, "utf-8");
|
|
3279
3315
|
p2.log.success(`Written: ${file.filePath}`);
|
|
3280
3316
|
}
|
|
3281
3317
|
p2.outro(`Synced ${files.length} rule(s) to ${target} format`);
|
|
@@ -3284,10 +3320,918 @@ var init_sync = __esm({
|
|
|
3284
3320
|
}
|
|
3285
3321
|
});
|
|
3286
3322
|
|
|
3323
|
+
// src/hooks/normalizer.ts
|
|
3324
|
+
function detectAgent(payload) {
|
|
3325
|
+
if ("agent_action_name" in payload) return "windsurf";
|
|
3326
|
+
if ("hook_event_name" in payload && "conversation_id" in payload) return "cursor";
|
|
3327
|
+
if ("hookEventName" in payload) {
|
|
3328
|
+
return "copilot";
|
|
3329
|
+
}
|
|
3330
|
+
if ("event_type" in payload) return "kiro";
|
|
3331
|
+
if ("hook_type" in payload) return "codex";
|
|
3332
|
+
return "claude";
|
|
3333
|
+
}
|
|
3334
|
+
function extractEventName(payload, agent) {
|
|
3335
|
+
switch (agent) {
|
|
3336
|
+
case "windsurf":
|
|
3337
|
+
return payload.agent_action_name ?? "";
|
|
3338
|
+
case "cursor":
|
|
3339
|
+
return payload.hook_event_name ?? "";
|
|
3340
|
+
case "copilot":
|
|
3341
|
+
case "claude":
|
|
3342
|
+
return payload.hookEventName ?? "";
|
|
3343
|
+
case "kiro":
|
|
3344
|
+
return payload.event_type ?? "";
|
|
3345
|
+
case "codex":
|
|
3346
|
+
return payload.hook_type ?? "";
|
|
3347
|
+
default:
|
|
3348
|
+
return "";
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
function normalizeClaude(payload, event) {
|
|
3352
|
+
const result = {
|
|
3353
|
+
sessionId: payload.sessionId ?? "",
|
|
3354
|
+
cwd: payload.cwd ?? "",
|
|
3355
|
+
transcriptPath: payload.transcript_path
|
|
3356
|
+
};
|
|
3357
|
+
const toolName = payload.tool_name ?? "";
|
|
3358
|
+
if (toolName) {
|
|
3359
|
+
result.toolName = toolName;
|
|
3360
|
+
result.toolInput = payload.tool_input;
|
|
3361
|
+
result.toolResult = payload.tool_result;
|
|
3362
|
+
if (toolName === "write" || toolName === "edit" || toolName === "multi_edit") {
|
|
3363
|
+
const input = payload.tool_input;
|
|
3364
|
+
result.filePath = input?.file_path ?? input?.filePath;
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
if (event === "user_prompt") {
|
|
3368
|
+
result.userPrompt = payload.prompt ?? "";
|
|
3369
|
+
}
|
|
3370
|
+
return result;
|
|
3371
|
+
}
|
|
3372
|
+
function normalizeWindsurf(payload, event) {
|
|
3373
|
+
const toolInfo = payload.tool_info ?? {};
|
|
3374
|
+
const result = {
|
|
3375
|
+
sessionId: payload.trajectory_id ?? "",
|
|
3376
|
+
cwd: ""
|
|
3377
|
+
};
|
|
3378
|
+
switch (event) {
|
|
3379
|
+
case "post_edit":
|
|
3380
|
+
result.filePath = toolInfo.file_path;
|
|
3381
|
+
if (Array.isArray(toolInfo.edits)) {
|
|
3382
|
+
result.edits = toolInfo.edits.map((e) => ({
|
|
3383
|
+
oldString: e.old_string ?? "",
|
|
3384
|
+
newString: e.new_string ?? ""
|
|
3385
|
+
}));
|
|
3386
|
+
}
|
|
3387
|
+
break;
|
|
3388
|
+
case "post_command":
|
|
3389
|
+
result.command = toolInfo.command_line;
|
|
3390
|
+
result.cwd = toolInfo.cwd ?? "";
|
|
3391
|
+
break;
|
|
3392
|
+
case "post_tool":
|
|
3393
|
+
result.toolName = toolInfo.mcp_tool_name;
|
|
3394
|
+
result.toolInput = toolInfo.mcp_tool_arguments;
|
|
3395
|
+
result.toolResult = toolInfo.mcp_result;
|
|
3396
|
+
break;
|
|
3397
|
+
case "user_prompt":
|
|
3398
|
+
result.userPrompt = toolInfo.user_prompt;
|
|
3399
|
+
break;
|
|
3400
|
+
case "post_response":
|
|
3401
|
+
result.aiResponse = toolInfo.response;
|
|
3402
|
+
break;
|
|
3403
|
+
}
|
|
3404
|
+
return result;
|
|
3405
|
+
}
|
|
3406
|
+
function normalizeCursor(payload, event) {
|
|
3407
|
+
const result = {
|
|
3408
|
+
sessionId: payload.conversation_id ?? "",
|
|
3409
|
+
cwd: payload.cwd ?? ""
|
|
3410
|
+
};
|
|
3411
|
+
const roots = payload.workspace_roots;
|
|
3412
|
+
if (roots?.length && !result.cwd) {
|
|
3413
|
+
result.cwd = roots[0];
|
|
3414
|
+
}
|
|
3415
|
+
switch (event) {
|
|
3416
|
+
case "user_prompt":
|
|
3417
|
+
result.userPrompt = payload.prompt ?? "";
|
|
3418
|
+
break;
|
|
3419
|
+
case "post_command":
|
|
3420
|
+
result.command = payload.command ?? "";
|
|
3421
|
+
break;
|
|
3422
|
+
case "post_edit":
|
|
3423
|
+
result.filePath = payload.file_path ?? "";
|
|
3424
|
+
break;
|
|
3425
|
+
}
|
|
3426
|
+
return result;
|
|
3427
|
+
}
|
|
3428
|
+
function normalizeHookInput(payload) {
|
|
3429
|
+
const agent = detectAgent(payload);
|
|
3430
|
+
const rawEventName = extractEventName(payload, agent);
|
|
3431
|
+
const event = EVENT_MAP[rawEventName] ?? "post_tool";
|
|
3432
|
+
const timestamp = payload.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3433
|
+
let agentSpecific = {};
|
|
3434
|
+
switch (agent) {
|
|
3435
|
+
case "claude":
|
|
3436
|
+
case "copilot":
|
|
3437
|
+
agentSpecific = normalizeClaude(payload, event);
|
|
3438
|
+
break;
|
|
3439
|
+
case "windsurf":
|
|
3440
|
+
agentSpecific = normalizeWindsurf(payload, event);
|
|
3441
|
+
break;
|
|
3442
|
+
case "cursor":
|
|
3443
|
+
agentSpecific = normalizeCursor(payload, event);
|
|
3444
|
+
break;
|
|
3445
|
+
default:
|
|
3446
|
+
agentSpecific = { sessionId: "", cwd: "" };
|
|
3447
|
+
}
|
|
3448
|
+
return {
|
|
3449
|
+
event,
|
|
3450
|
+
agent,
|
|
3451
|
+
timestamp,
|
|
3452
|
+
sessionId: agentSpecific.sessionId ?? "",
|
|
3453
|
+
cwd: agentSpecific.cwd ?? "",
|
|
3454
|
+
raw: payload,
|
|
3455
|
+
...agentSpecific
|
|
3456
|
+
};
|
|
3457
|
+
}
|
|
3458
|
+
var EVENT_MAP;
|
|
3459
|
+
var init_normalizer = __esm({
|
|
3460
|
+
"src/hooks/normalizer.ts"() {
|
|
3461
|
+
"use strict";
|
|
3462
|
+
init_esm_shims();
|
|
3463
|
+
EVENT_MAP = {
|
|
3464
|
+
// Claude Code / VS Code Copilot
|
|
3465
|
+
SessionStart: "session_start",
|
|
3466
|
+
UserPromptSubmit: "user_prompt",
|
|
3467
|
+
PreToolUse: "post_tool",
|
|
3468
|
+
// we handle pre as post for memory purposes
|
|
3469
|
+
PostToolUse: "post_tool",
|
|
3470
|
+
PreCompact: "pre_compact",
|
|
3471
|
+
Stop: "session_end",
|
|
3472
|
+
// Windsurf
|
|
3473
|
+
pre_user_prompt: "user_prompt",
|
|
3474
|
+
post_write_code: "post_edit",
|
|
3475
|
+
post_read_code: "post_tool",
|
|
3476
|
+
post_run_command: "post_command",
|
|
3477
|
+
pre_mcp_tool_use: "post_tool",
|
|
3478
|
+
post_mcp_tool_use: "post_tool",
|
|
3479
|
+
post_cascade_response: "post_response",
|
|
3480
|
+
// Cursor
|
|
3481
|
+
beforeSubmitPrompt: "user_prompt",
|
|
3482
|
+
beforeShellExecution: "post_command",
|
|
3483
|
+
beforeMCPExecution: "post_tool",
|
|
3484
|
+
afterFileEdit: "post_edit",
|
|
3485
|
+
stop: "session_end"
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
});
|
|
3489
|
+
|
|
3490
|
+
// src/hooks/pattern-detector.ts
|
|
3491
|
+
function detectPatterns(content) {
|
|
3492
|
+
if (!content || content.length < MIN_CONTENT_LENGTH) {
|
|
3493
|
+
return [];
|
|
3494
|
+
}
|
|
3495
|
+
const results = [];
|
|
3496
|
+
for (const pattern of PATTERNS) {
|
|
3497
|
+
if (content.length < pattern.minLength) continue;
|
|
3498
|
+
const matchedKeywords = [];
|
|
3499
|
+
let matchCount = 0;
|
|
3500
|
+
for (const regex of pattern.keywords) {
|
|
3501
|
+
const matches = content.match(new RegExp(regex.source, regex.flags + "g"));
|
|
3502
|
+
if (matches) {
|
|
3503
|
+
matchCount += matches.length;
|
|
3504
|
+
matchedKeywords.push(...matches.map((m) => m.trim()));
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
if (matchCount > 0) {
|
|
3508
|
+
const confidence = Math.min(1, pattern.baseConfidence + matchCount * 0.05);
|
|
3509
|
+
results.push({
|
|
3510
|
+
type: pattern.type,
|
|
3511
|
+
confidence,
|
|
3512
|
+
matchedKeywords: [...new Set(matchedKeywords)].slice(0, 5)
|
|
3513
|
+
});
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
results.sort((a, b) => b.confidence - a.confidence);
|
|
3517
|
+
return results;
|
|
3518
|
+
}
|
|
3519
|
+
function detectBestPattern(content, minConfidence = 0.5) {
|
|
3520
|
+
const patterns = detectPatterns(content);
|
|
3521
|
+
if (patterns.length === 0) return null;
|
|
3522
|
+
if (patterns[0].confidence < minConfidence) return null;
|
|
3523
|
+
return patterns[0];
|
|
3524
|
+
}
|
|
3525
|
+
function patternToObservationType(pattern) {
|
|
3526
|
+
const map = {
|
|
3527
|
+
decision: "decision",
|
|
3528
|
+
error: "problem-solution",
|
|
3529
|
+
gotcha: "gotcha",
|
|
3530
|
+
configuration: "what-changed",
|
|
3531
|
+
learning: "discovery",
|
|
3532
|
+
implementation: "what-changed"
|
|
3533
|
+
};
|
|
3534
|
+
return map[pattern] ?? "discovery";
|
|
3535
|
+
}
|
|
3536
|
+
var MIN_CONTENT_LENGTH, PATTERNS;
|
|
3537
|
+
var init_pattern_detector = __esm({
|
|
3538
|
+
"src/hooks/pattern-detector.ts"() {
|
|
3539
|
+
"use strict";
|
|
3540
|
+
init_esm_shims();
|
|
3541
|
+
MIN_CONTENT_LENGTH = 100;
|
|
3542
|
+
PATTERNS = [
|
|
3543
|
+
{
|
|
3544
|
+
type: "decision",
|
|
3545
|
+
keywords: [
|
|
3546
|
+
/\b(decided|chose|will use|settled on|going with|picked|selected)\b/i,
|
|
3547
|
+
/(决定|选择了|采用|确定用|最终选了)/,
|
|
3548
|
+
/\b(architecture|approach|strategy|pattern|framework)\b/i
|
|
3549
|
+
],
|
|
3550
|
+
minLength: 100,
|
|
3551
|
+
baseConfidence: 0.8
|
|
3552
|
+
},
|
|
3553
|
+
{
|
|
3554
|
+
type: "error",
|
|
3555
|
+
keywords: [
|
|
3556
|
+
/\b(error|bug|fix(ed)?|resolv(ed|ing)|crash|fail(ed|ure)?|broken)\b/i,
|
|
3557
|
+
/(错误|修复|报错|崩溃|失败|异常|解决了)/,
|
|
3558
|
+
/\b(workaround|hotfix|patch|regression|stack\s*trace)\b/i
|
|
3559
|
+
],
|
|
3560
|
+
minLength: 100,
|
|
3561
|
+
baseConfidence: 0.75
|
|
3562
|
+
},
|
|
3563
|
+
{
|
|
3564
|
+
type: "gotcha",
|
|
3565
|
+
keywords: [
|
|
3566
|
+
/\b(gotcha|pitfall|trap|caveat|watch out|careful|beware|warning)\b/i,
|
|
3567
|
+
/(坑|注意|陷阱|小心|踩坑|坑点)/,
|
|
3568
|
+
/\b(don'?t|never|avoid|must not|不要|千万别|切记)\b/i
|
|
3569
|
+
],
|
|
3570
|
+
minLength: 80,
|
|
3571
|
+
baseConfidence: 0.85
|
|
3572
|
+
},
|
|
3573
|
+
{
|
|
3574
|
+
type: "configuration",
|
|
3575
|
+
keywords: [
|
|
3576
|
+
/\b(config(ured?|uration)?|setting|environment|env\b|\.env|path|port)\b/i,
|
|
3577
|
+
/(配置|环境|路径|端口|设置|安装)/,
|
|
3578
|
+
/\b(gradle|webpack|vite|tsconfig|package\.json|docker)\b/i
|
|
3579
|
+
],
|
|
3580
|
+
minLength: 80,
|
|
3581
|
+
baseConfidence: 0.7
|
|
3582
|
+
},
|
|
3583
|
+
{
|
|
3584
|
+
type: "learning",
|
|
3585
|
+
keywords: [
|
|
3586
|
+
/\b(learn(ed)?|discover(ed)?|realiz(ed)?|turns?\s*out|found\s*out|TIL)\b/i,
|
|
3587
|
+
/(学到|发现|原来|才知道|了解到)/,
|
|
3588
|
+
/\b(insight|understanding|clarif(ied|ication))\b/i
|
|
3589
|
+
],
|
|
3590
|
+
minLength: 150,
|
|
3591
|
+
baseConfidence: 0.65
|
|
3592
|
+
},
|
|
3593
|
+
{
|
|
3594
|
+
type: "implementation",
|
|
3595
|
+
keywords: [
|
|
3596
|
+
/\b(implement(ed)?|creat(ed|ing)|built|added|integrat(ed|ing))\b/i,
|
|
3597
|
+
/(实现了|创建了|添加了|集成了|完成了)/,
|
|
3598
|
+
/\b(refactor(ed)?|migrat(ed|ing)|upgrad(ed|ing))\b/i
|
|
3599
|
+
],
|
|
3600
|
+
minLength: 200,
|
|
3601
|
+
baseConfidence: 0.5
|
|
3602
|
+
}
|
|
3603
|
+
];
|
|
3604
|
+
}
|
|
3605
|
+
});
|
|
3606
|
+
|
|
3607
|
+
// src/hooks/handler.ts
|
|
3608
|
+
var handler_exports = {};
|
|
3609
|
+
__export(handler_exports, {
|
|
3610
|
+
handleHookEvent: () => handleHookEvent,
|
|
3611
|
+
runHook: () => runHook
|
|
3612
|
+
});
|
|
3613
|
+
function isInCooldown(eventKey) {
|
|
3614
|
+
const last = cooldowns.get(eventKey);
|
|
3615
|
+
if (!last) return false;
|
|
3616
|
+
return Date.now() - last < COOLDOWN_MS;
|
|
3617
|
+
}
|
|
3618
|
+
function markTriggered(eventKey) {
|
|
3619
|
+
cooldowns.set(eventKey, Date.now());
|
|
3620
|
+
}
|
|
3621
|
+
function extractContent(input) {
|
|
3622
|
+
const parts = [];
|
|
3623
|
+
if (input.userPrompt) parts.push(input.userPrompt);
|
|
3624
|
+
if (input.aiResponse) parts.push(input.aiResponse);
|
|
3625
|
+
if (input.toolResult) parts.push(input.toolResult);
|
|
3626
|
+
if (input.commandOutput) parts.push(input.commandOutput);
|
|
3627
|
+
if (input.command) parts.push(`Command: ${input.command}`);
|
|
3628
|
+
if (input.filePath) parts.push(`File: ${input.filePath}`);
|
|
3629
|
+
if (input.edits) {
|
|
3630
|
+
for (const edit of input.edits) {
|
|
3631
|
+
parts.push(`Edit: ${edit.oldString} \u2192 ${edit.newString}`);
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
return parts.join("\n").slice(0, MAX_CONTENT_LENGTH);
|
|
3635
|
+
}
|
|
3636
|
+
function deriveEntityName(input) {
|
|
3637
|
+
if (input.filePath) {
|
|
3638
|
+
const parts = input.filePath.replace(/\\/g, "/").split("/");
|
|
3639
|
+
const filename = parts[parts.length - 1];
|
|
3640
|
+
return filename.replace(/\.[^.]+$/, "");
|
|
3641
|
+
}
|
|
3642
|
+
if (input.toolName) return input.toolName;
|
|
3643
|
+
if (input.command) {
|
|
3644
|
+
const firstWord = input.command.split(/\s+/)[0];
|
|
3645
|
+
return firstWord.replace(/[^a-zA-Z0-9-_]/g, "");
|
|
3646
|
+
}
|
|
3647
|
+
return "session";
|
|
3648
|
+
}
|
|
3649
|
+
function generateTitle(input, patternType) {
|
|
3650
|
+
const maxLen = 60;
|
|
3651
|
+
if (input.filePath) {
|
|
3652
|
+
const filename = input.filePath.replace(/\\/g, "/").split("/").pop() ?? "";
|
|
3653
|
+
const verb = patternType === "problem-solution" ? "Fixed issue in" : patternType === "what-changed" ? "Changed" : "Updated";
|
|
3654
|
+
return `${verb} ${filename}`.slice(0, maxLen);
|
|
3655
|
+
}
|
|
3656
|
+
if (input.command) {
|
|
3657
|
+
return `Ran: ${input.command}`.slice(0, maxLen);
|
|
3658
|
+
}
|
|
3659
|
+
if (input.userPrompt) {
|
|
3660
|
+
return input.userPrompt.slice(0, maxLen);
|
|
3661
|
+
}
|
|
3662
|
+
return `Session activity (${patternType})`;
|
|
3663
|
+
}
|
|
3664
|
+
function buildObservation(input, content) {
|
|
3665
|
+
const pattern = detectBestPattern(content);
|
|
3666
|
+
const obsType = pattern ? patternToObservationType(pattern.type) : "discovery";
|
|
3667
|
+
return {
|
|
3668
|
+
entityName: deriveEntityName(input),
|
|
3669
|
+
type: obsType,
|
|
3670
|
+
title: generateTitle(input, obsType),
|
|
3671
|
+
narrative: content.slice(0, 2e3),
|
|
3672
|
+
facts: [
|
|
3673
|
+
`Agent: ${input.agent}`,
|
|
3674
|
+
`Session: ${input.sessionId}`,
|
|
3675
|
+
...input.filePath ? [`File: ${input.filePath}`] : [],
|
|
3676
|
+
...input.command ? [`Command: ${input.command}`] : []
|
|
3677
|
+
],
|
|
3678
|
+
concepts: pattern?.matchedKeywords ?? [],
|
|
3679
|
+
filesModified: input.filePath ? [input.filePath] : []
|
|
3680
|
+
};
|
|
3681
|
+
}
|
|
3682
|
+
async function handleHookEvent(input) {
|
|
3683
|
+
const defaultOutput = { continue: true };
|
|
3684
|
+
if (input.toolName === "memorix_store" || input.toolName === "memorix_search") {
|
|
3685
|
+
return { observation: null, output: defaultOutput };
|
|
3686
|
+
}
|
|
3687
|
+
switch (input.event) {
|
|
3688
|
+
case "session_start":
|
|
3689
|
+
return {
|
|
3690
|
+
observation: null,
|
|
3691
|
+
output: {
|
|
3692
|
+
continue: true,
|
|
3693
|
+
systemMessage: "Memorix is active. Your memories from previous sessions are available via memorix_search."
|
|
3694
|
+
}
|
|
3695
|
+
};
|
|
3696
|
+
case "pre_compact":
|
|
3697
|
+
return {
|
|
3698
|
+
observation: buildObservation(input, extractContent(input)),
|
|
3699
|
+
output: defaultOutput
|
|
3700
|
+
};
|
|
3701
|
+
case "session_end":
|
|
3702
|
+
return {
|
|
3703
|
+
observation: buildObservation(input, extractContent(input)),
|
|
3704
|
+
output: defaultOutput
|
|
3705
|
+
};
|
|
3706
|
+
case "post_edit":
|
|
3707
|
+
case "post_command":
|
|
3708
|
+
case "post_tool":
|
|
3709
|
+
case "post_response":
|
|
3710
|
+
case "user_prompt": {
|
|
3711
|
+
const cooldownKey = `${input.event}:${input.filePath ?? input.command ?? "general"}`;
|
|
3712
|
+
if (isInCooldown(cooldownKey)) {
|
|
3713
|
+
return { observation: null, output: defaultOutput };
|
|
3714
|
+
}
|
|
3715
|
+
const content = extractContent(input);
|
|
3716
|
+
if (content.length < MIN_STORE_LENGTH) {
|
|
3717
|
+
return { observation: null, output: defaultOutput };
|
|
3718
|
+
}
|
|
3719
|
+
const pattern = detectBestPattern(content);
|
|
3720
|
+
if (!pattern) {
|
|
3721
|
+
return { observation: null, output: defaultOutput };
|
|
3722
|
+
}
|
|
3723
|
+
markTriggered(cooldownKey);
|
|
3724
|
+
return {
|
|
3725
|
+
observation: buildObservation(input, content),
|
|
3726
|
+
output: defaultOutput
|
|
3727
|
+
};
|
|
3728
|
+
}
|
|
3729
|
+
default:
|
|
3730
|
+
return { observation: null, output: defaultOutput };
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
async function runHook() {
|
|
3734
|
+
const chunks = [];
|
|
3735
|
+
for await (const chunk of process.stdin) {
|
|
3736
|
+
chunks.push(chunk);
|
|
3737
|
+
}
|
|
3738
|
+
const rawInput = Buffer.concat(chunks).toString("utf-8").trim();
|
|
3739
|
+
if (!rawInput) {
|
|
3740
|
+
process.stdout.write(JSON.stringify({ continue: true }));
|
|
3741
|
+
return;
|
|
3742
|
+
}
|
|
3743
|
+
let payload;
|
|
3744
|
+
try {
|
|
3745
|
+
payload = JSON.parse(rawInput);
|
|
3746
|
+
} catch {
|
|
3747
|
+
process.stdout.write(JSON.stringify({ continue: true }));
|
|
3748
|
+
return;
|
|
3749
|
+
}
|
|
3750
|
+
const input = normalizeHookInput(payload);
|
|
3751
|
+
const { observation, output } = await handleHookEvent(input);
|
|
3752
|
+
if (observation) {
|
|
3753
|
+
try {
|
|
3754
|
+
const { storeObservation: storeObservation2, initObservations: initObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
3755
|
+
const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
3756
|
+
const { getProjectDataDir: getProjectDataDir2 } = await Promise.resolve().then(() => (init_persistence(), persistence_exports));
|
|
3757
|
+
const project = await detectProject2(input.cwd || process.cwd());
|
|
3758
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
3759
|
+
await initObservations2(dataDir);
|
|
3760
|
+
await storeObservation2({ ...observation, projectId: project.id });
|
|
3761
|
+
} catch {
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
process.stdout.write(JSON.stringify(output));
|
|
3765
|
+
}
|
|
3766
|
+
var cooldowns, COOLDOWN_MS, MIN_STORE_LENGTH, MAX_CONTENT_LENGTH;
|
|
3767
|
+
var init_handler = __esm({
|
|
3768
|
+
"src/hooks/handler.ts"() {
|
|
3769
|
+
"use strict";
|
|
3770
|
+
init_esm_shims();
|
|
3771
|
+
init_normalizer();
|
|
3772
|
+
init_pattern_detector();
|
|
3773
|
+
cooldowns = /* @__PURE__ */ new Map();
|
|
3774
|
+
COOLDOWN_MS = 3e4;
|
|
3775
|
+
MIN_STORE_LENGTH = 100;
|
|
3776
|
+
MAX_CONTENT_LENGTH = 4e3;
|
|
3777
|
+
}
|
|
3778
|
+
});
|
|
3779
|
+
|
|
3780
|
+
// src/cli/commands/hook.ts
|
|
3781
|
+
var hook_exports = {};
|
|
3782
|
+
__export(hook_exports, {
|
|
3783
|
+
default: () => hook_default
|
|
3784
|
+
});
|
|
3785
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
3786
|
+
var hook_default;
|
|
3787
|
+
var init_hook = __esm({
|
|
3788
|
+
"src/cli/commands/hook.ts"() {
|
|
3789
|
+
"use strict";
|
|
3790
|
+
init_esm_shims();
|
|
3791
|
+
hook_default = defineCommand4({
|
|
3792
|
+
meta: {
|
|
3793
|
+
name: "hook",
|
|
3794
|
+
description: "Handle agent hook event (called by agent hook configs)"
|
|
3795
|
+
},
|
|
3796
|
+
run: async () => {
|
|
3797
|
+
const { runHook: runHook2 } = await Promise.resolve().then(() => (init_handler(), handler_exports));
|
|
3798
|
+
await runHook2();
|
|
3799
|
+
}
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3802
|
+
});
|
|
3803
|
+
|
|
3804
|
+
// src/hooks/installers/index.ts
|
|
3805
|
+
var installers_exports = {};
|
|
3806
|
+
__export(installers_exports, {
|
|
3807
|
+
detectInstalledAgents: () => detectInstalledAgents,
|
|
3808
|
+
getHookStatus: () => getHookStatus,
|
|
3809
|
+
installHooks: () => installHooks,
|
|
3810
|
+
uninstallHooks: () => uninstallHooks
|
|
3811
|
+
});
|
|
3812
|
+
import * as fs3 from "fs/promises";
|
|
3813
|
+
import * as path5 from "path";
|
|
3814
|
+
import * as os2 from "os";
|
|
3815
|
+
function generateClaudeConfig() {
|
|
3816
|
+
const hookEntry = {
|
|
3817
|
+
type: "command",
|
|
3818
|
+
command: `${HOOK_COMMAND} ${HOOK_ARGS.join(" ")}`,
|
|
3819
|
+
timeout: 10
|
|
3820
|
+
};
|
|
3821
|
+
return {
|
|
3822
|
+
hooks: {
|
|
3823
|
+
SessionStart: [hookEntry],
|
|
3824
|
+
PostToolUse: [hookEntry],
|
|
3825
|
+
UserPromptSubmit: [hookEntry],
|
|
3826
|
+
PreCompact: [hookEntry],
|
|
3827
|
+
Stop: [hookEntry]
|
|
3828
|
+
}
|
|
3829
|
+
};
|
|
3830
|
+
}
|
|
3831
|
+
function generateWindsurfConfig() {
|
|
3832
|
+
const hookEntry = {
|
|
3833
|
+
command: `${HOOK_COMMAND} ${HOOK_ARGS.join(" ")}`,
|
|
3834
|
+
timeout: 10
|
|
3835
|
+
};
|
|
3836
|
+
return {
|
|
3837
|
+
hooks: {
|
|
3838
|
+
post_write_code: [hookEntry],
|
|
3839
|
+
post_run_command: [hookEntry],
|
|
3840
|
+
post_mcp_tool_use: [hookEntry],
|
|
3841
|
+
pre_user_prompt: [hookEntry],
|
|
3842
|
+
post_cascade_response: [hookEntry]
|
|
3843
|
+
}
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3846
|
+
function generateCursorConfig() {
|
|
3847
|
+
return {
|
|
3848
|
+
hooks: {
|
|
3849
|
+
beforeSubmitPrompt: {
|
|
3850
|
+
command: `${HOOK_COMMAND} ${HOOK_ARGS.join(" ")}`
|
|
3851
|
+
},
|
|
3852
|
+
afterFileEdit: {
|
|
3853
|
+
command: `${HOOK_COMMAND} ${HOOK_ARGS.join(" ")}`
|
|
3854
|
+
},
|
|
3855
|
+
stop: {
|
|
3856
|
+
command: `${HOOK_COMMAND} ${HOOK_ARGS.join(" ")}`
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
function generateKiroHookFile() {
|
|
3862
|
+
return `---
|
|
3863
|
+
title: Memorix Auto-Memory
|
|
3864
|
+
description: Automatically record development context for cross-agent memory sharing
|
|
3865
|
+
event: file_saved
|
|
3866
|
+
filePattern: "**/*"
|
|
3867
|
+
---
|
|
3868
|
+
|
|
3869
|
+
Run the memorix hook command to analyze changes and store relevant memories:
|
|
3870
|
+
|
|
3871
|
+
\`\`\`bash
|
|
3872
|
+
memorix hook
|
|
3873
|
+
\`\`\`
|
|
3874
|
+
`;
|
|
3875
|
+
}
|
|
3876
|
+
function getProjectConfigPath(agent, projectRoot) {
|
|
3877
|
+
switch (agent) {
|
|
3878
|
+
case "claude":
|
|
3879
|
+
case "copilot":
|
|
3880
|
+
return path5.join(projectRoot, ".github", "hooks", "memorix.json");
|
|
3881
|
+
case "windsurf":
|
|
3882
|
+
return path5.join(projectRoot, ".windsurf", "hooks.json");
|
|
3883
|
+
case "cursor":
|
|
3884
|
+
return path5.join(projectRoot, ".cursor", "hooks.json");
|
|
3885
|
+
case "kiro":
|
|
3886
|
+
return path5.join(projectRoot, ".kiro", "hooks", "memorix.hook.md");
|
|
3887
|
+
case "codex":
|
|
3888
|
+
return path5.join(projectRoot, ".codex", "hooks.json");
|
|
3889
|
+
default:
|
|
3890
|
+
return path5.join(projectRoot, ".memorix", "hooks.json");
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
function getGlobalConfigPath(agent) {
|
|
3894
|
+
const home = os2.homedir();
|
|
3895
|
+
switch (agent) {
|
|
3896
|
+
case "claude":
|
|
3897
|
+
case "copilot":
|
|
3898
|
+
return path5.join(home, ".claude", "settings.json");
|
|
3899
|
+
case "windsurf":
|
|
3900
|
+
return path5.join(home, ".codeium", "windsurf", "hooks.json");
|
|
3901
|
+
case "cursor":
|
|
3902
|
+
return path5.join(home, ".cursor", "hooks.json");
|
|
3903
|
+
default:
|
|
3904
|
+
return path5.join(home, ".memorix", "hooks.json");
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
async function detectInstalledAgents() {
|
|
3908
|
+
const agents = [];
|
|
3909
|
+
const home = os2.homedir();
|
|
3910
|
+
const claudeDir = path5.join(home, ".claude");
|
|
3911
|
+
try {
|
|
3912
|
+
await fs3.access(claudeDir);
|
|
3913
|
+
agents.push("claude");
|
|
3914
|
+
} catch {
|
|
3915
|
+
}
|
|
3916
|
+
const windsurfDir = path5.join(home, ".codeium", "windsurf");
|
|
3917
|
+
try {
|
|
3918
|
+
await fs3.access(windsurfDir);
|
|
3919
|
+
agents.push("windsurf");
|
|
3920
|
+
} catch {
|
|
3921
|
+
}
|
|
3922
|
+
const cursorDir = path5.join(home, ".cursor");
|
|
3923
|
+
try {
|
|
3924
|
+
await fs3.access(cursorDir);
|
|
3925
|
+
agents.push("cursor");
|
|
3926
|
+
} catch {
|
|
3927
|
+
}
|
|
3928
|
+
if (!agents.includes("claude")) {
|
|
3929
|
+
const vscodeDir = path5.join(home, ".vscode");
|
|
3930
|
+
try {
|
|
3931
|
+
await fs3.access(vscodeDir);
|
|
3932
|
+
agents.push("copilot");
|
|
3933
|
+
} catch {
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
const kiroConfig = path5.join(home, ".kiro");
|
|
3937
|
+
try {
|
|
3938
|
+
await fs3.access(kiroConfig);
|
|
3939
|
+
agents.push("kiro");
|
|
3940
|
+
} catch {
|
|
3941
|
+
}
|
|
3942
|
+
return agents;
|
|
3943
|
+
}
|
|
3944
|
+
async function installHooks(agent, projectRoot, global = false) {
|
|
3945
|
+
const configPath = global ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
|
|
3946
|
+
let generated;
|
|
3947
|
+
switch (agent) {
|
|
3948
|
+
case "claude":
|
|
3949
|
+
case "copilot":
|
|
3950
|
+
generated = generateClaudeConfig();
|
|
3951
|
+
break;
|
|
3952
|
+
case "windsurf":
|
|
3953
|
+
generated = generateWindsurfConfig();
|
|
3954
|
+
break;
|
|
3955
|
+
case "cursor":
|
|
3956
|
+
generated = generateCursorConfig();
|
|
3957
|
+
break;
|
|
3958
|
+
case "kiro":
|
|
3959
|
+
generated = generateKiroHookFile();
|
|
3960
|
+
break;
|
|
3961
|
+
default:
|
|
3962
|
+
generated = generateClaudeConfig();
|
|
3963
|
+
}
|
|
3964
|
+
await fs3.mkdir(path5.dirname(configPath), { recursive: true });
|
|
3965
|
+
if (agent === "kiro") {
|
|
3966
|
+
await fs3.writeFile(configPath, generated, "utf-8");
|
|
3967
|
+
} else {
|
|
3968
|
+
let existing = {};
|
|
3969
|
+
try {
|
|
3970
|
+
const content = await fs3.readFile(configPath, "utf-8");
|
|
3971
|
+
existing = JSON.parse(content);
|
|
3972
|
+
} catch {
|
|
3973
|
+
}
|
|
3974
|
+
const merged = {
|
|
3975
|
+
...existing,
|
|
3976
|
+
...generated
|
|
3977
|
+
};
|
|
3978
|
+
await fs3.writeFile(configPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
3979
|
+
}
|
|
3980
|
+
const events = [];
|
|
3981
|
+
switch (agent) {
|
|
3982
|
+
case "claude":
|
|
3983
|
+
case "copilot":
|
|
3984
|
+
events.push("session_start", "post_tool", "user_prompt", "pre_compact", "session_end");
|
|
3985
|
+
break;
|
|
3986
|
+
case "windsurf":
|
|
3987
|
+
events.push("post_edit", "post_command", "post_tool", "user_prompt", "post_response");
|
|
3988
|
+
break;
|
|
3989
|
+
case "cursor":
|
|
3990
|
+
events.push("user_prompt", "post_edit", "session_end");
|
|
3991
|
+
break;
|
|
3992
|
+
case "kiro":
|
|
3993
|
+
events.push("post_edit");
|
|
3994
|
+
break;
|
|
3995
|
+
}
|
|
3996
|
+
return {
|
|
3997
|
+
agent,
|
|
3998
|
+
configPath,
|
|
3999
|
+
events,
|
|
4000
|
+
generated: typeof generated === "string" ? { content: generated } : generated
|
|
4001
|
+
};
|
|
4002
|
+
}
|
|
4003
|
+
async function uninstallHooks(agent, projectRoot, global = false) {
|
|
4004
|
+
const configPath = global ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
|
|
4005
|
+
try {
|
|
4006
|
+
if (agent === "kiro") {
|
|
4007
|
+
await fs3.unlink(configPath);
|
|
4008
|
+
} else {
|
|
4009
|
+
const content = await fs3.readFile(configPath, "utf-8");
|
|
4010
|
+
const config = JSON.parse(content);
|
|
4011
|
+
delete config.hooks;
|
|
4012
|
+
if (Object.keys(config).length === 0) {
|
|
4013
|
+
await fs3.unlink(configPath);
|
|
4014
|
+
} else {
|
|
4015
|
+
await fs3.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
return true;
|
|
4019
|
+
} catch {
|
|
4020
|
+
return false;
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
async function getHookStatus(projectRoot) {
|
|
4024
|
+
const results = [];
|
|
4025
|
+
const agents = ["claude", "copilot", "windsurf", "cursor", "kiro", "codex"];
|
|
4026
|
+
for (const agent of agents) {
|
|
4027
|
+
const projectPath = getProjectConfigPath(agent, projectRoot);
|
|
4028
|
+
const globalPath = getGlobalConfigPath(agent);
|
|
4029
|
+
let installed = false;
|
|
4030
|
+
let usedPath = projectPath;
|
|
4031
|
+
try {
|
|
4032
|
+
await fs3.access(projectPath);
|
|
4033
|
+
installed = true;
|
|
4034
|
+
} catch {
|
|
4035
|
+
try {
|
|
4036
|
+
await fs3.access(globalPath);
|
|
4037
|
+
installed = true;
|
|
4038
|
+
usedPath = globalPath;
|
|
4039
|
+
} catch {
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
results.push({ agent, installed, configPath: usedPath });
|
|
4043
|
+
}
|
|
4044
|
+
return results;
|
|
4045
|
+
}
|
|
4046
|
+
var HOOK_COMMAND, HOOK_ARGS;
|
|
4047
|
+
var init_installers = __esm({
|
|
4048
|
+
"src/hooks/installers/index.ts"() {
|
|
4049
|
+
"use strict";
|
|
4050
|
+
init_esm_shims();
|
|
4051
|
+
HOOK_COMMAND = "memorix";
|
|
4052
|
+
HOOK_ARGS = ["hook"];
|
|
4053
|
+
}
|
|
4054
|
+
});
|
|
4055
|
+
|
|
4056
|
+
// src/cli/commands/hooks-install.ts
|
|
4057
|
+
var hooks_install_exports = {};
|
|
4058
|
+
__export(hooks_install_exports, {
|
|
4059
|
+
default: () => hooks_install_default
|
|
4060
|
+
});
|
|
4061
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
4062
|
+
var hooks_install_default;
|
|
4063
|
+
var init_hooks_install = __esm({
|
|
4064
|
+
"src/cli/commands/hooks-install.ts"() {
|
|
4065
|
+
"use strict";
|
|
4066
|
+
init_esm_shims();
|
|
4067
|
+
hooks_install_default = defineCommand5({
|
|
4068
|
+
meta: {
|
|
4069
|
+
name: "install",
|
|
4070
|
+
description: "Install automatic memory hooks for agents"
|
|
4071
|
+
},
|
|
4072
|
+
args: {
|
|
4073
|
+
agent: {
|
|
4074
|
+
type: "string",
|
|
4075
|
+
description: "Target agent (claude|copilot|windsurf|cursor|kiro|codex). Auto-detects if omitted.",
|
|
4076
|
+
required: false
|
|
4077
|
+
},
|
|
4078
|
+
global: {
|
|
4079
|
+
type: "boolean",
|
|
4080
|
+
description: "Install globally instead of per-project",
|
|
4081
|
+
required: false
|
|
4082
|
+
}
|
|
4083
|
+
},
|
|
4084
|
+
run: async ({ args }) => {
|
|
4085
|
+
const { detectInstalledAgents: detectInstalledAgents2, installHooks: installHooks2 } = await Promise.resolve().then(() => (init_installers(), installers_exports));
|
|
4086
|
+
const cwd = process.cwd();
|
|
4087
|
+
let agents;
|
|
4088
|
+
if (args.agent) {
|
|
4089
|
+
agents = [args.agent];
|
|
4090
|
+
} else {
|
|
4091
|
+
agents = await detectInstalledAgents2();
|
|
4092
|
+
if (agents.length === 0) {
|
|
4093
|
+
console.log("No supported agents detected. Use --agent to specify one.");
|
|
4094
|
+
return;
|
|
4095
|
+
}
|
|
4096
|
+
console.log(`Detected agents: ${agents.join(", ")}`);
|
|
4097
|
+
}
|
|
4098
|
+
for (const agent of agents) {
|
|
4099
|
+
try {
|
|
4100
|
+
const config = await installHooks2(
|
|
4101
|
+
agent,
|
|
4102
|
+
cwd,
|
|
4103
|
+
args.global ?? false
|
|
4104
|
+
);
|
|
4105
|
+
console.log(`\u2705 ${agent}: hooks installed \u2192 ${config.configPath}`);
|
|
4106
|
+
console.log(` Events: ${config.events.join(", ")}`);
|
|
4107
|
+
} catch (err) {
|
|
4108
|
+
console.error(`\u274C ${agent}: failed \u2014 ${err}`);
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
console.log("\nMemory hooks are now active. Restart your agent to apply.");
|
|
4112
|
+
}
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4115
|
+
});
|
|
4116
|
+
|
|
4117
|
+
// src/cli/commands/hooks-uninstall.ts
|
|
4118
|
+
var hooks_uninstall_exports = {};
|
|
4119
|
+
__export(hooks_uninstall_exports, {
|
|
4120
|
+
default: () => hooks_uninstall_default
|
|
4121
|
+
});
|
|
4122
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
4123
|
+
var hooks_uninstall_default;
|
|
4124
|
+
var init_hooks_uninstall = __esm({
|
|
4125
|
+
"src/cli/commands/hooks-uninstall.ts"() {
|
|
4126
|
+
"use strict";
|
|
4127
|
+
init_esm_shims();
|
|
4128
|
+
hooks_uninstall_default = defineCommand6({
|
|
4129
|
+
meta: {
|
|
4130
|
+
name: "uninstall",
|
|
4131
|
+
description: "Remove automatic memory hooks for agents"
|
|
4132
|
+
},
|
|
4133
|
+
args: {
|
|
4134
|
+
agent: {
|
|
4135
|
+
type: "string",
|
|
4136
|
+
description: "Target agent (claude|copilot|windsurf|cursor|kiro|codex)",
|
|
4137
|
+
required: false
|
|
4138
|
+
},
|
|
4139
|
+
global: {
|
|
4140
|
+
type: "boolean",
|
|
4141
|
+
description: "Uninstall global hooks",
|
|
4142
|
+
required: false
|
|
4143
|
+
}
|
|
4144
|
+
},
|
|
4145
|
+
run: async ({ args }) => {
|
|
4146
|
+
const { detectInstalledAgents: detectInstalledAgents2, uninstallHooks: uninstallHooks2 } = await Promise.resolve().then(() => (init_installers(), installers_exports));
|
|
4147
|
+
const cwd = process.cwd();
|
|
4148
|
+
let agents;
|
|
4149
|
+
if (args.agent) {
|
|
4150
|
+
agents = [args.agent];
|
|
4151
|
+
} else {
|
|
4152
|
+
agents = await detectInstalledAgents2();
|
|
4153
|
+
}
|
|
4154
|
+
for (const agent of agents) {
|
|
4155
|
+
const ok = await uninstallHooks2(
|
|
4156
|
+
agent,
|
|
4157
|
+
cwd,
|
|
4158
|
+
args.global ?? false
|
|
4159
|
+
);
|
|
4160
|
+
if (ok) {
|
|
4161
|
+
console.log(`\u2705 ${agent}: hooks removed`);
|
|
4162
|
+
} else {
|
|
4163
|
+
console.log(`\u26A0\uFE0F ${agent}: no hooks found`);
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
});
|
|
4170
|
+
|
|
4171
|
+
// src/cli/commands/hooks-status.ts
|
|
4172
|
+
var hooks_status_exports = {};
|
|
4173
|
+
__export(hooks_status_exports, {
|
|
4174
|
+
default: () => hooks_status_default
|
|
4175
|
+
});
|
|
4176
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
4177
|
+
var hooks_status_default;
|
|
4178
|
+
var init_hooks_status = __esm({
|
|
4179
|
+
"src/cli/commands/hooks-status.ts"() {
|
|
4180
|
+
"use strict";
|
|
4181
|
+
init_esm_shims();
|
|
4182
|
+
hooks_status_default = defineCommand7({
|
|
4183
|
+
meta: {
|
|
4184
|
+
name: "status",
|
|
4185
|
+
description: "Show hook installation status for all agents"
|
|
4186
|
+
},
|
|
4187
|
+
run: async () => {
|
|
4188
|
+
const { getHookStatus: getHookStatus2 } = await Promise.resolve().then(() => (init_installers(), installers_exports));
|
|
4189
|
+
const cwd = process.cwd();
|
|
4190
|
+
const statuses = await getHookStatus2(cwd);
|
|
4191
|
+
console.log("\nMemorix Hooks Status");
|
|
4192
|
+
console.log("\u2550".repeat(50));
|
|
4193
|
+
for (const { agent, installed, configPath } of statuses) {
|
|
4194
|
+
const icon = installed ? "\u2705" : "\u2B1A";
|
|
4195
|
+
const label = agent.charAt(0).toUpperCase() + agent.slice(1);
|
|
4196
|
+
console.log(`${icon} ${label.padEnd(12)} ${installed ? configPath : "(not installed)"}`);
|
|
4197
|
+
}
|
|
4198
|
+
console.log("\nRun `memorix hooks install` to set up hooks for detected agents.");
|
|
4199
|
+
}
|
|
4200
|
+
});
|
|
4201
|
+
}
|
|
4202
|
+
});
|
|
4203
|
+
|
|
4204
|
+
// src/cli/commands/hooks.ts
|
|
4205
|
+
var hooks_exports = {};
|
|
4206
|
+
__export(hooks_exports, {
|
|
4207
|
+
default: () => hooks_default
|
|
4208
|
+
});
|
|
4209
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
4210
|
+
var hooks_default;
|
|
4211
|
+
var init_hooks = __esm({
|
|
4212
|
+
"src/cli/commands/hooks.ts"() {
|
|
4213
|
+
"use strict";
|
|
4214
|
+
init_esm_shims();
|
|
4215
|
+
hooks_default = defineCommand8({
|
|
4216
|
+
meta: {
|
|
4217
|
+
name: "hooks",
|
|
4218
|
+
description: "Manage automatic memory hooks for agents"
|
|
4219
|
+
},
|
|
4220
|
+
subCommands: {
|
|
4221
|
+
install: () => Promise.resolve().then(() => (init_hooks_install(), hooks_install_exports)).then((m) => m.default),
|
|
4222
|
+
uninstall: () => Promise.resolve().then(() => (init_hooks_uninstall(), hooks_uninstall_exports)).then((m) => m.default),
|
|
4223
|
+
status: () => Promise.resolve().then(() => (init_hooks_status(), hooks_status_exports)).then((m) => m.default)
|
|
4224
|
+
},
|
|
4225
|
+
run() {
|
|
4226
|
+
}
|
|
4227
|
+
});
|
|
4228
|
+
}
|
|
4229
|
+
});
|
|
4230
|
+
|
|
3287
4231
|
// src/cli/index.ts
|
|
3288
4232
|
init_esm_shims();
|
|
3289
|
-
import { defineCommand as
|
|
3290
|
-
var main =
|
|
4233
|
+
import { defineCommand as defineCommand9, runMain } from "citty";
|
|
4234
|
+
var main = defineCommand9({
|
|
3291
4235
|
meta: {
|
|
3292
4236
|
name: "memorix",
|
|
3293
4237
|
version: "0.1.0",
|
|
@@ -3296,7 +4240,9 @@ var main = defineCommand4({
|
|
|
3296
4240
|
subCommands: {
|
|
3297
4241
|
serve: () => Promise.resolve().then(() => (init_serve(), serve_exports)).then((m) => m.default),
|
|
3298
4242
|
status: () => Promise.resolve().then(() => (init_status(), status_exports)).then((m) => m.default),
|
|
3299
|
-
sync: () => Promise.resolve().then(() => (init_sync(), sync_exports)).then((m) => m.default)
|
|
4243
|
+
sync: () => Promise.resolve().then(() => (init_sync(), sync_exports)).then((m) => m.default),
|
|
4244
|
+
hook: () => Promise.resolve().then(() => (init_hook(), hook_exports)).then((m) => m.default),
|
|
4245
|
+
hooks: () => Promise.resolve().then(() => (init_hooks(), hooks_exports)).then((m) => m.default)
|
|
3300
4246
|
},
|
|
3301
4247
|
run() {
|
|
3302
4248
|
}
|