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.
Files changed (57) hide show
  1. package/README.md +109 -44
  2. package/dist/config.d.ts +2 -2
  3. package/dist/config.js +42 -8
  4. package/dist/config.js.map +1 -1
  5. package/dist/index.js +946 -308
  6. package/dist/index.js.map +1 -1
  7. package/dist/tools/app-manager.d.ts +13 -5
  8. package/dist/tools/app-manager.js +69 -46
  9. package/dist/tools/app-manager.js.map +1 -1
  10. package/dist/tools/architecture.js +13 -4
  11. package/dist/tools/architecture.js.map +1 -1
  12. package/dist/tools/build-check.d.ts +1 -1
  13. package/dist/tools/build-check.js +19 -9
  14. package/dist/tools/build-check.js.map +1 -1
  15. package/dist/tools/build.d.ts +43 -4
  16. package/dist/tools/build.js +147 -15
  17. package/dist/tools/build.js.map +1 -1
  18. package/dist/tools/diff-core.d.ts +5 -1
  19. package/dist/tools/diff-core.js +11 -6
  20. package/dist/tools/diff-core.js.map +1 -1
  21. package/dist/tools/idf-build.d.ts +1 -1
  22. package/dist/tools/idf-build.js +5 -5
  23. package/dist/tools/idf-build.js.map +1 -1
  24. package/dist/tools/idf-flash.d.ts +2 -2
  25. package/dist/tools/idf-flash.js +12 -11
  26. package/dist/tools/idf-flash.js.map +1 -1
  27. package/dist/tools/idf-monitor.d.ts +1 -1
  28. package/dist/tools/idf-monitor.js +57 -3
  29. package/dist/tools/idf-monitor.js.map +1 -1
  30. package/dist/tools/log.d.ts +2 -2
  31. package/dist/tools/log.js +6 -5
  32. package/dist/tools/log.js.map +1 -1
  33. package/dist/tools/repo-actions.js +88 -75
  34. package/dist/tools/repo-actions.js.map +1 -1
  35. package/dist/tools/repos.js +14 -10
  36. package/dist/tools/repos.js.map +1 -1
  37. package/dist/tools/screenshot.js +42 -7
  38. package/dist/tools/screenshot.js.map +1 -1
  39. package/dist/tools/settings.js +11 -1
  40. package/dist/tools/settings.js.map +1 -1
  41. package/dist/tools/symbols.js +13 -8
  42. package/dist/tools/symbols.js.map +1 -1
  43. package/dist/tools/test.d.ts +1 -9
  44. package/dist/tools/test.js +11 -92
  45. package/dist/tools/test.js.map +1 -1
  46. package/dist/utils/exec.d.ts +17 -5
  47. package/dist/utils/exec.js +73 -27
  48. package/dist/utils/exec.js.map +1 -1
  49. package/dist/utils/git.d.ts +9 -0
  50. package/dist/utils/git.js +61 -1
  51. package/dist/utils/git.js.map +1 -1
  52. package/dist/utils/remote-client.js +32 -14
  53. package/dist/utils/remote-client.js.map +1 -1
  54. package/package.json +4 -1
  55. package/dist/tools/scaffold.d.ts +0 -15
  56. package/dist/tools/scaffold.js +0 -192
  57. 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":"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"}
1
+ {"version":3,"file":"idf-monitor.js","sourceRoot":"","sources":["../../src/tools/idf-monitor.ts"],"names":[],"mappings":"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"}
@@ -9,8 +9,8 @@ export interface LogResult {
9
9
  truncated: boolean;
10
10
  }
