record_safer_pro_mcp 1.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.
Files changed (78) hide show
  1. package/README.md +205 -0
  2. package/dist/api-client.d.ts +159 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +991 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +4 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/prompts/index.d.ts +12 -0
  11. package/dist/prompts/index.d.ts.map +1 -0
  12. package/dist/prompts/index.js +235 -0
  13. package/dist/prompts/index.js.map +1 -0
  14. package/dist/resources/index.d.ts +7 -0
  15. package/dist/resources/index.d.ts.map +1 -0
  16. package/dist/resources/index.js +59 -0
  17. package/dist/resources/index.js.map +1 -0
  18. package/dist/resources/mixing-guide-content.d.ts +8 -0
  19. package/dist/resources/mixing-guide-content.d.ts.map +1 -0
  20. package/dist/resources/mixing-guide-content.js +194 -0
  21. package/dist/resources/mixing-guide-content.js.map +1 -0
  22. package/dist/runtime.d.ts +39 -0
  23. package/dist/runtime.d.ts.map +1 -0
  24. package/dist/runtime.js +320 -0
  25. package/dist/runtime.js.map +1 -0
  26. package/dist/telemetry-schema.d.ts +39 -0
  27. package/dist/telemetry-schema.d.ts.map +1 -0
  28. package/dist/telemetry-schema.js +15 -0
  29. package/dist/telemetry-schema.js.map +1 -0
  30. package/dist/tools/core.d.ts +4 -0
  31. package/dist/tools/core.d.ts.map +1 -0
  32. package/dist/tools/core.js +360 -0
  33. package/dist/tools/core.js.map +1 -0
  34. package/dist/tools/devices.d.ts +10 -0
  35. package/dist/tools/devices.d.ts.map +1 -0
  36. package/dist/tools/devices.js +53 -0
  37. package/dist/tools/devices.js.map +1 -0
  38. package/dist/tools/levels.d.ts +11 -0
  39. package/dist/tools/levels.d.ts.map +1 -0
  40. package/dist/tools/levels.js +25 -0
  41. package/dist/tools/levels.js.map +1 -0
  42. package/dist/tools/markers.d.ts +17 -0
  43. package/dist/tools/markers.d.ts.map +1 -0
  44. package/dist/tools/markers.js +142 -0
  45. package/dist/tools/markers.js.map +1 -0
  46. package/dist/tools/monitor.d.ts +19 -0
  47. package/dist/tools/monitor.d.ts.map +1 -0
  48. package/dist/tools/monitor.js +232 -0
  49. package/dist/tools/monitor.js.map +1 -0
  50. package/dist/tools/recording.d.ts +12 -0
  51. package/dist/tools/recording.d.ts.map +1 -0
  52. package/dist/tools/recording.js +85 -0
  53. package/dist/tools/recording.js.map +1 -0
  54. package/dist/tools/settings.d.ts +10 -0
  55. package/dist/tools/settings.d.ts.map +1 -0
  56. package/dist/tools/settings.js +43 -0
  57. package/dist/tools/settings.js.map +1 -0
  58. package/dist/tools/storage.d.ts +10 -0
  59. package/dist/tools/storage.d.ts.map +1 -0
  60. package/dist/tools/storage.js +20 -0
  61. package/dist/tools/storage.js.map +1 -0
  62. package/dist/tools/system.d.ts +10 -0
  63. package/dist/tools/system.d.ts.map +1 -0
  64. package/dist/tools/system.js +53 -0
  65. package/dist/tools/system.js.map +1 -0
  66. package/dist/tools/tool-metadata.d.ts +19 -0
  67. package/dist/tools/tool-metadata.d.ts.map +1 -0
  68. package/dist/tools/tool-metadata.js +25 -0
  69. package/dist/tools/tool-metadata.js.map +1 -0
  70. package/dist/types.d.ts +456 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +4 -0
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils.d.ts +80 -0
  75. package/dist/utils.d.ts.map +1 -0
  76. package/dist/utils.js +336 -0
  77. package/dist/utils.js.map +1 -0
  78. package/package.json +40 -0
