@kvell007/embed-labs-local-bridge 0.1.0-alpha.11 → 0.1.0-alpha.111

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 (50) hide show
  1. package/README.md +80 -24
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.js +130 -4
  4. package/package.json +10 -5
  5. package/dist/adapters/debug.d.ts +0 -2
  6. package/dist/adapters/debug.js +0 -124
  7. package/dist/adapters/debug.js.map +0 -1
  8. package/dist/adapters/deploy.d.ts +0 -5
  9. package/dist/adapters/deploy.js +0 -132
  10. package/dist/adapters/deploy.js.map +0 -1
  11. package/dist/adapters/flash.d.ts +0 -3
  12. package/dist/adapters/flash.js +0 -169
  13. package/dist/adapters/flash.js.map +0 -1
  14. package/dist/adapters/logo.d.ts +0 -2
  15. package/dist/adapters/logo.js +0 -108
  16. package/dist/adapters/logo.js.map +0 -1
  17. package/dist/adapters/network.d.ts +0 -22
  18. package/dist/adapters/network.js +0 -64
  19. package/dist/adapters/network.js.map +0 -1
  20. package/dist/adapters/rp2350-monitor.d.ts +0 -121
  21. package/dist/adapters/rp2350-monitor.js +0 -404
  22. package/dist/adapters/rp2350-monitor.js.map +0 -1
  23. package/dist/adapters/serial.d.ts +0 -3
  24. package/dist/adapters/serial.js +0 -133
  25. package/dist/adapters/serial.js.map +0 -1
  26. package/dist/adapters/taishanpi-live.d.ts +0 -163
  27. package/dist/adapters/taishanpi-live.js +0 -349
  28. package/dist/adapters/taishanpi-live.js.map +0 -1
  29. package/dist/adapters/uf2.d.ts +0 -1
  30. package/dist/adapters/uf2.js +0 -53
  31. package/dist/adapters/uf2.js.map +0 -1
  32. package/dist/adapters/usb.d.ts +0 -3
  33. package/dist/adapters/usb.js +0 -102
  34. package/dist/adapters/usb.js.map +0 -1
  35. package/dist/hardware.d.ts +0 -19
  36. package/dist/hardware.js +0 -417
  37. package/dist/hardware.js.map +0 -1
  38. package/dist/index.js.map +0 -1
  39. package/dist/jobs.d.ts +0 -4
  40. package/dist/jobs.js +0 -125
  41. package/dist/jobs.js.map +0 -1
  42. package/dist/process.d.ts +0 -13
  43. package/dist/process.js +0 -128
  44. package/dist/process.js.map +0 -1
  45. package/dist/server.d.ts +0 -6
  46. package/dist/server.js +0 -242
  47. package/dist/server.js.map +0 -1
  48. package/dist/tools.d.ts +0 -3
  49. package/dist/tools.js +0 -1254
  50. package/dist/tools.js.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @embed-labs/local-bridge
2
2
 
3
- Local HTTP bridge service for Embed Labs Cloud hardware discovery, bounded local
3
+ Local HTTP bridge service for EmbedLabs hardware discovery, bounded local
4
4
  operations, and guarded flash planning.
5
5
 
6
6
  ## Package Status
@@ -12,16 +12,24 @@ are complete.
12
12
 
13
13
  ## What It Provides
14
14
 
15
- - `embed-local-bridge` binary.
16
- - `startServer()` library entry point.
15
+ - `embed-local-bridge` npm launcher.
16
+ - Native Go bridge binaries delivered through platform optional packages:
17
+ `@embed-labs/local-bridge-darwin-arm64`,
18
+ `@embed-labs/local-bridge-linux-x64`,
19
+ `@embed-labs/local-bridge-linux-arm64`, and
20
+ `@embed-labs/local-bridge-win32-x64` / `win32-arm64`.
17
21
  - Local health endpoint.
18
- - Device discovery for serial ports, RP2350-compatible UF2 volumes, Rockchip
19
- USB Loader/Maskrom style devices, and the current TaishanPi USB ECM probe.
22
+ - Event-maintained device inventory for serial ports, RP2350-compatible UF2
23
+ volumes, Rockchip USB Loader/Maskrom style devices, RP2350 Monitor endpoints,
24
+ and TaishanPi USB ECM or configured-host probes.
20
25
  - Bounded TCP, serial path, serial capture, and SSH command probes.
