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.
Files changed (66) 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 +953 -219
  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 +94 -28
  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 +20 -0
  25. package/dist/tools/idf-flash.js +185 -0
  26. package/dist/tools/idf-flash.js.map +1 -0
  27. package/dist/tools/idf-monitor.d.ts +29 -0
  28. package/dist/tools/idf-monitor.js +222 -0
  29. package/dist/tools/idf-monitor.js.map +1 -0
  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/midi.d.ts +27 -0
  34. package/dist/tools/midi.js +112 -0
  35. package/dist/tools/midi.js.map +1 -0
  36. package/dist/tools/repo-actions.d.ts +46 -0
  37. package/dist/tools/repo-actions.js +286 -0
  38. package/dist/tools/repo-actions.js.map +1 -0
  39. package/dist/tools/repos.js +14 -10
  40. package/dist/tools/repos.js.map +1 -1
  41. package/dist/tools/screenshot.js +42 -7
  42. package/dist/tools/screenshot.js.map +1 -1
  43. package/dist/tools/settings.js +11 -1
  44. package/dist/tools/settings.js.map +1 -1
  45. package/dist/tools/symbols.d.ts +2 -1
  46. package/dist/tools/symbols.js +121 -53
  47. package/dist/tools/symbols.js.map +1 -1
  48. package/dist/tools/test.d.ts +1 -9
  49. package/dist/tools/test.js +11 -92
  50. package/dist/tools/test.js.map +1 -1
  51. package/dist/utils/device.d.ts +38 -0
  52. package/dist/utils/device.js +287 -0
  53. package/dist/utils/device.js.map +1 -0
  54. package/dist/utils/exec.d.ts +17 -5
  55. package/dist/utils/exec.js +73 -27
  56. package/dist/utils/exec.js.map +1 -1
  57. package/dist/utils/git.d.ts +9 -0
  58. package/dist/utils/git.js +61 -1
  59. package/dist/utils/git.js.map +1 -1
  60. package/dist/utils/remote-client.d.ts +1 -0
  61. package/dist/utils/remote-client.js +56 -15
  62. package/dist/utils/remote-client.js.map +1 -1
  63. package/package.json +4 -1
  64. package/dist/tools/scaffold.d.ts +0 -15
  65. package/dist/tools/scaffold.js +0 -192
  66. package/dist/tools/scaffold.js.map +0 -1
