crosspad-mcp-server 6.0.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 +946 -308
- package/dist/index.js.map +1 -1
- package/dist/tools/app-manager.d.ts +13 -5
- package/dist/tools/app-manager.js +69 -46
- 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 +2 -2
- package/dist/tools/idf-flash.js +12 -11
- package/dist/tools/idf-flash.js.map +1 -1
- package/dist/tools/idf-monitor.d.ts +1 -1
- package/dist/tools/idf-monitor.js +57 -3
- package/dist/tools/idf-monitor.js.map +1 -1
- 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/repo-actions.js +88 -75
- package/dist/tools/repo-actions.js.map +1 -1
- 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.js +13 -8
- 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/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.js +32 -14
- 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
|
@@ -10,7 +10,30 @@
|
|
|
10
10
|
import { IS_WINDOWS } from "../config.js";
|
|
11
11
|
import { getIdfEnv } from "../utils/exec.js";
|
|
12
12
|
import { findCrosspadPort } from "../utils/device.js";
|
|
13
|
-
import { spawn } from "child_process";
|
|
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
|
+
}
|
|
14
37
|
/**
|
|
15
38
|
* Build a Python script that reads from serial port for a given duration.
|
|
16
39
|
* Uses pyserial (available in IDF venv). No TTY dependency.
|
|
@@ -44,7 +67,7 @@ function buildSerialReaderScript(port, timeoutSeconds) {
|
|
|
44
67
|
* @param filter - Optional string filter — only return lines containing this
|
|
45
68
|
* @param onLine - Streaming callback for real-time output
|
|
46
69
|
*/
|
|
47
|
-
export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 500, filter, onLine) {
|
|
70
|
+
export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 500, filter, onLine, signal) {
|
|
48
71
|
const startTime = Date.now();
|
|
49
72
|
// Resolve port
|
|
50
73
|
const resolved = findCrosspadPort(port);
|
|
@@ -60,6 +83,21 @@ export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 5
|
|
|
60
83
|
};
|
|
61
84
|
}
|
|
62
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
|
+
}
|
|
63
101
|
onLine?.("stdout", `[idf-monitor] Capturing from ${targetPort} for ${timeoutSeconds}s...`);
|
|
64
102
|
// Get IDF environment (for Python with pyserial)
|
|
65
103
|
let env;
|
|
@@ -78,7 +116,6 @@ export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 5
|
|
|
78
116
|
};
|
|
79
117
|
}
|
|
80
118
|
const script = buildSerialReaderScript(targetPort, timeoutSeconds);
|
|
81
|
-
const shell = IS_WINDOWS ? "cmd.exe" : "/bin/bash";
|
|
82
119
|
return new Promise((resolve) => {
|
|
83
120
|
const lines = [];
|
|
84
121
|
let totalLines = 0;
|
|
@@ -100,6 +137,19 @@ export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 5
|
|
|
100
137
|
child.kill("SIGKILL");
|
|
101
138
|
}, 2000);
|
|
102
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
|
+
}
|
|
103
153
|
function processLine(line) {
|
|
104
154
|
// Strip ANSI escape codes
|
|
105
155
|
const clean = line.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\r/g, "");
|
|
@@ -136,6 +186,8 @@ export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 5
|
|
|
136
186
|
});
|
|
137
187
|
child.on("close", (code) => {
|
|
138
188
|
clearTimeout(timer);
|
|
189
|
+
if (signal)
|
|
190
|
+
signal.removeEventListener("abort", onAbort);
|
|
139
191
|
if (stdoutBuf.trim()) {
|
|
140
192
|
processLine(stdoutBuf);
|
|
141
193
|
}
|
|
@@ -152,6 +204,8 @@ export async function crosspadIdfMonitor(port, timeoutSeconds = 10, maxLines = 5
|
|
|
152
204
|
});
|
|
153
205
|
child.on("error", (err) => {
|
|
154
206
|
clearTimeout(timer);
|
|
207
|
+
if (signal)
|
|
208
|
+
signal.removeEventListener("abort", onAbort);
|
|
155
209
|
const duration = (Date.now() - startTime) / 1000;
|
|
156
210
|
resolve({
|
|
157
211
|
success: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idf-monitor.js","sourceRoot":"","sources":["../../src/tools/idf-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAqB,UAAU,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAU,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;
|
|
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"}
|
|
@@ -5,10 +5,25 @@
|
|
|
5
5
|
* to make the mutation surface explicit.
|
|
6
6
|
*/
|
|
7
7
|
import fs from "fs";
|
|
8
|
+
import os from "os";
|
|
8
9
|
import path from "path";
|
|
9
10
|
import { getRepos } from "../config.js";
|
|
10
|
-
import {
|
|
11
|
-
|
|
11
|
+
import { spawnSync } from "child_process";
|
|
12
|
+
/**
|
|
13
|
+
* Run git in argv mode (no shell). Use for any git invocation that takes
|
|
14
|
+
* user-controlled args (refs, paths). Returns ExecResult-shaped object so
|
|
15
|
+
* call sites stay uniform.
|
|
16
|
+
*/
|
|
17
|
+
function git(args, cwd, timeoutMs = 30_000) {
|
|
18
|
+
const r = spawnSync("git", args, { cwd, encoding: "utf-8", timeout: timeoutMs });
|
|
19
|
+
return {
|
|
20
|
+
success: r.status === 0,
|
|
21
|
+
stdout: (r.stdout ?? "").replace(/\r\n/g, "\n"),
|
|
22
|
+
stderr: (r.stderr ?? "").replace(/\r\n/g, "\n"),
|
|
23
|
+
exitCode: r.status ?? 1,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
import { getHead, listSubmodules, findSubmodulePath } from "../utils/git.js";
|
|
12
27
|
const REPO_ALIASES = {
|
|
13
28
|
idf: "platform-idf",
|
|
14
29
|
pc: "crosspad-pc",
|
|
@@ -22,38 +37,16 @@ function resolveRepo(repo) {
|
|
|
22
37
|
if (repos[canonical]) {
|
|
23
38
|
return { name: canonical, root: repos[canonical] };
|
|
24
39
|
}
|
|
25
|
-
// Try partial match
|
|
26
|
-
for (const [name, repoPath] of Object.entries(repos)) {
|
|
27
|
-
if (name.toLowerCase().includes(repo.toLowerCase())) {
|
|
28
|
-
return { name, root: repoPath };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
40
|
return null;
|
|
32
41
|
}
|
|
33
42
|
function getAvailableRepoNames() {
|
|
34
43
|
return Object.keys(getRepos());
|
|
35
44
|
}
|
|
36
45
|
// ═══════════════════════════════════════════════════════════════════════
|
|
37
|
-
// SUBMODULE
|
|
46
|
+
// SUBMODULE PATH RESOLUTION — dynamic via .gitmodules
|
|
38
47
|
// ═══════════════════════════════════════════════════════════════════════
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"crosspad-core": "components/crosspad-core",
|
|
42
|
-
"crosspad-gui": "components/crosspad-gui",
|
|
43
|
-
"crosspad-instructions": "components/crosspad-instructions",
|
|
44
|
-
"crosspad-sampler": "components/crosspad-sampler",
|
|
45
|
-
},
|
|
46
|
-
"crosspad-pc": {
|
|
47
|
-
"crosspad-core": "crosspad-core",
|
|
48
|
-
"crosspad-gui": "crosspad-gui",
|
|
49
|
-
},
|
|
50
|
-
"ESP32-S3": {
|
|
51
|
-
"crosspad-core": "lib/crosspad-core",
|
|
52
|
-
"crosspad-gui": "lib/crosspad-gui",
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
function getSubmodulePath(repoName, submodule) {
|
|
56
|
-
return SUBMODULE_PATHS[repoName]?.[submodule] ?? null;
|
|
48
|
+
function getSubmodulePath(repoRoot, submodule) {
|
|
49
|
+
return findSubmodulePath(repoRoot, submodule);
|
|
57
50
|
}
|
|
58
51
|
// ═══════════════════════════════════════════════════════════════════════
|
|
59
52
|
// SUBMODULE UPDATE
|
|
@@ -83,9 +76,9 @@ export function crosspadSubmoduleUpdate(submodule, repo, branch = "main") {
|
|
|
83
76
|
error: `Unknown repo "${repo}". Available: ${getAvailableRepoNames().join(", ")}`,
|
|
84
77
|
};
|
|
85
78
|
}
|
|
86
|
-
const subPath = getSubmodulePath(resolvedRepo.
|
|
79
|
+
const subPath = getSubmodulePath(resolvedRepo.root, submodule);
|
|
87
80
|
if (!subPath) {
|
|
88
|
-
const knownSubs = Object.keys(
|
|
81
|
+
const knownSubs = Object.keys(listSubmodules(resolvedRepo.root));
|
|
89
82
|
return {
|
|
90
83
|
success: false,
|
|
91
84
|
submodule,
|
|
@@ -115,7 +108,7 @@ export function crosspadSubmoduleUpdate(submodule, repo, branch = "main") {
|
|
|
115
108
|
// Get current SHA
|
|
116
109
|
const oldSha = getHead(fullSubPath);
|
|
117
110
|
// Fetch latest
|
|
118
|
-
const fetchResult =
|
|
111
|
+
const fetchResult = git(["fetch", "origin"], fullSubPath, 30_000);
|
|
119
112
|
if (!fetchResult.success) {
|
|
120
113
|
return {
|
|
121
114
|
success: false,
|
|
@@ -129,8 +122,8 @@ export function crosspadSubmoduleUpdate(submodule, repo, branch = "main") {
|
|
|
129
122
|
error: `git fetch failed: ${fetchResult.stderr}`,
|
|
130
123
|
};
|
|
131
124
|
}
|
|
132
|
-
// Checkout target
|
|
133
|
-
const checkoutResult =
|
|
125
|
+
// Checkout target — argv mode keeps `branch` out of any shell.
|
|
126
|
+
const checkoutResult = git(["checkout", `origin/${branch}`], fullSubPath, 15_000);
|
|
134
127
|
if (!checkoutResult.success) {
|
|
135
128
|
return {
|
|
136
129
|
success: false,
|
|
@@ -150,11 +143,12 @@ export function crosspadSubmoduleUpdate(submodule, repo, branch = "main") {
|
|
|
150
143
|
let commitsPulled = 0;
|
|
151
144
|
let changedFiles = [];
|
|
152
145
|
if (oldSha && newSha && oldSha !== newSha) {
|
|
153
|
-
const
|
|
146
|
+
const range = `${oldSha}..${newSha}`;
|
|
147
|
+
const countResult = git(["rev-list", "--count", range], fullSubPath);
|
|
154
148
|
if (countResult.success) {
|
|
155
149
|
commitsPulled = parseInt(countResult.stdout.trim(), 10) || 0;
|
|
156
150
|
}
|
|
157
|
-
const diffResult =
|
|
151
|
+
const diffResult = git(["diff", "--name-only", range], fullSubPath);
|
|
158
152
|
if (diffResult.success) {
|
|
159
153
|
changedFiles = diffResult.stdout
|
|
160
154
|
.trim()
|
|
@@ -163,7 +157,7 @@ export function crosspadSubmoduleUpdate(submodule, repo, branch = "main") {
|
|
|
163
157
|
}
|
|
164
158
|
}
|
|
165
159
|
// Stage the submodule update in parent repo
|
|
166
|
-
const addResult =
|
|
160
|
+
const addResult = git(["add", "--", subPath], resolvedRepo.root, 10_000);
|
|
167
161
|
return {
|
|
168
162
|
success: true,
|
|
169
163
|
submodule,
|
|
@@ -200,7 +194,7 @@ export function crosspadCommit(repo, message, files) {
|
|
|
200
194
|
};
|
|
201
195
|
}
|
|
202
196
|
// Check for merge conflicts
|
|
203
|
-
const statusResult =
|
|
197
|
+
const statusResult = git(["status", "--porcelain"], resolvedRepo.root);
|
|
204
198
|
if (statusResult.success) {
|
|
205
199
|
const conflicted = statusResult.stdout
|
|
206
200
|
.split("\n")
|
|
@@ -216,58 +210,77 @@ export function crosspadCommit(repo, message, files) {
|
|
|
216
210
|
};
|
|
217
211
|
}
|
|
218
212
|
}
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
213
|
+
// Use a private 0700 scratch dir for pathspec + commit-message tempfiles.
|
|
214
|
+
// Default umask leaves files in os.tmpdir() world-readable on multi-user
|
|
215
|
+
// hosts; mkdtemp creates a 0700 dir, and we write files with mode 0600.
|
|
216
|
+
const scratchDir = fs.mkdtempSync(path.join(os.tmpdir(), "crosspad-"));
|
|
217
|
+
const cleanup = () => {
|
|
218
|
+
try {
|
|
219
|
+
fs.rmSync(scratchDir, { recursive: true, force: true });
|
|
220
|
+
}
|
|
221
|
+
catch { /* ignore */ }
|
|
222
|
+
};
|
|
223
|
+
try {
|
|
224
|
+
// Stage specific files if provided — use --pathspec-from-file to avoid
|
|
225
|
+
// shell-quoting issues (paths with spaces, quotes, backslashes).
|
|
226
|
+
if (files && files.length > 0) {
|
|
227
|
+
const pathspecFile = path.join(scratchDir, "pathspec");
|
|
228
|
+
fs.writeFileSync(pathspecFile, files.join("\n"), { encoding: "utf-8", mode: 0o600 });
|
|
229
|
+
const addResult = git(["add", `--pathspec-from-file=${pathspecFile}`], resolvedRepo.root, 10_000);
|
|
230
|
+
if (!addResult.success) {
|
|
231
|
+
return {
|
|
232
|
+
success: false,
|
|
233
|
+
repo: resolvedRepo.name,
|
|
234
|
+
commit_hash: null,
|
|
235
|
+
message,
|
|
236
|
+
files_committed: [],
|
|
237
|
+
error: `git add failed: ${addResult.stderr}`,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Check something is staged
|
|
242
|
+
const diffResult = git(["diff", "--cached", "--name-only"], resolvedRepo.root);
|
|
243
|
+
const stagedFiles = diffResult.success
|
|
244
|
+
? diffResult.stdout.trim().split("\n").filter((l) => l.length > 0)
|
|
245
|
+
: [];
|
|
246
|
+
if (stagedFiles.length === 0) {
|
|
224
247
|
return {
|
|
225
248
|
success: false,
|
|
226
249
|
repo: resolvedRepo.name,
|
|
227
250
|
commit_hash: null,
|
|
228
251
|
message,
|
|
229
252
|
files_committed: [],
|
|
230
|
-
error:
|
|
253
|
+
error: "Nothing staged to commit. Stage files first or specify files parameter.",
|
|
231
254
|
};
|
|
232
255
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const commitResult = runCommand(`git commit -m '${escapedMessage}'`, resolvedRepo.root, 30_000);
|
|
252
|
-
if (!commitResult.success) {
|
|
256
|
+
// Commit via tempfile to avoid shell-quoting issues (newlines, quotes,
|
|
257
|
+
// backticks) on both bash and Windows cmd.
|
|
258
|
+
const msgFile = path.join(scratchDir, "commit.msg");
|
|
259
|
+
fs.writeFileSync(msgFile, message, { encoding: "utf-8", mode: 0o600 });
|
|
260
|
+
const commitResult = git(["commit", "-F", msgFile], resolvedRepo.root, 30_000);
|
|
261
|
+
if (!commitResult.success) {
|
|
262
|
+
return {
|
|
263
|
+
success: false,
|
|
264
|
+
repo: resolvedRepo.name,
|
|
265
|
+
commit_hash: null,
|
|
266
|
+
message,
|
|
267
|
+
files_committed: stagedFiles,
|
|
268
|
+
error: `git commit failed: ${commitResult.stderr || commitResult.stdout}`,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// Get the new commit hash
|
|
272
|
+
const hashResult = git(["rev-parse", "HEAD"], resolvedRepo.root);
|
|
273
|
+
const commitHash = hashResult.success ? hashResult.stdout.trim() : null;
|
|
253
274
|
return {
|
|
254
|
-
success:
|
|
275
|
+
success: true,
|
|
255
276
|
repo: resolvedRepo.name,
|
|
256
|
-
commit_hash:
|
|
277
|
+
commit_hash: commitHash,
|
|
257
278
|
message,
|
|
258
279
|
files_committed: stagedFiles,
|
|
259
|
-
error: `git commit failed: ${commitResult.stderr || commitResult.stdout}`,
|
|
260
280
|
};
|
|
261
281
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
success: true,
|
|
267
|
-
repo: resolvedRepo.name,
|
|
268
|
-
commit_hash: commitHash,
|
|
269
|
-
message,
|
|
270
|
-
files_committed: stagedFiles,
|
|
271
|
-
};
|
|
282
|
+
finally {
|
|
283
|
+
cleanup();
|
|
284
|
+
}
|
|
272
285
|
}
|
|
273
286
|
//# sourceMappingURL=repo-actions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo-actions.js","sourceRoot":"","sources":["../../src/tools/repo-actions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAuC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"repo-actions.js","sourceRoot":"","sources":["../../src/tools/repo-actions.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/repos.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { getRepos, CROSSPAD_PC_ROOT, CROSSPAD_IDF_ROOT } from "../config.js";
|
|
4
|
-
import { getRepoStatus, getSubmodulePin, getHead } from "../utils/git.js";
|
|
4
|
+
import { getRepoStatus, getSubmodulePin, getHead, listSubmodules, findSubmodulePath } from "../utils/git.js";
|
|
5
5
|
function detectMode(rootPath) {
|
|
6
|
-
const
|
|
6
|
+
const subs = listSubmodules(rootPath);
|
|
7
|
+
const corePathRel = subs["crosspad-core"];
|
|
8
|
+
if (!corePathRel)
|
|
9
|
+
return "unknown";
|
|
10
|
+
const corePath = path.join(rootPath, corePathRel);
|
|
7
11
|
try {
|
|
8
12
|
const stat = fs.lstatSync(corePath);
|
|
9
13
|
if (stat.isSymbolicLink())
|
|
@@ -47,16 +51,16 @@ export function crosspadReposStatus() {
|
|
|
47
51
|
if (!fs.existsSync(parent.root))
|
|
48
52
|
continue;
|
|
49
53
|
for (const sub of ["crosspad-core", "crosspad-gui"]) {
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const pinned = getSubmodulePin(parent.root,
|
|
54
|
+
// findSubmodulePath handles both "<name>" and "<dir>/<name>" entries
|
|
55
|
+
// in .gitmodules (e.g. platform-idf uses "components/crosspad-core").
|
|
56
|
+
const relPath = findSubmodulePath(parent.root, sub);
|
|
57
|
+
if (!relPath)
|
|
58
|
+
continue; // not a submodule in this parent
|
|
59
|
+
const pinned = getSubmodulePin(parent.root, sub);
|
|
56
60
|
if (pinned === null)
|
|
57
|
-
continue;
|
|
61
|
+
continue;
|
|
58
62
|
let localHead = null;
|
|
59
|
-
const fullSubPath = path.join(parent.root,
|
|
63
|
+
const fullSubPath = path.join(parent.root, relPath);
|
|
60
64
|
if (fs.existsSync(fullSubPath)) {
|
|
61
65
|
localHead = getHead(fullSubPath);
|
|
62
66
|
}
|
package/dist/tools/repos.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repos.js","sourceRoot":"","sources":["../../src/tools/repos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,OAAO,EAAc,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"repos.js","sourceRoot":"","sources":["../../src/tools/repos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAc,MAAM,iBAAiB,CAAC;AAczH,SAAS,UAAU,CAAC,QAAgB;IAClC,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;IAC1C,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE;YAAE,OAAO,UAAU,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,gBAAgB,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,QAAQ,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1D,IAAI,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI;gBACJ,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,EAAE;gBACV,IAAI,EAAE,EAAE;gBACR,UAAU,EAAE,CAAC,WAAW,GAAG,CAAC,OAAO,GAAG,CAAC;aACxC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAC1C,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAC9B,CAAC,CAAC,SAAS,CAAC;IAEd,gEAAgE;IAChE,MAAM,aAAa,GAAkC,EAAE,CAAC;IAExD,MAAM,WAAW,GAAG;QAClB,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,EAAE;QAC/C,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE;KAClD,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,SAAS;QAE1C,KAAK,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,cAAc,CAAC,EAAE,CAAC;YACpD,qEAAqE;YACrE,sEAAsE;YACtE,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACpD,IAAI,CAAC,OAAO;gBAAE,SAAS,CAAC,iCAAiC;YAEzD,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACjD,IAAI,MAAM,KAAK,IAAI;gBAAE,SAAS;YAE9B,IAAI,SAAS,GAAkB,IAAI,CAAC;YACpC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACpD,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/B,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;YACnC,CAAC;YAED,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;YACpC,aAAa,CAAC,GAAG,CAAC,GAAG;gBACnB,MAAM;gBACN,UAAU,EAAE,SAAS;gBACrB,OAAO,EAAE,MAAM,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;aAC3F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;AAC1E,CAAC"}
|
package/dist/tools/screenshot.js
CHANGED
|
@@ -8,7 +8,22 @@
|
|
|
8
8
|
import { sendRemoteCommand, isSimulatorRunning } from "../utils/remote-client.js";
|
|
9
9
|
import fs from "fs";
|
|
10
10
|
import path from "path";
|
|
11
|
+
import { z } from "zod";
|
|
11
12
|
import { CROSSPAD_PC_ROOT } from "../config.js";
|
|
13
|
+
// Validate the simulator's screenshot response — sim is in-process C++ but
|
|
14
|
+
// could ship malformed data after a crash. Better an error than NaN width.
|
|
15
|
+
const ScreenshotFileResponseSchema = z.object({
|
|
16
|
+
ok: z.literal(true),
|
|
17
|
+
width: z.number().int().positive(),
|
|
18
|
+
height: z.number().int().positive(),
|
|
19
|
+
size: z.number().int().nonnegative().optional(),
|
|
20
|
+
});
|
|
21
|
+
const ScreenshotInlineResponseSchema = z.object({
|
|
22
|
+
ok: z.literal(true),
|
|
23
|
+
width: z.number().int().positive(),
|
|
24
|
+
height: z.number().int().positive(),
|
|
25
|
+
data: z.string().min(1),
|
|
26
|
+
});
|
|
12
27
|
/**
|
|
13
28
|
* Take a screenshot of the simulator window.
|
|
14
29
|
* @param save_to_file If true, simulator writes PNG directly to disk (fast path).
|
|
@@ -25,7 +40,13 @@ export async function crosspadScreenshot(saveToFile = true, filename) {
|
|
|
25
40
|
try {
|
|
26
41
|
if (saveToFile) {
|
|
27
42
|
// Fast path: simulator writes PNG directly to disk
|
|
28
|
-
|
|
43
|
+
// Sanitize filename to prevent path traversal: strip any directory
|
|
44
|
+
// components, keep only the basename. Reject empty/invalid names.
|
|
45
|
+
let fname = filename || `screenshot_${Date.now()}.png`;
|
|
46
|
+
fname = path.basename(fname);
|
|
47
|
+
if (!fname || fname === "." || fname === "..") {
|
|
48
|
+
fname = `screenshot_${Date.now()}.png`;
|
|
49
|
+
}
|
|
29
50
|
const screenshotsDir = path.join(CROSSPAD_PC_ROOT, "screenshots");
|
|
30
51
|
if (!fs.existsSync(screenshotsDir)) {
|
|
31
52
|
fs.mkdirSync(screenshotsDir, { recursive: true });
|
|
@@ -38,13 +59,20 @@ export async function crosspadScreenshot(saveToFile = true, filename) {
|
|
|
38
59
|
error: resp.error || "Screenshot failed",
|
|
39
60
|
};
|
|
40
61
|
}
|
|
62
|
+
const parsed = ScreenshotFileResponseSchema.safeParse(resp);
|
|
63
|
+
if (!parsed.success) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: `Simulator returned malformed screenshot response: ${parsed.error.message}`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
41
69
|
return {
|
|
42
70
|
success: true,
|
|
43
|
-
width:
|
|
44
|
-
height:
|
|
71
|
+
width: parsed.data.width,
|
|
72
|
+
height: parsed.data.height,
|
|
45
73
|
format: "png",
|
|
46
74
|
file_path: filePath,
|
|
47
|
-
size:
|
|
75
|
+
size: parsed.data.size,
|
|
48
76
|
};
|
|
49
77
|
}
|
|
50
78
|
// Inline path: returns base64-encoded PNG
|
|
@@ -55,12 +83,19 @@ export async function crosspadScreenshot(saveToFile = true, filename) {
|
|
|
55
83
|
error: resp.error || "Screenshot failed",
|
|
56
84
|
};
|
|
57
85
|
}
|
|
86
|
+
const parsed = ScreenshotInlineResponseSchema.safeParse(resp);
|
|
87
|
+
if (!parsed.success) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: `Simulator returned malformed screenshot response: ${parsed.error.message}`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
58
93
|
return {
|
|
59
94
|
success: true,
|
|
60
|
-
width:
|
|
61
|
-
height:
|
|
95
|
+
width: parsed.data.width,
|
|
96
|
+
height: parsed.data.height,
|
|
62
97
|
format: "png",
|
|
63
|
-
data_base64:
|
|
98
|
+
data_base64: parsed.data.data,
|
|
64
99
|
};
|
|
65
100
|
}
|
|
66
101
|
catch (err) {
|