21
26
  - Non-destructive debug tool availability scans for OpenOCD, probe-rs, pyOCD,
22
27
  and SEGGER J-Link command-line tools.
23
28
  - Flash plan endpoints and local job tracking.
24
- - Shared response contracts from `@embed-labs/protocol`.
29
+ - RP2350/Pico 2 monitor capability catalog plus first-class GPIO, UART, I2C,
30
+ SPI, logic-analyzer, Wi-Fi, and debug-probe operations routed through the
31
+ shared `/api/operation` bridge.
32
+ - Stable HTTP/JSON response contracts used by the CLI and agent plugins.
25
33
 
26
34
  ## Install
27
35
 
@@ -50,19 +58,20 @@ The bridge listens on `127.0.0.1:18083` by default.
50
58
  EMBED_BRIDGE_HOST=127.0.0.1 EMBED_BRIDGE_PORT=18083 embed-local-bridge
51
59
  ```
52
60
 
53
- Library usage:
54
-
55
- ```ts
56
- import { startServer } from "@embed-labs/local-bridge";
57
-
58
- const server = startServer({ host: "127.0.0.1", port: 18083 });
59
- ```
61
+ This package no longer exports a TypeScript `startServer()` runtime. It is a
62
+ small JavaScript launcher for the Go binary. If optional dependencies were
63
+ omitted during install, reinstall without `--omit=optional`.
60
64
 
61
65
  ## HTTP Surface
62
66
 
63
67
  - `GET /healthz`
64
68
  - `GET /v1/devices`
69
+ - `GET /v1/devices?refresh=1`
70
+ - `GET /v1/devices/<local_device_id>`
71
+ - `GET /v1/devices/stream`
65
72
  - `GET /v1/debug/tools`
73
+ - `GET /v1/tools/capabilities`
74
+ - `POST /v1/tools/invoke`
66
75
  - `POST /v1/devices/probe`
67
76
  - `GET /v1/serial/ports`
68
77
  - `POST /v1/serial/capture`
@@ -71,33 +80,79 @@ const server = startServer({ host: "127.0.0.1", port: 18083 });
71
80
  - `POST /v1/flash/run`
72
81
  - `GET /v1/jobs`
73
82
  - `GET /v1/jobs/<local_job_id>`
83
+ - RP2350 Monitor paths: `GET /api/health`, `GET /api/snapshot`,
84
+ `POST /api/operation`, `GET /api/stream`, and `/rp2350-monitor/`.
85
+ These paths are served by the Go bridge itself. The Go runtime opens the
86
+ selected RP2350 USB CDC or Wi-Fi/TCP transport directly, maintains the
87
+ Monitor snapshot, publishes SSE updates, and serves the browser UI from the
88
+ installed runtime package. It no longer starts or depends on a Python
89
+ `rpmon_bridge.py` process.
74
90
 
75
91
  Examples:
76
92
 
77
93
  ```bash
78
94
  curl -fsS http://127.0.0.1:18083/healthz
79
95
  curl -fsS http://127.0.0.1:18083/v1/devices
96
+ curl -fsS http://127.0.0.1:18083/v1/devices?refresh=1
80
97
  curl -fsS http://127.0.0.1:18083/v1/debug/tools
81
98
  curl -fsS http://127.0.0.1:18083/v1/devices/probe \
82
99
  -H 'content-type: application/json' \
83
100
  -d '{"host":"198.19.77.2","ports":[22,15301],"timeout_ms":1000}'
