@mthines/reaper-mcp 0.70.2 → 0.71.0-beta.83.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/README.md +1 -1
- package/bridge-ui/mcp_bridge.html +42 -42
- package/main.js +84 -5
- package/package.json +1 -1
- package/reaper/mcp_bridge.lua +13 -3
package/main.js
CHANGED
|
@@ -4201,6 +4201,71 @@ function ensureSnapshotActions(kb) {
|
|
|
4201
4201
|
const body = kb === "" || kb.endsWith("\n") ? kb : kb + eol;
|
|
4202
4202
|
return { kb: body + lines.join(eol) + eol, added };
|
|
4203
4203
|
}
|
|
4204
|
+
var AUTOSTART_MARKER = "reaper-mcp: start the bridge with REAPER";
|
|
4205
|
+
var AUTOSTART_BEGIN = `-- ${AUTOSTART_MARKER} (begin)`;
|
|
4206
|
+
var AUTOSTART_END = `-- ${AUTOSTART_MARKER} (end)`;
|
|
4207
|
+
var AUTOSTART_BLOCK = [
|
|
4208
|
+
AUTOSTART_BEGIN,
|
|
4209
|
+
"-- Written by `reaper-mcp setup`. Turn it off in the bridge window: Settings \u2192 Start with REAPER.",
|
|
4210
|
+
"do",
|
|
4211
|
+
' local bridge = reaper.GetResourcePath() .. "/Scripts/mcp_bridge.lua"',
|
|
4212
|
+
' if reaper.GetExtState("MCPBridge", "cfg_autostart") ~= "0" and reaper.file_exists(bridge) then',
|
|
4213
|
+
" local id = reaper.AddRemoveReaScript(true, 0, bridge, true)",
|
|
4214
|
+
" if id and id > 0 then reaper.Main_OnCommand(id, 0) end",
|
|
4215
|
+
" end",
|
|
4216
|
+
"end",
|
|
4217
|
+
AUTOSTART_END
|
|
4218
|
+
];
|
|
4219
|
+
function ensureBridgeAutostart(startup) {
|
|
4220
|
+
const eol = startup.includes("\r\n") ? "\r\n" : "\n";
|
|
4221
|
+
const block = AUTOSTART_BLOCK.join(eol);
|
|
4222
|
+
const lines = startup.split(/\r?\n/);
|
|
4223
|
+
const begin = lines.indexOf(AUTOSTART_BEGIN);
|
|
4224
|
+
const end = begin === -1 ? -1 : lines.indexOf(AUTOSTART_END, begin);
|
|
4225
|
+
let text7;
|
|
4226
|
+
if (begin !== -1 && end !== -1) {
|
|
4227
|
+
text7 = [...lines.slice(0, begin), ...AUTOSTART_BLOCK, ...lines.slice(end + 1)].join(eol);
|
|
4228
|
+
} else if (startup.trim() === "") {
|
|
4229
|
+
text7 = block + eol;
|
|
4230
|
+
} else {
|
|
4231
|
+
text7 = block + eol + eol + startup;
|
|
4232
|
+
}
|
|
4233
|
+
return { text: text7, changed: text7 !== startup };
|
|
4234
|
+
}
|
|
4235
|
+
function readExtState(ini, section, key) {
|
|
4236
|
+
let inSection = false;
|
|
4237
|
+
for (const line of ini.split(/\r?\n/)) {
|
|
4238
|
+
const header = /^\s*\[(.*)\]\s*$/.exec(line);
|
|
4239
|
+
if (header) {
|
|
4240
|
+
inSection = header[1] === section;
|
|
4241
|
+
} else if (inSection) {
|
|
4242
|
+
const eq = line.indexOf("=");
|
|
4243
|
+
if (eq !== -1 && line.slice(0, eq).trim() === key) return line.slice(eq + 1).trim();
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
return void 0;
|
|
4247
|
+
}
|
|
4248
|
+
function autostartCheck(startup, extstate, reaperRunning) {
|
|
4249
|
+
const label = "Start with REAPER";
|
|
4250
|
+
if (startup === null || !startup.includes(AUTOSTART_MARKER)) {
|
|
4251
|
+
return {
|
|
4252
|
+
label,
|
|
4253
|
+
status: "warn",
|
|
4254
|
+
detail: "Not in REAPER's Scripts/__startup.lua: run mcp_bridge.lua by hand in each REAPER session",
|
|
4255
|
+
fix: "reaper-mcp setup"
|
|
4256
|
+
};
|
|
4257
|
+
}
|
|
4258
|
+
const saved = reaperRunning ? " (as REAPER last saved it)" : "";
|
|
4259
|
+
if (extstate !== null && readExtState(extstate, "MCPBridge", "cfg_autostart") === "0") {
|
|
4260
|
+
return {
|
|
4261
|
+
label,
|
|
4262
|
+
status: "info",
|
|
4263
|
+
detail: `Off in the bridge window${saved}: run mcp_bridge.lua by hand in each REAPER session`,
|
|
4264
|
+
fix: "turn it back on in the bridge window: Settings \u2192 Start with REAPER"
|
|
4265
|
+
};
|
|
4266
|
+
}
|
|
4267
|
+
return { label, status: "ok", detail: `On \xB7 REAPER's startup script runs the bridge at launch${saved}` };
|
|
4268
|
+
}
|
|
4204
4269
|
var MCP_TOOL_NAMES = [
|
|
4205
4270
|
// project
|
|
4206
4271
|
"get_project_info",
|
|
@@ -8922,13 +8987,13 @@ async function setup() {
|
|
|
8922
8987
|
}
|
|
8923
8988
|
const webPort = await enableWebInterface();
|
|
8924
8989
|
await registerSnapshotActions();
|
|
8990
|
+
installBridgeAutostart(scriptsDir);
|
|
8925
8991
|
console.log("\nSetup complete!\n");
|
|
8926
8992
|
console.log("Next steps:");
|
|
8927
|
-
console.log(" 1.
|
|
8928
|
-
console.log("
|
|
8929
|
-
console.log(`
|
|
8930
|
-
console.log("
|
|
8931
|
-
console.log(" 5. Add reaper-mcp to your Claude Code config (see: reaper-mcp doctor)");
|
|
8993
|
+
console.log(" 1. Start REAPER: the bridge starts with it. If REAPER is already open, restart it,");
|
|
8994
|
+
console.log(" or run the bridge once by hand: Actions > Show action list > Load ReaScript,");
|
|
8995
|
+
console.log(` select ${join12(scriptsDir, "mcp_bridge.lua")} and click Run.`);
|
|
8996
|
+
console.log(" 2. Add reaper-mcp to your Claude Code config (see: reaper-mcp doctor)");
|
|
8932
8997
|
if (webPort) {
|
|
8933
8998
|
console.log(`
|
|
8934
8999
|
The bridge opens its status window on start: http://localhost:${webPort}/${BRIDGE_UI_FILE}`);
|
|
@@ -8980,6 +9045,14 @@ async function enableWebInterface() {
|
|
|
8980
9045
|
console.log(` Enabled on port ${result.port} (override with REAPER_WEB_PORT)`);
|
|
8981
9046
|
return result.port;
|
|
8982
9047
|
}
|
|
9048
|
+
function installBridgeAutostart(scriptsDir) {
|
|
9049
|
+
console.log("\nStarting the bridge with REAPER...");
|
|
9050
|
+
const path = join12(scriptsDir, "__startup.lua");
|
|
9051
|
+
const { text: text7, changed } = ensureBridgeAutostart(existsSync7(path) ? readFileSync5(path, "utf-8") : "");
|
|
9052
|
+
if (changed) writeFileSync5(path, text7, "utf-8");
|
|
9053
|
+
console.log(changed ? " Added to Scripts/__startup.lua (REAPER runs it at launch)" : " Already in Scripts/__startup.lua");
|
|
9054
|
+
console.log(" Turn it off in the bridge window: Settings > Start with REAPER.");
|
|
9055
|
+
}
|
|
8983
9056
|
async function registerSnapshotActions() {
|
|
8984
9057
|
console.log("\nRegistering snapshot actions (quick save, next, previous)...");
|
|
8985
9058
|
const kbPath = join12(getReaperResourcePath(), "reaper-kb.ini");
|
|
@@ -9105,6 +9178,12 @@ async function doctor() {
|
|
|
9105
9178
|
core2.push(
|
|
9106
9179
|
bridgeRunning ? { label: "Lua bridge", status: "ok", detail: "Connected" } : { label: "Lua bridge", status: "fail", detail: "Not detected", fix: "reaper-mcp setup, then run mcp_bridge.lua in REAPER" }
|
|
9107
9180
|
);
|
|
9181
|
+
const readIfExists = (path) => existsSync7(path) ? readFileSync5(path, "utf-8") : null;
|
|
9182
|
+
core2.push(autostartCheck(
|
|
9183
|
+
readIfExists(join12(getReaperScriptsPath(), "__startup.lua")),
|
|
9184
|
+
readIfExists(join12(getReaperResourcePath(), "reaper-extstate.ini")),
|
|
9185
|
+
await isReaperRunning()
|
|
9186
|
+
));
|
|
9108
9187
|
const globalClaudeDir = join12(homedir8(), ".claude");
|
|
9109
9188
|
const localSkills = existsSync7(join12(process.cwd(), ".claude", "skills", "mixer", "SKILL.md"));
|
|
9110
9189
|
const globalSkills = existsSync7(join12(globalClaudeDir, "skills", "mixer", "SKILL.md"));
|
package/package.json
CHANGED
package/reaper/mcp_bridge.lua
CHANGED
|
@@ -4668,6 +4668,7 @@ end
|
|
|
4668
4668
|
|
|
4669
4669
|
-- Settings written by the status page through REAPER's web interface (/_/SET/EXTSTATE...).
|
|
4670
4670
|
-- cfg_paused is in-memory only (resets with REAPER); the others persist in reaper-extstate.ini.
|
|
4671
|
+
-- cfg_autostart is read at REAPER's launch by the startup block setup writes into Scripts/__startup.lua.
|
|
4671
4672
|
local function cfg(key)
|
|
4672
4673
|
return reaper.GetExtState(STATUS_SECTION, key) == "1"
|
|
4673
4674
|
end
|
|
@@ -4692,7 +4693,7 @@ local _, script_path, _, script_cmd_id = reaper.get_action_context()
|
|
|
4692
4693
|
local script_source = script_path and read_file(script_path)
|
|
4693
4694
|
local HEALTH_INTERVAL = 10
|
|
4694
4695
|
local last_health_check = -HEALTH_INTERVAL
|
|
4695
|
-
local health = { sws = false, jsfx = true, outdated = false }
|
|
4696
|
+
local health = { sws = false, jsfx = true, outdated = false, autostart = false }
|
|
4696
4697
|
local JSFX_FILES = { "mcp_analyzer.jsfx", "mcp_lufs_meter.jsfx", "mcp_correlation_meter.jsfx", "mcp_crest_factor.jsfx", "mcp_midi_emitter.jsfx" }
|
|
4697
4698
|
|
|
4698
4699
|
local function check_health(now)
|
|
@@ -4710,8 +4711,13 @@ local function check_health(now)
|
|
|
4710
4711
|
missingJsfx = #missing > 0 and missing or nil,
|
|
4711
4712
|
-- The installed script changed under us (setup ran): this running copy is stale until restarted
|
|
4712
4713
|
outdated = script_source ~= nil and installed ~= nil and installed ~= script_source,
|
|
4714
|
+
-- REAPER's startup script holds the block `reaper-mcp setup` writes (AUTOSTART_BLOCK in cli.ts), which
|
|
4715
|
+
-- starts the bridge with REAPER unless the page's cfg_autostart is "0"
|
|
4716
|
+
autostart = ((read_file(reaper.GetResourcePath() .. "/Scripts/__startup.lua") or "")
|
|
4717
|
+
:find("reaper-mcp: start the bridge with REAPER", 1, true)) ~= nil,
|
|
4713
4718
|
}
|
|
4714
|
-
if next_health.sws ~= health.sws or next_health.jsfx ~= health.jsfx or next_health.outdated ~= health.outdated
|
|
4719
|
+
if next_health.sws ~= health.sws or next_health.jsfx ~= health.jsfx or next_health.outdated ~= health.outdated
|
|
4720
|
+
or next_health.autostart ~= health.autostart then
|
|
4715
4721
|
status_dirty = true
|
|
4716
4722
|
end
|
|
4717
4723
|
health = next_health
|
|
@@ -5294,7 +5300,11 @@ local function publish_status(now, force)
|
|
|
5294
5300
|
deferMs = defer_n > 0 and math.floor(defer_sum / defer_n * 100000 + 0.5) / 100 or 0,
|
|
5295
5301
|
recent = status.recent,
|
|
5296
5302
|
sessions = session_list(),
|
|
5297
|
-
settings = {
|
|
5303
|
+
settings = {
|
|
5304
|
+
paused = cfg("cfg_paused"), readonly = cfg("cfg_readonly"), openOnStart = open_on_start(), dev = dev_mode(),
|
|
5305
|
+
-- Start with REAPER: on unless turned off ("0"); read by the startup block, not by this script
|
|
5306
|
+
autostart = reaper.GetExtState(STATUS_SECTION, "cfg_autostart") ~= "0",
|
|
5307
|
+
},
|
|
5298
5308
|
health = health,
|
|
5299
5309
|
web = web_watch.status,
|
|
5300
5310
|
control = control_status(),
|