claude-mem-lite 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +19 -0
- package/.mcp.json +9 -0
- package/LICENSE +21 -0
- package/README.md +486 -0
- package/README.zh-CN.md +486 -0
- package/commands/mem.md +34 -0
- package/dispatch-feedback.mjs +139 -0
- package/dispatch-inject.mjs +147 -0
- package/dispatch.mjs +692 -0
- package/haiku-client.mjs +165 -0
- package/hook-context.mjs +176 -0
- package/hook-episode.mjs +222 -0
- package/hook-llm.mjs +358 -0
- package/hook-semaphore.mjs +84 -0
- package/hook-shared.mjs +174 -0
- package/hook.mjs +849 -0
- package/hooks/hooks.json +77 -0
- package/install.mjs +948 -0
- package/package.json +69 -0
- package/registry/preinstalled.json +279 -0
- package/registry-indexer.mjs +172 -0
- package/registry-retriever.mjs +372 -0
- package/registry-scanner.mjs +253 -0
- package/registry.mjs +350 -0
- package/resource-discovery.mjs +189 -0
- package/schema.mjs +267 -0
- package/scripts/post-tool-use.sh +60 -0
- package/scripts/setup.sh +83 -0
- package/server-internals.mjs +195 -0
- package/server.mjs +938 -0
- package/skill.md +35 -0
- package/tool-schemas.mjs +56 -0
- package/utils.mjs +594 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// claude-mem-lite: Injection template rendering
|
|
2
|
+
// Formats resource recommendations for Claude Code's additionalContext
|
|
3
|
+
|
|
4
|
+
import { existsSync, readFileSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { homedir } from 'os';
|
|
7
|
+
import { truncate } from './utils.mjs';
|
|
8
|
+
import { DB_DIR } from './schema.mjs';
|
|
9
|
+
|
|
10
|
+
const MAX_INJECTION_CHARS = 3000;
|
|
11
|
+
|
|
12
|
+
// Allowed base directories for resource file reads (defense-in-depth)
|
|
13
|
+
const ALLOWED_BASES = [
|
|
14
|
+
join(homedir(), '.claude'),
|
|
15
|
+
join(DB_DIR, 'managed'),
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function isAllowedPath(filePath) {
|
|
19
|
+
if (!filePath) return false;
|
|
20
|
+
return ALLOWED_BASES.some(base => filePath.startsWith(base));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ─── Template Detection ──────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check if a skill exists in user's native ~/.claude/skills/ directory.
|
|
27
|
+
* If so, Claude can invoke it directly via /skill-name command.
|
|
28
|
+
*/
|
|
29
|
+
function isNativeSkill(name) {
|
|
30
|
+
const nativePath = join(homedir(), '.claude', 'skills', name);
|
|
31
|
+
return existsSync(nativePath);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── Injection Templates ─────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Native skill template -- tells Claude to use the skill command.
|
|
38
|
+
* Used when skill exists in ~/.claude/skills/.
|
|
39
|
+
* @param {object} resource Resource object from DB
|
|
40
|
+
* @returns {string} Injection text referencing the native skill command
|
|
41
|
+
*/
|
|
42
|
+
function injectSkillNative(resource) {
|
|
43
|
+
return `[Auto-suggestion] A relevant skill "${resource.name}" is available for this task. ` +
|
|
44
|
+
`Use: /skill ${resource.name}. ` +
|
|
45
|
+
`Capability: ${truncate(resource.capability_summary, 100)}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Managed skill template -- includes content for Claude to use directly.
|
|
50
|
+
* Used when skill is in managed/ directory (not installed natively).
|
|
51
|
+
* @param {object} resource Resource object from DB
|
|
52
|
+
* @returns {string} Injection text with embedded skill content
|
|
53
|
+
*/
|
|
54
|
+
function injectSkillManaged(resource) {
|
|
55
|
+
if (!isAllowedPath(resource.local_path)) return injectSkillNative(resource);
|
|
56
|
+
let content = '';
|
|
57
|
+
try {
|
|
58
|
+
content = readFileSync(resource.local_path, 'utf8');
|
|
59
|
+
} catch {
|
|
60
|
+
// Try reading from directory
|
|
61
|
+
try {
|
|
62
|
+
const candidates = ['skill.md', 'SKILL.md', 'README.md'];
|
|
63
|
+
for (const name of candidates) {
|
|
64
|
+
const fp = join(resource.local_path, name);
|
|
65
|
+
if (existsSync(fp)) { content = readFileSync(fp, 'utf8'); break; }
|
|
66
|
+
}
|
|
67
|
+
} catch {}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const truncatedContent = truncate(content, MAX_INJECTION_CHARS - 300);
|
|
71
|
+
|
|
72
|
+
return `[Auto-suggestion] Recommended skill for this task: "${resource.name}"
|
|
73
|
+
Capability: ${truncate(resource.capability_summary, 100)}
|
|
74
|
+
<skill-content>
|
|
75
|
+
${truncatedContent}
|
|
76
|
+
</skill-content>`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Agent template -- guides Claude to use Task tool with the agent definition.
|
|
81
|
+
* @param {object} resource Resource object from DB
|
|
82
|
+
* @returns {string} Injection text with agent definition for Task tool delegation
|
|
83
|
+
*/
|
|
84
|
+
function injectAgent(resource) {
|
|
85
|
+
if (!isAllowedPath(resource.local_path)) {
|
|
86
|
+
return `[Auto-suggestion] A specialized agent "${resource.name}" is recommended for this task. ` +
|
|
87
|
+
`Capability: ${truncate(resource.capability_summary, 100)}. ` +
|
|
88
|
+
`Use the Task tool to delegate this work.`;
|
|
89
|
+
}
|
|
90
|
+
let agentDef = '';
|
|
91
|
+
try {
|
|
92
|
+
agentDef = readFileSync(resource.local_path, 'utf8');
|
|
93
|
+
} catch {
|
|
94
|
+
try {
|
|
95
|
+
const candidates = ['agent.md', 'AGENT.md', 'README.md'];
|
|
96
|
+
for (const name of candidates) {
|
|
97
|
+
const fp = join(resource.local_path, name);
|
|
98
|
+
if (existsSync(fp)) { agentDef = readFileSync(fp, 'utf8'); break; }
|
|
99
|
+
}
|
|
100
|
+
} catch {}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (agentDef) {
|
|
104
|
+
const truncatedDef = truncate(agentDef, MAX_INJECTION_CHARS - 300);
|
|
105
|
+
return `[Auto-suggestion] A specialized agent "${resource.name}" is recommended for this task.
|
|
106
|
+
Capability: ${truncate(resource.capability_summary, 100)}
|
|
107
|
+
Use the Task tool with this agent definition:
|
|
108
|
+
<agent-definition>
|
|
109
|
+
${truncatedDef}
|
|
110
|
+
</agent-definition>`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return `[Auto-suggestion] A specialized agent "${resource.name}" is recommended for this task. ` +
|
|
114
|
+
`Capability: ${truncate(resource.capability_summary, 100)}. ` +
|
|
115
|
+
`Use the Task tool to delegate this work.`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ─── Main Render ─────────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Render injection text for a resource recommendation.
|
|
122
|
+
* Selects the appropriate template based on resource type and location.
|
|
123
|
+
* Enforces MAX_INJECTION_CHARS hard limit.
|
|
124
|
+
*
|
|
125
|
+
* @param {object} resource Resource object from DB
|
|
126
|
+
* @returns {string} Injection text for additionalContext
|
|
127
|
+
*/
|
|
128
|
+
export function renderInjection(resource) {
|
|
129
|
+
let injection;
|
|
130
|
+
|
|
131
|
+
if (resource.type === 'skill') {
|
|
132
|
+
if (isNativeSkill(resource.name)) {
|
|
133
|
+
injection = injectSkillNative(resource);
|
|
134
|
+
} else {
|
|
135
|
+
injection = injectSkillManaged(resource);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
injection = injectAgent(resource);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Hard limit enforcement
|
|
142
|
+
if (injection.length > MAX_INJECTION_CHARS) {
|
|
143
|
+
injection = injection.slice(0, MAX_INJECTION_CHARS - 3) + '...';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return injection;
|
|
147
|
+
}
|