@huaqiu/dsh-tool-schematic-gen 0.3.14 → 0.3.16

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/lib/client.js CHANGED
@@ -50,12 +50,17 @@ window.__ModuleLoader__.load({
50
50
  artifact = artOf(o.zipArtifact);
51
51
  if (artifact) artifacts.push(artifact);
52
52
  } else {
53
+ const zipRef = artOf(o.zipArtifact);
54
+ if (zipRef) {
55
+ artifact = zipRef;
56
+ artifacts.push(zipRef);
57
+ }
53
58
  const list = Array.isArray(o.schArtifacts) ? o.schArtifacts : [];
54
59
  for (const entry of list) {
55
60
  const ref = artOf(entry);
56
61
  if (ref) artifacts.push(ref);
57
62
  }
58
- artifact = artifacts.length > 0 ? artifacts[0] : null;
63
+ if (!artifact) artifact = artifacts.length > 0 ? artifacts[0] : null;
59
64
  }
60
65
  return {
61
66
  status,
@@ -489,6 +494,10 @@ window.__ModuleLoader__.load({
489
494
  "card.action.downloading": "下载中…",
490
495
  "card.action.place": "放置到编辑器",
491
496
  "card.action.placing": "放置中…",
497
+ "card.action.openInEda": "在 EDA 中打开",
498
+ "card.action.openingInEda": "导入中…",
499
+ "card.import.done": "已在 EDA 中打开设计({id})",
500
+ "card.import.failed": "在 EDA 中打开失败:{detail}",
492
501
  "card.place.done": "已放置 {count} 个文件到编辑器",
493
502
  "card.place.partial": "已放置 {placed} 个,{failed} 个失败:",
494
503
  "card.place.failed": "放置失败:",
@@ -542,6 +551,10 @@ window.__ModuleLoader__.load({
542
551
  "card.action.downloading": "Downloading…",
543
552
  "card.action.place": "Place in editor",
544
553
  "card.action.placing": "Placing…",
554
+ "card.action.openInEda": "Open in EDA",
555
+ "card.action.openingInEda": "Importing…",
556
+ "card.import.done": "Design opened in EDA ({id})",
557
+ "card.import.failed": "Failed to open in EDA: {detail}",
545
558
  "card.place.done": "Placed {count} file(s) into the editor",
546
559
  "card.place.partial": "Placed {placed}, {failed} failed: ",
547
560
  "card.place.failed": "Placement failed: ",
@@ -105632,6 +105645,20 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
105632
105645
  ] });
105633
105646
  }
105634
105647
  //#endregion
105648
+ //#region src/client/b64.ts
105649
+ /**
105650
+ * Base64-encode a byte array for transport inside JSON (the edge-bridge proxy
105651
+ * serializes object bodies to JSON, so binary must travel base64). Chunked to
105652
+ * avoid call-stack limits on large zips. Pure module — no DOM/ecad imports —
105653
+ * so node-side tests can import it directly.
105654
+ */
105655
+ function bytesToBase64(bytes) {
105656
+ let bin = "";
105657
+ const chunkSize = 32768;
105658
+ for (let i = 0; i < bytes.length; i += chunkSize) bin += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
105659
+ return btoa(bin);
105660
+ }
105661
+ //#endregion
105635
105662
  //#region src/client/hit-card.tsx
105636
105663
  /**
105637
105664
  * Keyed `tool.call.toolview` HIT card for schematic generation (both
@@ -105751,7 +105778,7 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
105751
105778
  });
105752
105779
  if (cancelled || canvas !== canvasRef.current) return;
105753
105780
  sizeCanvasFor(canvas);
105754
- if (payload.kind === "system" && payload.bytes) disposeViewer = await renderProjectZipToCanvas(payload.bytes, canvas);
105781
+ if (payload.bytes) disposeViewer = await renderProjectZipToCanvas(payload.bytes, canvas);
105755
105782
  else if (payload.source) disposeViewer = await renderSheetToCanvas(payload.source, canvas);
105756
105783
  else throw new Error("no preview source");
105757
105784
  if (cancelled || canvas !== canvasRef.current) return;
@@ -105898,7 +105925,7 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
105898
105925
  });
105899
105926
  (async () => {
105900
105927
  try {
105901
- if ((result.kind ?? "schematic") === "system") {
105928
+ if ((result?.artifact?.type ?? (result?.kind === "system" ? "zip" : "schematic")) === "zip") {
105902
105929
  const art = await resolveArtifactBytes(artifactKey);
105903
105930
  if (cancelled) return;
105904
105931
  setPayload({
@@ -105938,18 +105965,50 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
105938
105965
  }, [artifactKey, state.phase]);
105939
105966
  const [busy, setBusy] = (0, react.useState)(null);
105940
105967
  const [placeStatus, setPlaceStatus] = (0, react.useState)(null);
105968
+ const [importStatus, setImportStatus] = (0, react.useState)(null);
105941
105969
  function onDownload() {
105942
105970
  if (busy || payload.phase !== "ready") return;
105943
- const kind = result?.kind ?? "schematic";
105944
- const filename = downloadFilenameFor(kind, result?.artifact ?? null, result?.designName ?? null);
105971
+ const filename = downloadFilenameFor(result?.kind ?? "schematic", result?.artifact ?? null, result?.designName ?? null);
105945
105972
  setBusy("download");
105946
105973
  try {
105947
- if (kind === "system" && payload.bytes) downloadBytes(filename, payload.bytes);
105974
+ if (payload.bytes) downloadBytes(filename, payload.bytes);
105948
105975
  else if (payload.source != null) downloadText(filename, payload.source);
105949
105976
  } finally {
105950
105977
  setBusy(null);
105951
105978
  }
105952
105979
  }
105980
+ /**
105981
+ * Open the generated project in the EDA editor. Host mode only: the browser
105982
+ * half posts the project zip (base64 in JSON — the edge-bridge proxy cannot
105983
+ * carry multipart) to hq-edge `POST /api/v1/import/kicad-b64`, which runs
105984
+ * the ImportDesign pipeline (extract → gRPC → EDA opens the design).
105985
+ */
105986
+ async function onOpenInEda() {
105987
+ if (busy || payload.phase !== "ready" || !payload.bytes) return;
105988
+ const api = props.getHqEdge?.()?.api;
105989
+ if (!api || typeof api.request !== "function") return;
105990
+ setBusy("open-in-eda");
105991
+ setImportStatus(null);
105992
+ try {
105993
+ const body = await api.request({
105994
+ method: "POST",
105995
+ path: "/api/v1/import/kicad-b64",
105996
+ body: {
105997
+ zip_b64: bytesToBase64(payload.bytes),
105998
+ filename: payload.filename ?? "design.zip",
105999
+ project_name: result?.designName ?? "schematic",
106000
+ source_vendor: "circuit_agent",
106001
+ source_format: "kicad"
106002
+ }
106003
+ }) ?? {};
106004
+ setImportStatus(t("card.import.done", { id: body.design_id ?? body.status ?? "ok" }));
106005
+ } catch (e) {
106006
+ console.warn("[hq-schematic-gen] open-in-eda failed", e);
106007
+ setImportStatus(t("card.import.failed", { detail: String(e?.message || e) }));
106008
+ } finally {
106009
+ setBusy(null);
106010
+ }
106011
+ }
105953
106012
  function onRegenerate() {
105954
106013
  if (busy) return;
105955
106014
  setBusy("regenerate");
@@ -106081,6 +106140,7 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
106081
106140
  const placeSupport = placeSupportOf(props.getHqEdge, "schematic");
106082
106141
  const placeableCount = result.artifacts.filter((a) => a.uri).length;
106083
106142
  const canPlace = !!placeSupport?.() && placeableCount > 0;
106143
+ const canOpenInEda = payload.phase === "ready" && payload.bytes != null && !!props.getHqEdge?.()?.api?.request;
106084
106144
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
106085
106145
  className: "hq-sch",
106086
106146
  children: [
@@ -106101,6 +106161,13 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
106101
106161
  disabled: !canDownload || busy === "download",
106102
106162
  children: ["⭳ ", busy === "download" ? t("card.action.downloading") : t("card.action.download")]
106103
106163
  }),
106164
+ canOpenInEda ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
106165
+ type: "button",
106166
+ className: "hq-sch__act",
106167
+ onClick: onOpenInEda,
106168
+ disabled: busy === "open-in-eda",
106169
+ children: ["⇱ ", busy === "open-in-eda" ? t("card.action.openingInEda") : t("card.action.openInEda")]
106170
+ }) : null,
106104
106171
  canPlace ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
106105
106172
  type: "button",
106106
106173
  className: "hq-sch__act",
@@ -106123,6 +106190,10 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
106123
106190
  }) : null
106124
106191
  ]
106125
106192
  }),
106193
+ importStatus ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
106194
+ className: "hq-sch__note",
106195
+ children: importStatus
106196
+ }) : null,
106126
106197
  placeStatus ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
106127
106198
  className: "hq-sch__note",
106128
106199
  children: placeStatus