@mthines/reaper-mcp 0.19.0 → 0.70.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.
Files changed (116) hide show
  1. package/README.md +19 -570
  2. package/bridge-ui/mcp_bridge.html +129 -0
  3. package/bridge-ui/mcp_bridge.webmanifest +16 -0
  4. package/bridge-ui/mcp_bridge_icon_192.png +0 -0
  5. package/bridge-ui/mcp_bridge_icon_512.png +0 -0
  6. package/bridge-ui/mcp_bridge_sw.js +35 -0
  7. package/claude/agents/plugin-researcher.md +188 -0
  8. package/claude/knowledge/reference/aesthetics-scoring.md +48 -0
  9. package/{knowledge → claude/knowledge}/reference/common-mistakes.md +1 -1
  10. package/claude/knowledge/reference/lorekit-setup.md +36 -0
  11. package/claude/knowledge/reference/memory-protocol.md +377 -0
  12. package/{knowledge → claude/knowledge}/reference/metering.md +5 -5
  13. package/claude/knowledge/reference/perceived-loudness.md +182 -0
  14. package/{knowledge → claude/knowledge}/workflows/editing.md +4 -0
  15. package/{knowledge → claude/knowledge}/workflows/gain-staging.md +21 -23
  16. package/{knowledge → claude/knowledge}/workflows/learn-plugin.md +15 -48
  17. package/{knowledge → claude/knowledge}/workflows/master-bus.md +13 -1
  18. package/claude/knowledge/workflows/section-levels.md +138 -0
  19. package/{knowledge → claude/knowledge}/workflows/session-prep.md +4 -0
  20. package/claude/knowledge/workflows/transient-lighting.md +52 -0
  21. package/claude/skills/critique/SKILL.md +131 -0
  22. package/claude/skills/editing/SKILL.md +281 -0
  23. package/claude/skills/learn-plugin/SKILL.md +210 -0
  24. package/claude/skills/mastering/SKILL.md +151 -0
  25. package/claude/skills/mix-memory/SKILL.md +140 -0
  26. package/claude/skills/mixer/SKILL.md +253 -0
  27. package/claude/skills/new-extension/SKILL.md +324 -0
  28. package/main.js +7843 -1940
  29. package/package.json +17 -15
  30. package/reaper/CLAUDE.md +22 -4
  31. package/reaper/mcp_actions_lib.lua +375 -0
  32. package/reaper/mcp_analyzer.jsfx +27 -12
  33. package/reaper/mcp_arrange_lib.lua +949 -0
  34. package/reaper/mcp_bridge.lua +2321 -758
  35. package/reaper/mcp_edit_views_lib.lua +1378 -0
  36. package/reaper/mcp_envelopes_lib.lua +748 -0
  37. package/reaper/mcp_extensions_lib.lua +55 -0
  38. package/reaper/mcp_fxstate_lib.lua +144 -0
  39. package/reaper/mcp_gain_trace.jsfx +126 -0
  40. package/reaper/mcp_items_lib.lua +877 -0
  41. package/reaper/mcp_lufs_meter.jsfx +16 -13
  42. package/reaper/mcp_midi_lib.lua +555 -0
  43. package/reaper/mcp_mixing_lib.lua +1021 -0
  44. package/reaper/mcp_plan_lib.lua +801 -0
  45. package/reaper/mcp_prefs_lib.lua +127 -0
  46. package/reaper/mcp_project_lib.lua +1088 -0
  47. package/reaper/mcp_recording_lib.lua +595 -0
  48. package/reaper/mcp_render_lib.lua +492 -0
  49. package/reaper/mcp_snapshot_lib.lua +547 -120
  50. package/reaper/mcp_snapshot_next.lua +10 -4
  51. package/reaper/mcp_snapshot_prev.lua +11 -4
  52. package/reaper/mcp_snapshot_quick_save.lua +7 -32
  53. package/reaper/mcp_snapshots_ui_lib.lua +258 -0
  54. package/reaper/mcp_tracks_lib.lua +409 -0
  55. package/sidecar/analysis.py +661 -0
  56. package/sidecar/chords.py +96 -0
  57. package/sidecar/mixcheck.py +295 -0
  58. package/sidecar/requirements-chords.txt +6 -0
  59. package/sidecar/requirements-separation.txt +3 -0
  60. package/sidecar/requirements.txt +17 -0
  61. package/sidecar/separation.py +142 -0
  62. package/sidecar/server.py +622 -0
  63. package/sidecar/tests/test_analysis.py +249 -0
  64. package/sidecar/tests/test_chords.py +117 -0
  65. package/sidecar/tests/test_mixcheck.py +163 -0
  66. package/sidecar/tests/test_separation.py +73 -0
  67. package/sidecar/tests/test_server.py +464 -0
  68. package/sidecar/tests/test_verify.py +243 -0
  69. package/sidecar/tests/test_voice_render.py +268 -0
  70. package/sidecar/tests/test_voice_sketch.py +140 -0
  71. package/sidecar/verify.py +224 -0
  72. package/sidecar/voice_render.py +295 -0
  73. package/sidecar/voice_sketch.py +280 -0
  74. package/claude-agents/critique.md +0 -147
  75. package/claude-agents/editor.md +0 -184
  76. package/claude-agents/levels.md +0 -107
  77. package/claude-agents/mastering.md +0 -129
  78. package/claude-agents/mixer.md +0 -248
  79. package/claude-agents/preflight.md +0 -149
  80. package/claude-agents/producer.md +0 -159
  81. package/claude-agents/setup.md +0 -150
  82. package/claude-agents/stems.md +0 -135
  83. package/claude-rules/architecture.md +0 -39
  84. package/claude-rules/development.md +0 -54
  85. package/claude-rules/lua-bridge.md +0 -50
  86. package/claude-rules/testing.md +0 -42
  87. package/claude-skills/learn-plugin.md +0 -123
  88. package/knowledge/CLAUDE.md +0 -71
  89. package/knowledge/plugins/_template.md +0 -82
  90. package/knowledge/plugins/fabfilter/pro-c-2.md +0 -117
  91. package/knowledge/plugins/fabfilter/pro-l-2.md +0 -95
  92. package/knowledge/plugins/fabfilter/pro-q-3.md +0 -112
  93. package/knowledge/plugins/neural-dsp/helix-native.md +0 -104
  94. package/knowledge/plugins/stock-reaper/js-1175-compressor.md +0 -94
  95. package/knowledge/plugins/stock-reaper/rea-comp.md +0 -100
  96. package/knowledge/plugins/stock-reaper/rea-delay.md +0 -95
  97. package/knowledge/plugins/stock-reaper/rea-eq.md +0 -103
  98. package/knowledge/plugins/stock-reaper/rea-gate.md +0 -99
  99. package/knowledge/plugins/stock-reaper/rea-limit.md +0 -75
  100. package/knowledge/plugins/stock-reaper/rea-verb.md +0 -76
  101. package/knowledge/reference/perceived-loudness.md +0 -122
  102. package/reaper/mcp_snapshot_manager.lua +0 -1001
  103. /package/{knowledge → claude/knowledge}/genres/_template.md +0 -0
  104. /package/{knowledge → claude/knowledge}/genres/electronic.md +0 -0
  105. /package/{knowledge → claude/knowledge}/genres/hip-hop.md +0 -0
  106. /package/{knowledge → claude/knowledge}/genres/metal.md +0 -0
  107. /package/{knowledge → claude/knowledge}/genres/orchestral.md +0 -0
  108. /package/{knowledge → claude/knowledge}/genres/pop.md +0 -0
  109. /package/{knowledge → claude/knowledge}/genres/rock.md +0 -0
  110. /package/{knowledge → claude/knowledge}/reference/compression.md +0 -0
  111. /package/{knowledge → claude/knowledge}/reference/frequencies.md +0 -0
  112. /package/{knowledge → claude/knowledge}/workflows/delivery.md +0 -0
  113. /package/{knowledge → claude/knowledge}/workflows/drum-bus.md +0 -0
  114. /package/{knowledge → claude/knowledge}/workflows/low-end.md +0 -0
  115. /package/{knowledge → claude/knowledge}/workflows/stem-prep.md +0 -0
  116. /package/{knowledge → claude/knowledge}/workflows/vocal-chain.md +0 -0