@@ -0,0 +1,80 @@
1
+ import type { PermissionLevel } from "./types.js";
2
+ import { RecordSaferClient } from "./api-client.js";
3
+ export interface ToolResult {
4
+ [x: string]: unknown;
5
+ content: Array<{
6
+ type: "text";
7
+ text: string;
8
+ }>;
9
+ structuredContent?: Record<string, unknown>;
10
+ _meta?: Record<string, unknown>;
11
+ isError?: boolean;
12
+ }
13
+ /**
14
+ * 审计日志:输出到 stderr,不干扰 stdio 传输的 stdout 通道
15
+ */
16
+ export declare function logToolCall(toolName: string, permissionLevel: string): void;
17
+ /**
18
+ * 统一前置条件检查:后端预检 + 录音控制台检查 + 录音状态检查
19
+ *
20
+ * 检查顺序:
21
+ * 1. 后端连接预检(端口文件 + token 是否存在)— 所有工具
22
+ * 2. 录音控制台页面检查 — 非豁免工具
23
+ * 3. 录音进行中检查 — recording_active 工具
24
+ *
25
+ * @returns null 表示条件满足,错误消息字符串表示条件不满足
26
+ */
27
+ export declare function ensureReady(client: RecordSaferClient, toolName: string, permissionLevel: PermissionLevel): Promise<string | null>;
28
+ /**
29
+ * 统一 tool 调用包装:前置条件检查 + 审计日志 + try/catch + 格式化响应
30
+ *
31
+ * 每个工具调用前自动执行:
32
+ * 1. 后端连接预检(端口 + token)
33
+ * 2. 录音控制台页面检查(非豁免工具)
34
+ * 3. 录音状态检查(recording_active 工具)
35
+ *
36
+ * 如果前置条件不满足,立即返回清晰的错误消息,不会发起无效的 HTTP 请求。
37
+ */
38
+ export declare function handleToolCall<T>(toolName: string, permissionLevel: PermissionLevel, fn: () => Promise<T>, client?: RecordSaferClient): Promise<ToolResult>;
39
+ export type DependencyLevel = 'none' | 'console_ready' | 'recording_active';
40
+ export declare const TOOL_DEPENDENCIES: Record<string, DependencyLevel>;
41
+ /**
42
+ * @deprecated 使用 ensureReady 替代。保留此函数仅为向后兼容。
43
+ */
44
+ export declare function checkPrecondition(client: {
45
+ getRecordingStatus: () => Promise<{
46
+ recording: boolean;
47
+ deviceHealth: {
48
+ alive: boolean;
49
+ } | null;
50
+ }>;
51
+ getUIState?: () => Promise<{
52
+ page: string;
53
+ pageStep: number;
54
+ }>;
55
+ getMcpStatus?: () => Promise<{
56
+ ready: boolean;
57
+ recording: boolean;
58
+ duration: number;
59
+ }>;
60
+ }, toolName: string): Promise<string | null>;
61
+ /**
62
+ * 校验混音操作的安全模式前置条件
63
+ * 规则:安全模式录音中禁止混音操作
64
+ */
65
+ export declare function checkMixPrecondition(client: {
66
+ getMcpMix: () => Promise<{
67
+ safeMode: boolean;
68
+ recording: boolean;
69
+ }>;
70
+ }, toolName: string): Promise<string | null>;
71
+ export interface SampleRateValidationResult {
72
+ valid: boolean;
73
+ error?: string;
74
+ supportedRates?: number[];
75
+ }
76
+ /**
77
+ * 校验用户指定的采样率是否在设备支持范围内
78
+ */
79
+ export declare function validateSampleRate(deviceSupportedRates: number[], requestedRate: number): SampleRateValidationResult;
80
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAY,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAG9D,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,IAAI,CAKN;AA0GD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyExB;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,eAAe,EAChC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,iBAAiB,GACzB,OAAO,CAAC,UAAU,CAAC,CA+BrB;AA0BD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAE5E,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAO7D,CAAC;AAEF;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE;IACN,kBAAkB,EAAE,MAAM,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE;YAAE,KAAK,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACnG,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxF,EACD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCxB;AAuBD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CAAE,EAC/E,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAID,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,oBAAoB,EAAE,MAAM,EAAE,EAC9B,aAAa,EAAE,MAAM,GACpB,0BAA0B,CAS5B"}
package/dist/utils.js ADDED
@@ -0,0 +1,336 @@
1
+ import { ApiError } from "./api-client.js";
2
+ /**
3
+ * 审计日志:输出到 stderr,不干扰 stdio 传输的 stdout 通道
4
+ */
5
+ export function logToolCall(toolName, permissionLevel) {
6
+ const timestamp = new Date().toISOString();
7
+ console.error(`[${timestamp}] TOOL_CALL: ${toolName} (permission: ${permissionLevel})`);
8
+ }
9
+ // ===== 前置条件:不需要录音控制台的工具(全局豁免列表) =====
10
+ /**
11
+ * 这些工具不需要用户在录音控制台界面,也不需要后端端口/token 预检。
12
+ * 它们是纯系统查询或录音前配置工具。
13
+ */
14
+ const CONSOLE_EXEMPT_TOOLS = new Set([
15
+ // 设备查询 — 录音前配置阶段使用
16
+ 'list_audio_devices',
17
+ 'list_output_devices',
18
+ 'get_buffer_sizes',
19
+ 'get_device_signals',
20
+ 'get_device_levels',
21
+ 'stop_level_monitoring',
22
+ // 系统信息 — 随时可用
23
+ 'get_system_info',
24
+ 'get_disk_space',
25
+ 'check_disk_health',
26
+ // 存储查询 — 随时可用
27
+ 'list_volumes',
28
+ 'list_external_drives',
29
+ 'validate_storage_path',
30
+ // 更新与激活 — 随时可用
31
+ 'check_updates',
32
+ 'get_update_badge',
33
+ 'install_update',
34
+ 'get_download_progress',
35
+ 'activate_license',
36
+ 'get_activation_status',
37
+ 'set_activation',
38
+ 'restore_license',
39
+ // 配置查询 — 随时可用
40
+ 'get_settings',
41
+ 'get_output_path',
42
+ 'get_audio_format',
43
+ 'set_output_path',
44
+ 'set_audio_format',
45
+ 'update_settings',
46
+ 'start_record_mcp',
47
+ // 遥测与关机 — 随时可用
48
+ 'send_telemetry',
49
+ 'shutdown',
50
+ ]);
51
+ // ===== 前置条件:需要录音进行中的工具 =====
52
+ const RECORDING_ACTIVE_TOOLS = new Set([
53
+ 'add_marker',
54
+ 'stop_recording',
55
+ 'sync_markers',
56
+ 'stop_track',
57
+ ]);
58
+ // ===== 安全模式限制工具 =====
59
+ // 安全模式录音中禁止监听/混音/电平相关工具
60
+ const SAFE_MODE_BLOCKED_TOOLS = new Set([
61
+ // Level metering
62
+ 'subscribe_levels',
63
+ 'enable_level_callback',
64
+ 'get_device_levels',
65
+ // Monitoring
66
+ 'start_monitor',
67
+ 'get_mix_levels',
68
+ // Mixing
69
+ 'set_channels_mix',
70
+ 'set_channel_volume',
71
+ 'set_channel_pan',
72
+ 'set_channel_solo',
73
+ 'set_channel_mute',
74
+ 'set_channel_ms_process',
75
+ 'set_channel_phase_invert',
76
+ 'set_master_volume',
77
+ 'set_monitor_volume',
78
+ 'merge_channels_stereo',
79
+ 'split_stereo_channel',
80
+ ]);
81
+ const SAFE_MODE_MSG = 'Safe-mode recording disables monitoring, mixing, and level metering. Stop recording or switch to Studio Mode to enable monitoring and metering.';
82
+ // ===== 前置条件:需要录音控制台的工具(所有不在豁免列表中的工具) =====
83
+ // 包括:get_channels, get_mix, get_health, get_status, get_recording_status,
84
+ // reset_session, start_monitor, stop_monitor, rename_channel, set_channel_color,
85
+ // set_channel_volume, set_channel_pan, set_channel_solo, set_channel_mute,
86
+ // set_channel_ms_process, set_channel_phase_invert, set_master_volume,
87
+ // subscribe_levels, unsubscribe_levels, get_monitor_status, get_mix_levels,
88
+ // lock_storage, unlock_storage, start_split, get_split_progress, cancel_split,
89
+ // rename_marker, disable_level_callback, enable_level_callback,
90
+ // 以及所有 RECORDING_ACTIVE_TOOLS
91
+ const NOT_ON_CONSOLE_MSG = 'Due to the DADAO Engine safety architecture, please open Record Safer Pro and enter the recording console before using MCP tools that require an active session. If you want MCP to prepare the console for you, call start_record_mcp first.';
92
+ const NOT_RECORDING_MSG = 'Recording is not active. Please start recording manually in the Record Safer Pro recording console.';
93
+ const BACKEND_NOT_READY_MSG = 'DADAO Record Safer MCP could not connect to the Record Safer Pro application. Please open or restart Record Safer Pro, wait until startup completes, and try again.';
94
+ /**
95
+ * 录音控制台页面名称集合
96
+ * 只有当用户在这些页面时,MCP 的会话/录音相关工具才可用
97
+ */
98
+ const RECORDING_CONSOLE_PAGES = new Set([
99
+ 'RECORDING',
100
+ 'RECORDING_COMPLETE',
101
+ 'CONFIG_HEALTH_CHECK',
102
+ ]);
103
+ /**
104
+ * 统一前置条件检查:后端预检 + 录音控制台检查 + 录音状态检查
105
+ *
106
+ * 检查顺序:
107
+ * 1. 后端连接预检(端口文件 + token 是否存在)— 所有工具
108
+ * 2. 录音控制台页面检查 — 非豁免工具
109
+ * 3. 录音进行中检查 — recording_active 工具
110
+ *
111
+ * @returns null 表示条件满足,错误消息字符串表示条件不满足
112
+ */
113
+ export async function ensureReady(client, toolName, permissionLevel) {
114
+ // ===== 第 1 步:尝试拉起或验证应用运行状态 =====
115
+ const didLaunch = permissionLevel === "read"
116
+ ? false
117
+ : await client.ensureAppRunning();
118
+ const preflightErr = client.preflight();
119
+ if (preflightErr) {
120
+ if (didLaunch) {
121
+ return 'Record Safer Pro was opened automatically by DADAO Record Safer MCP. ' + NOT_ON_CONSOLE_MSG;
122
+ }
123
+ return preflightErr;
124
+ }
125
+ // ===== 第 2 步:豁免工具直接放行 =====
126
+ if (CONSOLE_EXEMPT_TOOLS.has(toolName)) {
127
+ return null;
128
+ }
129
+ // ===== 第 3 步:检查录音控制台状态 =====
130
+ const needsRecording = RECORDING_ACTIVE_TOOLS.has(toolName);
131
+ const msgNotOnConsole = didLaunch
132
+ ? 'Record Safer Pro was opened automatically by DADAO Record Safer MCP. ' + NOT_ON_CONSOLE_MSG
133
+ : NOT_ON_CONSOLE_MSG;
134
+ // 优先使用轻量级 /api/mcp/status
135
+ try {
136
+ const status = await client.getMcpStatus({ allowAutoLaunch: false });
137
+ if (!status.ready) {
138
+ return msgNotOnConsole;
139
+ }
140
+ if (needsRecording && !status.recording) {
141
+ return NOT_RECORDING_MSG;
142
+ }
143
+ }
144
+ catch {
145
+ // getMcpStatus 失败时回退到下面的 getUIState
146
+ try {
147
+ const uiState = await client.getUIState({ allowAutoLaunch: false });
148
+ if (!RECORDING_CONSOLE_PAGES.has(uiState.page)) {
149
+ return msgNotOnConsole;
150
+ }
151
+ }
152
+ catch {
153
+ return BACKEND_NOT_READY_MSG;
154
+ }
155
+ if (needsRecording) {
156
+ try {
157
+ const recStatus = await client.getRecordingStatus({ allowAutoLaunch: false });
158
+ if (!recStatus.recording) {
159
+ return NOT_RECORDING_MSG;
160
+ }
161
+ }
162
+ catch {
163
+ return BACKEND_NOT_READY_MSG;
164
+ }
165
+ }
166
+ }
167
+ // ===== 第 4 步:安全模式检查 =====
168
+ // 安全模式录音中仅禁止电平相关工具
169
+ if (SAFE_MODE_BLOCKED_TOOLS.has(toolName)) {
170
+ try {
171
+ const mix = await client.getMcpMix({ allowAutoLaunch: false });
172
+ if (mix.safeMode && mix.recording) {
173
+ return SAFE_MODE_MSG;
174
+ }
175
+ }
176
+ catch {
177
+ // getMcpMix 失败时不阻止(兼容旧版后端)
178
+ }
179
+ }
180
+ return null;
181
+ }
182
+ /**
183
+ * 统一 tool 调用包装:前置条件检查 + 审计日志 + try/catch + 格式化响应
184
+ *
185
+ * 每个工具调用前自动执行:
186
+ * 1. 后端连接预检(端口 + token)
187
+ * 2. 录音控制台页面检查(非豁免工具)
188
+ * 3. 录音状态检查(recording_active 工具)
189
+ *
190
+ * 如果前置条件不满足,立即返回清晰的错误消息,不会发起无效的 HTTP 请求。
191
+ */
192
+ export async function handleToolCall(toolName, permissionLevel, fn, client) {
193
+ logToolCall(toolName, permissionLevel);
194
+ // 前置条件检查(需要 client 实例)
195
+ if (client) {
196
+ const err = await ensureReady(client, toolName, permissionLevel);
197
+ if (err) {
198
+ return {
199
+ content: [{ type: "text", text: err }],
200
+ isError: true,
201
+ };
202
+ }
203
+ }
204
+ try {
205
+ const result = await fn();
206
+ const structuredContent = isStructuredToolPayload(result)
207
+ ? result
208
+ : undefined;
209
+ const payload = structuredContent ?? normalizeTextPayload(result);
210
+ return {
211
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
212
+ ...(structuredContent ? { structuredContent } : {}),
213
+ };
214
+ }
215
+ catch (error) {
216
+ const message = formatToolErrorMessage(error);
217
+ return {
218
+ content: [{ type: "text", text: `Operation failed: ${message}` }],
219
+ isError: true,
220
+ };
221
+ }
222
+ }
223
+ function isStructuredToolPayload(value) {
224
+ return typeof value === "object" && value !== null && !Array.isArray(value);
225
+ }
226
+ function normalizeTextPayload(value) {
227
+ return value !== undefined && value !== null
228
+ ? value
229
+ : { success: true };
230
+ }
231
+ function formatToolErrorMessage(error) {
232
+ if (error instanceof ApiError) {
233
+ return error.message;
234
+ }
235
+ if (error instanceof Error) {
236
+ return error.message;
237
+ }
238
+ return String(error);
239
+ }
240
+ export const TOOL_DEPENDENCIES = {
241
+ list_tracks: 'console_ready',
242
+ list_markers: 'console_ready',
243
+ add_marker: 'recording_active',
244
+ stop_recording: 'recording_active',
245
+ sync_markers: 'recording_active',
246
+ stop_track: 'recording_active',
247
+ };
248
+ /**
249
+ * @deprecated 使用 ensureReady 替代。保留此函数仅为向后兼容。
250
+ */
251
+ export async function checkPrecondition(client, toolName) {
252
+ const level = TOOL_DEPENDENCIES[toolName] || 'none';
253
+ if (level === 'none')
254
+ return null;
255
+ if (client.getMcpStatus) {
256
+ try {
257
+ const status = await client.getMcpStatus();
258
+ if (!status.ready) {
259
+ return NOT_ON_CONSOLE_MSG;
260
+ }
261
+ if (level === 'recording_active' && !status.recording) {
262
+ return NOT_RECORDING_MSG;
263
+ }
264
+ return null;
265
+ }
266
+ catch {
267
+ // 回退
268
+ }
269
+ }
270
+ if (client.getUIState) {
271
+ try {
272
+ const uiState = await client.getUIState();
273
+ if (!RECORDING_CONSOLE_PAGES.has(uiState.page)) {
274
+ return NOT_ON_CONSOLE_MSG;
275
+ }
276
+ }
277
+ catch {
278
+ // 回退
279
+ }
280
+ }
281
+ const status = await client.getRecordingStatus();
282
+ if (level === 'recording_active' && !status.recording) {
283
+ return NOT_RECORDING_MSG;
284
+ }
285
+ return null;
286
+ }
287
+ // ===== 安全模式混音前置条件校验 =====
288
+ /**
289
+ * 混音操作的工具名称集合
290
+ * 安全模式录音中禁止混音操作
291
+ */
292
+ const MIX_TOOLS = new Set([
293
+ 'set_channels_mix',
294
+ 'set_channel_volume',
295
+ 'set_channel_pan',
296
+ 'set_channel_solo',
297
+ 'set_channel_mute',
298
+ 'set_channel_ms_process',
299
+ 'set_channel_phase_invert',
300
+ 'set_master_volume',
301
+ 'set_monitor_volume',
302
+ 'merge_channels_stereo',
303
+ 'split_stereo_channel',
304
+ ]);
305
+ /**
306
+ * 校验混音操作的安全模式前置条件
307
+ * 规则:安全模式录音中禁止混音操作
308
+ */
309
+ export async function checkMixPrecondition(client, toolName) {
310
+ if (!MIX_TOOLS.has(toolName))
311
+ return null;
312
+ try {
313
+ const mix = await client.getMcpMix();
314
+ if (mix.safeMode && mix.recording) {
315
+ return SAFE_MODE_MSG;
316
+ }
317
+ }
318
+ catch {
319
+ // getMcpMix 失败时不阻止(兼容旧版后端)
320
+ }
321
+ return null;
322
+ }
323
+ /**
324
+ * 校验用户指定的采样率是否在设备支持范围内
325
+ */
326
+ export function validateSampleRate(deviceSupportedRates, requestedRate) {
327
+ if (deviceSupportedRates.includes(requestedRate)) {
328
+ return { valid: true };
329
+ }
330
+ return {
331
+ valid: false,
332
+ error: `The device does not support sample rate ${requestedRate}Hz. Supported sample rates: ${deviceSupportedRates.join(', ')}Hz`,
333
+ supportedRates: deviceSupportedRates,
334
+ };
335
+ }
336
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "record_safer_pro_mcp",
3
+ "version": "1.0.0",
4
+ "description": "Record Safer Pro MCP Server — 专业多通道录音软件 AI 接口 / Professional multi-channel recording software AI interface",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "record_safer_pro_mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "postbuild": "node scripts/ensure-bin-executable.mjs",
17
+ "start": "node dist/index.js",
18
+ "dev": "tsc --watch",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.27.1",
25
+ "typescript": "^5.8.3",
26
+ "zod": "^3.25.67"
27
+ },
28
+ "overrides": {
29
+ "@hono/node-server": "^1.19.11",
30
+ "hono": "^4.12.5"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^22.15.31",
34
+ "fast-check": "^4.1.1",
35
+ "vitest": "^3.2.3"
36
+ },
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ }
40
+ }