@rainbow-robotics/muscat-plugin-kit 1.10.1 → 1.10.2-dev.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/cli/src/dev.mjs +2 -1
- package/cli/src/muscatLocal.mjs +20 -4
- package/cli/src/util.mjs +3 -3
- package/cli/storybook-dist/project.json +1 -1
- package/cli/templates/common/py/main.py +4 -4
- package/cli/templates/cpp/cpp/main.cpp +2 -2
- package/cli/templates/readme-cpp/README.md +7 -5
- package/package.json +3 -3
package/cli/src/dev.mjs
CHANGED
|
@@ -115,7 +115,8 @@ export async function runDev(args = []) {
|
|
|
115
115
|
ensureDocker();
|
|
116
116
|
const { robotIp, robotToken } = await promptRobotConnection(args);
|
|
117
117
|
process.env.MUSCAT_ROBOT_HOST = robotIp;
|
|
118
|
-
|
|
118
|
+
// Even when empty: the dev:back child (stdin ignored) must not prompt for the token again.
|
|
119
|
+
process.env.MUSCAT_ROBOT_TOKEN = robotToken;
|
|
119
120
|
|
|
120
121
|
const remoteRobot = isRemoteRobot(robotIp);
|
|
121
122
|
const hostAgent = await maybeStartHostAgent(root, { robotIp, robotToken });
|
package/cli/src/muscatLocal.mjs
CHANGED
|
@@ -29,10 +29,26 @@ const dockerArch = () => {
|
|
|
29
29
|
return a === "arm64" || a === "amd64" ? a : process.arch === "arm64" ? "arm64" : "amd64";
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
// Node's fetch reports every network error as "fetch failed"; the real reason (ECONNRESET, ...) is in `cause`.
|
|
33
|
+
const fetchErrorReason = (e) => e.cause?.code ?? e.code ?? e.cause?.message ?? e.message;
|
|
34
|
+
|
|
35
|
+
// The S3 zips are ~200MB, so a dropped connection mid-download is retried. 4xx is not.
|
|
36
|
+
export async function fetchBuffer(url, attempts = 3) {
|
|
37
|
+
for (let i = 1; ; i++) {
|
|
38
|
+
let err;
|
|
39
|
+
try {
|
|
40
|
+
const res = await fetch(url);
|
|
41
|
+
if (res.ok) return Buffer.from(await res.arrayBuffer());
|
|
42
|
+
err = new Error(`HTTP ${res.status}: ${url}`);
|
|
43
|
+
if (res.status < 500 && res.status !== 429) throw err;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
if (e === err) throw e;
|
|
46
|
+
err = new Error(`fetch failed (${fetchErrorReason(e)}): ${url}`, { cause: e });
|
|
47
|
+
}
|
|
48
|
+
if (i >= attempts) throw err;
|
|
49
|
+
log.warn(`${err.message} — retrying (${i + 1}/${attempts})…`);
|
|
50
|
+
await new Promise((r) => setTimeout(r, 1000 * i));
|
|
51
|
+
}
|
|
36
52
|
}
|
|
37
53
|
|
|
38
54
|
// macOS/Windows `tar` reads zip; GNU tar does not, Linux has `unzip`.
|
package/cli/src/util.mjs
CHANGED
|
@@ -137,9 +137,10 @@ export async function prompt(question, fallback = "") {
|
|
|
137
137
|
const LOCAL_HOSTS = new Set(["", "localhost", "127.0.0.1", "::1"]);
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
* Ask for robot IP (and token if remote). Returns { robotIp, robotToken }.
|
|
140
|
+
* Ask for robot IP (and optional token if remote). Returns { robotIp, robotToken }.
|
|
141
141
|
* Skips prompts if already set in process.env (from a parent command like `dev`).
|
|
142
142
|
* Supports --robot-ip / --robot-token flags for non-interactive use.
|
|
143
|
+
* An empty token is allowed: the robot API is then called without an Authorization header.
|
|
143
144
|
*/
|
|
144
145
|
export async function promptRobotConnection(args = []) {
|
|
145
146
|
const parsed = parseArgs(args);
|
|
@@ -153,9 +154,8 @@ export async function promptRobotConnection(args = []) {
|
|
|
153
154
|
const robotToken =
|
|
154
155
|
parsed["robot-token"] ??
|
|
155
156
|
process.env.MUSCAT_ROBOT_TOKEN ??
|
|
156
|
-
(await prompt(" SDK Token (
|
|
157
|
+
(await prompt(" SDK Token (optional, Enter to skip): "));
|
|
157
158
|
|
|
158
|
-
if (!robotToken) throw new Error("SDK token is required for remote robot connection.");
|
|
159
159
|
return { robotIp, robotToken };
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"generatedAt":
|
|
1
|
+
{"generatedAt":1792687510358,"userSince":1750997484097,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"testPackages":{"@vitest/browser":"3.2.4","@vitest/coverage-v8":"3.2.4","playwright":"1.59.1","vitest":"3.2.4"},"hasRouterPackage":false,"monorepo":"Turborepo","packageManager":{"type":"yarn","version":"berry","agent":"yarn@berry"},"preview":{"usesGlobals":false},"framework":{"name":"@storybook/react-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/react","portableStoriesFileCount":0,"applicationFileCount":0,"storybookVersion":"8.6.18","storybookVersionSpecifier":"^8.6.4","language":"typescript","storybookPackages":{"@chromatic-com/storybook":{"version":"3.2.7"},"@storybook/addon-essentials":{"version":"8.6.18"},"@storybook/addon-links":{"version":"8.6.18"},"@storybook/addon-onboarding":{"version":"8.6.18"},"@storybook/addon-themes":{"version":"8.6.18"},"@storybook/blocks":{"version":"8.6.18"},"@storybook/experimental-addon-test":{"version":"8.6.18"},"@storybook/react":{"version":"8.6.18"},"@storybook/react-vite":{"version":"8.6.18"},"@storybook/test":{"version":"8.6.18"},"@storybook/theming":{"version":"8.6.18"},"eslint-plugin-storybook":{"version":"0.11.6"},"storybook":{"version":"8.6.18"},"storybook-addon-react-docgen":{"version":"1.2.44"}},"addons":{"$SNIP/node_modules/@storybook/addon-links":{"version":null},"$SNIP/node_modules/@storybook/addon-essentials":{"version":null},"$SNIP/node_modules/@chromatic-com/storybook":{"version":null},"$SNIP/node_modules/@storybook/addon-themes":{"version":null},"$SNIP/node_modules/@storybook/experimental-addon-test":{"version":null}}}
|
|
@@ -8,7 +8,7 @@ On-robot (default):
|
|
|
8
8
|
Remote dev (from your laptop):
|
|
9
9
|
Set env vars before running:
|
|
10
10
|
MUSCAT_ROBOT_HOST=192.168.1.100
|
|
11
|
-
MUSCAT_ROBOT_TOKEN=<service token>
|
|
11
|
+
MUSCAT_ROBOT_TOKEN=<service token> (optional; needed only when the robot's login policy is on)
|
|
12
12
|
Then: muscat-pk dev:back
|
|
13
13
|
|
|
14
14
|
Handlers:
|
|
@@ -90,9 +90,9 @@ def move_j_example():
|
|
|
90
90
|
|
|
91
91
|
async def main():
|
|
92
92
|
robot_host = os.getenv("MUSCAT_ROBOT_HOST")
|
|
93
|
-
robot_token = os.getenv("MUSCAT_ROBOT_TOKEN")
|
|
93
|
+
robot_token = os.getenv("MUSCAT_ROBOT_TOKEN", "") # empty is fine when the login policy is off
|
|
94
94
|
|
|
95
|
-
if robot_host
|
|
95
|
+
if robot_host:
|
|
96
96
|
# Remote dev: connect to the robot before registering any handlers.
|
|
97
97
|
# connect() closes and reopens the Zenoh session, so handlers registered
|
|
98
98
|
# before this call would be lost.
|
|
@@ -113,7 +113,7 @@ async def main():
|
|
|
113
113
|
except (KeyboardInterrupt, asyncio.CancelledError):
|
|
114
114
|
pass
|
|
115
115
|
finally:
|
|
116
|
-
if robot_host
|
|
116
|
+
if robot_host:
|
|
117
117
|
await manipulate.disconnect()
|
|
118
118
|
print(f"[{PLUGIN_NAME}] stopped")
|
|
119
119
|
|
|
@@ -30,8 +30,8 @@ int main() {
|
|
|
30
30
|
// Remote dev: connect before registering handlers (connect() reopens the session).
|
|
31
31
|
RBManipulateSDK manipulate;
|
|
32
32
|
const char* host = std::getenv("MUSCAT_ROBOT_HOST");
|
|
33
|
-
const char* token = std::getenv("MUSCAT_ROBOT_TOKEN");
|
|
34
|
-
if (host
|
|
33
|
+
const char* token = std::getenv("MUSCAT_ROBOT_TOKEN"); // optional: needed only when the login policy is on
|
|
34
|
+
if (host) manipulate.connect({.token = token ? token : "", .host = host});
|
|
35
35
|
|
|
36
36
|
// plugin id comes from RB_PLUGIN_ID.
|
|
37
37
|
auto plugin = RBPluginCall::get_instance(RBPluginCall::resolve_plugin_id(std::nullopt));
|
|
@@ -531,14 +531,16 @@ manipulate.move.call_move_j("C500920", t, std::nullopt, MoveSpeedArg{1, 60.f, 12
|
|
|
531
531
|
manipulate.move.call_move_wait("C500920", -1);
|
|
532
532
|
```
|
|
533
533
|
|
|
534
|
-
Remote dev (`muscat-pk dev --robot-ip <ip> --robot-token <token
|
|
534
|
+
Remote dev (`muscat-pk dev --robot-ip <ip> [--robot-token <token>]`) sets
|
|
535
535
|
`MUSCAT_ROBOT_HOST` / `MUSCAT_ROBOT_TOKEN`; connect **before** registering
|
|
536
|
-
subscriptions, because `connect()` reopens the Zenoh session
|
|
536
|
+
subscriptions, because `connect()` reopens the Zenoh session. The token is
|
|
537
|
+
optional — it is needed only when the robot's login policy is on:
|
|
537
538
|
|
|
538
539
|
```cpp
|
|
539
|
-
if (const char* host = std::getenv("MUSCAT_ROBOT_HOST"))
|
|
540
|
-
|
|
541
|
-
|
|
540
|
+
if (const char* host = std::getenv("MUSCAT_ROBOT_HOST")) {
|
|
541
|
+
const char* token = std::getenv("MUSCAT_ROBOT_TOKEN");
|
|
542
|
+
manipulate.connect({.token = token ? token : "", .host = host});
|
|
543
|
+
}
|
|
542
544
|
```
|
|
543
545
|
|
|
544
546
|
AMR and RB-Y1 SDKs are Python-only for now.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rainbow-robotics/muscat-plugin-kit",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.2-dev.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20"
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
|
-
"@rainbow-robotics/plugin-ui": "1.10.
|
|
56
|
-
"@rainbow-robotics/preview-host": "1.10.
|
|
55
|
+
"@rainbow-robotics/plugin-ui": "1.10.2-dev.0",
|
|
56
|
+
"@rainbow-robotics/preview-host": "1.10.2-dev.0",
|
|
57
57
|
"@types/react": "^19.0.10",
|
|
58
58
|
"postcss": "^8.5.8",
|
|
59
59
|
"typescript": "^5.8.0",
|