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
package/dist/utils/git.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
1
3
|
import { runCommand } from "./exec.js";
|
|
2
4
|
export function getRepoStatus(name, repoPath) {
|
|
3
5
|
const branch = runCommand("git branch --show-current", repoPath);
|
|
@@ -14,8 +16,25 @@ export function getRepoStatus(name, repoPath) {
|
|
|
14
16
|
.filter((l) => l.length > 0),
|
|
15
17
|
};
|
|
16
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the pinned commit hash of a submodule.
|
|
21
|
+
*
|
|
22
|
+
* `submodule` may be either a canonical name (e.g. "crosspad-core") or a
|
|
23
|
+
* relative path (e.g. "lib/crosspad-core"). Names are resolved via .gitmodules.
|
|
24
|
+
*/
|
|
17
25
|
export function getSubmodulePin(repoPath, submodule) {
|
|
18
|
-
|
|
26
|
+
// Resolve name → path if needed
|
|
27
|
+
let subPath = submodule;
|
|
28
|
+
const subs = listSubmodules(repoPath);
|
|
29
|
+
if (!subs[submodule] && Object.values(subs).includes(submodule)) {
|
|
30
|
+
// already a path, keep as-is
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const resolved = findSubmodulePath(repoPath, submodule);
|
|
34
|
+
if (resolved)
|
|
35
|
+
subPath = resolved;
|
|
36
|
+
}
|
|
37
|
+
const result = runCommand(`git submodule status "${subPath}"`, repoPath);
|
|
19
38
|
if (!result.success)
|
|
20
39
|
return null;
|
|
21
40
|
// Output format: " abc1234 submodule-name (desc)" or "+abc1234 ..."
|
|
@@ -26,4 +45,45 @@ export function getHead(repoPath) {
|
|
|
26
45
|
const result = runCommand("git rev-parse HEAD", repoPath);
|
|
27
46
|
return result.success ? result.stdout.trim() : null;
|
|
28
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Parse `.gitmodules` and return map of submodule name → path within parent.
|
|
50
|
+
* Returns empty map if no submodules or `.gitmodules` missing.
|
|
51
|
+
*
|
|
52
|
+
* Cached per repoPath since `.gitmodules` rarely changes during server lifetime.
|
|
53
|
+
*/
|
|
54
|
+
const submoduleMapCache = new Map();
|
|
55
|
+
export function listSubmodules(repoPath) {
|
|
56
|
+
const cached = submoduleMapCache.get(repoPath);
|
|
57
|
+
if (cached)
|
|
58
|
+
return cached;
|
|
59
|
+
const gitmodules = path.join(repoPath, ".gitmodules");
|
|
60
|
+
if (!fs.existsSync(gitmodules)) {
|
|
61
|
+
submoduleMapCache.set(repoPath, {});
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
// git config returns lines like: submodule.<name>.path <relative-path>
|
|
65
|
+
const result = runCommand(`git config -f .gitmodules --get-regexp "^submodule\\..*\\.path$"`, repoPath);
|
|
66
|
+
const map = {};
|
|
67
|
+
if (result.success) {
|
|
68
|
+
for (const line of result.stdout.split("\n")) {
|
|
69
|
+
const m = line.match(/^submodule\.(.+)\.path\s+(.+)$/);
|
|
70
|
+
if (m)
|
|
71
|
+
map[m[1]] = m[2].trim();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
submoduleMapCache.set(repoPath, map);
|
|
75
|
+
return map;
|
|
76
|
+
}
|
|
77
|
+
/** Resolve a submodule's path within a parent repo by canonical name. Null if not present. */
|
|
78
|
+
export function findSubmodulePath(repoPath, submoduleName) {
|
|
79
|
+
const subs = listSubmodules(repoPath);
|
|
80
|
+
if (subs[submoduleName])
|
|
81
|
+
return subs[submoduleName];
|
|
82
|
+
// Fallback: search by basename match (e.g. "crosspad-core" matching "lib/crosspad-core")
|
|
83
|
+
for (const [, p] of Object.entries(subs)) {
|
|
84
|
+
if (path.basename(p) === submoduleName)
|
|
85
|
+
return p;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
29
89
|
//# sourceMappingURL=git.js.map
|
package/dist/utils/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAUvC,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,QAAgB;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,2BAA2B,EAAE,QAAQ,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,UAAU,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,UAAU,CAAC,wBAAwB,EAAE,QAAQ,CAAC,CAAC;IAE9D,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QAC5B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE;QACvB,UAAU,EAAE,MAAM,CAAC,MAAM;aACtB,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,SAAiB;IAEjB,MAAM,MAAM,GAAG,UAAU,CACvB,
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ export interface RemoteResponse {
|
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* Send a JSON command to the running simulator and return the response.
|
|
11
|
+
* Retries up to MAX_RETRIES times on timeout errors (simulator may be loading).
|
|
11
12
|
* Opens a fresh TCP connection per call (simple, stateless).
|
|
12
13
|
*/
|
|
13
14
|
export declare function sendRemoteCommand(command: Record<string, unknown>): Promise<RemoteResponse>;
|
|
@@ -3,15 +3,66 @@
|
|
|
3
3
|
* Protocol: newline-delimited JSON over TCP on localhost:19840.
|
|
4
4
|
*/
|
|
5
5
|
import { Socket } from "net";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
/**
|
|
8
|
+
* Minimal contract enforced on every TCP simulator response.
|
|
9
|
+
* Body must be a JSON object with `ok` boolean. Anything else (array, scalar,
|
|
10
|
+
* missing `ok`) is treated as a malformed response — caller gets a synthetic
|
|
11
|
+
* `{ok:false, error:"..."}` so downstream code can rely on the shape.
|
|
12
|
+
*/
|
|
13
|
+
const RemoteEnvelopeSchema = z.object({ ok: z.boolean() }).passthrough();
|
|
14
|
+
function parseRemoteResponse(raw) {
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = JSON.parse(raw);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { ok: false, error: "invalid JSON response", raw };
|
|
21
|
+
}
|
|
22
|
+
const result = RemoteEnvelopeSchema.safeParse(parsed);
|
|
23
|
+
if (!result.success) {
|
|
24
|
+
return { ok: false, error: "malformed response (expected object with `ok` boolean)", raw };
|
|
25
|
+
}
|
|
26
|
+
return result.data;
|
|
27
|
+
}
|
|
28
|
+
const REMOTE_PORT = (() => {
|
|
29
|
+
const raw = process.env.CROSSPAD_REMOTE_PORT;
|
|
30
|
+
if (!raw)
|
|
31
|
+
return 19840;
|
|
32
|
+
const n = parseInt(raw, 10);
|
|
33
|
+
return Number.isFinite(n) && n > 0 && n < 65536 ? n : 19840;
|
|
34
|
+
})();
|
|
35
|
+
const REMOTE_HOST = process.env.CROSSPAD_REMOTE_HOST || "127.0.0.1";
|
|
8
36
|
const CONNECT_TIMEOUT = 3000;
|
|
9
37
|
const RESPONSE_TIMEOUT = 15000;
|
|
38
|
+
const MAX_RETRIES = 3;
|
|
39
|
+
const RETRY_DELAY_MS = 500;
|
|
40
|
+
function delay(ms) {
|
|
41
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
42
|
+
}
|
|
10
43
|
/**
|
|
11
44
|
* Send a JSON command to the running simulator and return the response.
|
|
45
|
+
* Retries up to MAX_RETRIES times on timeout errors (simulator may be loading).
|
|
12
46
|
* Opens a fresh TCP connection per call (simple, stateless).
|
|
13
47
|
*/
|
|
14
|
-
export function sendRemoteCommand(command) {
|
|
48
|
+
export async function sendRemoteCommand(command) {
|
|
49
|
+
let lastError;
|
|
50
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
51
|
+
try {
|
|
52
|
+
return await sendRemoteCommandOnce(command);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
lastError = err;
|
|
56
|
+
// Only retry on timeout, not on connection refused (simulator not running)
|
|
57
|
+
if (err.message?.includes("Connection refused"))
|
|
58
|
+
throw err;
|
|
59
|
+
if (attempt < MAX_RETRIES)
|
|
60
|
+
await delay(RETRY_DELAY_MS * attempt);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw lastError;
|
|
64
|
+
}
|
|
65
|
+
function sendRemoteCommandOnce(command) {
|
|
15
66
|
return new Promise((resolve, reject) => {
|
|
16
67
|
const socket = new Socket();
|
|
17
68
|
let buffer = "";
|
|
@@ -39,12 +90,7 @@ export function sendRemoteCommand(command) {
|
|
|
39
90
|
const line = buffer.slice(0, nlIdx);
|
|
40
91
|
resolved = true;
|
|
41
92
|
socket.destroy();
|
|
42
|
-
|
|
43
|
-
resolve(JSON.parse(line));
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
resolve({ ok: false, error: "invalid JSON response", raw: line });
|
|
47
|
-
}
|
|
93
|
+
resolve(parseRemoteResponse(line));
|
|
48
94
|
}
|
|
49
95
|
});
|
|
50
96
|
socket.on("timeout", () => {
|
|
@@ -64,12 +110,7 @@ export function sendRemoteCommand(command) {
|
|
|
64
110
|
if (!resolved) {
|
|
65
111
|
resolved = true;
|
|
66
112
|
if (buffer.length > 0) {
|
|
67
|
-
|
|
68
|
-
resolve(JSON.parse(buffer));
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
resolve({ ok: false, error: "incomplete response", raw: buffer });
|
|
72
|
-
}
|
|
113
|
+
resolve(parseRemoteResponse(buffer));
|
|
73
114
|
}
|
|
74
115
|
else {
|
|
75
116
|
reject(new Error("Connection closed without response"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-client.js","sourceRoot":"","sources":["../../src/utils/remote-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"remote-client.js","sourceRoot":"","sources":["../../src/utils/remote-client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crosspad-mcp-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"description": "MCP development server for CrossPad — build, test, manage apps, interact with simulator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"url": "https://github.com/CrossPad/crosspad-mcp.git"
|
|
26
26
|
},
|
|
27
27
|
"license": "MIT",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
28
31
|
"scripts": {
|
|
29
32
|
"build": "tsc",
|
|
30
33
|
"prepublishOnly": "tsc",
|
package/dist/tools/scaffold.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export interface ScaffoldParams {
|
|
2
|
-
name: string;
|
|
3
|
-
display_name?: string;
|
|
4
|
-
has_pad_logic?: boolean;
|
|
5
|
-
icon?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface ScaffoldResult {
|
|
8
|
-
files: Record<string, string>;
|
|
9
|
-
cmake_patch: {
|
|
10
|
-
file: string;
|
|
11
|
-
after_pattern: string;
|
|
12
|
-
content: string;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
export declare function crosspadScaffoldApp(params: ScaffoldParams): ScaffoldResult;
|
package/dist/tools/scaffold.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
export function crosspadScaffoldApp(params) {
|
|
2
|
-
const { name, display_name = name, has_pad_logic = false, icon = "CrossPad_Logo_110w.png", } = params;
|
|
3
|
-
const lower = name.toLowerCase();
|
|
4
|
-
const upper = name.toUpperCase();
|
|
5
|
-
const dir = `src/apps/${lower}`;
|
|
6
|
-
const files = {};
|
|
7
|
-
// --- CMakeLists.txt ---
|
|
8
|
-
const sources = [`\${CMAKE_CURRENT_SOURCE_DIR}/${name}App.cpp`];
|
|
9
|
-
if (has_pad_logic) {
|
|
10
|
-
sources.push(`\${CMAKE_CURRENT_SOURCE_DIR}/${name}PadLogic.cpp`);
|
|
11
|
-
}
|
|
12
|
-
files[`${dir}/CMakeLists.txt`] = `# ${display_name} app sources
|
|
13
|
-
set(${upper}_APP_SOURCES
|
|
14
|
-
${sources.join("\n ")}
|
|
15
|
-
PARENT_SCOPE
|
|
16
|
-
)
|
|
17
|
-
`;
|
|
18
|
-
// --- App header ---
|
|
19
|
-
files[`${dir}/${name}App.hpp`] = `#pragma once
|
|
20
|
-
|
|
21
|
-
#include "lvgl.h"
|
|
22
|
-
|
|
23
|
-
class App;
|
|
24
|
-
|
|
25
|
-
lv_obj_t* ${name}_create(lv_obj_t* parent, App* app);
|
|
26
|
-
void ${name}_destroy(lv_obj_t* app_obj);
|
|
27
|
-
`;
|
|
28
|
-
// --- App implementation ---
|
|
29
|
-
let appCpp = `/**
|
|
30
|
-
* @file ${name}App.cpp
|
|
31
|
-
* @brief ${display_name} app — LVGL GUI
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
#include "${name}App.hpp"
|
|
35
|
-
#include "pc_stubs/PcApp.hpp"
|
|
36
|
-
#include "pc_stubs/pc_platform.h"
|
|
37
|
-
|
|
38
|
-
#include <crosspad/app/AppRegistry.hpp>
|
|
39
|
-
#include <crosspad/pad/PadManager.hpp>
|
|
40
|
-
#include "crosspad-gui/components/app_lifecycle.h"
|
|
41
|
-
#include "crosspad-gui/platform/IGuiPlatform.h"
|
|
42
|
-
#include "crosspad_app.hpp"
|
|
43
|
-
|
|
44
|
-
#include "lvgl.h"
|
|
45
|
-
|
|
46
|
-
#include <cstdio>
|
|
47
|
-
`;
|
|
48
|
-
if (has_pad_logic) {
|
|
49
|
-
appCpp += `#include "${name}PadLogic.hpp"
|
|
50
|
-
#include <memory>
|
|
51
|
-
|
|
52
|
-
static std::shared_ptr<${name}PadLogic> s_padLogic;
|
|
53
|
-
`;
|
|
54
|
-
}
|
|
55
|
-
appCpp += `
|
|
56
|
-
static App* s_app = nullptr;
|
|
57
|
-
|
|
58
|
-
/* ── App create / destroy ────────────────────────────────────────────── */
|
|
59
|
-
|
|
60
|
-
lv_obj_t* ${name}_create(lv_obj_t* parent, App* a)
|
|
61
|
-
{
|
|
62
|
-
s_app = a;
|
|
63
|
-
lv_obj_t* cont = lv_obj_create(parent);
|
|
64
|
-
lv_obj_set_size(cont, lv_pct(100), lv_pct(100));
|
|
65
|
-
lv_obj_set_style_bg_color(cont, lv_color_black(), 0);
|
|
66
|
-
lv_obj_set_style_bg_opa(cont, LV_OPA_COVER, 0);
|
|
67
|
-
lv_obj_set_style_pad_all(cont, 4, 0);
|
|
68
|
-
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
|
|
69
|
-
lv_obj_set_style_pad_row(cont, 2, 0);
|
|
70
|
-
lv_obj_remove_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
|
|
71
|
-
|
|
72
|
-
/* ── Title bar with close button ─────────────────────────── */
|
|
73
|
-
lv_obj_t* titleBar = lv_obj_create(cont);
|
|
74
|
-
lv_obj_set_size(titleBar, lv_pct(100), 24);
|
|
75
|
-
lv_obj_set_style_bg_opa(titleBar, LV_OPA_TRANSP, 0);
|
|
76
|
-
lv_obj_set_style_border_width(titleBar, 0, 0);
|
|
77
|
-
lv_obj_set_style_pad_all(titleBar, 0, 0);
|
|
78
|
-
lv_obj_remove_flag(titleBar, LV_OBJ_FLAG_SCROLLABLE);
|
|
79
|
-
|
|
80
|
-
lv_obj_t* titleLabel = lv_label_create(titleBar);
|
|
81
|
-
lv_label_set_text(titleLabel, "${display_name}");
|
|
82
|
-
lv_obj_set_style_text_color(titleLabel, lv_color_white(), 0);
|
|
83
|
-
lv_obj_set_style_text_font(titleLabel, &lv_font_montserrat_14, 0);
|
|
84
|
-
lv_obj_align(titleLabel, LV_ALIGN_LEFT_MID, 4, 0);
|
|
85
|
-
|
|
86
|
-
lv_obj_t* closeBtn = lv_button_create(titleBar);
|
|
87
|
-
lv_obj_set_size(closeBtn, 28, 20);
|
|
88
|
-
lv_obj_align(closeBtn, LV_ALIGN_RIGHT_MID, -2, 0);
|
|
89
|
-
lv_obj_set_style_bg_color(closeBtn, lv_color_hex(0x662222), 0);
|
|
90
|
-
lv_obj_set_style_bg_color(closeBtn, lv_color_hex(0xAA3333), LV_STATE_PRESSED);
|
|
91
|
-
lv_obj_set_style_radius(closeBtn, 4, 0);
|
|
92
|
-
lv_obj_set_style_shadow_width(closeBtn, 0, 0);
|
|
93
|
-
lv_obj_t* closeLbl = lv_label_create(closeBtn);
|
|
94
|
-
lv_label_set_text(closeLbl, "X");
|
|
95
|
-
lv_obj_set_style_text_font(closeLbl, &lv_font_montserrat_12, 0);
|
|
96
|
-
lv_obj_center(closeLbl);
|
|
97
|
-
lv_obj_add_event_cb(closeBtn, [](lv_event_t*) {
|
|
98
|
-
if (s_app) crosspad_gui::app_request_close(s_app);
|
|
99
|
-
}, LV_EVENT_CLICKED, nullptr);
|
|
100
|
-
`;
|
|
101
|
-
if (has_pad_logic) {
|
|
102
|
-
appCpp += `
|
|
103
|
-
/* ── Register pad logic ──────────────────────────────────── */
|
|
104
|
-
s_padLogic = std::make_shared<${name}PadLogic>();
|
|
105
|
-
crosspad::getPadManager().registerPadLogic("${name}", s_padLogic);
|
|
106
|
-
|
|
107
|
-
if (a) {
|
|
108
|
-
a->setOnShow([](lv_obj_t*) {
|
|
109
|
-
crosspad::getPadManager().setActivePadLogic("${name}");
|
|
110
|
-
crosspad_app_update_pad_icon();
|
|
111
|
-
});
|
|
112
|
-
a->setOnHide([](lv_obj_t*) {
|
|
113
|
-
crosspad::getPadManager().setActivePadLogic("");
|
|
114
|
-
crosspad_app_update_pad_icon();
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
`;
|
|
118
|
-
}
|
|
119
|
-
appCpp += `
|
|
120
|
-
/* ── TODO: Add your UI here ──────────────────────────────── */
|
|
121
|
-
|
|
122
|
-
printf("[${name}] App created\\n");
|
|
123
|
-
return cont;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
void ${name}_destroy(lv_obj_t* app_obj)
|
|
127
|
-
{
|
|
128
|
-
`;
|
|
129
|
-
if (has_pad_logic) {
|
|
130
|
-
appCpp += ` crosspad::getPadManager().setActivePadLogic("");
|
|
131
|
-
crosspad::getPadManager().unregisterPadLogic("${name}");
|
|
132
|
-
crosspad_app_update_pad_icon();
|
|
133
|
-
s_padLogic.reset();
|
|
134
|
-
`;
|
|
135
|
-
}
|
|
136
|
-
appCpp += ` s_app = nullptr;
|
|
137
|
-
lv_obj_delete_async(app_obj);
|
|
138
|
-
printf("[${name}] App destroyed\\n");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/* ── App registration ────────────────────────────────────────────────── */
|
|
142
|
-
|
|
143
|
-
void _register_${name}_app() {
|
|
144
|
-
static char icon_path[256];
|
|
145
|
-
snprintf(icon_path, sizeof(icon_path), "%s${icon}",
|
|
146
|
-
crosspad_gui::getGuiPlatform().assetPathPrefix());
|
|
147
|
-
|
|
148
|
-
static const crosspad::AppEntry entry = {
|
|
149
|
-
"${name}", icon_path, ${name}_create, ${name}_destroy,
|
|
150
|
-
nullptr, nullptr, nullptr, nullptr, 0
|
|
151
|
-
};
|
|
152
|
-
crosspad::AppRegistry::getInstance().registerApp(entry);
|
|
153
|
-
}
|
|
154
|
-
`;
|
|
155
|
-
files[`${dir}/${name}App.cpp`] = appCpp;
|
|
156
|
-
// --- Pad logic (optional) ---
|
|
157
|
-
if (has_pad_logic) {
|
|
158
|
-
files[`${dir}/${name}PadLogic.hpp`] = `#pragma once
|
|
159
|
-
|
|
160
|
-
#include <crosspad/pad/IPadLogicHandler.hpp>
|
|
161
|
-
|
|
162
|
-
class ${name}PadLogic : public crosspad::IPadLogicHandler {
|
|
163
|
-
public:
|
|
164
|
-
void onPadPressed(uint8_t padIndex, uint8_t velocity) override;
|
|
165
|
-
void onPadReleased(uint8_t padIndex) override;
|
|
166
|
-
};
|
|
167
|
-
`;
|
|
168
|
-
files[`${dir}/${name}PadLogic.cpp`] = `#include "${name}PadLogic.hpp"
|
|
169
|
-
#include <cstdio>
|
|
170
|
-
|
|
171
|
-
void ${name}PadLogic::onPadPressed(uint8_t padIndex, uint8_t velocity)
|
|
172
|
-
{
|
|
173
|
-
printf("[${name}PadLogic] Pad %d pressed (vel=%d)\\n", padIndex, velocity);
|
|
174
|
-
// TODO: Implement pad press logic
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
void ${name}PadLogic::onPadReleased(uint8_t padIndex)
|
|
178
|
-
{
|
|
179
|
-
printf("[${name}PadLogic] Pad %d released\\n", padIndex);
|
|
180
|
-
// TODO: Implement pad release logic
|
|
181
|
-
}
|
|
182
|
-
`;
|
|
183
|
-
}
|
|
184
|
-
// --- CMake patch instructions ---
|
|
185
|
-
const cmakePatch = {
|
|
186
|
-
file: "CMakeLists.txt",
|
|
187
|
-
after_pattern: "add_subdirectory(src/apps/",
|
|
188
|
-
content: `add_subdirectory(${dir})\nlist(APPEND MAIN_SOURCES \${${upper}_APP_SOURCES})`,
|
|
189
|
-
};
|
|
190
|
-
return { files, cmake_patch: cmakePatch };
|
|
191
|
-
}
|
|
192
|
-
//# sourceMappingURL=scaffold.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/tools/scaffold.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,mBAAmB,CAAC,MAAsB;IACxD,MAAM,EACJ,IAAI,EACJ,YAAY,GAAG,IAAI,EACnB,aAAa,GAAG,KAAK,EACrB,IAAI,GAAG,wBAAwB,GAChC,GAAG,MAAM,CAAC;IAEX,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,YAAY,KAAK,EAAE,CAAC;IAEhC,MAAM,KAAK,GAA2B,EAAE,CAAC;IAEzC,yBAAyB;IACzB,MAAM,OAAO,GAAG,CAAC,gCAAgC,IAAI,SAAS,CAAC,CAAC;IAChE,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,gCAAgC,IAAI,cAAc,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,GAAG,GAAG,iBAAiB,CAAC,GAAG,KAAK,YAAY;MAC9C,KAAK;MACL,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;;;CAG3B,CAAC;IAEA,qBAAqB;IACrB,KAAK,CAAC,GAAG,GAAG,IAAI,IAAI,SAAS,CAAC,GAAG;;;;;;YAMvB,IAAI;OACT,IAAI;CACV,CAAC;IAEA,6BAA6B;IAC7B,IAAI,MAAM,GAAG;WACJ,IAAI;YACH,YAAY;;;YAGZ,IAAI;;;;;;;;;;;;;CAaf,CAAC;IAEA,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,IAAI,aAAa,IAAI;;;yBAGN,IAAI;CAC5B,CAAC;IACA,CAAC;IAED,MAAM,IAAI;;;;;YAKA,IAAI;;;;;;;;;;;;;;;;;;;;;qCAqBqB,YAAY;;;;;;;;;;;;;;;;;;;CAmBhD,CAAC;IAEA,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,IAAI;;oCAEsB,IAAI;kDACU,IAAI;;;;2DAIK,IAAI;;;;;;;;CAQ9D,CAAC;IACA,CAAC;IAED,MAAM,IAAI;;;eAGG,IAAI;;;;OAIZ,IAAI;;CAEV,CAAC;IAEA,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,IAAI;oDACsC,IAAI;;;CAGvD,CAAC;IACA,CAAC;IAED,MAAM,IAAI;;eAEG,IAAI;;;;;iBAKF,IAAI;;gDAE2B,IAAI;;;;WAIzC,IAAI,iBAAiB,IAAI,YAAY,IAAI;;;;;CAKnD,CAAC;IAEA,KAAK,CAAC,GAAG,GAAG,IAAI,IAAI,SAAS,CAAC,GAAG,MAAM,CAAC;IAExC,+BAA+B;IAC/B,IAAI,aAAa,EAAE,CAAC;QAClB,KAAK,CAAC,GAAG,GAAG,IAAI,IAAI,cAAc,CAAC,GAAG;;;;QAIlC,IAAI;;;;;CAKX,CAAC;QAEE,KAAK,CAAC,GAAG,GAAG,IAAI,IAAI,cAAc,CAAC,GAAG,aAAa,IAAI;;;OAGpD,IAAI;;eAEI,IAAI;;;;OAIZ,IAAI;;eAEI,IAAI;;;CAGlB,CAAC;IACA,CAAC;IAED,mCAAmC;IACnC,MAAM,UAAU,GAAG;QACjB,IAAI,EAAE,gBAAgB;QACtB,aAAa,EAAE,4BAA4B;QAC3C,OAAO,EAAE,oBAAoB,GAAG,kCAAkC,KAAK,gBAAgB;KACxF,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AAC5C,CAAC"}
|