@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 +77 -6
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +87 -8
- package/package.json +7 -7
- package/src/client/b64.ts +14 -0
- package/src/client/hit-card.tsx +61 -4
- package/src/client/i18n.ts +8 -0
- package/src/client/parse.ts +8 -1
- package/src/tools.ts +101 -12
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.
|
|
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
|
|
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
|
|
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 (
|
|
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
|