crosspad-mcp-server 5.1.0 → 8.1.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 +109 -44
- package/dist/config.d.ts +2 -2
- package/dist/config.js +42 -8
- package/dist/config.js.map +1 -1
- package/dist/index.js +953 -219
- package/dist/index.js.map +1 -1
- package/dist/tools/app-manager.d.ts +13 -5
- package/dist/tools/app-manager.js +94 -28
- package/dist/tools/app-manager.js.map +1 -1
- package/dist/tools/architecture.js +13 -4
- package/dist/tools/architecture.js.map +1 -1
- package/dist/tools/build-check.d.ts +1 -1
- package/dist/tools/build-check.js +19 -9
- package/dist/tools/build-check.js.map +1 -1
- package/dist/tools/build.d.ts +43 -4
- package/dist/tools/build.js +147 -15
- package/dist/tools/build.js.map +1 -1
- package/dist/tools/diff-core.d.ts +5 -1
- package/dist/tools/diff-core.js +11 -6
- package/dist/tools/diff-core.js.map +1 -1
- package/dist/tools/idf-build.d.ts +1 -1
- package/dist/tools/idf-build.js +5 -5
- package/dist/tools/idf-build.js.map +1 -1
- package/dist/tools/idf-flash.d.ts +20 -0
- package/dist/tools/idf-flash.js +185 -0
- package/dist/tools/idf-flash.js.map +1 -0
- package/dist/tools/idf-monitor.d.ts +29 -0
- package/dist/tools/idf-monitor.js +222 -0
- package/dist/tools/idf-monitor.js.map +1 -0
- package/dist/tools/log.d.ts +2 -2
- package/dist/tools/log.js +6 -5
- package/dist/tools/log.js.map +1 -1
- package/dist/tools/midi.d.ts +27 -0
- package/dist/tools/midi.js +112 -0
- package/dist/tools/midi.js.map +1 -0
- package/dist/tools/repo-actions.d.ts +46 -0
- package/dist/tools/repo-actions.js +286 -0
- package/dist/tools/repo-actions.js.map +1 -0
- package/dist/tools/repos.js +14 -10
- package/dist/tools/repos.js.map +1 -1
- package/dist/tools/screenshot.js +42 -7
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/settings.js +11 -1
- package/dist/tools/settings.js.map +1 -1
- package/dist/tools/symbols.d.ts +2 -1
- package/dist/tools/symbols.js +121 -53
- package/dist/tools/symbols.js.map +1 -1
- package/dist/tools/test.d.ts +1 -9
- package/dist/tools/test.js +11 -92
- package/dist/tools/test.js.map +1 -1
- package/dist/utils/device.d.ts +38 -0
- package/dist/utils/device.js +287 -0
- package/dist/utils/device.js.map +1 -0
- package/dist/utils/exec.d.ts +17 -5
- package/dist/utils/exec.js +73 -27
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/git.d.ts +9 -0
- package/dist/utils/git.js +61 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/remote-client.d.ts +1 -0
- package/dist/utils/remote-client.js +56 -15
- package/dist/utils/remote-client.js.map +1 -1
- package/package.json +4 -1
- package/dist/tools/scaffold.d.ts +0 -15
- package/dist/tools/scaffold.js +0 -192
- package/dist/tools/scaffold.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idf-flash.js","sourceRoot":"","sources":["../../src/tools/idf-flash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serial log capture from a connected CrossPad device.
|
|
3
|
+
*
|
|
4
|
+
* Uses Python/pyserial for direct serial reading — no TTY required.
|
|
5
|
+
* This avoids idf.py monitor's TTY dependency while still using
|
|
6
|
+
* the IDF Python venv (which has pyserial installed).
|
|
7
|
+
*
|
|
8
|
+
* Multi-device aware: requires port when multiple devices connected.
|
|
9
|
+
*/
|
|
10
|
+
import { OnLine } from "../utils/exec.js";
|
|
11
|
+
export interface MonitorResult {
|
|
12
|
+
success: boolean;
|
|
13
|
+
port: string;
|
|
14
|
+
duration_seconds: number;
|
|
15
|
+
lines: string[];
|
|
16
|
+
line_count: number;
|
|
17
|
+
truncated: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Capture serial logs from a connected CrossPad device.
|
|
22
|
+
*
|
|
23
|
+
* @param port - Serial port (auto-detect if undefined)
|
|
24
|
+
* @param timeoutSeconds - How long to capture (default 10)
|
|
25
|
+
* @param maxLines - Maximum lines to return (default 500)
|
|
26
|
+
* @param filter - Optional string filter — only return lines containing this
|
|
27
|
+
* @param onLine - Streaming callback for real-time output
|
|
28
|
+
*/
|
|
29
|
+
export declare function crosspadIdfMonitor(port: string | undefined, timeoutSeconds: number | undefined, maxLines: number | undefined, filter: string | undefined, onLine?: OnLine, signal?: AbortSignal): Promise<MonitorResult>;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serial log capture from a connected CrossPad device.
|
|
3
|
+
*
|
|
4
|
+
* Uses Python/pyserial for direct serial reading — no TTY required.
|
|
5
|
+
* This avoids idf.py monitor's TTY dependency while still using
|
|
6
|
+
* the IDF Python venv (which has pyserial installed).
|
|
7
|
+
*
|
|
8
|
+
* Multi-device aware: requires port when multiple devices connected.
|
|
9
|
+
*/
|
|
10
|
+
import { IS_WINDOWS } from "../config.js";
|
|
11
|
+
import { getIdfEnv } from "../utils/exec.js";
|
|
12
|
+
import { findCrosspadPort } from "../utils/device.js";
|
|
13
|
+
import { spawn, spawnSync } from "child_process";
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort check: is some other process already holding this serial port?
|
|
16
|
+
* Linux/macOS only (relies on lsof). Returns the holding PID(s) or null.
|
|
17
|
+
* Returning null on Windows / when lsof is missing is the safe default —
|
|
18
|
+
* we treat "unknown" as "ok to proceed" so this never blocks legitimate use.
|
|
19
|
+
*/
|
|
20
|
+
function findHoldersOfPort(port) {
|
|
21
|
+
if (IS_WINDOWS)
|
|
22
|
+
return null;
|
|
23
|
+
try {
|
|
24
|
+
const r = spawnSync("lsof", ["-t", port], { encoding: "utf-8", timeout: 3000 });
|
|
25
|
+
if (r.status !== 0)
|
|
26
|
+
return [];
|
|
27
|
+
const pids = r.stdout
|
|
28
|
+
.split("\n")
|
|
29
|
+
.map((s) => parseInt(s.trim(), 10))
|
|
30
|
+
.filter((n) => Number.isFinite(n) && n !== process.pid);
|
|
31
|
+
return pids;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a Python script that reads from serial port for a given duration.
|
|
39
|
+
* Uses pyserial (available in IDF venv). No TTY dependency.
|
|
40
|
+
*/
|
|
41
|
+
function buildSerialReaderScript(port, timeoutSeconds) {
|
|
42
|
+
// Escape for embedding in shell command
|
|
43
|
+
const escapedPort = port.replace(/'/g, "\\'");
|
|
44
|
+
return [
|
|
45
|
+
"import serial, sys, time",
|
|
46
|
+
`ser = serial.Serial('${escapedPort}', 115200, timeout=1)`,
|
|
47
|
+
`end = time.time() + ${timeoutSeconds}`,
|
|
48
|
+
"try:",
|
|
49
|
+
" while time.time() < end:",
|
|
50
|
+
" line = ser.readline()",
|
|
51
|
+
" if line:",
|
|
52
|
+
" text = line.decode('utf-8', errors='replace').rstrip()",
|
|
53
|
+
" if text:",
|
|
54
|
+
" print(text, flush=True)",
|
|
55
|
+
"except KeyboardInterrupt:",
|
|
56
|
+
" pass",
|
|
57
|
+
"finally:",
|
|
58
|
+
" ser.close()",
|
|
59
|
+
].join("\n");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Capture serial logs from a connected CrossPad device.
|
|
63
|
+
*
|
|
64
|
+
* @param port - Serial port (auto-detect if undefined)
|
|
65
|
+
* @param timeoutSeconds - How long to capture (default 10)
|
|
66
|
+
* @param maxLines - Maximum lines to return (default 500)
|
|
67
|
+
* @param filter - Optional string filter — only return lines containing this
|
|
68
|
+
* @param onLine - Streaming callback for real-time output
|
|
69
|
+
*/
|
|
70
|
+
export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 500, filter, onLine, signal) {
|
|
71
|
+
const startTime = Date.now();
|
|
72
|
+
// Resolve port
|
|
73
|
+
const resolved = findCrosspadPort(port);
|
|
74
|
+
if (resolved.error) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
port: "",
|
|
78
|
+
duration_seconds: 0,
|
|
79
|
+
lines: [],
|
|
80
|
+
line_count: 0,
|
|
81
|
+
truncated: false,
|
|
82
|
+
error: resolved.error,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const targetPort = resolved.port;
|
|
86
|
+
// Refuse to grab the port if another process is already reading it (e.g.
|
|
87
|
+
// an idf.py monitor in a terminal). Two readers race on bytes and produce
|
|
88
|
+
// garbled output. lsof-based check, Linux/macOS only — best effort.
|
|
89
|
+
const holders = findHoldersOfPort(targetPort);
|
|
90
|
+
if (holders && holders.length > 0) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
port: targetPort,
|
|
94
|
+
duration_seconds: 0,
|
|
95
|
+
lines: [],
|
|
96
|
+
line_count: 0,
|
|
97
|
+
truncated: false,
|
|
98
|
+
error: `Serial port ${targetPort} is in use by PID(s) ${holders.join(", ")}. Close that monitor (or kill the process) and retry.`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
onLine?.("stdout", `[idf-monitor] Capturing from ${targetPort} for ${timeoutSeconds}s...`);
|
|
102
|
+
// Get IDF environment (for Python with pyserial)
|
|
103
|
+
let env;
|
|
104
|
+
try {
|
|
105
|
+
env = getIdfEnv();
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
port: targetPort,
|
|
111
|
+
duration_seconds: 0,
|
|
112
|
+
lines: [],
|
|
113
|
+
line_count: 0,
|
|
114
|
+
truncated: false,
|
|
115
|
+
error: `Failed to initialize IDF environment: ${err.message}`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const script = buildSerialReaderScript(targetPort, timeoutSeconds);
|
|
119
|
+
return new Promise((resolve) => {
|
|
120
|
+
const lines = [];
|
|
121
|
+
let totalLines = 0;
|
|
122
|
+
let truncated = false;
|
|
123
|
+
let stdoutBuf = "";
|
|
124
|
+
// Run Python script with IDF env (has pyserial on PATH)
|
|
125
|
+
const child = spawn("python3", ["-c", script], {
|
|
126
|
+
env,
|
|
127
|
+
shell: false,
|
|
128
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
129
|
+
windowsHide: true,
|
|
130
|
+
});
|
|
131
|
+
// Safety kill: slightly after the Python timeout
|
|
132
|
+
const timer = setTimeout(() => {
|
|
133
|
+
onLine?.("stdout", `[idf-monitor] Timeout reached (${timeoutSeconds}s), stopping...`);
|
|
134
|
+
child.kill("SIGTERM");
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
if (!child.killed)
|
|
137
|
+
child.kill("SIGKILL");
|
|
138
|
+
}, 2000);
|
|
139
|
+
}, (timeoutSeconds + 3) * 1000);
|
|
140
|
+
// External cancellation (MCP client cancelled the request).
|
|
141
|
+
const onAbort = () => {
|
|
142
|
+
onLine?.("stdout", `[idf-monitor] Cancelled, stopping...`);
|
|
143
|
+
child.kill("SIGTERM");
|
|
144
|
+
setTimeout(() => { if (!child.killed)
|
|
145
|
+
child.kill("SIGKILL"); }, 2000);
|
|
146
|
+
};
|
|
147
|
+
if (signal) {
|
|
148
|
+
if (signal.aborted)
|
|
149
|
+
onAbort();
|
|
150
|
+
else
|
|
151
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
152
|
+
}
|
|
153
|
+
function processLine(line) {
|
|
154
|
+
// Strip ANSI escape codes
|
|
155
|
+
const clean = line.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\r/g, "");
|
|
156
|
+
if (!clean.trim())
|
|
157
|
+
return;
|
|
158
|
+
totalLines++;
|
|
159
|
+
// Apply filter if specified
|
|
160
|
+
if (filter && !clean.toLowerCase().includes(filter.toLowerCase())) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (lines.length < maxLines) {
|
|
164
|
+
lines.push(clean);
|
|
165
|
+
onLine?.("stdout", clean);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
truncated = true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
child.stdout?.on("data", (chunk) => {
|
|
172
|
+
stdoutBuf += chunk.toString();
|
|
173
|
+
const parts = stdoutBuf.split("\n");
|
|
174
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
175
|
+
processLine(parts[i]);
|
|
176
|
+
}
|
|
177
|
+
stdoutBuf = parts[parts.length - 1];
|
|
178
|
+
});
|
|
179
|
+
child.stderr?.on("data", (chunk) => {
|
|
180
|
+
const text = chunk.toString();
|
|
181
|
+
for (const sline of text.split("\n")) {
|
|
182
|
+
if (sline.trim()) {
|
|
183
|
+
onLine?.("stderr", sline.replace(/\r/g, ""));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
child.on("close", (code) => {
|
|
188
|
+
clearTimeout(timer);
|
|
189
|
+
if (signal)
|
|
190
|
+
signal.removeEventListener("abort", onAbort);
|
|
191
|
+
if (stdoutBuf.trim()) {
|
|
192
|
+
processLine(stdoutBuf);
|
|
193
|
+
}
|
|
194
|
+
const duration = (Date.now() - startTime) / 1000;
|
|
195
|
+
onLine?.("stdout", `[idf-monitor] Captured ${lines.length} lines in ${duration.toFixed(1)}s`);
|
|
196
|
+
resolve({
|
|
197
|
+
success: code === 0 || lines.length > 0,
|
|
198
|
+
port: targetPort,
|
|
199
|
+
duration_seconds: duration,
|
|
200
|
+
lines,
|
|
201
|
+
line_count: totalLines,
|
|
202
|
+
truncated,
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
child.on("error", (err) => {
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
if (signal)
|
|
208
|
+
signal.removeEventListener("abort", onAbort);
|
|
209
|
+
const duration = (Date.now() - startTime) / 1000;
|
|
210
|
+
resolve({
|
|
211
|
+
success: false,
|
|
212
|
+
port: targetPort,
|
|
213
|
+
duration_seconds: duration,
|
|
214
|
+
lines,
|
|
215
|
+
line_count: totalLines,
|
|
216
|
+
truncated,
|
|
217
|
+
error: err.message,
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=idf-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idf-monitor.js","sourceRoot":"","sources":["../../src/tools/idf-monitor.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/log.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export interface LogResult {
|
|
|
9
9
|
truncated: boolean;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* Launch
|
|
12
|
+
* Launch the CrossPad binary, capture stdout/stderr for up to `timeout_seconds`,
|
|
13
13
|
* then kill the process and return the output.
|
|
14
14
|
* Streams lines in real-time via onLine callback.
|
|
15
15
|
*/
|
|
16
|
-
export declare function crosspadLog(timeoutSeconds?: number, maxLines?: number, onLine?: OnLine): Promise<LogResult>;
|
|
16
|
+
export declare function crosspadLog(timeoutSeconds?: number, maxLines?: number, onLine?: OnLine, signal?: AbortSignal): Promise<LogResult>;
|
package/dist/tools/log.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import { BIN_EXE, CROSSPAD_PC_ROOT } from "../config.js";
|
|
3
|
-
import {
|
|
3
|
+
import { runArgvStream } from "../utils/exec.js";
|
|
4
4
|
/**
|
|
5
|
-
* Launch
|
|
5
|
+
* Launch the CrossPad binary, capture stdout/stderr for up to `timeout_seconds`,
|
|
6
6
|
* then kill the process and return the output.
|
|
7
7
|
* Streams lines in real-time via onLine callback.
|
|
8
8
|
*/
|
|
9
|
-
export async function crosspadLog(timeoutSeconds = 5, maxLines = 200, onLine) {
|
|
9
|
+
export async function crosspadLog(timeoutSeconds = 5, maxLines = 200, onLine, signal) {
|
|
10
10
|
if (!fs.existsSync(BIN_EXE)) {
|
|
11
11
|
return {
|
|
12
12
|
success: false,
|
|
13
13
|
exe_path: BIN_EXE,
|
|
14
14
|
stdout: "",
|
|
15
|
-
stderr:
|
|
15
|
+
stderr: `${BIN_EXE} not found — build first`,
|
|
16
16
|
exit_code: null,
|
|
17
17
|
duration_seconds: 0,
|
|
18
18
|
truncated: false,
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
onLine?.("stdout", `[crosspad] Launching ${BIN_EXE} (capturing for ${timeoutSeconds}s)...`);
|
|
22
|
-
|
|
22
|
+
// argv mode — BIN_EXE may contain spaces; never let the path touch a shell.
|
|
23
|
+
const result = await runArgvStream(BIN_EXE, [], CROSSPAD_PC_ROOT, onLine ?? (() => { }), timeoutSeconds * 1000, signal);
|
|
23
24
|
// Truncate to maxLines
|
|
24
25
|
let stdout = result.stdout;
|
|
25
26
|
let stderr = result.stderr;
|
package/dist/tools/log.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/tools/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/tools/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,aAAa,EAAU,MAAM,kBAAkB,CAAC;AAYzD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,iBAAyB,CAAC,EAC1B,WAAmB,GAAG,EACtB,MAAe,EACf,MAAoB;IAEpB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,GAAG,OAAO,0BAA0B;YAC5C,SAAS,EAAE,IAAI;YACf,gBAAgB,EAAE,CAAC;YACnB,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,CAAC,QAAQ,EAAE,wBAAwB,OAAO,mBAAmB,cAAc,OAAO,CAAC,CAAC;IAE5F,4EAA4E;IAC5E,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,OAAO,EAAE,EAAE,EACX,gBAAgB,EAChB,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,EACpB,cAAc,GAAG,IAAI,EACrB,MAAM,CACP,CAAC;IAEF,uBAAuB;IACvB,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,WAAW,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAClC,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,WAAW,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAClC,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAEjE,OAAO;QACL,OAAO,EAAE,QAAQ,KAAK,CAAC,IAAI,QAAQ,KAAK,IAAI;QAC5C,QAAQ,EAAE,OAAO;QACjB,MAAM;QACN,MAAM;QACN,SAAS,EAAE,QAAQ;QACnB,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE;QAC1D,SAAS;KACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send MIDI events to the CrossPad simulator via TCP remote control.
|
|
3
|
+
*
|
|
4
|
+
* Supports: note_on, note_off, cc (control change), program_change.
|
|
5
|
+
* Uses the same remote control protocol as other sim commands.
|
|
6
|
+
*/
|
|
7
|
+
export type MidiEventType = "note_on" | "note_off" | "cc" | "program_change";
|
|
8
|
+
export interface MidiSendParams {
|
|
9
|
+
type: MidiEventType;
|
|
10
|
+
channel: number;
|
|
11
|
+
note?: number;
|
|
12
|
+
velocity?: number;
|
|
13
|
+
cc_num?: number;
|
|
14
|
+
value?: number;
|
|
15
|
+
program?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface MidiSendResult {
|
|
18
|
+
success: boolean;
|
|
19
|
+
type: MidiEventType;
|
|
20
|
+
channel: number;
|
|
21
|
+
details: Record<string, number>;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Send a MIDI event to the running simulator.
|
|
26
|
+
*/
|
|
27
|
+
export declare function crosspadMidiSend(params: MidiSendParams): Promise<MidiSendResult>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send MIDI events to the CrossPad simulator via TCP remote control.
|
|
3
|
+
*
|
|
4
|
+
* Supports: note_on, note_off, cc (control change), program_change.
|
|
5
|
+
* Uses the same remote control protocol as other sim commands.
|
|
6
|
+
*/
|
|
7
|
+
import { sendRemoteCommand, isSimulatorRunning } from "../utils/remote-client.js";
|
|
8
|
+
/**
|
|
9
|
+
* Send a MIDI event to the running simulator.
|
|
10
|
+
*/
|
|
11
|
+
export async function crosspadMidiSend(params) {
|
|
12
|
+
const running = await isSimulatorRunning();
|
|
13
|
+
if (!running) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
type: params.type,
|
|
17
|
+
channel: params.channel,
|
|
18
|
+
details: {},
|
|
19
|
+
error: "Simulator is not running. Use crosspad_build action=pc_run to start it.",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Validate channel
|
|
23
|
+
if (params.channel < 0 || params.channel > 15) {
|
|
24
|
+
return {
|
|
25
|
+
success: false,
|
|
26
|
+
type: params.type,
|
|
27
|
+
channel: params.channel,
|
|
28
|
+
details: {},
|
|
29
|
+
error: "MIDI channel must be 0-15",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
let cmd;
|
|
33
|
+
const details = { channel: params.channel };
|
|
34
|
+
switch (params.type) {
|
|
35
|
+
case "note_on": {
|
|
36
|
+
const note = params.note ?? 60;
|
|
37
|
+
const velocity = params.velocity ?? 127;
|
|
38
|
+
if (note < 0 || note > 127) {
|
|
39
|
+
return { success: false, type: params.type, channel: params.channel, details, error: "Note must be 0-127" };
|
|
40
|
+
}
|
|
41
|
+
if (velocity < 0 || velocity > 127) {
|
|
42
|
+
return { success: false, type: params.type, channel: params.channel, details, error: "Velocity must be 0-127" };
|
|
43
|
+
}
|
|
44
|
+
cmd = { cmd: "midi", type: "note_on", channel: params.channel, note, velocity };
|
|
45
|
+
details.note = note;
|
|
46
|
+
details.velocity = velocity;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case "note_off": {
|
|
50
|
+
const note = params.note ?? 60;
|
|
51
|
+
const velocity = params.velocity ?? 0;
|
|
52
|
+
if (note < 0 || note > 127) {
|
|
53
|
+
return { success: false, type: params.type, channel: params.channel, details, error: "Note must be 0-127" };
|
|
54
|
+
}
|
|
55
|
+
cmd = { cmd: "midi", type: "note_off", channel: params.channel, note, velocity };
|
|
56
|
+
details.note = note;
|
|
57
|
+
details.velocity = velocity;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "cc": {
|
|
61
|
+
const ccNum = params.cc_num ?? 0;
|
|
62
|
+
const value = params.value ?? 0;
|
|
63
|
+
if (ccNum < 0 || ccNum > 127) {
|
|
64
|
+
return { success: false, type: params.type, channel: params.channel, details, error: "CC number must be 0-127" };
|
|
65
|
+
}
|
|
66
|
+
if (value < 0 || value > 127) {
|
|
67
|
+
return { success: false, type: params.type, channel: params.channel, details, error: "Value must be 0-127" };
|
|
68
|
+
}
|
|
69
|
+
cmd = { cmd: "midi", type: "cc", channel: params.channel, cc: ccNum, value };
|
|
70
|
+
details.cc = ccNum;
|
|
71
|
+
details.value = value;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "program_change": {
|
|
75
|
+
const program = params.program ?? 0;
|
|
76
|
+
if (program < 0 || program > 127) {
|
|
77
|
+
return { success: false, type: params.type, channel: params.channel, details, error: "Program must be 0-127" };
|
|
78
|
+
}
|
|
79
|
+
cmd = { cmd: "midi", type: "program_change", channel: params.channel, program };
|
|
80
|
+
details.program = program;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
default:
|
|
84
|
+
return {
|
|
85
|
+
success: false,
|
|
86
|
+
type: params.type,
|
|
87
|
+
channel: params.channel,
|
|
88
|
+
details: {},
|
|
89
|
+
error: `Unknown MIDI event type: ${params.type}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const resp = await sendRemoteCommand(cmd);
|
|
94
|
+
return {
|
|
95
|
+
success: resp.ok === true,
|
|
96
|
+
type: params.type,
|
|
97
|
+
channel: params.channel,
|
|
98
|
+
details,
|
|
99
|
+
error: resp.ok ? undefined : resp.error ?? "Simulator rejected MIDI command",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
type: params.type,
|
|
106
|
+
channel: params.channel,
|
|
107
|
+
details,
|
|
108
|
+
error: err.message,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=midi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"midi.js","sourceRoot":"","sources":["../../src/tools/midi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutable repo operations: submodule update and commit.
|
|
3
|
+
*
|
|
4
|
+
* These are intentionally separate from repos.ts (read-only status)
|
|
5
|
+
* to make the mutation surface explicit.
|
|
6
|
+
*/
|
|
7
|
+
export interface SubmoduleUpdateResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
submodule: string;
|
|
10
|
+
repo: string;
|
|
11
|
+
old_sha: string | null;
|
|
12
|
+
new_sha: string | null;
|
|
13
|
+
commits_pulled: number;
|
|
14
|
+
changed_files: string[];
|
|
15
|
+
staged: boolean;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CommitResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
repo: string;
|
|
21
|
+
commit_hash: string | null;
|
|
22
|
+
message: string;
|
|
23
|
+
files_committed: string[];
|
|
24
|
+
error?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Update a submodule in a parent repo to the latest commit on its tracking branch.
|
|
28
|
+
*
|
|
29
|
+
* Workflow:
|
|
30
|
+
* 1. cd into submodule
|
|
31
|
+
* 2. git fetch origin
|
|
32
|
+
* 3. git checkout origin/<branch> (default: main)
|
|
33
|
+
* 4. cd back to parent, git add <submodule>
|
|
34
|
+
* 5. Report old→new SHA, commits pulled, files changed
|
|
35
|
+
*/
|
|
36
|
+
export declare function crosspadSubmoduleUpdate(submodule: string, repo: string, branch?: string): SubmoduleUpdateResult;
|
|
37
|
+
/**
|
|
38
|
+
* Commit changes in a specific repo.
|
|
39
|
+
*
|
|
40
|
+
* Safety:
|
|
41
|
+
* - Refuses if working tree has merge conflicts
|
|
42
|
+
* - If files specified, stages only those files
|
|
43
|
+
* - If no files specified, commits whatever is currently staged
|
|
44
|
+
* - Never pushes to remote
|
|
45
|
+
*/
|
|
46
|
+
export declare function crosspadCommit(repo: string, message: string, files?: string[]): CommitResult;
|