@@ -0,0 +1,286 @@
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
+ import fs from "fs";
8
+ import os from "os";
9
+ import path from "path";
10
+ import { getRepos } from "../config.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";
27
+ const REPO_ALIASES = {
28
+ idf: "platform-idf",
29
+ pc: "crosspad-pc",
30
+ arduino: "ESP32-S3",
31
+ core: "crosspad-core",
32
+ gui: "crosspad-gui",
33
+ };
34
+ function resolveRepo(repo) {
35
+ const repos = getRepos();
36
+ const canonical = REPO_ALIASES[repo] ?? repo;
37
+ if (repos[canonical]) {
38
+ return { name: canonical, root: repos[canonical] };
39
+ }
40
+ return null;
41
+ }
42
+ function getAvailableRepoNames() {
43
+ return Object.keys(getRepos());
44
+ }
45
+ // ═══════════════════════════════════════════════════════════════════════
46
+ // SUBMODULE PATH RESOLUTION — dynamic via .gitmodules
47
+ // ═══════════════════════════════════════════════════════════════════════
48
+ function getSubmodulePath(repoRoot, submodule) {
49
+ return findSubmodulePath(repoRoot, submodule);
50
+ }
51
+ // ═══════════════════════════════════════════════════════════════════════
52
+ // SUBMODULE UPDATE
53
+ // ═══════════════════════════════════════════════════════════════════════
54
+ /**
55
+ * Update a submodule in a parent repo to the latest commit on its tracking branch.
56
+ *
57
+ * Workflow:
58
+ * 1. cd into submodule
59
+ * 2. git fetch origin
60
+ * 3. git checkout origin/<branch> (default: main)
61
+ * 4. cd back to parent, git add <submodule>
62
+ * 5. Report old→new SHA, commits pulled, files changed
63
+ */
64
+ export function crosspadSubmoduleUpdate(submodule, repo, branch = "main") {
65
+ const resolvedRepo = resolveRepo(repo);
66
+ if (!resolvedRepo) {
67
+ return {
68
+ success: false,
69
+ submodule,
70
+ repo,
71
+ old_sha: null,
72
+ new_sha: null,
73
+ commits_pulled: 0,
74
+ changed_files: [],
75
+ staged: false,
76
+ error: `Unknown repo "${repo}". Available: ${getAvailableRepoNames().join(", ")}`,
77
+ };
78
+ }
79
+ const subPath = getSubmodulePath(resolvedRepo.root, submodule);
80
+ if (!subPath) {
81
+ const knownSubs = Object.keys(listSubmodules(resolvedRepo.root));
82
+ return {
83
+ success: false,
84
+ submodule,
85
+ repo: resolvedRepo.name,
86
+ old_sha: null,
87
+ new_sha: null,
88
+ commits_pulled: 0,
89
+ changed_files: [],
90
+ staged: false,
91
+ error: `Submodule "${submodule}" not found in ${resolvedRepo.name}. Known: ${knownSubs.join(", ")}`,
92
+ };
93
+ }
94
+ const fullSubPath = path.join(resolvedRepo.root, subPath);
95
+ if (!fs.existsSync(fullSubPath)) {
96
+ return {
97
+ success: false,
98
+ submodule,
99
+ repo: resolvedRepo.name,
100
+ old_sha: null,
101
+ new_sha: null,
102
+ commits_pulled: 0,
103
+ changed_files: [],
104
+ staged: false,
105
+ error: `Submodule directory not found: ${fullSubPath}`,
106
+ };
107
+ }
108
+ // Get current SHA
109
+ const oldSha = getHead(fullSubPath);
110
+ // Fetch latest
111
+ const fetchResult = git(["fetch", "origin"], fullSubPath, 30_000);
112
+ if (!fetchResult.success) {
113
+ return {
114
+ success: false,
115
+ submodule,
116
+ repo: resolvedRepo.name,
117
+ old_sha: oldSha,
118
+ new_sha: null,
119
+ commits_pulled: 0,
120
+ changed_files: [],
121
+ staged: false,
122
+ error: `git fetch failed: ${fetchResult.stderr}`,
123
+ };
124
+ }
125
+ // Checkout target — argv mode keeps `branch` out of any shell.
126
+ const checkoutResult = git(["checkout", `origin/${branch}`], fullSubPath, 15_000);
127
+ if (!checkoutResult.success) {
128
+ return {
129
+ success: false,
130
+ submodule,
131
+ repo: resolvedRepo.name,
132
+ old_sha: oldSha,
133
+ new_sha: null,
134
+ commits_pulled: 0,
135
+ changed_files: [],
136
+ staged: false,
137
+ error: `git checkout origin/${branch} failed: ${checkoutResult.stderr}`,
138
+ };
139
+ }
140
+ // Get new SHA
141
+ const newSha = getHead(fullSubPath);
142
+ // Count commits between old and new
143
+ let commitsPulled = 0;
144
+ let changedFiles = [];
145
+ if (oldSha && newSha && oldSha !== newSha) {
146
+ const range = `${oldSha}..${newSha}`;
147
+ const countResult = git(["rev-list", "--count", range], fullSubPath);
148
+ if (countResult.success) {
149
+ commitsPulled = parseInt(countResult.stdout.trim(), 10) || 0;
150
+ }
151
+ const diffResult = git(["diff", "--name-only", range], fullSubPath);
152
+ if (diffResult.success) {
153
+ changedFiles = diffResult.stdout
154
+ .trim()
155
+ .split("\n")
156
+ .filter((l) => l.length > 0);
157
+ }
158
+ }
159
+ // Stage the submodule update in parent repo
160
+ const addResult = git(["add", "--", subPath], resolvedRepo.root, 10_000);
161
+ return {
162
+ success: true,
163
+ submodule,
164
+ repo: resolvedRepo.name,
165
+ old_sha: oldSha,
166
+ new_sha: newSha,
167
+ commits_pulled: commitsPulled,
168
+ changed_files: changedFiles,
169
+ staged: addResult.success,
170
+ };
171
+ }
172
+ // ═══════════════════════════════════════════════════════════════════════
173
+ // COMMIT
174
+ // ═══════════════════════════════════════════════════════════════════════
175
+ /**
176
+ * Commit changes in a specific repo.
177
+ *
178
+ * Safety:
179
+ * - Refuses if working tree has merge conflicts
180
+ * - If files specified, stages only those files
181
+ * - If no files specified, commits whatever is currently staged
182
+ * - Never pushes to remote
183
+ */
184
+ export function crosspadCommit(repo, message, files) {
185
+ const resolvedRepo = resolveRepo(repo);
186
+ if (!resolvedRepo) {
187
+ return {
188
+ success: false,
189
+ repo,
190
+ commit_hash: null,
191
+ message,
192
+ files_committed: [],
193
+ error: `Unknown repo "${repo}". Available: ${getAvailableRepoNames().join(", ")}`,
194
+ };
195
+ }
196
+ // Check for merge conflicts
197
+ const statusResult = git(["status", "--porcelain"], resolvedRepo.root);
198
+ if (statusResult.success) {
199
+ const conflicted = statusResult.stdout
200
+ .split("\n")
201
+ .filter((l) => l.startsWith("UU") || l.startsWith("AA") || l.startsWith("DD"));
202
+ if (conflicted.length > 0) {
203
+ return {
204
+ success: false,
205
+ repo: resolvedRepo.name,
206
+ commit_hash: null,
207
+ message,
208
+ files_committed: [],
209
+ error: `Merge conflicts detected:\n${conflicted.join("\n")}\nResolve conflicts before committing.`,
210
+ };
211
+ }
212
+ }
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) {
247
+ return {
248
+ success: false,
249
+ repo: resolvedRepo.name,
250
+ commit_hash: null,
251
+ message,
252
+ files_committed: [],
253
+ error: "Nothing staged to commit. Stage files first or specify files parameter.",
254
+ };
255
+ }
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;
274
+ return {
275
+ success: true,
276
+ repo: resolvedRepo.name,
277
+ commit_hash: commitHash,
278
+ message,
279
+ files_committed: stagedFiles,
280
+ };
281
+ }
282
+ finally {
283
+ cleanup();
284
+ }
285
+ }
286
+ //# sourceMappingURL=repo-actions.js.map
@@ -0,0 +1 @@
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) {
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAahD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,aAAsB,IAAI,EAC1B,QAAiB;IAEjB,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,yDAAyD;SACjE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,IAAI,UAAU,EAAE,CAAC;YACf,mDAAmD;YACnD,MAAM,KAAK,GAAG,QAAQ,IAAI,cAAc,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;YACzD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;YAClE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBACnC,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAEtE,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YAE5E,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,mBAAmB;iBACrD,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE,IAAI,CAAC,KAAe;gBAC3B,MAAM,EAAE,IAAI,CAAC,MAAgB;gBAC7B,MAAM,EAAE,KAAK;gBACb,SAAS,EAAE,QAAQ;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAc;aAC1B,CAAC;QACJ,CAAC;QAED,0CAA0C;QAC1C,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;QAE5D,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,mBAAmB;aACrD,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,IAAI,CAAC,KAAe;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAgB;YAC7B,MAAM,EAAE,KAAK;YACb,WAAW,EAAE,IAAI,CAAC,IAAc;SACjC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,CAAC,OAAO;SACnB,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,12 @@
2
2
  * MCP tool: read/write CrossPad settings via the running simulator.
3
3
  */
4
4
  import { sendRemoteCommand, isSimulatorRunning } from "../utils/remote-client.js";
5
+ import { z } from "zod";
6
+ const SettingsSetResponseSchema = z.object({
7
+ ok: z.literal(true),
8
+ key: z.string(),
9
+ value: z.number(),
10
+ });
5
11
  /**
6
12
  * Read settings from the running simulator.
7
13
  * @param category "all", "display", "keypad", "vibration", "wireless", "audio", "system"
@@ -39,7 +45,11 @@ export async function crosspadSettingsSet(key, value) {
39
45
  if (!resp.ok) {
40
46
  return { success: false, error: resp.error || "settings_set failed" };
41
47
  }
42
- return { success: true, key: resp.key, value: resp.value };
48
+ const parsed = SettingsSetResponseSchema.safeParse(resp);
49
+ if (!parsed.success) {
50
+ return { success: false, error: `Simulator returned malformed settings_set response: ${parsed.error.message}` };
51
+ }
52
+ return { success: true, key: parsed.data.key, value: parsed.data.value };
43
53
  }
44
54
  catch (err) {
45
55
  return { success: false, error: err.message };
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/tools/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAelF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,KAAK;IAExB,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,yDAAyD,EAAE,CAAC;IAC9F,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,qBAAqB,EAAE,CAAC;QACpF,CAAC;QACD,+CAA+C;QAC/C,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACrC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAW,EACX,KAAa;IAEb,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,yDAAyD,EAAE,CAAC;IAC9F,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,qBAAqB,EAAE,CAAC;QACpF,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAa,EAAE,KAAK,EAAE,IAAI,CAAC,KAAe,EAAE,CAAC;IACjF,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/tools/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACnB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;CAClB,CAAC,CAAC;AAeH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,KAAK;IAExB,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,yDAAyD,EAAE,CAAC;IAC9F,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,qBAAqB,EAAE,CAAC;QACpF,CAAC;QACD,+CAA+C;QAC/C,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACrC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAW,EACX,KAAa;IAEb,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,yDAAyD,EAAE,CAAC;IAC9F,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,qBAAqB,EAAE,CAAC;QACpF,CAAC;QACD,MAAM,MAAM,GAAG,yBAAyB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uDAAuD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAClH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;AACH,CAAC"}
@@ -4,6 +4,7 @@ export interface SymbolResult {
4
4
  file: string;
5
5
  line: number;
6
6
  context: string;
7
+ surrounding?: string[];
7
8
  repo: string;
8
9
  }
9
10
  export interface SymbolSearchResult {
@@ -23,7 +24,7 @@ export declare function buildPattern(query: string, kind: string): string;
23
24
  * Search for symbol definitions (classes, functions, macros, enums) across CrossPad repos.
24
25
  * Only matches definition lines, not usages.
25
26
  */
26
- export declare function crosspadSearchSymbols(query: string, kind?: string, repos?: string[], maxResults?: number): SymbolSearchResult;
27
+ export declare function crosspadSearchSymbols(query: string, kind?: string, repos?: string[], maxResults?: number, contextLines?: number): SymbolSearchResult;
27
28
  /** @internal exported for testing */
28
29
  export declare function escapeForShell(s: string): string;
29
30
  /** @internal exported for testing */