@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/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. Open REAPER");
8928
- console.log(" 2. Actions > Show action list > Load ReaScript");
8929
- console.log(` 3. Select: ${join12(scriptsDir, "mcp_bridge.lua")}`);
8930
- console.log(" 4. Run the script (it will keep running in background via defer loop)");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mthines/reaper-mcp",
3
- "version": "0.70.2",
3
+ "version": "0.71.0-beta.83.2",
4
4
  "type": "module",
5
5
  "description": "MCP server for controlling REAPER DAW — real-time mixing, FX control, and frequency analysis for AI agents",
6
6
  "license": "MIT",
@@ -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 then
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 = { paused = cfg("cfg_paused"), readonly = cfg("cfg_readonly"), openOnStart = open_on_start(), dev = dev_mode() },
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(),