101
+ curl -fsS http://127.0.0.1:18083/v1/tools/invoke \
102
+ -H 'content-type: application/json' \
103
+ -d '{"capability_id":"rp2350.monitor.capabilities","input":{}}'
104
+ curl -fsS http://127.0.0.1:18083/v1/tools/invoke \
105
+ -H 'content-type: application/json' \
106
+ -d '{"capability_id":"rp2350.monitor.gpio.read","approved":true,"input":{"pins":[16,17],"pull":"none"}}'
107
+ curl -fsS http://127.0.0.1:18083/v1/tools/invoke \
108
+ -H 'content-type: application/json' \
109
+ -d '{"capability_id":"rp2350.monitor.spi.transfer","approved":true,"input":{"hex":"a55a3cc3"}}'
84
110
  ```
85
111
 
112
+ RP2350/Pico 2 monitor capabilities are intentionally exposed as a complete
113
+ hardware surface: `rp2350.monitor.capabilities`, `status`, `gpio.read`,
114
+ `gpio.write`, `uart.write`, `i2c.transfer`, `spi.transfer`, `logic.capture`,
115
+ `logic.decode`, `wifi.manage`, `probe.debug`, `operation`, and legacy
116
+ `command`. Agents should ask for the catalog first when the protocol or
117
+ operation is unclear, then use the specific tool rather than scraping the
118
+ monitor UI.
119
+
120
+ `GET /v1/devices` and `/v1/devices/stream` read the bridge's current
121
+ in-memory inventory. They do not perform hardware scans as a side effect. The
122
+ bridge keeps that inventory warm through startup refresh, platform device
123
+ events, cheap locator polling, and a low-frequency fallback scan. Use
124
+ `/v1/devices?refresh=1` or the `device.scan` tool only for explicit diagnostic
125
+ refreshes.
126
+
86
127
  ## Hardware Support Boundary
87
128
 
88
129
  Current local behavior is intentionally narrow:
89
130
 
90
- - Device discovery can report serial ports, RP2350 UF2 boot volumes,
91
- Rockchip-style USB Loader/Maskrom matches, and TaishanPi USB ECM reachability
92
- at the current default probe address.
131
+ - Device discovery observes OS USB/serial/network changes without claiming or
132
+ opening unrelated peripherals. The main inventory promotes only EmbedLabs
133
+ manageable development-board records: initialized board runtimes, RP2350
134
+ BOOTSEL/UF2 download targets, Rockchip-style USB Loader/Maskrom matches,
135
+ and TaishanPi USB ECM/runtime candidates. Generic USB devices, hubs, cameras,
136
+ debuggers, storage devices, and unrelated serial ports remain diagnostic
137
+ evidence only and are not operation targets.
138
+ - First-use boards that have no initialization image are handled through their
139
+ download mode. RP2350/Pico boards must enumerate as BOOTSEL/UF2, and
140
+ TaishanPi/RK3566 boards must enumerate as Loader/Maskrom/RockUSB or an
141
+ explicit user-selected target before initialization flashing. If an empty
142
+ board does not enumerate at all, the bridge cannot identify it; the user must
143
+ enter the board's download mode or explicitly select the board type before an
144
+ approved initialization flash plan can be built.
93
145
  - Debug tool scans only check PATH and bounded version/help command evidence;
94
146
  they do not open probes, start GDB servers, or create debug sessions.
95
147
  - RP2350 UF2 flashing copies a `.uf2` artifact to a mounted UF2 volume only
96
148
  after a ready flash plan and explicit approval.
97
- - TaishanPi image-set planning can check required image files and
98
- `rkdeveloptool` availability, but real destructive TaishanPi flashing is
99
- guarded and not enabled. The bridge returns a blocked job until the exact
100
- hardware profile and Board Pack command templates are accepted.
149
+ - RP2350 Monitor protocol operations are exposed through the capability catalog
150
+ and specific local tools. Agents should not scrape the monitor UI or call raw
151
+ serial/TCP endpoints to learn operation formats.
152
+ - TaishanPi initialization image flashing resolves the installed SDK
153
+ `images/current` set when `image_dir` is omitted, parses `parameter.txt`
154
+ partition offsets, and runs the guarded `rkdeveloptool` flow only after a
155
+ ready plan and explicit approval.
101
156
 
102
157
  These behaviors are local evidence and planning tools, not broad board support
103
158
  claims.
@@ -107,14 +162,15 @@ claims.
107
162
  - The default bind address is localhost. Do not expose the bridge on a shared
108
163
  network without an approved authentication and network access design.
109
164
  - JSON request bodies are bounded.
110
- - Serial capture and SSH operations are time-bounded.
111
- - Windows serial capture is not implemented in the current no-native-helper
112
- path.
165
+ - Serial capture and SSH operations are time-bounded. Windows serial capture
166
+ uses a bounded PowerShell `System.IO.Ports.SerialPort` helper in the Go
167
+ runtime. The legacy TypeScript bridge path has been removed.
113
168
  - Destructive operations must remain approval-gated.
114
169
 
115
170
  ## Runtime Requirements
116
171
 
117
- - Node.js 20 or newer.
172
+ - Node.js 20 or newer for the npm launcher.
173
+ - The matching native optional package for the current OS/CPU.
118
174
  - Optional platform tools depending on the requested action, such as OpenSSH
119
175
  for `POST /v1/ssh/run`, `rkdeveloptool` for TaishanPi planning checks, and
120
176
  debug tools such as `openocd`, `probe-rs`, `pyocd`, `JLinkExe`, and
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export { startServer } from "./server.js";
2
+ export declare function resolveBridgeBinary(): string;
3
+ export declare function startBridgeProcess(args?: string[]): Promise<number>;
package/dist/index.js CHANGED
@@ -1,10 +1,136 @@
1
1
  #!/usr/bin/env node
2
- import { realpathSync } from "node:fs";
2
+ import { spawn } from "node:child_process";
3
+ import { accessSync, constants, realpathSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { arch, platform } from "node:os";
3
7
  import { fileURLToPath } from "node:url";
4
- import { startServer } from "./server.js";
5
- export { startServer } from "./server.js";
8
+ const require = createRequire(import.meta.url);
9
+ const TARGETS = {
10
+ "darwin-arm64": {
11
+ packageName: "@embed-labs/local-bridge-darwin-arm64",
12
+ artifactDir: "darwin-arm64",
13
+ binaryName: "embed-local-bridge"
14
+ },
15
+ "linux-x64": {
16
+ packageName: "@embed-labs/local-bridge-linux-x64",
17
+ artifactDir: "linux-x64",
18
+ binaryName: "embed-local-bridge"
19
+ },
20
+ "linux-arm64": {
21
+ packageName: "@embed-labs/local-bridge-linux-arm64",
22
+ artifactDir: "linux-arm64",
23
+ binaryName: "embed-local-bridge"
24
+ },
25
+ "win32-x64": {
26
+ packageName: "@embed-labs/local-bridge-win32-x64",
27
+ artifactDir: "win32-x64",
28
+ binaryName: "embed-local-bridge.exe"
29
+ },
30
+ "win32-arm64": {
31
+ packageName: "@embed-labs/local-bridge-win32-arm64",
32
+ artifactDir: "win32-arm64",
33
+ binaryName: "embed-local-bridge.exe"
34
+ }
35
+ };
36
+ export function resolveBridgeBinary() {
37
+ const explicit = process.env.EMBED_LOCAL_BRIDGE_BINARY?.trim();
38
+ if (explicit) {
39
+ return assertExecutable(explicit, `EMBED_LOCAL_BRIDGE_BINARY points to a non-executable file: ${explicit}`);
40
+ }
41
+ const targetKey = `${platform()}-${arch()}`;
42
+ const target = TARGETS[targetKey];
43
+ if (!target) {
44
+ throw new Error(`EmbedLabs Local Bridge does not provide a native binary for ${targetKey}. Supported targets: ${Object.keys(TARGETS).join(", ")}.`);
45
+ }
46
+ const packagedBinary = resolvePackagedBinary(target);
47
+ if (packagedBinary) {
48
+ return packagedBinary;
49
+ }
50
+ const repoBinary = resolveRepoArtifactBinary(target);
51
+ if (repoBinary) {
52
+ return repoBinary;
53
+ }
54
+ throw new Error([
55
+ `EmbedLabs Local Bridge native package is missing for ${targetKey}.`,
56
+ `Expected optional dependency ${target.packageName}.`,
57
+ "Reinstall without omitting optional dependencies:",
58
+ " npm install",
59
+ "or install the CLI package again without --omit=optional.",
60
+ "For source-tree development, run npm run build:bridge-go first."
61
+ ].join("\n"));
62
+ }
63
+ export function startBridgeProcess(args = process.argv.slice(2)) {
64
+ const binary = resolveBridgeBinary();
65
+ const child = spawn(binary, args, {
66
+ stdio: "inherit",
67
+ env: process.env
68
+ });
69
+ const forwardSignal = (signal) => {
70
+ if (!child.killed) {
71
+ child.kill(signal);
72
+ }
73
+ };
74
+ process.once("SIGINT", forwardSignal);
75
+ process.once("SIGTERM", forwardSignal);
76
+ return new Promise((resolve) => {
77
+ child.on("error", (error) => {
78
+ console.error(error instanceof Error ? error.message : String(error));
79
+ resolve(1);
80
+ });
81
+ child.on("close", (code, signal) => {
82
+ process.off("SIGINT", forwardSignal);
83
+ process.off("SIGTERM", forwardSignal);
84
+ if (signal) {
85
+ resolve(signal === "SIGINT" || signal === "SIGTERM" ? 0 : 1);
86
+ }
87
+ else {
88
+ resolve(code ?? 0);
89
+ }
90
+ });
91
+ });
92
+ }
6
93
  if (isDirectRun()) {
7
- startServer();
94
+ startBridgeProcess().then((code) => {
95
+ process.exitCode = code;
96
+ });
97
+ }
98
+ function resolvePackagedBinary(target) {
99
+ try {
100
+ const packageJson = require.resolve(`${target.packageName}/package.json`);
101
+ return assertExecutable(join(dirname(packageJson), "bin", target.binaryName), "");
102
+ }
103
+ catch {
104
+ return undefined;
105
+ }
106
+ }
107
+ function resolveRepoArtifactBinary(target) {
108
+ const here = dirname(fileURLToPath(import.meta.url));
109
+ const candidates = [
110
+ resolve(here, "../../../artifacts/local-bridge-bin", target.artifactDir, target.binaryName),
111
+ resolve(here, "../../artifacts/local-bridge-bin", target.artifactDir, target.binaryName)
112
+ ];
113
+ for (const candidate of candidates) {
114
+ try {
115
+ return assertExecutable(candidate, "");
116
+ }
117
+ catch {
118
+ // Keep searching fallback candidates.
119
+ }
120
+ }
121
+ return undefined;
122
+ }
123
+ function assertExecutable(path, message) {
124
+ try {
125
+ accessSync(path, constants.X_OK);
126
+ }
127
+ catch (error) {
128
+ if (message) {
129
+ throw new Error(message);
130
+ }
131
+ throw error;
132
+ }
133
+ return path;
8
134
  }
9
135
  function isDirectRun() {
10
136
  if (!process.argv[1]) {
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@kvell007/embed-labs-local-bridge",
3
- "version": "0.1.0-alpha.11",
4
- "description": "Local hardware bridge service for Embed Labs Cloud. Experimental npm publish.",
3
+ "version": "0.1.0-alpha.111",
4
+ "description": "Go Local Bridge launcher for EmbedLabs local hardware inventory and board workflows. Experimental npm publish.",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
9
9
  "files": [
10
- "dist",
10
+ "dist/index.js",
11
+ "dist/index.d.ts",
11
12
  "README.md"
12
13
  ],
13
14
  "engines": {
@@ -16,8 +17,12 @@
16
17
  "bin": {
17
18
  "embed-local-bridge": "dist/index.js"
18
19
  },
19
- "dependencies": {
20
- "@embed-labs/protocol": "npm:@kvell007/embed-labs-protocol@0.1.0-alpha.11"
20
+ "optionalDependencies": {
21
+ "@embed-labs/local-bridge-darwin-arm64": "npm:@kvell007/embed-labs-local-bridge-darwin-arm64@0.1.0-alpha.111",
22
+ "@embed-labs/local-bridge-linux-arm64": "npm:@kvell007/embed-labs-local-bridge-linux-arm64@0.1.0-alpha.111",
23
+ "@embed-labs/local-bridge-linux-x64": "npm:@kvell007/embed-labs-local-bridge-linux-x64@0.1.0-alpha.111",
24
+ "@embed-labs/local-bridge-win32-arm64": "npm:@kvell007/embed-labs-local-bridge-win32-arm64@0.1.0-alpha.111",
25
+ "@embed-labs/local-bridge-win32-x64": "npm:@kvell007/embed-labs-local-bridge-win32-x64@0.1.0-alpha.111"
21
26
  },
22
27
  "publishConfig": {
23
28
  "access": "public",
@@ -1,2 +0,0 @@
1
- import type { DebugToolScanResult } from "@embed-labs/protocol";
2
- export declare function scanDebugTools(): Promise<DebugToolScanResult>;
@@ -1,124 +0,0 @@
1
- import { resolveCommand, runCommand, tailLines } from "../process.js";
2
- const VERSION_TIMEOUT_MS = 2500;
3
- const DEBUG_TOOLS = [
4
- {
5
- tool_id: "openocd",
6
- display_name: "OpenOCD",
7
- command: "openocd",
8
- version_args: ["--version"]
9
- },
10
- {
11
- tool_id: "probe-rs",
12
- display_name: "probe-rs",
13
- command: "probe-rs",
14
- version_args: ["--version"]
15
- },
16
- {
17
- tool_id: "pyocd",
18
- display_name: "pyOCD",
19
- command: "pyocd",
20
- version_args: ["--version"]
21
- },
22
- {
23
- tool_id: "jlink-commander",
24
- display_name: "SEGGER J-Link Commander",
25
- command: "JLinkExe",
26
- version_args: ["-?"]
27
- },
28
- {
29
- tool_id: "jlink-gdb-server",
30
- display_name: "SEGGER J-Link GDB Server",
31
- command: "JLinkGDBServerCLExe",
32
- version_args: ["-?"]
33
- }
34
- ];
35
- export async function scanDebugTools() {
36
- const observedAt = new Date().toISOString();
37
- const tools = await Promise.all(DEBUG_TOOLS.map((tool) => scanDebugTool(tool, observedAt)));
38
- const availableCount = tools.filter((tool) => tool.available).length;
39
- return {
40
- tools,
41
- observed_at: observedAt,
42
- summary_for_user: `Debug tool scan finished: ${availableCount}/${tools.length} tools available. No debug sessions or probe connections were opened.`
43
- };
44
- }
45
- async function scanDebugTool(spec, observedAt) {
46
- const evidence = [];
47
- const resolvedPath = await resolveCommand(spec.command);
48
- evidence.push({
49
- evidence_id: evidenceId(spec.tool_id, "path", observedAt),
50
- tool_id: spec.tool_id,
51
- kind: "path_lookup",
52
- command: spec.command,
53
- observed_at: observedAt,
54
- available: resolvedPath !== undefined,
55
- resolved_path: resolvedPath,
56
- summary: resolvedPath
57
- ? `Found ${spec.command} on PATH or an Embed Labs local toolchain path.`
58
- : `${spec.command} was not found on PATH or an Embed Labs local toolchain path.`
59
- });
60
- if (!resolvedPath) {
61
- return {
62
- tool_id: spec.tool_id,
63
- display_name: spec.display_name,
64
- command: spec.command,
65
- available: false,
66
- evidence,
67
- summary_for_user: `${spec.display_name} is not available on PATH or an Embed Labs local toolchain path.`
68
- };
69
- }
70
- const versionResult = await runCommand(resolvedPath, spec.version_args, VERSION_TIMEOUT_MS);
71
- const stdoutTail = tailLines(versionResult.stdout, 8);
72
- const stderrTail = tailLines(versionResult.stderr, 8);
73
- const version = extractVersionLine(`${versionResult.stdout}\n${versionResult.stderr}`);
74
- evidence.push({
75
- evidence_id: evidenceId(spec.tool_id, "version", observedAt),
76
- tool_id: spec.tool_id,
77
- kind: "version_command",
78
- command: spec.command,
79
- args: spec.version_args,
80
- observed_at: observedAt,
81
- exit_code: versionResult.exit_code,
82
- timed_out: versionResult.timed_out,
83
- stdout_tail: stdoutTail.length > 0 ? stdoutTail : undefined,
84
- stderr_tail: stderrTail.length > 0 ? stderrTail : undefined,
85
- error_code: versionResult.timed_out
86
- ? "version_command_timeout"
87
- : versionResult.exit_code === 0
88
- ? undefined
89
- : "version_command_nonzero",
90
- error_message: versionResult.timed_out
91
- ? `Version/help command exceeded ${VERSION_TIMEOUT_MS}ms.`
92
- : versionResult.exit_code === 0
93
- ? undefined
94
- : `Version/help command exited with code ${versionResult.exit_code ?? "unknown"}.`,
95
- summary: versionResult.timed_out
96
- ? `${spec.command} was found, but the bounded version/help command timed out.`
97
- : versionResult.exit_code === 0
98
- ? `${spec.command} version/help command completed.`
99
- : `${spec.command} was found, but its version/help command exited non-zero.`
100
- });
101
- return {
102
- tool_id: spec.tool_id,
103
- display_name: spec.display_name,
104
- command: spec.command,
105
- available: true,
106
- version,
107
- evidence,
108
- summary_for_user: version
109
- ? `${spec.display_name} is available (${version}).`
110
- : `${spec.display_name} is available; version output was not recognized.`
111
- };
112
- }
113
- function extractVersionLine(output) {
114
- return output
115
- .split(/\r?\n/)
116
- .map((line) => line.trim())
117
- .find((line) => line.length > 0)
118
- ?.slice(0, 160);
119
- }
120
- function evidenceId(toolId, kind, observedAt) {
121
- const stableTime = observedAt.replace(/[^0-9]/g, "");
122
- return `debug_${toolId}_${kind}_${stableTime}`;
123
- }
124
- //# sourceMappingURL=debug.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/adapters/debug.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { BoardDeployRequest, BoardDeployResult, ErrorEnvelope } from "@embed-labs/protocol";
2
- export declare function deployTaishanPiArtifact(request: BoardDeployRequest): Promise<BoardDeployResult | {
3
- ok: false;
4
- error: ErrorEnvelope;
5
- }>;
@@ -1,132 +0,0 @@
1
- import { readFile, stat } from "node:fs/promises";
2
- import { posix } from "node:path";
3
- import { commandExists, runCommand, tailLines } from "../process.js";
4
- const DEFAULT_REMOTE_PATH = "/userdata/embed-labs/apps/app";
5
- const REMOTE_ROOT = "/userdata/embed-labs/apps";
6
- const MAX_ARTIFACT_BYTES = 16 * 1024 * 1024;
7
- export async function deployTaishanPiArtifact(request) {
8
- const observedAt = new Date().toISOString();
9
- if (request.board_id !== "taishanpi") {
10
- return failDeploy("unsupported_board", `board_id must be taishanpi, got ${request.board_id}.`);
11
- }
12
- const host = request.host.trim();
13
- const user = request.user?.trim() || "root";
14
- const remotePath = normalizeRemotePath(request.remote_path ?? DEFAULT_REMOTE_PATH);
15
- const timeoutSeconds = clampTimeoutSeconds(request.timeout_seconds);
16
- if (!remotePath) {
17
- return failDeploy("invalid_remote_path", `remote_path must stay under ${REMOTE_ROOT} and contain only safe path characters.`);
18
- }
19
- if (!/^[A-Za-z0-9._-]{1,64}$/.test(user)) {
20
- return failDeploy("invalid_user", "SSH user must contain only letters, numbers, dots, underscores, or hyphens.");
21
- }
22
- if (!await commandExists("ssh")) {
23
- return failDeploy("ssh_not_found", "ssh binary was not found on PATH.", "Install OpenSSH client or add ssh to PATH.");
24
- }
25
- const artifactStat = await stat(request.artifact_path).catch(() => undefined);
26
- if (!artifactStat?.isFile()) {
27
- return failDeploy("artifact_file_not_found", `Local artifact file is not available: ${request.artifact_path}`);
28
- }
29
- if (artifactStat.size > MAX_ARTIFACT_BYTES) {
30
- return failDeploy("artifact_file_too_large", `Local Bridge deploy currently accepts artifacts up to ${MAX_ARTIFACT_BYTES} bytes on the SSH/base64 MVP path.`);
31
- }
32
- const artifactBytes = await readFile(request.artifact_path);
33
- const remoteDir = posix.dirname(remotePath);
34
- const tmpPath = `${remotePath}.tmp.${Date.now()}`;
35
- const logPath = `${remotePath}.log`;
36
- const pidPath = `${remotePath}.pid`;
37
- const upload = await ssh(host, user, [
38
- `mkdir -p ${shellQuote(remoteDir)}`,
39
- "umask 077",
40
- `base64 -d > ${shellQuote(tmpPath)}`,
41
- `chmod 0755 ${shellQuote(tmpPath)}`,
42
- `mv -f ${shellQuote(tmpPath)} ${shellQuote(remotePath)}`
43
- ].join(" && "), timeoutSeconds, artifactBytes.toString("base64"));
44
- if (upload.exit_code !== 0) {
45
- return commandFailure(upload.timed_out ? "artifact_upload_timeout" : "artifact_upload_failed", "Failed to upload the artifact to the board over SSH/base64.", upload);
46
- }
47
- let runResult;
48
- if (request.run === true) {
49
- runResult = await ssh(host, user, [
50
- `cd ${shellQuote(remoteDir)}`,
51
- `(nohup ${shellQuote(remotePath)} > ${shellQuote(logPath)} 2>&1 < /dev/null & printf '%s' "$!" > ${shellQuote(pidPath)})`,
52
- "sleep 1",
53
- "printf 'pid='",
54
- `cat ${shellQuote(pidPath)}`,
55
- "printf '\\n'",
56
- `tail -n 40 ${shellQuote(logPath)} 2>/dev/null || true`
57
- ].join(" && "), timeoutSeconds);
58
- if (runResult.exit_code !== 0) {
59
- return commandFailure(runResult.timed_out ? "artifact_run_timeout" : "artifact_run_failed", "The artifact was deployed, but the start/log command failed.", runResult);
60
- }
61
- }
62
- return {
63
- board_id: "taishanpi",
64
- host,
65
- user,
66
- artifact_path: request.artifact_path,
67
- artifact_size_bytes: artifactStat.size,
68
- remote_path: remotePath,
69
- deployed: true,
70
- ran: request.run === true && runResult?.exit_code === 0,
71
- remote_pid: runResult ? extractPid(runResult.stdout) : undefined,
72
- log_path: logPath,
73
- exit_code: runResult?.exit_code,
74
- stdout: runResult?.stdout,
75
- stderr: runResult?.stderr,
76
- output_tail: runResult ? tailLines(`${runResult.stdout}\n${runResult.stderr}`) : tailLines(`${upload.stdout}\n${upload.stderr}`),
77
- observed_at: observedAt
78
- };
79
- }
80
- async function ssh(host, user, command, timeoutSeconds, stdin) {
81
- return runCommand("ssh", [
82
- "-o", "BatchMode=yes",
83
- "-o", "UserKnownHostsFile=/dev/null",
84
- "-o", "StrictHostKeyChecking=no",
85
- "-o", `ConnectTimeout=${Math.max(1, Math.min(timeoutSeconds, 30))}`,
86
- `${user}@${host}`,
87
- command
88
- ], timeoutSeconds * 1000 + 1000, stdin);
89
- }
90
- function normalizeRemotePath(input) {
91
- if (!input.startsWith("/") || /[\u0000-\u001f\u007f]/.test(input)) {
92
- return undefined;
93
- }
94
- const normalized = posix.normalize(input);
95
- if (normalized === REMOTE_ROOT || !normalized.startsWith(`${REMOTE_ROOT}/`)) {
96
- return undefined;
97
- }
98
- if (!/^\/[A-Za-z0-9._/-]+$/.test(normalized) || normalized.endsWith("/")) {
99
- return undefined;
100
- }
101
- return normalized;
102
- }
103
- function clampTimeoutSeconds(value) {
104
- const timeout = Number.isFinite(value) ? Number(value) : 30;
105
- return Math.max(5, Math.min(Math.trunc(timeout), 120));
106
- }
107
- function failDeploy(code, message, remediation) {
108
- return { ok: false, error: { code, message, remediation } };
109
- }
110
- function commandFailure(code, message, result) {
111
- return {
112
- ok: false,
113
- error: {
114
- code,
115
- message,
116
- details: {
117
- exit_code: result.exit_code,
118
- stdout: result.stdout,
119
- stderr: result.stderr,
120
- timed_out: result.timed_out
121
- }
122
- }
123
- };
124
- }
125
- function shellQuote(value) {
126
- return `'${value.replace(/'/g, "'\\''")}'`;
127
- }
128
- function extractPid(stdout) {
129
- const match = stdout.match(/^pid=(\d+)/m);
130
- return match?.[1];
131
- }
132
- //# sourceMappingURL=deploy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/adapters/deploy.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { FlashPlan, FlashPlanRequest } from "@embed-labs/protocol";
2
- export declare function buildFlashPlan(request: FlashPlanRequest): Promise<FlashPlan>;
3
- export declare function executeRp2350Uf2Flash(plan: FlashPlan): Promise<Record<string, unknown>>;