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,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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"}
|
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) {
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/settings.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
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"}
|
package/dist/tools/symbols.d.ts
CHANGED
|
@@ -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 */
|