@williamzujkowski/live-coding-music-mcp 3.0.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 +37 -102
- package/dist/server/server.js +8 -8
- package/dist/server/tools/ai.js +5 -61
- package/dist/server/tools/analysis.js +2 -32
- package/dist/server/tools/capture.js +3 -41
- package/dist/server/tools/compose.js +2 -16
- package/dist/server/tools/diagnostics.js +3 -50
- package/dist/server/tools/editor.js +3 -66
- package/dist/server/tools/generate.js +7 -152
- package/dist/server/tools/history.js +5 -58
- package/dist/server/tools/playback.js +5 -21
- package/dist/server/tools/session.js +3 -41
- package/dist/server/tools/storage.js +1 -49
- package/dist/server/tools/transform.js +9 -156
- package/package.json +1 -1
|
@@ -2,17 +2,13 @@
|
|
|
2
2
|
* diagnostics domain — observability tools (browser status, errors,
|
|
3
3
|
* server metrics).
|
|
4
4
|
*
|
|
5
|
-
* Owns one consolidated tool (`diagnostics(level)`)
|
|
6
|
-
*
|
|
7
|
-
* per #120 / #144.
|
|
5
|
+
* Owns one consolidated tool (`diagnostics(level)`) with status/full/
|
|
6
|
+
* perf/memory/errors levels.
|
|
8
7
|
*
|
|
9
8
|
* The `<15ms` SLA on `level='status'` is preserved — that branch only
|
|
10
9
|
* reads from the controller's cache, not the browser. Other levels can
|
|
11
10
|
* touch the browser (`level='full'`) or just inspect server state
|
|
12
11
|
* (`perf`, `memory`).
|
|
13
|
-
*
|
|
14
|
-
* `screenshot` stays separate; it folds into `browser_window` per
|
|
15
|
-
* Phase 3 (#156).
|
|
16
12
|
*/
|
|
17
13
|
const SESSION_ID_PROP = {
|
|
18
14
|
session_id: {
|
|
@@ -31,7 +27,7 @@ export const tools = [
|
|
|
31
27
|
'level=errors returns captured console errors and warnings from Strudel. ' +
|
|
32
28
|
'Default level=full preserves the pre-consolidation behaviour. ' +
|
|
33
29
|
'Example: diagnostics({ level: "status" }) — millisecond-cheap. ' +
|
|
34
|
-
'For screenshots use browser_window
|
|
30
|
+
'For screenshots use browser_window; for tool listings use the strudel://docs/tools resource.',
|
|
35
31
|
inputSchema: {
|
|
36
32
|
type: 'object',
|
|
37
33
|
properties: {
|
|
@@ -44,37 +40,6 @@ export const tools = [
|
|
|
44
40
|
},
|
|
45
41
|
},
|
|
46
42
|
},
|
|
47
|
-
{
|
|
48
|
-
name: 'status',
|
|
49
|
-
description: '[DEPRECATED — use diagnostics({ level: "status" }) instead] Get current browser and playback status (quick state check)',
|
|
50
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'show_errors',
|
|
54
|
-
description: '[DEPRECATED — use diagnostics({ level: "errors" }) instead] Display captured console errors and warnings from Strudel',
|
|
55
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: 'performance_report',
|
|
59
|
-
description: '[DEPRECATED — use diagnostics({ level: "perf" }) instead] Get performance metrics and bottlenecks',
|
|
60
|
-
inputSchema: { type: 'object', properties: {} },
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: 'memory_usage',
|
|
64
|
-
description: '[DEPRECATED — use diagnostics({ level: "memory" }) instead] Get current memory usage statistics',
|
|
65
|
-
inputSchema: { type: 'object', properties: {} },
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'screenshot',
|
|
69
|
-
description: '[DEPRECATED — use browser_window({ action: "screenshot" }) instead] Take a screenshot of the current Strudel editor state',
|
|
70
|
-
inputSchema: {
|
|
71
|
-
type: 'object',
|
|
72
|
-
properties: {
|
|
73
|
-
filename: { type: 'string', description: 'Optional filename for screenshot' },
|
|
74
|
-
...SESSION_ID_PROP,
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
43
|
];
|
|
79
44
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
80
45
|
function getPerformanceReport(ctx) {
|
|
@@ -129,18 +94,6 @@ export async function execute(name, args, ctx) {
|
|
|
129
94
|
throw new Error(`Invalid level: ${level}. Must be one of: status, full, perf, memory, errors`);
|
|
130
95
|
}
|
|
131
96
|
}
|
|
132
|
-
// Deprecated aliases — forward to consolidated handler. Kept for ≥1
|
|
133
|
-
// release per #120 migration policy.
|
|
134
|
-
case 'status': return getStatus(ctx, sid);
|
|
135
|
-
case 'show_errors': return getErrors(ctx, sid);
|
|
136
|
-
case 'performance_report': return getPerformanceReport(ctx);
|
|
137
|
-
case 'memory_usage': return getMemoryUsage(ctx);
|
|
138
|
-
case 'screenshot': {
|
|
139
|
-
if (!sid && !ctx.isInitialized()) {
|
|
140
|
-
return 'Browser not initialized. Run init first.';
|
|
141
|
-
}
|
|
142
|
-
return await ctx.getController(sid).takeScreenshot(args?.filename);
|
|
143
|
-
}
|
|
144
97
|
default:
|
|
145
98
|
throw new Error(`diagnostics module does not handle tool: ${name}`);
|
|
146
99
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* editor domain — pattern editing in the CodeMirror editor.
|
|
3
3
|
*
|
|
4
|
-
* Owns one consolidated mutation tool (`edit_pattern(mode)`)
|
|
5
|
-
* `get_pattern` (kept
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Aliases forward to `edit_pattern` and will be removed in a future
|
|
9
|
-
* release per the deprecation policy.
|
|
4
|
+
* Owns one consolidated mutation tool (`edit_pattern(mode)`) with
|
|
5
|
+
* write/append/insert/replace/clear modes, plus `get_pattern` (kept
|
|
6
|
+
* separate — hot read path).
|
|
10
7
|
*/
|
|
11
8
|
import { InputValidator } from '../../utils/InputValidator.js';
|
|
12
9
|
const SESSION_ID_PROP = {
|
|
@@ -50,60 +47,6 @@ export const tools = [
|
|
|
50
47
|
description: 'Get current pattern code',
|
|
51
48
|
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
52
49
|
},
|
|
53
|
-
{
|
|
54
|
-
name: 'write',
|
|
55
|
-
description: '[DEPRECATED — use edit_pattern({ mode: "write" }) instead] Write pattern to editor with optional auto-play and validation',
|
|
56
|
-
inputSchema: {
|
|
57
|
-
type: 'object',
|
|
58
|
-
properties: {
|
|
59
|
-
pattern: { type: 'string', description: 'Pattern code' },
|
|
60
|
-
auto_play: { type: 'boolean', description: 'Start playback immediately after writing (default: false)' },
|
|
61
|
-
validate: { type: 'boolean', description: 'Validate pattern before writing (default: true)' },
|
|
62
|
-
...SESSION_ID_PROP,
|
|
63
|
-
},
|
|
64
|
-
required: ['pattern'],
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'append',
|
|
69
|
-
description: '[DEPRECATED — use edit_pattern({ mode: "append" }) instead] Append code to current pattern',
|
|
70
|
-
inputSchema: {
|
|
71
|
-
type: 'object',
|
|
72
|
-
properties: { code: { type: 'string', description: 'Code to append' }, ...SESSION_ID_PROP },
|
|
73
|
-
required: ['code'],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: 'insert',
|
|
78
|
-
description: '[DEPRECATED — use edit_pattern({ mode: "insert" }) instead] Insert code at specific line',
|
|
79
|
-
inputSchema: {
|
|
80
|
-
type: 'object',
|
|
81
|
-
properties: {
|
|
82
|
-
position: { type: 'number', description: 'Line number' },
|
|
83
|
-
code: { type: 'string', description: 'Code to insert' },
|
|
84
|
-
...SESSION_ID_PROP,
|
|
85
|
-
},
|
|
86
|
-
required: ['position', 'code'],
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'replace',
|
|
91
|
-
description: '[DEPRECATED — use edit_pattern({ mode: "replace" }) instead] Replace pattern section',
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: 'object',
|
|
94
|
-
properties: {
|
|
95
|
-
search: { type: 'string', description: 'Text to replace' },
|
|
96
|
-
replace: { type: 'string', description: 'Replacement text' },
|
|
97
|
-
...SESSION_ID_PROP,
|
|
98
|
-
},
|
|
99
|
-
required: ['search', 'replace'],
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: 'clear',
|
|
104
|
-
description: '[DEPRECATED — use edit_pattern({ mode: "clear" }) instead] Clear the editor',
|
|
105
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
106
|
-
},
|
|
107
50
|
];
|
|
108
51
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
109
52
|
async function doWrite(args, ctx, sid) {
|
|
@@ -177,12 +120,6 @@ export async function execute(name, args, ctx) {
|
|
|
177
120
|
throw new Error(`Invalid mode: ${mode}. Must be one of: write, append, insert, replace, clear`);
|
|
178
121
|
}
|
|
179
122
|
}
|
|
180
|
-
// Deprecated aliases — forward to consolidated handler.
|
|
181
|
-
case 'write': return await doWrite(args, ctx, sid);
|
|
182
|
-
case 'append': return await doAppend(args, ctx, sid);
|
|
183
|
-
case 'insert': return await doInsert(args, ctx, sid);
|
|
184
|
-
case 'replace': return await doReplace(args, ctx, sid);
|
|
185
|
-
case 'clear': return await doClear(ctx, sid);
|
|
186
123
|
case 'get_pattern':
|
|
187
124
|
return await ctx.getCurrentPatternSafe(sid);
|
|
188
125
|
default:
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* generate domain — pattern and music-theory generation (no browser needed).
|
|
3
3
|
*
|
|
4
|
-
* Owns (
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Owns (3 tools):
|
|
5
|
+
* generate_part(role) — drums/bass/melody/fill layers
|
|
6
|
+
* music_theory(query) — scale notes, chord progressions
|
|
7
|
+
* generate_rhythm(type) — euclidean / polyrhythm patterns
|
|
8
8
|
*
|
|
9
|
-
* `compose`
|
|
10
|
-
* + play + optional AI feedback
|
|
11
|
-
* happens. Per the #110 audit, compose eventually absorbs generate_pattern
|
|
12
|
-
* and the four generate_* drums/bass/melody/fill tools collapse into
|
|
13
|
-
* `generate_part(role)`, while scale+chord_prog become `music_theory`.
|
|
9
|
+
* Full-composition generation lives in `compose` (compose.ts), which
|
|
10
|
+
* orchestrates init + generate + play + optional AI feedback.
|
|
14
11
|
*/
|
|
15
12
|
import { InputValidator } from '../../utils/InputValidator.js';
|
|
16
13
|
const SESSION_ID_PROP = {
|
|
@@ -20,21 +17,6 @@ const SESSION_ID_PROP = {
|
|
|
20
17
|
},
|
|
21
18
|
};
|
|
22
19
|
export const tools = [
|
|
23
|
-
{
|
|
24
|
-
name: 'generate_pattern',
|
|
25
|
-
description: '[DEPRECATED — use compose instead, which auto-inits and returns richer metadata] Generate complete pattern from style with optional auto-play.',
|
|
26
|
-
inputSchema: {
|
|
27
|
-
type: 'object',
|
|
28
|
-
properties: {
|
|
29
|
-
style: { type: 'string', description: 'Music style (techno/house/dnb/ambient/etc)' },
|
|
30
|
-
key: { type: 'string', description: 'Musical key' },
|
|
31
|
-
bpm: { type: 'number', description: 'Tempo in BPM' },
|
|
32
|
-
auto_play: { type: 'boolean', description: 'Start playback immediately (default: false)' },
|
|
33
|
-
...SESSION_ID_PROP,
|
|
34
|
-
},
|
|
35
|
-
required: ['style'],
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
20
|
{
|
|
39
21
|
name: 'generate_part',
|
|
40
22
|
description: 'Generate a single instrumental layer and append it to the current session pattern. ' +
|
|
@@ -60,51 +42,11 @@ export const tools = [
|
|
|
60
42
|
required: ['role'],
|
|
61
43
|
},
|
|
62
44
|
},
|
|
63
|
-
{
|
|
64
|
-
name: 'generate_drums',
|
|
65
|
-
description: '[DEPRECATED — use generate_part({ role: "drums" }) instead] Generate drum pattern',
|
|
66
|
-
inputSchema: {
|
|
67
|
-
type: 'object',
|
|
68
|
-
properties: {
|
|
69
|
-
style: { type: 'string', description: 'Drum style' },
|
|
70
|
-
complexity: { type: 'number', description: 'Complexity (0-1)' },
|
|
71
|
-
...SESSION_ID_PROP,
|
|
72
|
-
},
|
|
73
|
-
required: ['style'],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: 'generate_bassline',
|
|
78
|
-
description: '[DEPRECATED — use generate_part({ role: "bass" }) instead] Generate bassline',
|
|
79
|
-
inputSchema: {
|
|
80
|
-
type: 'object',
|
|
81
|
-
properties: {
|
|
82
|
-
key: { type: 'string', description: 'Musical key' },
|
|
83
|
-
style: { type: 'string', description: 'Bass style' },
|
|
84
|
-
...SESSION_ID_PROP,
|
|
85
|
-
},
|
|
86
|
-
required: ['key', 'style'],
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'generate_melody',
|
|
91
|
-
description: '[DEPRECATED — use generate_part({ role: "melody" }) instead] Generate melody from scale',
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: 'object',
|
|
94
|
-
properties: {
|
|
95
|
-
scale: { type: 'string', description: 'Scale name' },
|
|
96
|
-
root: { type: 'string', description: 'Root note' },
|
|
97
|
-
length: { type: 'number', description: 'Number of notes' },
|
|
98
|
-
...SESSION_ID_PROP,
|
|
99
|
-
},
|
|
100
|
-
required: ['scale', 'root'],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
45
|
{
|
|
104
46
|
name: 'music_theory',
|
|
105
47
|
description: 'Music-theory queries. ' +
|
|
106
48
|
'query=scale returns the notes of a scale (e.g. "C major scale: C, D, E, F, G, A, B"). ' +
|
|
107
|
-
'query=chord_progression returns a chord progression for the key/style AND writes the resulting chord pattern into the current session
|
|
49
|
+
'query=chord_progression returns a chord progression for the key/style AND writes the resulting chord pattern into the current session. ' +
|
|
108
50
|
'Example: music_theory({ query: "scale", root: "C", scale: "major" }). ' +
|
|
109
51
|
'For pattern generation (drums/bass/melody) use generate_part; for rhythmic patterns use generate_rhythm.',
|
|
110
52
|
inputSchema: {
|
|
@@ -120,31 +62,6 @@ export const tools = [
|
|
|
120
62
|
required: ['query'],
|
|
121
63
|
},
|
|
122
64
|
},
|
|
123
|
-
{
|
|
124
|
-
name: 'generate_scale',
|
|
125
|
-
description: '[DEPRECATED — use music_theory({ query: "scale" }) instead] Generate scale notes',
|
|
126
|
-
inputSchema: {
|
|
127
|
-
type: 'object',
|
|
128
|
-
properties: {
|
|
129
|
-
root: { type: 'string', description: 'Root note' },
|
|
130
|
-
scale: { type: 'string', description: 'Scale type' },
|
|
131
|
-
},
|
|
132
|
-
required: ['root', 'scale'],
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
name: 'generate_chord_progression',
|
|
137
|
-
description: '[DEPRECATED — use music_theory({ query: "chord_progression" }) instead] Generate chord progression',
|
|
138
|
-
inputSchema: {
|
|
139
|
-
type: 'object',
|
|
140
|
-
properties: {
|
|
141
|
-
key: { type: 'string', description: 'Key' },
|
|
142
|
-
style: { type: 'string', description: 'Style (pop/jazz/blues/etc)' },
|
|
143
|
-
...SESSION_ID_PROP,
|
|
144
|
-
},
|
|
145
|
-
required: ['key', 'style'],
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
65
|
{
|
|
149
66
|
name: 'generate_rhythm',
|
|
150
67
|
description: 'Generate a rhythmic pattern and append it to the current session. ' +
|
|
@@ -166,46 +83,6 @@ export const tools = [
|
|
|
166
83
|
required: ['type'],
|
|
167
84
|
},
|
|
168
85
|
},
|
|
169
|
-
{
|
|
170
|
-
name: 'generate_euclidean',
|
|
171
|
-
description: '[DEPRECATED — use generate_rhythm({ type: "euclidean" }) instead] Generate Euclidean rhythm',
|
|
172
|
-
inputSchema: {
|
|
173
|
-
type: 'object',
|
|
174
|
-
properties: {
|
|
175
|
-
hits: { type: 'number', description: 'Number of hits' },
|
|
176
|
-
steps: { type: 'number', description: 'Total steps' },
|
|
177
|
-
sound: { type: 'string', description: 'Sound to use' },
|
|
178
|
-
...SESSION_ID_PROP,
|
|
179
|
-
},
|
|
180
|
-
required: ['hits', 'steps'],
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: 'generate_polyrhythm',
|
|
185
|
-
description: '[DEPRECATED — use generate_rhythm({ type: "polyrhythm" }) instead] Generate polyrhythm',
|
|
186
|
-
inputSchema: {
|
|
187
|
-
type: 'object',
|
|
188
|
-
properties: {
|
|
189
|
-
sounds: { type: 'array', items: { type: 'string' }, description: 'Sounds to use' },
|
|
190
|
-
patterns: { type: 'array', items: { type: 'number' }, description: 'Pattern numbers' },
|
|
191
|
-
...SESSION_ID_PROP,
|
|
192
|
-
},
|
|
193
|
-
required: ['sounds', 'patterns'],
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
name: 'generate_fill',
|
|
198
|
-
description: '[DEPRECATED — use generate_part({ role: "fill" }) instead] Generate drum fill',
|
|
199
|
-
inputSchema: {
|
|
200
|
-
type: 'object',
|
|
201
|
-
properties: {
|
|
202
|
-
style: { type: 'string', description: 'Fill style' },
|
|
203
|
-
bars: { type: 'number', description: 'Number of bars' },
|
|
204
|
-
...SESSION_ID_PROP,
|
|
205
|
-
},
|
|
206
|
-
required: ['style'],
|
|
207
|
-
},
|
|
208
|
-
},
|
|
209
86
|
];
|
|
210
87
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
211
88
|
async function appendOrSet(generated, ctx, sessionId) {
|
|
@@ -278,20 +155,6 @@ async function doFill(args, ctx, sid) {
|
|
|
278
155
|
export async function execute(name, args, ctx) {
|
|
279
156
|
const sid = args?.session_id;
|
|
280
157
|
switch (name) {
|
|
281
|
-
case 'generate_pattern': {
|
|
282
|
-
InputValidator.validateStringLength(args.style, 'style', 100, false);
|
|
283
|
-
if (args.key)
|
|
284
|
-
InputValidator.validateRootNote(args.key);
|
|
285
|
-
if (args.bpm !== undefined)
|
|
286
|
-
InputValidator.validateBPM(args.bpm);
|
|
287
|
-
const generated = ctx.generator.generateCompletePattern(args.style, args.key || 'C', args.bpm || 120);
|
|
288
|
-
await ctx.writePatternSafe(generated, sid);
|
|
289
|
-
if (args.auto_play && (sid || ctx.isInitialized())) {
|
|
290
|
-
await ctx.getController(sid).play();
|
|
291
|
-
return `Generated ${args.style} pattern. Playing.`;
|
|
292
|
-
}
|
|
293
|
-
return `Generated ${args.style} pattern`;
|
|
294
|
-
}
|
|
295
158
|
case 'generate_part': {
|
|
296
159
|
const role = args?.role;
|
|
297
160
|
switch (role) {
|
|
@@ -303,9 +166,6 @@ export async function execute(name, args, ctx) {
|
|
|
303
166
|
throw new Error(`Invalid role: ${role}. Must be one of: drums, bass, melody, fill`);
|
|
304
167
|
}
|
|
305
168
|
}
|
|
306
|
-
case 'generate_drums': return await doDrums(args, ctx, sid);
|
|
307
|
-
case 'generate_bassline': return await doBassline(args, ctx, sid);
|
|
308
|
-
case 'generate_melody': return await doMelody(args, ctx, sid);
|
|
309
169
|
case 'music_theory': {
|
|
310
170
|
const q = args?.query;
|
|
311
171
|
if (q !== 'scale' && q !== 'chord_progression') {
|
|
@@ -313,8 +173,6 @@ export async function execute(name, args, ctx) {
|
|
|
313
173
|
}
|
|
314
174
|
return q === 'scale' ? doScale(args, ctx) : await doChordProgression(args, ctx, sid);
|
|
315
175
|
}
|
|
316
|
-
case 'generate_scale': return doScale(args, ctx);
|
|
317
|
-
case 'generate_chord_progression': return await doChordProgression(args, ctx, sid);
|
|
318
176
|
case 'generate_rhythm': {
|
|
319
177
|
const t = args?.type;
|
|
320
178
|
if (t !== 'euclidean' && t !== 'polyrhythm') {
|
|
@@ -324,9 +182,6 @@ export async function execute(name, args, ctx) {
|
|
|
324
182
|
? await doEuclidean(args, ctx, sid)
|
|
325
183
|
: await doPolyrhythm(args, ctx, sid);
|
|
326
184
|
}
|
|
327
|
-
case 'generate_euclidean': return await doEuclidean(args, ctx, sid);
|
|
328
|
-
case 'generate_polyrhythm': return await doPolyrhythm(args, ctx, sid);
|
|
329
|
-
case 'generate_fill': return await doFill(args, ctx, sid);
|
|
330
185
|
default:
|
|
331
186
|
throw new Error(`generate module does not handle tool: ${name}`);
|
|
332
187
|
}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* history domain — undo/redo stacks and the pattern history browser.
|
|
3
3
|
*
|
|
4
|
-
* Owns (
|
|
5
|
-
*
|
|
6
|
-
* single `history` tool with an `action` enum. For now we keep the
|
|
7
|
-
* individual verbs.
|
|
4
|
+
* Owns one consolidated tool (`history(action)`) with undo/redo/list/
|
|
5
|
+
* restore/compare actions.
|
|
8
6
|
*
|
|
9
7
|
* The history module mutates the three state arrays (undoStack,
|
|
10
|
-
* redoStack, historyStack)
|
|
11
|
-
* server pushes onto these arrays on
|
|
12
|
-
*
|
|
8
|
+
* redoStack, historyStack) reached through ctx.getHistory(). The outer
|
|
9
|
+
* server pushes onto these arrays on every edit_pattern call, so all
|
|
10
|
+
* mutations share the same underlying storage.
|
|
13
11
|
*/
|
|
14
12
|
const SESSION_ID_PROP = {
|
|
15
13
|
session_id: {
|
|
@@ -45,51 +43,6 @@ export const tools = [
|
|
|
45
43
|
required: ['action'],
|
|
46
44
|
},
|
|
47
45
|
},
|
|
48
|
-
{
|
|
49
|
-
name: 'undo',
|
|
50
|
-
description: '[DEPRECATED — use history({ action: "undo" }) instead] Undo last action',
|
|
51
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: 'redo',
|
|
55
|
-
description: '[DEPRECATED — use history({ action: "redo" }) instead] Redo action',
|
|
56
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'list_history',
|
|
60
|
-
description: '[DEPRECATED — use history({ action: "list" }) instead] List recent pattern history with timestamps and previews',
|
|
61
|
-
inputSchema: {
|
|
62
|
-
type: 'object',
|
|
63
|
-
properties: {
|
|
64
|
-
limit: { type: 'number', description: 'Maximum entries to return (default: 10)' },
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'restore_history',
|
|
70
|
-
description: '[DEPRECATED — use history({ action: "restore" }) instead] Restore a previous pattern from history by ID',
|
|
71
|
-
inputSchema: {
|
|
72
|
-
type: 'object',
|
|
73
|
-
properties: {
|
|
74
|
-
id: { type: 'number', description: 'History entry ID to restore' },
|
|
75
|
-
...SESSION_ID_PROP,
|
|
76
|
-
},
|
|
77
|
-
required: ['id'],
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: 'compare_patterns',
|
|
82
|
-
description: '[DEPRECATED — use history({ action: "compare" }) instead] Compare two patterns from history showing differences',
|
|
83
|
-
inputSchema: {
|
|
84
|
-
type: 'object',
|
|
85
|
-
properties: {
|
|
86
|
-
id1: { type: 'number', description: 'First pattern ID' },
|
|
87
|
-
id2: { type: 'number', description: 'Second pattern ID (default: current pattern)' },
|
|
88
|
-
...SESSION_ID_PROP,
|
|
89
|
-
},
|
|
90
|
-
required: ['id1'],
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
46
|
];
|
|
94
47
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
95
48
|
function formatTimeAgo(date) {
|
|
@@ -244,12 +197,6 @@ export async function execute(name, args, ctx) {
|
|
|
244
197
|
throw new Error(`Invalid action: ${action}. Must be one of: undo, redo, list, restore, compare`);
|
|
245
198
|
}
|
|
246
199
|
}
|
|
247
|
-
// Deprecated aliases — forward to consolidated handler.
|
|
248
|
-
case 'undo': return await doUndo(ctx, sid);
|
|
249
|
-
case 'redo': return await doRedo(ctx, sid);
|
|
250
|
-
case 'list_history': return doList(args, ctx, sid);
|
|
251
|
-
case 'restore_history': return await doRestore(args, ctx, sid);
|
|
252
|
-
case 'compare_patterns': return await doCompare(args, ctx, sid);
|
|
253
200
|
default:
|
|
254
201
|
throw new Error(`history module does not handle tool: ${name}`);
|
|
255
202
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* playback domain — transport controls.
|
|
3
3
|
*
|
|
4
|
-
* Owns one consolidated tool (`playback(action)`)
|
|
5
|
-
* aliases (play, pause, stop) per #120 / #152.
|
|
6
|
-
*
|
|
7
|
-
* Aliases forward to `playback` and will be removed in a future release
|
|
8
|
-
* per the deprecation policy.
|
|
4
|
+
* Owns one consolidated tool (`playback(action)`) with play/pause/stop.
|
|
9
5
|
*/
|
|
10
6
|
const SESSION_ID_PROP = {
|
|
11
7
|
session_id: {
|
|
@@ -35,21 +31,6 @@ export const tools = [
|
|
|
35
31
|
required: ['action'],
|
|
36
32
|
},
|
|
37
33
|
},
|
|
38
|
-
{
|
|
39
|
-
name: 'play',
|
|
40
|
-
description: '[DEPRECATED — use playback({ action: "play" }) instead] Start playing pattern',
|
|
41
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: 'pause',
|
|
45
|
-
description: '[DEPRECATED — use playback({ action: "pause" }) instead] Pause playback',
|
|
46
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: 'stop',
|
|
50
|
-
description: '[DEPRECATED — use playback({ action: "stop" }) instead] Stop playback',
|
|
51
|
-
inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
|
|
52
|
-
},
|
|
53
34
|
];
|
|
54
35
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
55
36
|
export async function execute(name, args, ctx) {
|
|
@@ -58,7 +39,10 @@ export async function execute(name, args, ctx) {
|
|
|
58
39
|
return 'Browser not initialized. Run init first.';
|
|
59
40
|
}
|
|
60
41
|
const controller = ctx.getController(sid);
|
|
61
|
-
|
|
42
|
+
if (name !== 'playback') {
|
|
43
|
+
throw new Error(`playback module does not handle tool: ${name}`);
|
|
44
|
+
}
|
|
45
|
+
const action = args?.action;
|
|
62
46
|
switch (action) {
|
|
63
47
|
case 'play':
|
|
64
48
|
return await controller.play();
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* session domain — multi-session lifecycle management.
|
|
3
3
|
*
|
|
4
|
-
* Owns one consolidated tool (`session(action)`)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* not a session operation.
|
|
4
|
+
* Owns one consolidated tool (`session(action)`) with create/destroy/
|
|
5
|
+
* list/switch actions. `init` stays separate — it's the global
|
|
6
|
+
* bootstrap, not a session operation.
|
|
8
7
|
*/
|
|
9
8
|
import { InputValidator } from '../../utils/InputValidator.js';
|
|
10
9
|
export const tools = [
|
|
@@ -26,38 +25,6 @@ export const tools = [
|
|
|
26
25
|
required: ['action'],
|
|
27
26
|
},
|
|
28
27
|
},
|
|
29
|
-
{
|
|
30
|
-
name: 'create_session',
|
|
31
|
-
description: '[DEPRECATED — use session({ action: "create" }) instead] Create a new isolated Strudel browser session.',
|
|
32
|
-
inputSchema: {
|
|
33
|
-
type: 'object',
|
|
34
|
-
properties: { session_id: { type: 'string', description: 'Unique identifier for the session' } },
|
|
35
|
-
required: ['session_id'],
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'destroy_session',
|
|
40
|
-
description: '[DEPRECATED — use session({ action: "destroy" }) instead] Close and destroy a Strudel session.',
|
|
41
|
-
inputSchema: {
|
|
42
|
-
type: 'object',
|
|
43
|
-
properties: { session_id: { type: 'string', description: 'Session identifier to destroy' } },
|
|
44
|
-
required: ['session_id'],
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: 'list_sessions',
|
|
49
|
-
description: '[DEPRECATED — use session({ action: "list" }) instead] List all active Strudel sessions.',
|
|
50
|
-
inputSchema: { type: 'object', properties: {} },
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'switch_session',
|
|
54
|
-
description: '[DEPRECATED — use session({ action: "switch" }) instead] Change the default session.',
|
|
55
|
-
inputSchema: {
|
|
56
|
-
type: 'object',
|
|
57
|
-
properties: { session_id: { type: 'string', description: 'Session identifier to set as default' } },
|
|
58
|
-
required: ['session_id'],
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
28
|
];
|
|
62
29
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
63
30
|
async function doCreate(args, ctx) {
|
|
@@ -141,11 +108,6 @@ export async function execute(name, args, ctx) {
|
|
|
141
108
|
throw new Error(`Invalid action: ${a}. Must be one of: create, destroy, list, switch`);
|
|
142
109
|
}
|
|
143
110
|
}
|
|
144
|
-
// Deprecated aliases.
|
|
145
|
-
case 'create_session': return await doCreate(args, ctx);
|
|
146
|
-
case 'destroy_session': return await doDestroy(args, ctx);
|
|
147
|
-
case 'list_sessions': return doList(ctx);
|
|
148
|
-
case 'switch_session': return doSwitch(args, ctx);
|
|
149
111
|
default:
|
|
150
112
|
throw new Error(`session module does not handle tool: ${name}`);
|
|
151
113
|
}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* storage domain — pattern persistence.
|
|
3
3
|
*
|
|
4
|
-
* Owns one consolidated tool (`pattern_store`)
|
|
5
|
-
* aliases (`save`, `load`, `list`) per the #120 / #143 consolidation.
|
|
6
|
-
*
|
|
7
|
-
* The consolidation also resolves the `list` / `list_sessions` naming
|
|
8
|
-
* collision from #110 — `pattern_store(action='list')` is unambiguous
|
|
9
|
-
* versus `session(action='list')` after the #158 session consolidation.
|
|
10
|
-
*
|
|
11
|
-
* Aliases forward to `pattern_store` and will be removed in a future
|
|
12
|
-
* release per the deprecation policy in #120.
|
|
4
|
+
* Owns one consolidated tool (`pattern_store`) with save/load/list actions.
|
|
13
5
|
*/
|
|
14
6
|
import { InputValidator } from '../../utils/InputValidator.js';
|
|
15
7
|
const SESSION_ID_PROP = {
|
|
@@ -43,41 +35,6 @@ export const tools = [
|
|
|
43
35
|
required: ['action'],
|
|
44
36
|
},
|
|
45
37
|
},
|
|
46
|
-
{
|
|
47
|
-
name: 'save',
|
|
48
|
-
description: '[DEPRECATED — use pattern_store({ action: "save" }) instead] Save pattern with metadata',
|
|
49
|
-
inputSchema: {
|
|
50
|
-
type: 'object',
|
|
51
|
-
properties: {
|
|
52
|
-
name: { type: 'string', description: 'Pattern name' },
|
|
53
|
-
tags: { type: 'array', items: { type: 'string' } },
|
|
54
|
-
...SESSION_ID_PROP,
|
|
55
|
-
},
|
|
56
|
-
required: ['name'],
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'load',
|
|
61
|
-
description: '[DEPRECATED — use pattern_store({ action: "load" }) instead] Load saved pattern',
|
|
62
|
-
inputSchema: {
|
|
63
|
-
type: 'object',
|
|
64
|
-
properties: {
|
|
65
|
-
name: { type: 'string', description: 'Pattern name' },
|
|
66
|
-
...SESSION_ID_PROP,
|
|
67
|
-
},
|
|
68
|
-
required: ['name'],
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: 'list',
|
|
73
|
-
description: '[DEPRECATED — use pattern_store({ action: "list" }) instead] List saved patterns',
|
|
74
|
-
inputSchema: {
|
|
75
|
-
type: 'object',
|
|
76
|
-
properties: {
|
|
77
|
-
tag: { type: 'string', description: 'Filter by tag' },
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
38
|
];
|
|
82
39
|
export const toolNames = new Set(tools.map(t => t.name));
|
|
83
40
|
async function doSave(args, ctx, sid) {
|
|
@@ -121,11 +78,6 @@ export async function execute(name, args, ctx) {
|
|
|
121
78
|
// Unreachable due to enum check above, but TypeScript wants it.
|
|
122
79
|
return undefined;
|
|
123
80
|
}
|
|
124
|
-
// Aliases — forward to consolidated handler. Kept for ≥1 release per
|
|
125
|
-
// #120 migration rules; removed afterwards.
|
|
126
|
-
case 'save': return await doSave(args, ctx, sid);
|
|
127
|
-
case 'load': return await doLoad(args, ctx, sid);
|
|
128
|
-
case 'list': return await doList(args, ctx);
|
|
129
81
|
default:
|
|
130
82
|
throw new Error(`storage module does not handle tool: ${name}`);
|
|
131
83
|
}
|