@pcircle/memesh 2.9.0 → 2.9.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/dist/mcp/ToolDefinitions.d.ts.map +1 -1
- package/dist/mcp/ToolDefinitions.js +0 -104
- package/dist/mcp/ToolDefinitions.js.map +1 -1
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/scripts/hooks/README.md +230 -0
- package/scripts/hooks/__tests__/hook-test-harness.js +218 -0
- package/scripts/hooks/__tests__/hooks.test.js +267 -0
- package/scripts/hooks/hook-utils.js +899 -0
- package/scripts/hooks/post-commit.js +307 -0
- package/scripts/hooks/post-tool-use.js +812 -0
- package/scripts/hooks/pre-tool-use.js +462 -0
- package/scripts/hooks/session-start.js +544 -0
- package/scripts/hooks/stop.js +673 -0
- package/scripts/hooks/subagent-stop.js +184 -0
- package/scripts/postinstall-lib.js +8 -4
- package/scripts/postinstall-new.js +15 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolDefinitions.d.ts","sourceRoot":"","sources":["../../src/mcp/ToolDefinitions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BzB,CAAC;AAKF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;IAMF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"ToolDefinitions.d.ts","sourceRoot":"","sources":["../../src/mcp/ToolDefinitions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BzB,CAAC;AAKF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;IAMF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAud3D"}
|
|
@@ -371,110 +371,6 @@ tags: ["tech:jwt", "tech:nodejs", "domain:authentication", "security"]`,
|
|
|
371
371
|
openWorldHint: false,
|
|
372
372
|
},
|
|
373
373
|
};
|
|
374
|
-
const cloudSyncTool = {
|
|
375
|
-
name: 'memesh-cloud-sync',
|
|
376
|
-
description: `☁️ Sync local Knowledge Graph memories with MeMesh Cloud.
|
|
377
|
-
|
|
378
|
-
**Actions:**
|
|
379
|
-
• {action: "status"}: Compare local vs cloud memory counts
|
|
380
|
-
• {action: "push"}: Push local memories to cloud
|
|
381
|
-
• {action: "pull"}: Pull cloud memories to local
|
|
382
|
-
• {action: "push", dryRun: true}: Preview what would be synced
|
|
383
|
-
|
|
384
|
-
Requires MEMESH_API_KEY to be configured. Without it, all actions return a setup guide.`,
|
|
385
|
-
inputSchema: {
|
|
386
|
-
type: 'object',
|
|
387
|
-
properties: {
|
|
388
|
-
action: {
|
|
389
|
-
type: 'string',
|
|
390
|
-
enum: ['push', 'pull', 'status'],
|
|
391
|
-
description: 'Sync action: push (local→cloud), pull (cloud→local), status (compare)',
|
|
392
|
-
},
|
|
393
|
-
query: {
|
|
394
|
-
type: 'string',
|
|
395
|
-
description: 'Optional search query to filter which memories to sync',
|
|
396
|
-
},
|
|
397
|
-
space: {
|
|
398
|
-
type: 'string',
|
|
399
|
-
description: 'Cloud memory space to sync with (default: "default")',
|
|
400
|
-
default: 'default',
|
|
401
|
-
},
|
|
402
|
-
limit: {
|
|
403
|
-
type: 'number',
|
|
404
|
-
description: 'Max memories per batch (default: 100, max: 500)',
|
|
405
|
-
minimum: 1,
|
|
406
|
-
maximum: 500,
|
|
407
|
-
default: 100,
|
|
408
|
-
},
|
|
409
|
-
dryRun: {
|
|
410
|
-
type: 'boolean',
|
|
411
|
-
description: 'Preview sync without executing (default: false)',
|
|
412
|
-
default: false,
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
required: ['action'],
|
|
416
|
-
},
|
|
417
|
-
outputSchema: OutputSchemas.cloudSync,
|
|
418
|
-
annotations: {
|
|
419
|
-
title: 'Cloud Sync',
|
|
420
|
-
readOnlyHint: false,
|
|
421
|
-
destructiveHint: false,
|
|
422
|
-
idempotentHint: false,
|
|
423
|
-
openWorldHint: true,
|
|
424
|
-
},
|
|
425
|
-
};
|
|
426
|
-
const agentRegisterTool = {
|
|
427
|
-
name: 'memesh-agent-register',
|
|
428
|
-
description: `🤖 Register this agent with MeMesh Cloud for agent-specific capabilities.
|
|
429
|
-
|
|
430
|
-
**What Registration Provides:**
|
|
431
|
-
• Agent ID for tracking and analytics
|
|
432
|
-
• Access to agent-specific features
|
|
433
|
-
• Message queue for inter-agent communication
|
|
434
|
-
• Heartbeat monitoring and status tracking
|
|
435
|
-
|
|
436
|
-
**Agent Types (API enum):**
|
|
437
|
-
• "claude" - Claude / Claude Code
|
|
438
|
-
• "chatgpt" - ChatGPT
|
|
439
|
-
• "gemini" - Google Gemini
|
|
440
|
-
• "grok" - xAI Grok
|
|
441
|
-
• "deepseek" - DeepSeek
|
|
442
|
-
• "codex" - OpenAI Codex
|
|
443
|
-
• "cursor" - Cursor IDE
|
|
444
|
-
• "custom" - Other / custom agents
|
|
445
|
-
|
|
446
|
-
Requires MEMESH_API_KEY to be configured.`,
|
|
447
|
-
inputSchema: {
|
|
448
|
-
type: 'object',
|
|
449
|
-
properties: {
|
|
450
|
-
agentType: {
|
|
451
|
-
type: 'string',
|
|
452
|
-
description: 'Type of agent. Valid: "claude", "chatgpt", "gemini", "grok", "deepseek", "codex", "cursor", "custom"',
|
|
453
|
-
},
|
|
454
|
-
agentName: {
|
|
455
|
-
type: 'string',
|
|
456
|
-
description: 'Optional agent name (no spaces — use hyphens, e.g., "my-agent")',
|
|
457
|
-
},
|
|
458
|
-
agentVersion: {
|
|
459
|
-
type: 'string',
|
|
460
|
-
description: 'Optional version string (e.g., "1.0.0")',
|
|
461
|
-
},
|
|
462
|
-
capabilities: {
|
|
463
|
-
type: 'object',
|
|
464
|
-
description: 'Optional capabilities object describing what the agent can do',
|
|
465
|
-
},
|
|
466
|
-
},
|
|
467
|
-
required: ['agentType'],
|
|
468
|
-
},
|
|
469
|
-
outputSchema: OutputSchemas.agentRegister,
|
|
470
|
-
annotations: {
|
|
471
|
-
title: 'Agent Registration',
|
|
472
|
-
readOnlyHint: false,
|
|
473
|
-
destructiveHint: false,
|
|
474
|
-
idempotentHint: true,
|
|
475
|
-
openWorldHint: false,
|
|
476
|
-
},
|
|
477
|
-
};
|
|
478
374
|
const generateTestsTool = {
|
|
479
375
|
name: 'memesh-generate-tests',
|
|
480
376
|
aliases: ['generate-tests'],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolDefinitions.js","sourceRoot":"","sources":["../../src/mcp/ToolDefinitions.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAM3D,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,SAAS,EAAE;QACT,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,eAAe,EAAE;gBACf,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,yCAAyC;aACvD;YACD,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gCAAgC;gBAC7C,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,EAAE;aACZ;SACF;QACD,QAAQ,EAAE,CAAC,iBAAiB,CAAC;KAC9B;IAED,cAAc,EAAE;QACd,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,qDAAqD;gBAClE,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;aAC9B;SACF;KACF;CACF,CAAC;AA4BF,MAAM,UAAU,qBAAqB;IAMnC,MAAM,WAAW,GAAsB;QACrC,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE;;;;;;;;;;;mHAWkG;QAC/G,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wFAAwF;iBACtG;aACF;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;SACnB;QACD,YAAY,EAAE,aAAa,CAAC,OAAO;QACnC,WAAW,EAAE;YACX,KAAK,EAAE,qBAAqB;YAC5B,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,CAAC;IAEF,MAAM,iBAAiB,GAAsB;QAC3C,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE;;;;;;;;;;;;kGAYiF;QAC9F,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,+DAA+D;iBAC7E;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC;oBACvC,WAAW,EAAE,uGAAuG;iBACrH;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,yDAAyD;oBACtE,OAAO,EAAE,CAAC;oBACV,OAAO,EAAE,EAAE;iBACZ;gBACD,aAAa,EAAE;oBACb,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,yEAAyE;oBACtF,OAAO,EAAE,CAAC;oBACV,OAAO,EAAE,CAAC;iBACX;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,8FAA8F;iBAC5G;aACF;YACD,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB;QACD,YAAY,EAAE,aAAa,CAAC,aAAa;QACzC,WAAW,EAAE;YACX,KAAK,EAAE,uBAAuB;YAC9B,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,CAAC;IAEF,MAAM,aAAa,GAAsB;QACvC,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,mEAAmE;QAChF,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,qEAAqE;iBACnF;aACF;SACF;QACD,YAAY,EAAE,aAAa,CAAC,SAAS;QACrC,WAAW,EAAE;YACX,KAAK,EAAE,sBAAsB;YAC7B,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,CAAC;IAMF,MAAM,sBAAsB,GAAsB;QAChD,IAAI,EAAE,uBAAuB;QAC7B,OAAO,EAAE,CAAC,sBAAsB,CAAC;QACjC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEA2C+C;QAC5D,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,uCAAuC;iBACrD;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,sBAAsB;oBACnC,IAAI,EAAE;wBACJ,qBAAqB;wBACrB,eAAe;wBACf,kBAAkB;wBAClB,iBAAiB;wBACjB,qBAAqB;wBACrB,cAAc;wBACd,iBAAiB;wBACjB,mBAAmB;wBACnB,kBAAkB;qBACnB;iBACF;gBACD,cAAc,EAAE;oBACd,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,6BAA6B;iBAC3C;gBACD,aAAa,EAAE;oBACb,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,oCAAoC;iBAClD;gBACD,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,uBAAuB;iBACrC;gBACD,gBAAgB,EAAE;oBAChB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,mCAAmC;iBACjD;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,mCAAmC;iBACjD;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,+BAA+B;iBAC7C;aACF;YACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,kBAAkB,CAAC;SACnG;QACD,YAAY,EAAE,aAAa,CAAC,kBAAkB;QAC9C,WAAW,EAAE;YACX,KAAK,EAAE,kBAAkB;YACzB,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,CAAC;IAMF,MAAM,eAAe,GAAsB;QACzC,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,CAAC,eAAe,CAAC;QAC1B,WAAW,EAAE,mHAAmH;QAChI,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,mEAAmE;iBACjF;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wCAAwC;iBACtD;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,sCAAsC;iBACpD;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,+CAA+C;iBAC7D;gBACD,UAAU,EAAE;oBACV,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,yCAAyC;iBACvD;gBACD,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wBAAwB;iBACtC;aACF;YACD,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC;SAClC;QACD,YAAY,EAAE,aAAa,CAAC,WAAW;QACvC,WAAW,EAAE;YACX,KAAK,EAAE,sBAAsB;YAC7B,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,CAAC;IAMF,MAAM,kBAAkB,GAAsB;QAC5C,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,CAAC,iBAAiB,CAAC;QAC5B,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAmCsD;QACnE,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,QAAQ,EAAE;oBACR,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,6BAA6B;oBAC1C,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,IAAI,EAAE;gCACJ,IAAI,EAAE,QAAQ;gCACd,WAAW,EAAE,iCAAiC;6BAC/C;4BACD,UAAU,EAAE;gCACV,IAAI,EAAE,QAAQ;gCACd,WAAW,EAAE,wEAAwE;6BACtF;4BACD,YAAY,EAAE;gCACZ,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCACzB,WAAW,EAAE,+CAA+C;6BAC7D;4BACD,IAAI,EAAE;gCACJ,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCACzB,WAAW,EAAE,qGAAqG;6BACnH;4BACD,QAAQ,EAAE;gCACR,IAAI,EAAE,QAAQ;gCACd,WAAW,EAAE,mBAAmB;6BACjC;yBACF;wBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,CAAC;qBACjD;iBACF;aACF;YACD,QAAQ,EAAE,CAAC,UAAU,CAAC;SACvB;QACD,YAAY,EAAE,aAAa,CAAC,cAAc;QAC1C,WAAW,EAAE;YACX,KAAK,EAAE,yBAAyB;YAChC,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,KAAK;SACrB;KACF,CAAC;
|
|
1
|
+
{"version":3,"file":"ToolDefinitions.js","sourceRoot":"","sources":["../../src/mcp/ToolDefinitions.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pcircle/memesh",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.2",
|
|
4
4
|
"description": "MeMesh — Persistent memory plugin for Claude Code. Remembers architecture decisions, coding patterns, and project context across sessions.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"scripts/postinstall-new.js",
|
|
13
13
|
"scripts/postinstall-lib.js",
|
|
14
14
|
"scripts/skills/",
|
|
15
|
+
"scripts/hooks/",
|
|
15
16
|
"plugin.json",
|
|
16
17
|
"mcp.json",
|
|
17
18
|
"README.md",
|
package/plugin.json
CHANGED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# MeMesh Hooks for Claude Code
|
|
2
|
+
|
|
3
|
+
**What are these?** Scripts that run automatically when you use Claude Code. They provide memory management, smart routing, code quality enforcement, and planning assistance.
|
|
4
|
+
|
|
5
|
+
## What They Do
|
|
6
|
+
|
|
7
|
+
| When | What Happens |
|
|
8
|
+
|------|--------------|
|
|
9
|
+
| **You open Claude Code** | Reloads CLAUDE.md, shows last session recap (cache-first) |
|
|
10
|
+
| **Before a tool runs** | Smart routing, planning template injection, dry-run gate, code review reminder |
|
|
11
|
+
| **After a tool runs** | Tracks work patterns, file modifications, test executions |
|
|
12
|
+
| **You make a git commit** | Saves commit context to knowledge graph (batched) |
|
|
13
|
+
| **A subagent finishes** | Saves code review results, tracks completion |
|
|
14
|
+
| **You close Claude Code** | Saves session summary + cache for fast next startup |
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Copy hooks to Claude Code
|
|
20
|
+
cp scripts/hooks/*.js ~/.claude/hooks/
|
|
21
|
+
cp -r scripts/hooks/templates/ ~/.claude/hooks/templates/
|
|
22
|
+
chmod +x ~/.claude/hooks/*.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Done!** Restart Claude Code to activate.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
### Smart Router (PreToolUse)
|
|
32
|
+
|
|
33
|
+
Routes subagent tasks to optimal models and controls background execution.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Task(Explore) → model: haiku (fast search)
|
|
37
|
+
Task(Plan) → inject SDD+BDD planning template
|
|
38
|
+
Task(heavy) → check for untested code, warn if found
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Configuration: `~/.memesh/routing-config.json`
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"modelRouting": {
|
|
46
|
+
"rules": [
|
|
47
|
+
{ "subagentType": "Explore", "model": "haiku", "reason": "Fast search" }
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"backgroundRules": [
|
|
51
|
+
{ "subagentType": "Explore", "forceBackground": false }
|
|
52
|
+
],
|
|
53
|
+
"planningEnforcement": { "enabled": true },
|
|
54
|
+
"dryRunGate": { "enabled": true },
|
|
55
|
+
"auditLog": true
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Audit log: `~/.memesh/routing-audit.log`
|
|
60
|
+
|
|
61
|
+
### Planning Enforcement
|
|
62
|
+
|
|
63
|
+
When a Plan subagent is dispatched, the hook injects a template requiring:
|
|
64
|
+
- System Design Description (SDD)
|
|
65
|
+
- Behavior-Driven Design (BDD) with Gherkin scenarios
|
|
66
|
+
- Edge case handling table
|
|
67
|
+
- Dry-run test plan
|
|
68
|
+
- Risk assessment
|
|
69
|
+
|
|
70
|
+
The plan is always presented to the user for approval before implementation.
|
|
71
|
+
|
|
72
|
+
### Dry-Run Gate
|
|
73
|
+
|
|
74
|
+
Tracks which files were modified (Write/Edit) and which were tested
|
|
75
|
+
(vitest/jest/tsc/node --check). Before heavy Task dispatches, warns if
|
|
76
|
+
modified files haven't been tested yet.
|
|
77
|
+
|
|
78
|
+
**Advisory only** — never blocks, just informs.
|
|
79
|
+
|
|
80
|
+
### Pre-Commit Code Review
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
git commit detected → Code review done? → Yes → Allow
|
|
84
|
+
→ No → Inject reminder
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Auto-Memory (Batched)
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Open Claude Code → Work normally → Git commit → Close Claude Code
|
|
91
|
+
↓ ↓ ↓ ↓
|
|
92
|
+
Cache-first recall Track patterns Batch save to KG Cache + archive
|
|
93
|
+
(0 SQLite spawns) (async writes) (2 spawns vs 8)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### What Gets Tracked
|
|
97
|
+
|
|
98
|
+
| Symbol | Meaning |
|
|
99
|
+
|--------|---------|
|
|
100
|
+
| 📁 | Files you changed |
|
|
101
|
+
| ✅ | Git commits you made |
|
|
102
|
+
| 💡 | Things you learned |
|
|
103
|
+
| ⚠️ | Problems you ran into |
|
|
104
|
+
| 🎯 | Decisions you made |
|
|
105
|
+
| 🔍 | Code review findings |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Troubleshooting
|
|
110
|
+
|
|
111
|
+
### "Hooks not working"
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
ls ~/.claude/hooks/
|
|
115
|
+
cp scripts/hooks/*.js ~/.claude/hooks/
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### "No memory showing"
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
ls ~/.memesh/knowledge-graph.db
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### "Routing not applying"
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Check config
|
|
128
|
+
cat ~/.memesh/routing-config.json
|
|
129
|
+
|
|
130
|
+
# Check audit log
|
|
131
|
+
tail -20 ~/.memesh/routing-audit.log
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Limitations
|
|
135
|
+
|
|
136
|
+
| What | Details |
|
|
137
|
+
|------|---------|
|
|
138
|
+
| **Claude Code only** | Doesn't work in Cursor |
|
|
139
|
+
| **30-day memory** | Old session memories auto-deleted |
|
|
140
|
+
| **Local only** | No sync between computers |
|
|
141
|
+
| **Advisory gates** | Dry-run and review are reminders, not blockers |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Files
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
scripts/hooks/
|
|
149
|
+
├── session-start.js ← SessionStart: reload CLAUDE.md, cache-first recall
|
|
150
|
+
├── pre-tool-use.js ← PreToolUse: handler registry (4 handlers)
|
|
151
|
+
│ ├── codeReviewHandler — git commit review enforcement
|
|
152
|
+
│ ├── routingHandler — model/background selection
|
|
153
|
+
│ ├── planningHandler — SDD+BDD template injection
|
|
154
|
+
│ └── dryRunGateHandler — untested code warning
|
|
155
|
+
├── post-tool-use.js ← PostToolUse: patterns, file/test tracking, async writes
|
|
156
|
+
├── post-commit.js ← PostToolUse: batch save commit to KG
|
|
157
|
+
├── subagent-stop.js ← SubagentStop: capture code review results
|
|
158
|
+
├── stop.js ← Stop: batch save, cache, archive, cleanup
|
|
159
|
+
├── hook-utils.js ← Shared: sqliteBatch, async I/O, constants
|
|
160
|
+
├── templates/
|
|
161
|
+
│ └── planning-template.md ← SDD+BDD+edge case template
|
|
162
|
+
└── __tests__/
|
|
163
|
+
├── hook-test-harness.js ← Test runner (no Claude Code needed)
|
|
164
|
+
└── hooks.test.js ← 15 test cases
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Handler Flow (PreToolUse)
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
PreToolUse event
|
|
171
|
+
↓
|
|
172
|
+
┌──────────────────────┐
|
|
173
|
+
│ Handler Registry │
|
|
174
|
+
│ ├─ codeReview │ → additionalContext (review reminder)
|
|
175
|
+
│ ├─ routing │ → updatedInput (model, background)
|
|
176
|
+
│ ├─ planning │ → updatedInput.prompt (template)
|
|
177
|
+
│ └─ dryRunGate │ → additionalContext (untested warning)
|
|
178
|
+
└──────────────────────┘
|
|
179
|
+
↓
|
|
180
|
+
┌──────────────────────┐
|
|
181
|
+
│ Response Merger │
|
|
182
|
+
│ • updatedInput: deep-merge
|
|
183
|
+
│ • additionalContext: concatenate
|
|
184
|
+
│ • permissionDecision: most-restrictive
|
|
185
|
+
└──────────────────────┘
|
|
186
|
+
↓
|
|
187
|
+
Single JSON → Claude Code
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Testing
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Run all 15 tests
|
|
196
|
+
node scripts/hooks/__tests__/hooks.test.js
|
|
197
|
+
|
|
198
|
+
# Test individual hook with mock input
|
|
199
|
+
node scripts/hooks/__tests__/hook-test-harness.js pre-tool-use.js \
|
|
200
|
+
'{"tool_name":"Task","tool_input":{"subagent_type":"Plan","prompt":"test"}}'
|
|
201
|
+
|
|
202
|
+
# Syntax check all hooks
|
|
203
|
+
for f in scripts/hooks/*.js; do node --check "$f" && echo "OK: $f"; done
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Configuration
|
|
207
|
+
|
|
208
|
+
### Routing Config (`~/.memesh/routing-config.json`)
|
|
209
|
+
|
|
210
|
+
| Field | Description |
|
|
211
|
+
|-------|-------------|
|
|
212
|
+
| `modelRouting.rules` | Subagent → model mapping |
|
|
213
|
+
| `backgroundRules` | Subagent → force background |
|
|
214
|
+
| `planningEnforcement.enabled` | Inject SDD+BDD template |
|
|
215
|
+
| `dryRunGate.enabled` | Warn on untested code |
|
|
216
|
+
| `auditLog` | Log routing decisions |
|
|
217
|
+
|
|
218
|
+
### Thresholds (`hook-utils.js`)
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
THRESHOLDS = {
|
|
222
|
+
TOKEN_SAVE: 250_000,
|
|
223
|
+
RETENTION_DAYS: 30,
|
|
224
|
+
MAX_ARCHIVED_SESSIONS: 30
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
Part of MeMesh project. License: MIT.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook Test Harness — Simulates Claude Code hook execution.
|
|
5
|
+
*
|
|
6
|
+
* Pipes mock stdin JSON to a hook script and validates the output.
|
|
7
|
+
* Does NOT require Claude Code runtime.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node hook-test-harness.js <hook-script> <mock-stdin-json>
|
|
11
|
+
* node hook-test-harness.js ../pre-tool-use.js '{"tool_name":"Bash","tool_input":{"command":"git commit -m test"}}'
|
|
12
|
+
*
|
|
13
|
+
* Or programmatically:
|
|
14
|
+
* import { runHook, assertJSON, assertContains } from './hook-test-harness.js';
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { execFile } from 'child_process';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
|
+
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = path.dirname(__filename);
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Core Test Functions
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Run a hook script with mock stdin and capture output.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} hookPath - Path to hook script (relative to hooks/ dir or absolute)
|
|
32
|
+
* @param {Object|string} stdinData - JSON data to pipe as stdin
|
|
33
|
+
* @param {Object} options - Options
|
|
34
|
+
* @param {number} options.timeout - Timeout in ms (default: 10000)
|
|
35
|
+
* @param {Object} options.env - Additional environment variables
|
|
36
|
+
* @returns {Promise<{ stdout: string, stderr: string, exitCode: number, parsed: Object|null }>}
|
|
37
|
+
*/
|
|
38
|
+
export function runHook(hookPath, stdinData, options = {}) {
|
|
39
|
+
const { timeout = 10000, env = {} } = options;
|
|
40
|
+
|
|
41
|
+
// Resolve hook path relative to hooks directory
|
|
42
|
+
const resolvedPath = path.isAbsolute(hookPath)
|
|
43
|
+
? hookPath
|
|
44
|
+
: path.resolve(__dirname, '..', hookPath);
|
|
45
|
+
|
|
46
|
+
const stdinStr = typeof stdinData === 'string'
|
|
47
|
+
? stdinData
|
|
48
|
+
: JSON.stringify(stdinData);
|
|
49
|
+
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
const child = execFile('node', [resolvedPath], {
|
|
52
|
+
encoding: 'utf-8',
|
|
53
|
+
timeout,
|
|
54
|
+
env: { ...process.env, ...env },
|
|
55
|
+
}, (error, stdout, stderr) => {
|
|
56
|
+
let parsed = null;
|
|
57
|
+
try {
|
|
58
|
+
if (stdout.trim()) {
|
|
59
|
+
parsed = JSON.parse(stdout.trim());
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// Not JSON output — that's fine for some hooks
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
resolve({
|
|
66
|
+
stdout: stdout || '',
|
|
67
|
+
stderr: stderr || '',
|
|
68
|
+
exitCode: error ? (error.code || 1) : 0,
|
|
69
|
+
parsed,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Pipe stdin
|
|
74
|
+
if (child.stdin) {
|
|
75
|
+
child.stdin.write(stdinStr);
|
|
76
|
+
child.stdin.end();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Assertion Helpers
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Assert that the hook output is valid JSON with expected structure.
|
|
87
|
+
* @param {Object} result - Result from runHook()
|
|
88
|
+
* @param {string} hookEventName - Expected hookEventName
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
*/
|
|
91
|
+
export function assertHookResponse(result, hookEventName) {
|
|
92
|
+
if (!result.parsed) {
|
|
93
|
+
console.error(` FAIL: No JSON output`);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const output = result.parsed.hookSpecificOutput;
|
|
98
|
+
if (!output) {
|
|
99
|
+
console.error(` FAIL: Missing hookSpecificOutput`);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (output.hookEventName !== hookEventName) {
|
|
104
|
+
console.error(` FAIL: hookEventName is "${output.hookEventName}", expected "${hookEventName}"`);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Assert that stdout contains a substring.
|
|
113
|
+
* @param {Object} result - Result from runHook()
|
|
114
|
+
* @param {string} substring - Expected substring
|
|
115
|
+
* @returns {boolean}
|
|
116
|
+
*/
|
|
117
|
+
export function assertContains(result, substring) {
|
|
118
|
+
const fullOutput = result.stdout + result.stderr;
|
|
119
|
+
if (!fullOutput.includes(substring)) {
|
|
120
|
+
console.error(` FAIL: Output does not contain "${substring}"`);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Assert hook exited silently (no stdout, exit 0).
|
|
128
|
+
* @param {Object} result - Result from runHook()
|
|
129
|
+
* @returns {boolean}
|
|
130
|
+
*/
|
|
131
|
+
export function assertSilent(result) {
|
|
132
|
+
if (result.stdout.trim() !== '') {
|
|
133
|
+
console.error(` FAIL: Expected silent exit, got stdout: ${result.stdout.substring(0, 100)}`);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// Test Runner
|
|
141
|
+
// ============================================================================
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Simple test runner for hook tests.
|
|
145
|
+
* @param {string} suiteName - Test suite name
|
|
146
|
+
* @param {Array<{name: string, fn: Function}>} tests - Test cases
|
|
147
|
+
*/
|
|
148
|
+
export async function runTests(suiteName, tests) {
|
|
149
|
+
console.log(`\n ${suiteName}`);
|
|
150
|
+
console.log(' ' + '─'.repeat(50));
|
|
151
|
+
|
|
152
|
+
let passed = 0;
|
|
153
|
+
let failed = 0;
|
|
154
|
+
|
|
155
|
+
for (const test of tests) {
|
|
156
|
+
try {
|
|
157
|
+
const result = await test.fn();
|
|
158
|
+
if (result !== false) {
|
|
159
|
+
console.log(` ✅ ${test.name}`);
|
|
160
|
+
passed++;
|
|
161
|
+
} else {
|
|
162
|
+
console.log(` ❌ ${test.name}`);
|
|
163
|
+
failed++;
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.log(` ❌ ${test.name}`);
|
|
167
|
+
console.error(` Error: ${error.message}`);
|
|
168
|
+
failed++;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(' ' + '─'.repeat(50));
|
|
173
|
+
console.log(` Results: ${passed} passed, ${failed} failed\n`);
|
|
174
|
+
|
|
175
|
+
return { passed, failed };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// CLI Mode
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
async function main() {
|
|
183
|
+
const args = process.argv.slice(2);
|
|
184
|
+
|
|
185
|
+
if (args.length < 2) {
|
|
186
|
+
console.log('Usage: node hook-test-harness.js <hook-script> <mock-stdin-json>');
|
|
187
|
+
console.log('');
|
|
188
|
+
console.log('Examples:');
|
|
189
|
+
console.log(' node hook-test-harness.js pre-tool-use.js \'{"tool_name":"Bash","tool_input":{"command":"git commit -m test"}}\'');
|
|
190
|
+
console.log(' node hook-test-harness.js post-tool-use.js \'{"tool_name":"Read","tool_input":{"file_path":"/tmp/test.js"}}\'');
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const [hookScript, stdinJSON] = args;
|
|
195
|
+
|
|
196
|
+
console.log(`\nRunning: ${hookScript}`);
|
|
197
|
+
console.log(`Stdin: ${stdinJSON.substring(0, 100)}...`);
|
|
198
|
+
console.log('');
|
|
199
|
+
|
|
200
|
+
const result = await runHook(hookScript, stdinJSON);
|
|
201
|
+
|
|
202
|
+
console.log(`Exit code: ${result.exitCode}`);
|
|
203
|
+
if (result.stdout.trim()) {
|
|
204
|
+
console.log(`Stdout: ${result.stdout.trim()}`);
|
|
205
|
+
}
|
|
206
|
+
if (result.stderr.trim()) {
|
|
207
|
+
console.log(`Stderr: ${result.stderr.trim()}`);
|
|
208
|
+
}
|
|
209
|
+
if (result.parsed) {
|
|
210
|
+
console.log(`Parsed JSON:`);
|
|
211
|
+
console.log(JSON.stringify(result.parsed, null, 2));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Run CLI mode if invoked directly
|
|
216
|
+
if (process.argv[1] && process.argv[1].includes('hook-test-harness')) {
|
|
217
|
+
main().catch(console.error);
|
|
218
|
+
}
|