@@ -0,0 +1,127 @@
1
+ -- =============================================================================
2
+ -- Shared tokens for the status page (apps/bridge-ui, Settings → LoreKit)
3
+ -- =============================================================================
4
+ -- The page keeps the viewer's read-only LoreKit token (lk_ro_) in ~/.config/reaper-mcp/lorekit.json instead of the
5
+ -- browser's localStorage, which is per origin (dev server :8098, REAPER's :8099, a PWA window) and
6
+ -- is wiped with the browser's site data. One file means every way of opening the page, and every
7
+ -- reinstall, sees the same tokens. Through REAPER's web interface ExtState (the page has no file access):
8
+ --
9
+ -- lorekit_tokens = {"v":1,"read":…,"req":…,"ok":…,"error":…}
10
+ -- Published once on start and after every request. REAPER's web server
11
+ -- answers anyone who can reach its port, so only a READ-ONLY token goes
12
+ -- through here: a token that doesn't start with lk_ro_ is refused, and the
13
+ -- write token (lk_rw_, publishing into LoreKit's built-in layer) stays in
14
+ -- the browser, never in this file or in ExtState.
15
+ -- tokens_req = <id>-<control token>-<hex read>
16
+ -- Replaces the token (an empty hex removes it). The control token is
17
+ -- the bridge's per-run token, only readable from the status feed.
18
+ --
19
+ -- The file is JSON {"readToken":…}, created with mode 600 where chmod exists. A file that holds anything
20
+ -- else (an earlier version also kept a publishToken) is rewritten without it when the bridge starts.
21
+ -- Loaded by mcp_bridge.lua (keeps the bridge under Lua's 200-locals limit).
22
+ -- =============================================================================
23
+
24
+ local M = {}
25
+
26
+ local ctx
27
+ local loaded = false
28
+ local state = { read = nil }
29
+ local TOKEN_MAX = 512
30
+ local FILE = "lorekit.json"
31
+
32
+ -- The folder of the shared config: $XDG_CONFIG_HOME/reaper-mcp, else ~/.config/reaper-mcp (macOS and Linux),
33
+ -- %APPDATA%/reaper-mcp on Windows. getenv is injected so it can be tested.
34
+ function M.default_dir(getenv, windows)
35
+ local xdg = getenv("XDG_CONFIG_HOME")
36
+ if xdg and xdg ~= "" then return (xdg:gsub("\\", "/")) .. "/reaper-mcp/" end
37
+ if windows then
38
+ local appdata = getenv("APPDATA")
39
+ if appdata and appdata ~= "" then return (appdata:gsub("\\", "/")) .. "/reaper-mcp/" end
40
+ end
41
+ local home = getenv("HOME") or getenv("USERPROFILE")
42
+ if not home or home == "" then return nil end
43
+ return (home:gsub("\\", "/")) .. "/.config/reaper-mcp/"
44
+ end
45
+
46
+ -- ctx: api (reaper), section (ExtState section), dir (the config folder with a trailing slash, or nil),
47
+ -- decode, encode (JSON), read_file, token() (the control token), chmod(path) (owner-only access; optional).
48
+ function M.init(c)
49
+ ctx = c
50
+ end
51
+
52
+ -- Only a read-only token: a write token must never reach the file or the web interface
53
+ local function valid_token(t)
54
+ return type(t) == "string" and #t <= TOKEN_MAX and t:sub(1, 6) == "lk_ro_" and #t > 6 and not t:find("%c") and not t:find("%s")
55
+ end
56
+
57
+ -- Returns true when the file held more than the read token and needs rewriting
58
+ local function load()
59
+ state = { read = nil }
60
+ local text = ctx.dir and ctx.read_file(ctx.dir .. FILE)
61
+ if not text then return false end
62
+ local ok, data = pcall(ctx.decode, text)
63
+ if not ok or type(data) ~= "table" then return false end
64
+ if valid_token(data.readToken) then state.read = data.readToken end
65
+ for k in pairs(data) do if k ~= "readToken" then return true end end
66
+ return false
67
+ end
68
+
69
+ local function publish(req, ok, err)
70
+ ctx.api.SetExtState(ctx.section, "lorekit_tokens", ctx.encode({
71
+ v = 1, read = state.read, req = req, ok = ok, error = err,
72
+ -- the page tells "no file to share" from "the bridge can't write one"
73
+ writable = ctx.dir ~= nil,
74
+ }), false)
75
+ end
76
+
77
+ local function save()
78
+ if not ctx.dir then return nil, "No home folder to keep the tokens in" end
79
+ ctx.api.RecursiveCreateDirectory(ctx.dir, 0)
80
+ local path = ctx.dir .. FILE
81
+ -- Create the file and close its permissions before a token goes in it
82
+ local f, err = io.open(path, "w")
83
+ if not f then return nil, err or "Can't write " .. path end
84
+ f:close()
85
+ if ctx.chmod then pcall(ctx.chmod, path) end
86
+ f = io.open(path, "w")
87
+ if not f then return nil, "Can't write " .. path end
88
+ f:write(ctx.encode({ readToken = state.read }))
89
+ f:close()
90
+ return true
91
+ end
92
+
93
+ local function unhex(s)
94
+ if #s % 2 ~= 0 then return nil end
95
+ return (s:gsub("%x%x", function(h) return string.char(tonumber(h, 16)) end))
96
+ end
97
+
98
+ local function handle(req)
99
+ local id, token, read_hex = req:match("^([%w_]+)%-(%w+)%-(%x*)$")
100
+ -- Anything but a request carrying this run's control token is ignored, like the snapshot requests
101
+ if not id or token ~= ctx.token() then return end
102
+ local read = unhex(read_hex)
103
+ if read == nil then return publish(id, false, "Malformed request") end
104
+ if read ~= "" and not valid_token(read) then return publish(id, false, "Only a read-only token (lk_ro_…) is kept here") end
105
+ local before = state.read
106
+ state.read = read ~= "" and read or nil
107
+ local ok, err = save()
108
+ if not ok then state.read = before end
109
+ publish(id, ok and true or false, err)
110
+ end
111
+
112
+ -- Called every defer tick
113
+ function M.poll()
114
+ if not loaded then
115
+ loaded = true
116
+ -- An older file also kept the write token: take it out
117
+ if load() then save() end
118
+ publish(nil, true)
119
+ end
120
+ local req = ctx.api.GetExtState(ctx.section, "tokens_req")
121
+ if req ~= "" then
122
+ ctx.api.DeleteExtState(ctx.section, "tokens_req", false)
123
+ handle(req)
124
+ end
125
+ end
126
+
127
+ return M