@kvell007/embed-labs-cli 0.1.0-alpha.89 → 0.1.0-alpha.90

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.
@@ -12,7 +12,7 @@ const DEFAULT_HOST = "198.19.77.2";
12
12
  const DEFAULT_PORTS = "22,15301";
13
13
  const DEFAULT_STATUS_PORTS = "22";
14
14
  const TOOL_INTEGRITY_RELOGIN_MESSAGE = "工具完整性校验失败,请在当前电脑重新执行 embedlabs auth login --token <key>";
15
- const MCP_SERVER_VERSION = "0.2.40";
15
+ const MCP_SERVER_VERSION = "0.2.41";
16
16
  const MCP_ICON_FILES = [
17
17
  { fileName: "embed-labs-icon-dark.png", theme: "dark" },
18
18
  { fileName: "embed-labs-icon-light.png", theme: "light" }
@@ -150,8 +150,8 @@ const tools = [
150
150
  },
151
151
  {
152
152
  name: "dbt_rp2350_uart_write",
153
- description: "Send text or HEX data over the current/default RP2350 UART channel, with optional tx/rx/baud override. Requires approved=true.",
154
- inputSchema: { type: "object", properties: { id: { type: "number" }, instance: { type: "number" }, tx: { type: "number" }, rx: { type: "number" }, baud: { type: "number" }, text: { type: "string" }, hex: { type: "string" }, data_hex: { type: "string" }, line_ending: { type: "string" }, approved: { type: "boolean" }, approve: { type: "boolean" }, transport: { type: "string" }, local_device_id: { type: "string" }, monitor_bridge_url: { type: "string" }, serial_path: { type: "string" }, tcp: { type: "string" }, tcp_endpoint: { type: "string" }, host: { type: "string" }, port: { type: "number" }, timeout_ms: { type: "number" } } }
153
+ description: "Send text or HEX data over a configurable RP2350 UART channel, with optional tx/rx/baud override. Accepts uart_id such as uart1 and data/data_format aliases. Requires approved=true.",
154
+ inputSchema: { type: "object", properties: { id: { type: "number" }, instance: { type: "number" }, uart_id: { type: "string", description: "Alias such as uart0 or uart1; normalized to instance." }, tx: { type: "number" }, rx: { type: "number" }, baud: { type: "number" }, text: { type: "string" }, hex: { type: "string" }, data: { type: "string", description: "Text or hex payload depending on data_format." }, data_format: { type: "string", description: "hex, text, string, utf8, or ascii." }, data_hex: { type: "string" }, line_ending: { type: "string" }, approved: { type: "boolean" }, approve: { type: "boolean" }, transport: { type: "string" }, local_device_id: { type: "string" }, monitor_bridge_url: { type: "string" }, serial_path: { type: "string" }, tcp: { type: "string" }, tcp_endpoint: { type: "string" }, host: { type: "string" }, port: { type: "number" }, timeout_ms: { type: "number" } } }
155
155
  },
156
156
  {
157
157
  name: "dbt_rp2350_i2c_transfer",
@@ -163,7 +163,6 @@ const tools = [
163
163
  description: "Capture a compact RP2350-Monitor logic-analyzer JSONL file and optionally generate UART/SPI/I2C stimulus in the same operation. Requires approved=true because it arms local hardware. For closed-loop validation, do not call uart/spi write separately; pass stimulus here. UART/SPI/I2C/GPIO/logic functions may be combined freely when their GPIO sets do not overlap; only overlapping pins conflict. Example UART loopback: UART1 GP8/GP9 wired to logic GP16/GP17. Supports USB serial or board LAN IP/TCP transport.",
164
164
  inputSchema: {
165
165
  type: "object",
166
- required: ["pin_base", "pin_count"],
167
166
  properties: {
168
167
  transport: { type: "string" },
169
168
  local_device_id: { type: "string" },
@@ -173,10 +172,14 @@ const tools = [
173
172
  tcp_endpoint: { type: "string" },
174
173
  host: { type: "string", description: "Board LAN IP/hostname for network mode. Defaults to RP2350 Monitor TCP port 4242." },
175
174
  port: { type: "number", description: "Network-mode RP2350 Monitor TCP port. Defaults to 4242." },
176
- pin_base: { type: "number" },
177
- pin_count: { type: "number" },
175
+ pin_base: { type: "number", description: "First contiguous analyzer GPIO. Optional when channels/pins is provided." },
176
+ pin_count: { type: "number", description: "Number of contiguous analyzer GPIOs. Optional when channels/pins is provided." },
177
+ channels: { type: "array", items: { anyOf: [{ type: "number" }, { type: "string" }] }, description: "Analyzer GPIO aliases such as [\"gpio8\",\"gpio9\"]. The bridge derives pin_base/pin_count when possible." },
178
+ pins: { type: "array", items: { anyOf: [{ type: "number" }, { type: "string" }] }, description: "Alias for channels." },
178
179
  sample_rate: { type: "number" },
180
+ sample_rate_hz: { type: "number", description: "Alias for sample_rate." },
179
181
  samples: { type: "number" },
182
+ duration_ms: { type: "number", description: "Alias that computes samples from sample_rate/sample_rate_hz." },
180
183
  output_path: { type: "string" },
181
184
  decoder: { type: "string", description: "Optional decoder hint such as uart, spi, summary, or structure. If provided with decode=true/default, the bridge decodes the generated capture file." },
182
185
  decode: { type: "boolean" },
@@ -210,14 +213,14 @@ const tools = [
210
213
  description: "Decode a local RP2350-Monitor logic JSONL capture without touching hardware. Supported decoders: summary, bursts, edges, uart, spi, and structure/auto/unknown. The result includes summary_for_user, decoded_preview, protocol_data, and analysis so the AI can report actual sampled data; use structure/unknown when the protocol is not known.",
211
214
  inputSchema: {
212
215
  type: "object",
213
- required: ["input_path"],
214
216
  properties: {
215
217
  local_device_id: { type: "string" },
216
- input_path: { type: "string" },
218
+ input_path: { type: "string", description: "Preferred capture file path from logic-capture output_path." },
219
+ capture_id: { type: "number", description: "Optional capture id; when input_path is omitted, the bridge searches the default capture directory." },
217
220
  decoder: { type: "string", description: "summary, bursts, edges, uart, spi, structure, auto, or unknown." },
218
221
  output_path: { type: "string" },
219
222
  preview_limit: { type: "number" },
220
- pins: { type: "array", items: { type: "number" } },
223
+ pins: { type: "array", items: { anyOf: [{ type: "number" }, { type: "string" }] }, description: "GPIO aliases such as [\"gpio8\",\"gpio9\"]." },
221
224
  rx_pin: { type: "number" },
222
225
  baud: { type: "number" },
223
226
  data_bits: { type: "number" },
@@ -1549,8 +1552,24 @@ async function boardControl(args) {
1549
1552
 
1550
1553
  function normalizeRp2350Input(args) {
1551
1554
  const input = compactObject({ ...args });
1555
+ if (input.local_device_id == null && input.device_id != null) {
1556
+ input.local_device_id = input.device_id;
1557
+ }
1558
+ if (input.sample_rate == null && input.sample_rate_hz != null) {
1559
+ input.sample_rate = input.sample_rate_hz;
1560
+ }
1561
+ if (input.hex == null && input.data != null && ["hex", "data_hex", ""].includes(asString(input.data_format).toLowerCase())) {
1562
+ input.hex = input.data;
1563
+ } else if (input.text == null && input.data != null && ["text", "string", "utf8", "ascii"].includes(asString(input.data_format).toLowerCase())) {
1564
+ input.text = input.data;
1565
+ }
1566
+ if (input.instance == null && typeof input.uart_id === "string") {
1567
+ const match = input.uart_id.match(/\d+/);
1568
+ if (match) input.instance = Number(match[0]);
1569
+ }
1570
+ normalizeRp2350LogicChannels(input);
1552
1571
  for (const key of [
1553
- "port", "baud", "timeout_ms", "pin_base", "pin_count", "sample_rate", "samples",
1572
+ "port", "baud", "timeout_ms", "duration_ms", "sample_rate_hz", "pin_base", "pin_count", "sample_rate", "samples",
1554
1573
  "wait_timeout_ms", "read_timeout_ms", "pre_samples", "post_samples", "search_samples",
1555
1574
  "burst_count", "trigger_pin", "trigger_mask", "trigger_value", "capture_id",
1556
1575
  "start_sample", "end_sample", "preview_limit", "rx_pin", "data_bits", "sck_pin", "mosi_pin",
@@ -1564,14 +1583,22 @@ function normalizeRp2350Input(args) {
1564
1583
  input[key] = Number(value);
1565
1584
  }
1566
1585
  }
1567
- for (const key of ["include_caps", "release", "trigger_level", "invert", "cs_active_high", "level", "save", "use_current_channel", "decode", "strict_pins"]) {
1586
+ for (const key of ["include_caps", "release", "release_after", "trigger_level", "invert", "cs_active_high", "level", "save", "use_current_channel", "decode", "strict_pins"]) {
1568
1587
  if (typeof input[key] === "string") {
1569
1588
  input[key] = boolValue(input[key]);
1570
1589
  }
1571
1590
  }
1572
1591
  if (typeof input.pins === "string") {
1573
- input.pins = input.pins.split(/[,\s]+/g).map((item) => Number(item)).filter((item) => Number.isFinite(item));
1592
+ input.pins = parseGPIOList(input.pins);
1593
+ }
1594
+ normalizeRp2350LogicChannels(input);
1595
+ if (input.samples == null && Number.isFinite(input.duration_ms) && Number.isFinite(input.sample_rate)) {
1596
+ input.samples = Math.max(1, Math.round(input.sample_rate * input.duration_ms / 1000));
1574
1597
  }
1598
+ delete input.sample_rate_hz;
1599
+ delete input.data;
1600
+ delete input.data_format;
1601
+ delete input.uart_id;
1575
1602
  for (const key of ["channel_names", "pin_pulls", "stimulus", "params"]) {
1576
1603
  const parsed = objectValue(input[key]);
1577
1604
  if (parsed) input[key] = parsed;
@@ -1580,6 +1607,31 @@ function normalizeRp2350Input(args) {
1580
1607
  return input;
1581
1608
  }
1582
1609
 
1610
+ function normalizeRp2350LogicChannels(input) {
1611
+ const pins = parseGPIOList(input.channels ?? input.channel ?? input.pins);
1612
+ if (pins.length === 0) return;
1613
+ input.pins = pins;
1614
+ if (input.pin_base == null || input.pin_count == null) {
1615
+ const min = Math.min(...pins);
1616
+ const max = Math.max(...pins);
1617
+ input.pin_base = min;
1618
+ input.pin_count = max - min + 1;
1619
+ input.channel_names ??= Object.fromEntries(pins.map((pin) => [String(pin), `gpio${pin}`]));
1620
+ }
1621
+ }
1622
+
1623
+ function parseGPIOList(value) {
1624
+ if (value == null) return [];
1625
+ const raw = Array.isArray(value) ? value : String(value).split(/[,\s]+/g);
1626
+ return raw
1627
+ .map((item) => {
1628
+ if (typeof item === "number") return item;
1629
+ const match = String(item).trim().toLowerCase().match(/^(?:gp|gpio|pin)?\s*(\d+)$/);
1630
+ return match ? Number(match[1]) : Number.NaN;
1631
+ })
1632
+ .filter((item) => Number.isInteger(item) && item >= 0 && item <= 47);
1633
+ }
1634
+
1583
1635
  async function rp2350MonitorStatus(args) {
1584
1636
  return await rp2350MonitorTool("dbt_rp2350_monitor_status", "rp2350.monitor.status", args);
1585
1637
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kvell007/embed-labs-cli",
3
- "version": "0.1.0-alpha.89",
3
+ "version": "0.1.0-alpha.90",
4
4
  "description": "Command-line interface for Embed Labs Cloud. Experimental npm publish.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -18,8 +18,8 @@
18
18
  "embedlabs": "dist/index.js"
19
19
  },
20
20
  "dependencies": {
21
- "@embed-labs/local-bridge": "npm:@kvell007/embed-labs-local-bridge@0.1.0-alpha.89",
22
- "@embed-labs/protocol": "npm:@kvell007/embed-labs-protocol@0.1.0-alpha.89",
21
+ "@embed-labs/local-bridge": "npm:@kvell007/embed-labs-local-bridge@0.1.0-alpha.90",
22
+ "@embed-labs/protocol": "npm:@kvell007/embed-labs-protocol@0.1.0-alpha.90",
23
23
  "qrcode-terminal": "^0.12.0"
24
24
  },
25
25
  "publishConfig": {