create-merlin-brain 3.22.0 → 4.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/README.md +38 -4
- package/bin/merlin-ask.cjs +111 -0
- package/bin/merlin-cli.cjs +22 -0
- package/bin/runtime-adapters.cjs +709 -28
- package/dist/server/api/client.d.ts +2 -0
- package/dist/server/api/client.d.ts.map +1 -1
- package/dist/server/api/client.js +4 -0
- package/dist/server/api/client.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +56 -4
- package/dist/server/server.js.map +1 -1
- package/dist/server/tools/auto-mode.d.ts +9 -0
- package/dist/server/tools/auto-mode.d.ts.map +1 -0
- package/dist/server/tools/auto-mode.js +231 -0
- package/dist/server/tools/auto-mode.js.map +1 -0
- package/dist/server/tools/computer-use.d.ts +8 -0
- package/dist/server/tools/computer-use.d.ts.map +1 -0
- package/dist/server/tools/computer-use.js +355 -0
- package/dist/server/tools/computer-use.js.map +1 -0
- package/dist/server/tools/dream.d.ts +9 -0
- package/dist/server/tools/dream.d.ts.map +1 -0
- package/dist/server/tools/dream.js +246 -0
- package/dist/server/tools/dream.js.map +1 -0
- package/dist/server/tools/help.d.ts +3 -0
- package/dist/server/tools/help.d.ts.map +1 -0
- package/dist/server/tools/help.js +110 -0
- package/dist/server/tools/help.js.map +1 -0
- package/dist/server/tools/hud.d.ts +13 -0
- package/dist/server/tools/hud.d.ts.map +1 -0
- package/dist/server/tools/hud.js +295 -0
- package/dist/server/tools/hud.js.map +1 -0
- package/dist/server/tools/index.d.ts +5 -0
- package/dist/server/tools/index.d.ts.map +1 -1
- package/dist/server/tools/index.js +5 -0
- package/dist/server/tools/index.js.map +1 -1
- package/dist/server/tools/provider-ask.d.ts +10 -0
- package/dist/server/tools/provider-ask.d.ts.map +1 -0
- package/dist/server/tools/provider-ask.js +234 -0
- package/dist/server/tools/provider-ask.js.map +1 -0
- package/dist/server/tools/rate-limit.d.ts +8 -0
- package/dist/server/tools/rate-limit.d.ts.map +1 -0
- package/dist/server/tools/rate-limit.js +184 -0
- package/dist/server/tools/rate-limit.js.map +1 -0
- package/dist/server/tools/skills.d.ts +16 -0
- package/dist/server/tools/skills.d.ts.map +1 -0
- package/dist/server/tools/skills.js +326 -0
- package/dist/server/tools/skills.js.map +1 -0
- package/dist/server/tools/team-workers.d.ts +7 -0
- package/dist/server/tools/team-workers.d.ts.map +1 -0
- package/dist/server/tools/team-workers.js +271 -0
- package/dist/server/tools/team-workers.js.map +1 -0
- package/dist/server/utils/merlin-manifest.d.ts +6 -1
- package/dist/server/utils/merlin-manifest.d.ts.map +1 -1
- package/dist/server/utils/merlin-manifest.js +34 -1
- package/dist/server/utils/merlin-manifest.js.map +1 -1
- package/files/CLAUDE.md +22 -0
- package/files/hooks/rate-limit-watch.sh +120 -0
- package/files/hooks/statusline.sh +148 -0
- package/files/merlin/skills/SKILLS-INDEX.md +82 -0
- package/files/merlin/skills/automation/payments.md +14 -0
- package/files/merlin/skills/automation/webhooks.md +14 -0
- package/files/merlin/skills/coding/accessibility.md +14 -0
- package/files/merlin/skills/coding/api-design.md +14 -0
- package/files/merlin/skills/coding/debug-mode.md +14 -0
- package/files/merlin/skills/coding/focus-mode.md +14 -0
- package/files/merlin/skills/coding/loop.md +14 -0
- package/files/merlin/skills/coding/performance.md +14 -0
- package/files/merlin/skills/coding/react-patterns.md +51 -0
- package/files/merlin/skills/coding/security-hardening.md +56 -0
- package/files/merlin/skills/coding/verify.md +14 -0
- package/files/merlin/skills/communication/dispatcher.md +40 -0
- package/files/merlin/skills/communication/email-gmail.md +31 -0
- package/files/merlin/skills/communication/telegram.md +50 -0
- package/files/merlin/skills/communication/whatsapp.md +47 -0
- package/files/merlin/skills/data/google-sheets.md +14 -0
- package/files/merlin/skills/design/animation.md +14 -0
- package/files/merlin/skills/devops/docker-containers.md +14 -0
- package/files/merlin/skills/research/brainstorm.md +14 -0
- package/files/merlin/skills/testing/tdd-workflow.md +58 -0
- package/package.json +4 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limit Tools
|
|
3
|
+
* Monitor Claude/provider rate-limit state and configure auto-resume behavior.
|
|
4
|
+
* State is written by the rate-limit-watch.sh PostToolUse hook.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
import { coachWrap } from '../session-coach.js';
|
|
11
|
+
const STATE_DIR = join(homedir(), '.merlin', 'state');
|
|
12
|
+
const RATE_LIMIT_STATE_FILE = join(STATE_DIR, 'rate-limit.json');
|
|
13
|
+
const SESSION_COST_FILE = join(STATE_DIR, 'session-cost.json');
|
|
14
|
+
const CONFIG_FILE = join(STATE_DIR, 'rate-limit-config.json');
|
|
15
|
+
/** Default config values */
|
|
16
|
+
const DEFAULTS = {
|
|
17
|
+
warningThreshold: 80,
|
|
18
|
+
autoResume: true,
|
|
19
|
+
cooldownMinutes: 2,
|
|
20
|
+
notifyDesktop: true,
|
|
21
|
+
};
|
|
22
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
23
|
+
function readJson(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
if (!existsSync(filePath))
|
|
26
|
+
return null;
|
|
27
|
+
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function ensureStateDir() {
|
|
34
|
+
if (!existsSync(STATE_DIR)) {
|
|
35
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function readConfig() {
|
|
39
|
+
const saved = readJson(CONFIG_FILE);
|
|
40
|
+
return {
|
|
41
|
+
warningThreshold: saved?.warningThreshold ?? DEFAULTS.warningThreshold,
|
|
42
|
+
autoResume: saved?.autoResume ?? DEFAULTS.autoResume,
|
|
43
|
+
cooldownMinutes: saved?.cooldownMinutes ?? DEFAULTS.cooldownMinutes,
|
|
44
|
+
notifyDesktop: saved?.notifyDesktop ?? DEFAULTS.notifyDesktop,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Seconds until the estimated reset time (negative = already passed) */
|
|
48
|
+
function secondsUntilReset(estimatedResetAt) {
|
|
49
|
+
try {
|
|
50
|
+
const resetMs = new Date(estimatedResetAt).getTime();
|
|
51
|
+
return Math.round((resetMs - Date.now()) / 1000);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Seconds since a given ISO timestamp */
|
|
58
|
+
function secondsSince(isoTs) {
|
|
59
|
+
try {
|
|
60
|
+
return Math.round((Date.now() - new Date(isoTs).getTime()) / 1000);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Determine effective status including cooldown transition */
|
|
67
|
+
function effectiveStatus(state, config, usagePercent) {
|
|
68
|
+
if (state?.status === 'blocked')
|
|
69
|
+
return 'blocked';
|
|
70
|
+
// Cooldown: recently cleared within cooldownMinutes window
|
|
71
|
+
if (state?.status === 'ok' && state.clearedAt) {
|
|
72
|
+
const elapsed = secondsSince(state.clearedAt);
|
|
73
|
+
if (elapsed < config.cooldownMinutes * 60)
|
|
74
|
+
return 'cooldown';
|
|
75
|
+
}
|
|
76
|
+
if (usagePercent >= config.warningThreshold)
|
|
77
|
+
return 'warning';
|
|
78
|
+
return 'ok';
|
|
79
|
+
}
|
|
80
|
+
// ── Tool registration ─────────────────────────────────────────────────────────
|
|
81
|
+
export function registerRateLimitTools(ctx) {
|
|
82
|
+
const { server } = ctx;
|
|
83
|
+
// ── merlin_rate_limit_status ────────────────────────────────────────────────
|
|
84
|
+
server.tool('merlin_rate_limit_status', 'Check current rate limit status across providers. Returns current state (ok/warning/blocked/cooldown), time until reset, and session usage metrics. Use before spawning agents to decide whether to throttle. Blocked = stop spawning. Warning = spawn cautiously. Cooldown = recently unblocked, proceed slowly.', {}, async () => {
|
|
85
|
+
try {
|
|
86
|
+
const state = readJson(RATE_LIMIT_STATE_FILE);
|
|
87
|
+
const cost = readJson(SESSION_COST_FILE);
|
|
88
|
+
const config = readConfig();
|
|
89
|
+
const usagePercent = cost?.usagePercent ?? 0;
|
|
90
|
+
const status = effectiveStatus(state, config, usagePercent);
|
|
91
|
+
let statusLine = '';
|
|
92
|
+
let recommendation = '';
|
|
93
|
+
let resetInfo = '';
|
|
94
|
+
if (status === 'blocked') {
|
|
95
|
+
const secsLeft = state?.estimatedResetAt ? secondsUntilReset(state.estimatedResetAt) : 0;
|
|
96
|
+
const minsLeft = secsLeft > 0 ? Math.ceil(secsLeft / 60) : 0;
|
|
97
|
+
resetInfo = secsLeft > 0
|
|
98
|
+
? `Estimated reset: ~${minsLeft} min (${state.estimatedResetAt})`
|
|
99
|
+
: `Reset time has passed — state may clear on next tool call`;
|
|
100
|
+
statusLine = `**Status: BLOCKED** (trigger: ${state?.trigger ?? 'unknown'})`;
|
|
101
|
+
recommendation = config.autoResume
|
|
102
|
+
? `Auto-resume is enabled. Do not spawn new agents. Wait ${minsLeft > 0 ? `~${minsLeft} min` : 'for the next tool call to clear state'}.`
|
|
103
|
+
: 'Auto-resume is disabled. Manually call merlin_rate_limit_status again after waiting.';
|
|
104
|
+
}
|
|
105
|
+
else if (status === 'cooldown') {
|
|
106
|
+
const elapsed = state?.clearedAt ? secondsSince(state.clearedAt) : 0;
|
|
107
|
+
const remaining = Math.max(0, config.cooldownMinutes * 60 - elapsed);
|
|
108
|
+
statusLine = `**Status: COOLDOWN** (${Math.ceil(remaining / 60)} min remaining)`;
|
|
109
|
+
recommendation = 'Recently unblocked. Proceed cautiously — spawn agents at reduced rate.';
|
|
110
|
+
}
|
|
111
|
+
else if (status === 'warning') {
|
|
112
|
+
statusLine = `**Status: WARNING** (${usagePercent}% usage — threshold: ${config.warningThreshold}%)`;
|
|
113
|
+
recommendation = 'Approaching rate limits. Avoid spawning multiple parallel agents.';
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
statusLine = `**Status: OK** (${usagePercent}% usage)`;
|
|
117
|
+
recommendation = 'Normal operations. No restrictions.';
|
|
118
|
+
}
|
|
119
|
+
const text = `
|
|
120
|
+
${statusLine}
|
|
121
|
+
|
|
122
|
+
${resetInfo ? `${resetInfo}\n` : ''}**Recommendation:** ${recommendation}
|
|
123
|
+
|
|
124
|
+
**Config:** warning at ${config.warningThreshold}% · auto-resume: ${config.autoResume} · cooldown: ${config.cooldownMinutes}min
|
|
125
|
+
|
|
126
|
+
To update these settings, call \`merlin_rate_limit_configure\`.
|
|
127
|
+
`.trim();
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: 'text', text: coachWrap('merlin_rate_limit_status', text) }],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
content: [{
|
|
135
|
+
type: 'text',
|
|
136
|
+
text: `**Error reading rate limit state:** ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
137
|
+
}],
|
|
138
|
+
isError: true,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// ── merlin_rate_limit_configure ─────────────────────────────────────────────
|
|
143
|
+
server.tool('merlin_rate_limit_configure', 'Configure rate limit thresholds and auto-resume behavior for Merlin. Sets the warning percentage, whether blocked sessions auto-resume, cooldown duration after unblocking, and desktop notifications. Config is persisted to ~/.merlin/state/rate-limit-config.json.', {
|
|
144
|
+
warningThreshold: z.number().min(1).max(100).optional().describe('Usage percentage at which to warn (default: 80)'),
|
|
145
|
+
autoResume: z.boolean().optional().describe('Whether to auto-resume blocked sessions when the rate limit clears (default: true)'),
|
|
146
|
+
cooldownMinutes: z.number().min(0).max(60).optional().describe('Minutes to stay in cooldown after unblocking (default: 2)'),
|
|
147
|
+
notifyDesktop: z.boolean().optional().describe('Send macOS desktop notification when rate limit is detected (default: true)'),
|
|
148
|
+
}, async ({ warningThreshold, autoResume, cooldownMinutes, notifyDesktop }) => {
|
|
149
|
+
try {
|
|
150
|
+
ensureStateDir();
|
|
151
|
+
const current = readConfig();
|
|
152
|
+
const updated = {
|
|
153
|
+
warningThreshold: warningThreshold ?? current.warningThreshold,
|
|
154
|
+
autoResume: autoResume ?? current.autoResume,
|
|
155
|
+
cooldownMinutes: cooldownMinutes ?? current.cooldownMinutes,
|
|
156
|
+
notifyDesktop: notifyDesktop ?? current.notifyDesktop,
|
|
157
|
+
};
|
|
158
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), 'utf-8');
|
|
159
|
+
const text = `
|
|
160
|
+
**Rate limit config updated**
|
|
161
|
+
|
|
162
|
+
- Warning threshold: ${updated.warningThreshold}%
|
|
163
|
+
- Auto-resume: ${updated.autoResume}
|
|
164
|
+
- Cooldown after unblock: ${updated.cooldownMinutes} min
|
|
165
|
+
- Desktop notifications: ${updated.notifyDesktop}
|
|
166
|
+
|
|
167
|
+
Saved to \`~/.merlin/state/rate-limit-config.json\`
|
|
168
|
+
`.trim();
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: 'text', text: coachWrap('merlin_rate_limit_configure', text) }],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
content: [{
|
|
176
|
+
type: 'text',
|
|
177
|
+
text: `**Error saving rate limit config:** ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
178
|
+
}],
|
|
179
|
+
isError: true,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../../src/server/tools/rate-limit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Tools — Discover, load, evolve, and track skills
|
|
3
|
+
*
|
|
4
|
+
* Skills are prompt injections stored as .md files in ~/.claude/merlin/skills/.
|
|
5
|
+
* Claude reads SKILLS-INDEX.md to find relevant skills, then loads the full .md.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by OpenSpace's self-evolving skill system:
|
|
8
|
+
* - Skills track usage and success rates
|
|
9
|
+
* - Skills can be improved after use (auto-evolution)
|
|
10
|
+
* - Improvements push to the server for collective intelligence
|
|
11
|
+
*
|
|
12
|
+
* Works identically in CLI (via MCP) and Studio (same file paths).
|
|
13
|
+
*/
|
|
14
|
+
import type { ToolContext } from './types.js';
|
|
15
|
+
export declare function registerSkillsTools(ctx: ToolContext): void;
|
|
16
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../../src/server/tools/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4H9C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CA0M1D"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Tools — Discover, load, evolve, and track skills
|
|
3
|
+
*
|
|
4
|
+
* Skills are prompt injections stored as .md files in ~/.claude/merlin/skills/.
|
|
5
|
+
* Claude reads SKILLS-INDEX.md to find relevant skills, then loads the full .md.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by OpenSpace's self-evolving skill system:
|
|
8
|
+
* - Skills track usage and success rates
|
|
9
|
+
* - Skills can be improved after use (auto-evolution)
|
|
10
|
+
* - Improvements push to the server for collective intelligence
|
|
11
|
+
*
|
|
12
|
+
* Works identically in CLI (via MCP) and Studio (same file paths).
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync, mkdirSync } from 'fs';
|
|
16
|
+
import { join, relative, basename } from 'path';
|
|
17
|
+
import { homedir } from 'os';
|
|
18
|
+
import { coachWrap } from '../session-coach.js';
|
|
19
|
+
// ─── Paths ────────────────────────────────────────────────────────────────────
|
|
20
|
+
const SKILLS_DIR = join(homedir(), '.claude', 'merlin', 'skills');
|
|
21
|
+
const SKILLS_INDEX = join(SKILLS_DIR, 'SKILLS-INDEX.md');
|
|
22
|
+
const SKILL_STATS_FILE = join(homedir(), '.claude', 'merlin', 'skill-stats.json');
|
|
23
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
24
|
+
function loadStats() {
|
|
25
|
+
try {
|
|
26
|
+
if (existsSync(SKILL_STATS_FILE)) {
|
|
27
|
+
return JSON.parse(readFileSync(SKILL_STATS_FILE, 'utf-8'));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch { /* ignore */ }
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
function saveStats(stats) {
|
|
34
|
+
try {
|
|
35
|
+
mkdirSync(join(homedir(), '.claude', 'merlin'), { recursive: true });
|
|
36
|
+
writeFileSync(SKILL_STATS_FILE, JSON.stringify(stats, null, 2), 'utf-8');
|
|
37
|
+
}
|
|
38
|
+
catch { /* non-critical */ }
|
|
39
|
+
}
|
|
40
|
+
/** Find all .md files recursively in a directory */
|
|
41
|
+
function findSkillFiles(dir) {
|
|
42
|
+
const results = [];
|
|
43
|
+
if (!existsSync(dir))
|
|
44
|
+
return results;
|
|
45
|
+
for (const entry of readdirSync(dir)) {
|
|
46
|
+
const fullPath = join(dir, entry);
|
|
47
|
+
try {
|
|
48
|
+
const stat = statSync(fullPath);
|
|
49
|
+
if (stat.isDirectory()) {
|
|
50
|
+
results.push(...findSkillFiles(fullPath));
|
|
51
|
+
}
|
|
52
|
+
else if (entry.endsWith('.md') && entry !== 'SKILLS-INDEX.md') {
|
|
53
|
+
results.push(fullPath);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { /* skip unreadable */ }
|
|
57
|
+
}
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
/** Parse frontmatter from a skill .md file */
|
|
61
|
+
function parseFrontmatter(content) {
|
|
62
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
63
|
+
if (!match)
|
|
64
|
+
return {};
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const line of match[1].split('\n')) {
|
|
67
|
+
const colonIdx = line.indexOf(':');
|
|
68
|
+
if (colonIdx > 0) {
|
|
69
|
+
const key = line.slice(0, colonIdx).trim();
|
|
70
|
+
let value = line.slice(colonIdx + 1).trim();
|
|
71
|
+
// Parse arrays
|
|
72
|
+
if (typeof value === 'string' && value.startsWith('[')) {
|
|
73
|
+
try {
|
|
74
|
+
value = JSON.parse(value.replace(/'/g, '"'));
|
|
75
|
+
}
|
|
76
|
+
catch { /* keep as string */ }
|
|
77
|
+
}
|
|
78
|
+
// Parse numbers
|
|
79
|
+
if (typeof value === 'string' && /^\d+$/.test(value)) {
|
|
80
|
+
value = parseInt(value, 10);
|
|
81
|
+
}
|
|
82
|
+
result[key] = value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
/** Search skills by keyword matching against tags and name */
|
|
88
|
+
function searchSkills(query) {
|
|
89
|
+
const files = findSkillFiles(SKILLS_DIR);
|
|
90
|
+
const queryWords = query.toLowerCase().split(/\s+/);
|
|
91
|
+
const results = [];
|
|
92
|
+
for (const filePath of files) {
|
|
93
|
+
try {
|
|
94
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
95
|
+
const fm = parseFrontmatter(content);
|
|
96
|
+
const id = fm.id || basename(filePath, '.md');
|
|
97
|
+
const name = fm.name || id;
|
|
98
|
+
const tags = fm.tags || [];
|
|
99
|
+
const domain = fm.domain || '';
|
|
100
|
+
const category = fm.category || '';
|
|
101
|
+
// Score: exact tag match = 3, partial tag match = 2, name match = 2, domain/category = 1
|
|
102
|
+
let score = 0;
|
|
103
|
+
const allSearchable = [...tags, name.toLowerCase(), domain, category];
|
|
104
|
+
for (const word of queryWords) {
|
|
105
|
+
for (const term of allSearchable) {
|
|
106
|
+
if (term === word)
|
|
107
|
+
score += 3;
|
|
108
|
+
else if (term.includes(word) || word.includes(term))
|
|
109
|
+
score += 1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (score > 0) {
|
|
113
|
+
const relPath = relative(SKILLS_DIR, filePath).replace(/\.md$/, '');
|
|
114
|
+
results.push({ id, name, path: relPath, score, tags });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch { /* skip unreadable */ }
|
|
118
|
+
}
|
|
119
|
+
return results.sort((a, b) => b.score - a.score);
|
|
120
|
+
}
|
|
121
|
+
// ─── Register Tools ───────────────────────────────────────────────────────────
|
|
122
|
+
export function registerSkillsTools(ctx) {
|
|
123
|
+
const { server } = ctx;
|
|
124
|
+
// ── merlin_find_skill — search the skills index ──────────────────────────
|
|
125
|
+
server.tool('merlin_find_skill', 'Search the Merlin Skills Index for relevant skills to load. ' +
|
|
126
|
+
'Describe what you need (e.g., "react performance", "stripe payments", "telegram bot") ' +
|
|
127
|
+
'and get back the best matching skills with their file paths. ' +
|
|
128
|
+
'Load the top 1-3 skills by reading their .md files.', {
|
|
129
|
+
query: z.string().describe('What kind of skill you need (e.g., "react hooks", "security audit", "whatsapp messaging")'),
|
|
130
|
+
limit: z.number().optional().describe('Max results to return (default 5)'),
|
|
131
|
+
}, async ({ query, limit }) => {
|
|
132
|
+
const maxResults = Math.min(limit || 5, 20);
|
|
133
|
+
// First try local file search
|
|
134
|
+
const localResults = searchSkills(query);
|
|
135
|
+
// Also try server index if available
|
|
136
|
+
let serverResults = [];
|
|
137
|
+
try {
|
|
138
|
+
const skills = await ctx.client.request(`/api/skills/search?q=${encodeURIComponent(query)}&limit=${maxResults}`);
|
|
139
|
+
serverResults = skills.skills || [];
|
|
140
|
+
}
|
|
141
|
+
catch { /* server unavailable — local-only is fine */ }
|
|
142
|
+
// Merge results (local first, deduplicated)
|
|
143
|
+
const seen = new Set();
|
|
144
|
+
const merged = [];
|
|
145
|
+
for (const r of localResults.slice(0, maxResults)) {
|
|
146
|
+
seen.add(r.id);
|
|
147
|
+
const stats = loadStats()[r.id];
|
|
148
|
+
const successRate = stats && stats.usageCount > 0
|
|
149
|
+
? `${Math.round((stats.successCount / stats.usageCount) * 100)}%`
|
|
150
|
+
: 'new';
|
|
151
|
+
merged.push(`**${r.name}** (${r.path})\n` +
|
|
152
|
+
` Tags: ${r.tags.join(', ')}\n` +
|
|
153
|
+
` Score: ${r.score} | Success: ${successRate} | Uses: ${stats?.usageCount || 0}\n` +
|
|
154
|
+
` Load: Read ~/.claude/merlin/skills/${r.path}.md`);
|
|
155
|
+
}
|
|
156
|
+
for (const r of serverResults) {
|
|
157
|
+
if (!seen.has(r.id) && merged.length < maxResults) {
|
|
158
|
+
seen.add(r.id);
|
|
159
|
+
merged.push(`**${r.name}** (server)\n` +
|
|
160
|
+
` ${r.description}\n` +
|
|
161
|
+
` Install: merlin_install_skill("${r.id}")`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const response = merged.length > 0
|
|
165
|
+
? `Found ${merged.length} skill(s) for "${query}":\n\n${merged.join('\n\n')}`
|
|
166
|
+
: `No skills found for "${query}". You can create one with merlin_evolve_skill after completing the task.`;
|
|
167
|
+
return {
|
|
168
|
+
content: [{ type: 'text', text: coachWrap('merlin_find_skill', response) }],
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
// ── merlin_track_skill — record skill usage outcome ──────────────────────
|
|
172
|
+
server.tool('merlin_track_skill', 'Record that a skill was used and whether it helped. ' +
|
|
173
|
+
'Call this after using a skill to track quality. ' +
|
|
174
|
+
'Skills with high success rates get recommended more often.', {
|
|
175
|
+
skillId: z.string().describe('The skill ID (from frontmatter)'),
|
|
176
|
+
success: z.boolean().describe('Did the skill help accomplish the task?'),
|
|
177
|
+
feedback: z.string().optional().describe('What worked or didn\'t work'),
|
|
178
|
+
}, async ({ skillId, success, feedback }) => {
|
|
179
|
+
const stats = loadStats();
|
|
180
|
+
if (!stats[skillId]) {
|
|
181
|
+
stats[skillId] = { usageCount: 0, successCount: 0, failCount: 0, lastUsed: '', version: 1 };
|
|
182
|
+
}
|
|
183
|
+
stats[skillId].usageCount++;
|
|
184
|
+
if (success)
|
|
185
|
+
stats[skillId].successCount++;
|
|
186
|
+
else
|
|
187
|
+
stats[skillId].failCount++;
|
|
188
|
+
stats[skillId].lastUsed = new Date().toISOString();
|
|
189
|
+
saveStats(stats);
|
|
190
|
+
// Push stats to server (background, non-blocking)
|
|
191
|
+
try {
|
|
192
|
+
void ctx.client.request('/api/skills/usage', {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
headers: { 'Content-Type': 'application/json' },
|
|
195
|
+
body: JSON.stringify({ skillId, success, feedback }),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
catch { /* non-critical */ }
|
|
199
|
+
const rate = Math.round((stats[skillId].successCount / stats[skillId].usageCount) * 100);
|
|
200
|
+
const response = success
|
|
201
|
+
? `Tracked: ${skillId} succeeded (${rate}% success rate, ${stats[skillId].usageCount} uses)`
|
|
202
|
+
: `Tracked: ${skillId} failed (${rate}% success rate). ${feedback ? `Feedback: ${feedback}` : 'Consider evolving this skill.'}`;
|
|
203
|
+
return {
|
|
204
|
+
content: [{ type: 'text', text: coachWrap('merlin_track_skill', response) }],
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
// ── merlin_evolve_skill — improve or create a skill ──────────────────────
|
|
208
|
+
server.tool('merlin_evolve_skill', 'Improve an existing skill or create a new one based on what you learned during a task. ' +
|
|
209
|
+
'This is how skills self-evolve: after using a skill, if you found it lacking or wrong, ' +
|
|
210
|
+
'update it with better instructions. New skills are created from successful task patterns.', {
|
|
211
|
+
skillId: z.string().describe('Skill ID to evolve (or new ID for a new skill)'),
|
|
212
|
+
name: z.string().describe('Human-readable skill name'),
|
|
213
|
+
domain: z.enum(['coding', 'non-coding']).describe('Top-level domain'),
|
|
214
|
+
category: z.string().describe('Sub-category (e.g., frontend, security, communication, automation)'),
|
|
215
|
+
tags: z.array(z.string()).describe('Search tags for discovery'),
|
|
216
|
+
content: z.string().describe('The full skill instructions (markdown)'),
|
|
217
|
+
reason: z.string().describe('Why this skill was created or what changed'),
|
|
218
|
+
}, async ({ skillId, name, domain, category, tags, content, reason }) => {
|
|
219
|
+
// Determine file path
|
|
220
|
+
const categoryDir = join(SKILLS_DIR, domain === 'non-coding' ? category : `coding`);
|
|
221
|
+
// For non-coding, use the category directly; for coding, check if the category subdir makes more sense
|
|
222
|
+
const targetDir = existsSync(join(SKILLS_DIR, category)) ? join(SKILLS_DIR, category) : categoryDir;
|
|
223
|
+
mkdirSync(targetDir, { recursive: true });
|
|
224
|
+
const filePath = join(targetDir, `${skillId}.md`);
|
|
225
|
+
// Check if evolving an existing skill
|
|
226
|
+
let version = 1;
|
|
227
|
+
const evolutionLog = [];
|
|
228
|
+
if (existsSync(filePath)) {
|
|
229
|
+
const existing = readFileSync(filePath, 'utf-8');
|
|
230
|
+
const fm = parseFrontmatter(existing);
|
|
231
|
+
version = (fm.version || 0) + 1;
|
|
232
|
+
const existingEvolution = fm.evolution || [];
|
|
233
|
+
evolutionLog.push(...existingEvolution);
|
|
234
|
+
}
|
|
235
|
+
evolutionLog.push(`v${version}: ${reason}`);
|
|
236
|
+
// Write the skill file
|
|
237
|
+
const frontmatter = [
|
|
238
|
+
'---',
|
|
239
|
+
`id: ${skillId}`,
|
|
240
|
+
`name: ${name}`,
|
|
241
|
+
`domain: ${domain}`,
|
|
242
|
+
`category: ${category}`,
|
|
243
|
+
`tags: [${tags.join(', ')}]`,
|
|
244
|
+
`version: ${version}`,
|
|
245
|
+
`source: ${version === 1 ? 'evolved' : 'evolved'}`,
|
|
246
|
+
`successRate: 0`,
|
|
247
|
+
`usageCount: 0`,
|
|
248
|
+
`evolution:`,
|
|
249
|
+
...evolutionLog.map(e => ` - "${e}"`),
|
|
250
|
+
'---',
|
|
251
|
+
'',
|
|
252
|
+
].join('\n');
|
|
253
|
+
writeFileSync(filePath, frontmatter + content, 'utf-8');
|
|
254
|
+
// Update stats
|
|
255
|
+
const stats = loadStats();
|
|
256
|
+
if (stats[skillId]) {
|
|
257
|
+
stats[skillId].lastEvolved = new Date().toISOString();
|
|
258
|
+
stats[skillId].version = version;
|
|
259
|
+
}
|
|
260
|
+
saveStats(stats);
|
|
261
|
+
// Push to server (background)
|
|
262
|
+
try {
|
|
263
|
+
void ctx.client.request('/api/skills', {
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: { 'Content-Type': 'application/json' },
|
|
266
|
+
body: JSON.stringify({
|
|
267
|
+
id: skillId, name, domain, category, tags,
|
|
268
|
+
content, version, reason,
|
|
269
|
+
}),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
catch { /* non-critical */ }
|
|
273
|
+
// Update the index file
|
|
274
|
+
updateSkillsIndex();
|
|
275
|
+
const action = version === 1 ? 'Created' : `Evolved to v${version}`;
|
|
276
|
+
const response = `${action}: **${name}** (${skillId})\n` +
|
|
277
|
+
`Path: ${relative(join(homedir(), '.claude', 'merlin'), filePath)}\n` +
|
|
278
|
+
`Reason: ${reason}\n` +
|
|
279
|
+
`Tags: ${tags.join(', ')}`;
|
|
280
|
+
return {
|
|
281
|
+
content: [{ type: 'text', text: coachWrap('merlin_evolve_skill', response) }],
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// ─── Index Regeneration ───────────────────────────────────────────────────────
|
|
286
|
+
/** Rebuild SKILLS-INDEX.md from all skill files on disk */
|
|
287
|
+
function updateSkillsIndex() {
|
|
288
|
+
const files = findSkillFiles(SKILLS_DIR);
|
|
289
|
+
const byCategory = new Map();
|
|
290
|
+
for (const filePath of files) {
|
|
291
|
+
try {
|
|
292
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
293
|
+
const fm = parseFrontmatter(content);
|
|
294
|
+
const id = fm.id || basename(filePath, '.md');
|
|
295
|
+
const name = fm.name || id;
|
|
296
|
+
const tags = fm.tags || [];
|
|
297
|
+
const domain = fm.domain || 'coding';
|
|
298
|
+
const category = fm.category || 'other';
|
|
299
|
+
const key = `${domain} > ${category}`;
|
|
300
|
+
const relPath = relative(SKILLS_DIR, filePath).replace(/\.md$/, '');
|
|
301
|
+
if (!byCategory.has(key))
|
|
302
|
+
byCategory.set(key, []);
|
|
303
|
+
byCategory.get(key).push({ id, name, tags, relPath });
|
|
304
|
+
}
|
|
305
|
+
catch { /* skip */ }
|
|
306
|
+
}
|
|
307
|
+
const lines = [
|
|
308
|
+
'# Merlin Skills Index',
|
|
309
|
+
'',
|
|
310
|
+
'Search this index to find skills. Load by reading the .md file.',
|
|
311
|
+
'Only load 1-3 per task. After use, track with merlin_track_skill.',
|
|
312
|
+
'',
|
|
313
|
+
];
|
|
314
|
+
for (const [category, skills] of [...byCategory.entries()].sort()) {
|
|
315
|
+
lines.push(`## ${category}`);
|
|
316
|
+
for (const s of skills) {
|
|
317
|
+
lines.push(`- \`${s.relPath}\` — ${s.name} — [${s.tags.join(', ')}]`);
|
|
318
|
+
}
|
|
319
|
+
lines.push('');
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
writeFileSync(SKILLS_INDEX, lines.join('\n'), 'utf-8');
|
|
323
|
+
}
|
|
324
|
+
catch { /* non-critical */ }
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/server/tools/skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team Workers Tools — Spawn parallel AI CLI workers in tmux panes.
|
|
3
|
+
* Job state persisted to ~/.merlin/state/team/ for status/cleanup queries.
|
|
4
|
+
*/
|
|
5
|
+
import type { ToolContext } from './types.js';
|
|
6
|
+
export declare function registerTeamWorkerTools(ctx: ToolContext): void;
|
|
7
|
+
//# sourceMappingURL=team-workers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-workers.d.ts","sourceRoot":"","sources":["../../../src/server/tools/team-workers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0H9C,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CA4J9D"}
|