11
11
  /**
12
- * Launch main.exe, capture stdout/stderr for up to `timeout_seconds`,
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 { runCommandStream } from "../utils/exec.js";
3
+ import { runArgvStream } from "../utils/exec.js";
4
4
  /**
5
- * Launch main.exe, capture stdout/stderr for up to `timeout_seconds`,
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: "bin/main.exe not found — build first",
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
- const result = await runCommandStream(`"${BIN_EXE}"`, CROSSPAD_PC_ROOT, onLine ?? (() => { }), timeoutSeconds * 1000);
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;
@@ -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,gBAAgB,EAAU,MAAM,kBAAkB,CAAC;AAY5D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,iBAAyB,CAAC,EAC1B,WAAmB,GAAG,EACtB,MAAe;IAEf,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,sCAAsC;YAC9C,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,MAAM,MAAM,GAAG,MAAM,gBAAgB,CACnC,IAAI,OAAO,GAAG,EACd,gBAAgB,EAChB,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,EACpB,cAAc,GAAG,IAAI,CACtB,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"}
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 { runCommand } from "../utils/exec.js";
11
- import { getHead } from "../utils/git.js";
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 PATHSwhere each submodule lives inside parent repos
46
+ // SUBMODULE PATH RESOLUTION dynamic via .gitmodules
38
47
  // ═══════════════════════════════════════════════════════════════════════
39
- const SUBMODULE_PATHS = {
40
- "platform-idf": {
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.name, submodule);
79
+ const subPath = getSubmodulePath(resolvedRepo.root, submodule);
87
80
  if (!subPath) {
88
- const knownSubs = Object.keys(SUBMODULE_PATHS[resolvedRepo.name] ?? {});
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 = runCommand("git fetch origin", fullSubPath, 30_000);
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 = runCommand(`git checkout origin/${branch}`, fullSubPath, 15_000);
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 countResult = runCommand(`git rev-list --count ${oldSha}..${newSha}`, fullSubPath);
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 = runCommand(`git diff --name-only ${oldSha}..${newSha}`, fullSubPath);
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 = runCommand(`git add ${subPath}`, resolvedRepo.root, 10_000);
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 = runCommand("git status --porcelain", resolvedRepo.root);
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
- // Stage specific files if provided
220
- if (files && files.length > 0) {
221
- const fileList = files.map((f) => `"${f}"`).join(" ");
222
- const addResult = runCommand(`git add ${fileList}`, resolvedRepo.root, 10_000);
223
- if (!addResult.success) {
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: `git add failed: ${addResult.stderr}`,
253
+ error: "Nothing staged to commit. Stage files first or specify files parameter.",
231
254
  };
232
255
  }
233
- }
234
- // Check something is staged
235
- const diffResult = runCommand("git diff --cached --name-only", resolvedRepo.root);
236
- const stagedFiles = diffResult.success
237
- ? diffResult.stdout.trim().split("\n").filter((l) => l.length > 0)
238
- : [];
239
- if (stagedFiles.length === 0) {
240
- return {
241
- success: false,
242
- repo: resolvedRepo.name,
243
- commit_hash: null,
244
- message,
245
- files_committed: [],
246
- error: "Nothing staged to commit. Stage files first or specify files parameter.",
247
- };
248
- }
249
- // Commit escape message for shell safety
250
- const escapedMessage = message.replace(/'/g, "'\\''");
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: false,
275
+ success: true,
255
276
  repo: resolvedRepo.name,
256
- commit_hash: null,
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
- // Get the new commit hash
263
- const hashResult = runCommand("git rev-parse HEAD", resolvedRepo.root);
264
- const commitHash = hashResult.success ? hashResult.stdout.trim() : null;
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":"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"}
1
+ {"version":3,"file":"repo-actions.js","sourceRoot":"","sources":["../../src/tools/repo-actions.ts"],"names":[],"mappings":"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"}
@@ -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 corePath = path.join(rootPath, "crosspad-core");
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
- const subPath = path.join(parent.root, sub.includes("/") ? sub : `components/${sub}`);
51
- // crosspad-pc has crosspad-core at root, platform-idf has it in components/
52
- const actualSubPath = fs.existsSync(path.join(parent.root, sub))
53
- ? sub
54
- : `components/${sub}`;
55
- const pinned = getSubmodulePin(parent.root, actualSubPath);
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; // not a submodule in this repo
61
+ continue;
58
62
  let localHead = null;
59
- const fullSubPath = path.join(parent.root, actualSubPath);
63
+ const fullSubPath = path.join(parent.root, relPath);
60
64
  if (fs.existsSync(fullSubPath)) {
61
65
  localHead = getHead(fullSubPath);
62
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"repos.js","sourceRoot":"","sources":["../../src/tools/repos.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repos.js","sourceRoot":"","sources":["../../src/tools/repos.ts"],"names":[],"mappings":"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"}
@@ -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
- const fname = filename || `screenshot_${Date.now()}.png`;
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: resp.width,
44
- height: resp.height,
71
+ width: parsed.data.width,
72
+ height: parsed.data.height,
45
73
  format: "png",
46
74
  file_path: filePath,
47
- size: resp.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: resp.width,
61
- height: resp.height,
95
+ width: parsed.data.width,
96
+ height: parsed.data.height,
62
97
  format: "png",
63
- data_base64: resp.data,
98
+ data_base64: parsed.data.data,
64
99
  };
65
100
  }
66
101
  catch (err) {