@huaqiu/dsh-tool-schematic-gen 0.3.7 → 0.3.8
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 +151 -6
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +31 -15
- package/package.json +6 -6
- package/src/client/hit-card.tsx +78 -0
- package/src/client/i18n.ts +10 -0
- package/src/client/index.ts +8 -0
- package/src/client/parse.ts +22 -3
- package/src/client/place.ts +17 -0
- package/src/tools.ts +43 -7
package/lib/client.js
CHANGED
|
@@ -27,7 +27,8 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
id,
|
|
28
28
|
type: typeof o.type === "string" ? o.type : null,
|
|
29
29
|
filename: typeof o.filename === "string" ? o.filename : null,
|
|
30
|
-
size: typeof o.size === "number" ? o.size : null
|
|
30
|
+
size: typeof o.size === "number" ? o.size : null,
|
|
31
|
+
uri: typeof o.uri === "string" && o.uri.length > 0 ? o.uri : null
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
function parseSchResult(text) {
|
|
@@ -44,15 +45,23 @@ window.__ModuleLoader__.load({
|
|
|
44
45
|
const status = typeof o.status === "string" ? o.status : null;
|
|
45
46
|
const kind = typeof o.kind === "string" ? o.kind : null;
|
|
46
47
|
let artifact = null;
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
const artifacts = [];
|
|
49
|
+
if (kind === "system") {
|
|
50
|
+
artifact = artOf(o.zipArtifact);
|
|
51
|
+
if (artifact) artifacts.push(artifact);
|
|
52
|
+
} else {
|
|
49
53
|
const list = Array.isArray(o.schArtifacts) ? o.schArtifacts : [];
|
|
50
|
-
|
|
54
|
+
for (const entry of list) {
|
|
55
|
+
const ref = artOf(entry);
|
|
56
|
+
if (ref) artifacts.push(ref);
|
|
57
|
+
}
|
|
58
|
+
artifact = artifacts.length > 0 ? artifacts[0] : null;
|
|
51
59
|
}
|
|
52
60
|
return {
|
|
53
61
|
status,
|
|
54
62
|
kind,
|
|
55
63
|
artifact,
|
|
64
|
+
artifacts,
|
|
56
65
|
designName: typeof o.design_name === "string" && o.design_name ? o.design_name : null,
|
|
57
66
|
fileCount: Array.isArray(o.schFiles) ? o.schFiles.length : Array.isArray(o.schArtifacts) ? o.schArtifacts.length : null,
|
|
58
67
|
moduleCount: typeof o.module_count === "number" ? o.module_count : null,
|
|
@@ -476,6 +485,11 @@ window.__ModuleLoader__.load({
|
|
|
476
485
|
"card.meta.connections": "{count} 条连接",
|
|
477
486
|
"card.action.download": "下载",
|
|
478
487
|
"card.action.downloading": "下载中…",
|
|
488
|
+
"card.action.place": "放置到编辑器",
|
|
489
|
+
"card.action.placing": "放置中…",
|
|
490
|
+
"card.place.done": "已放置 {count} 个文件到编辑器",
|
|
491
|
+
"card.place.partial": "已放置 {placed} 个,{failed} 个失败:",
|
|
492
|
+
"card.place.failed": "放置失败:",
|
|
479
493
|
"card.action.regenerate": "重新生成",
|
|
480
494
|
"card.action.regenerating": "重新生成中…",
|
|
481
495
|
"card.action.inspect": "详情",
|
|
@@ -522,6 +536,11 @@ window.__ModuleLoader__.load({
|
|
|
522
536
|
"card.meta.connections": "{count} connection(s)",
|
|
523
537
|
"card.action.download": "Download",
|
|
524
538
|
"card.action.downloading": "Downloading…",
|
|
539
|
+
"card.action.place": "Place in editor",
|
|
540
|
+
"card.action.placing": "Placing…",
|
|
541
|
+
"card.place.done": "Placed {count} file(s) into the editor",
|
|
542
|
+
"card.place.partial": "Placed {placed}, {failed} failed: ",
|
|
543
|
+
"card.place.failed": "Placement failed: ",
|
|
525
544
|
"card.action.regenerate": "Regenerate",
|
|
526
545
|
"card.action.regenerating": "Regenerating…",
|
|
527
546
|
"card.action.inspect": "Inspect",
|
|
@@ -104849,6 +104868,69 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
104849
104868
|
}
|
|
104850
104869
|
}
|
|
104851
104870
|
//#endregion
|
|
104871
|
+
//#region ../dsh-artifacts/lib/placement.mjs
|
|
104872
|
+
/**
|
|
104873
|
+
* Editors each artifact type may be placed into.
|
|
104874
|
+
*
|
|
104875
|
+
* | Artifact | sch | pcb | symbol | footprint | generic |
|
|
104876
|
+
* |-----------|-----|-----|--------|-----------|---------|
|
|
104877
|
+
* | schematic | yes | no | no | no | no |
|
|
104878
|
+
* | symbol | yes | no | yes | no | no |
|
|
104879
|
+
* | footprint | no | yes | no | yes | no |
|
|
104880
|
+
*
|
|
104881
|
+
* `generic` appears in no row: HQ Edge may be inside *some* EDA host without
|
|
104882
|
+
* knowing which editor, so placement must fail closed.
|
|
104883
|
+
*/
|
|
104884
|
+
const COMPATIBLE_EDITORS = {
|
|
104885
|
+
schematic: /* @__PURE__ */ new Set(["sch"]),
|
|
104886
|
+
symbol: /* @__PURE__ */ new Set(["sch", "symbol"]),
|
|
104887
|
+
footprint: /* @__PURE__ */ new Set(["pcb", "footprint"])
|
|
104888
|
+
};
|
|
104889
|
+
/**
|
|
104890
|
+
* Can `artifactType` be placed into the editor identified by `editorType`?
|
|
104891
|
+
*
|
|
104892
|
+
* Fails closed: an unrecognized artifact or editor type yields `false`.
|
|
104893
|
+
*/
|
|
104894
|
+
function canPlaceArtifact(artifactType, editorType) {
|
|
104895
|
+
const allowed = COMPATIBLE_EDITORS[artifactType];
|
|
104896
|
+
return allowed ? allowed.has(editorType) : false;
|
|
104897
|
+
}
|
|
104898
|
+
/**
|
|
104899
|
+
* Build the Place support for `artifactType` from a lazily-resolved `hqEdge`.
|
|
104900
|
+
*
|
|
104901
|
+
* Returns null when `getHqEdge` is unavailable (standalone DSH has no
|
|
104902
|
+
* edge-bridge, hence no `hqEdge` service). Otherwise returns a GETTER so
|
|
104903
|
+
* callers resolve the service lazily — plugin load order and HQ Edge restarts
|
|
104904
|
+
* both resolve correctly at click time. The getter yields null when
|
|
104905
|
+
* placement is unavailable or the current editor cannot accept the artifact
|
|
104906
|
+
* type (the card hides the button in that case).
|
|
104907
|
+
*
|
|
104908
|
+
* Editor gating is UX-only; HQ Edge re-enforces the matrix server-side (409).
|
|
104909
|
+
*/
|
|
104910
|
+
function placeSupportOf(getHqEdge, artifactType) {
|
|
104911
|
+
if (typeof getHqEdge !== "function") return null;
|
|
104912
|
+
return () => {
|
|
104913
|
+
let hqEdge;
|
|
104914
|
+
try {
|
|
104915
|
+
hqEdge = getHqEdge();
|
|
104916
|
+
} catch {
|
|
104917
|
+
return null;
|
|
104918
|
+
}
|
|
104919
|
+
if (!hqEdge || typeof hqEdge.placeArtifact !== "function") return null;
|
|
104920
|
+
let editorType = "";
|
|
104921
|
+
try {
|
|
104922
|
+
editorType = hqEdge.context?.getEditorType?.() ?? hqEdge.context?.getCurrent?.()?.editorType ?? "";
|
|
104923
|
+
} catch {
|
|
104924
|
+
return null;
|
|
104925
|
+
}
|
|
104926
|
+
if (!editorType || !canPlaceArtifact(artifactType, editorType)) return null;
|
|
104927
|
+
return {
|
|
104928
|
+
editorType,
|
|
104929
|
+
place: (request) => hqEdge.placeArtifact(request)
|
|
104930
|
+
};
|
|
104931
|
+
};
|
|
104932
|
+
}
|
|
104933
|
+
//#endregion
|
|
104852
104934
|
//#region src/trace.ts
|
|
104853
104935
|
/**
|
|
104854
104936
|
* Marker appended to the leaf of a synthesized instance path. It is invisible
|
|
@@ -105798,6 +105880,7 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
105798
105880
|
};
|
|
105799
105881
|
}, [artifactKey, state.phase]);
|
|
105800
105882
|
const [busy, setBusy] = (0, react.useState)(null);
|
|
105883
|
+
const [placeStatus, setPlaceStatus] = (0, react.useState)(null);
|
|
105801
105884
|
function onDownload() {
|
|
105802
105885
|
if (busy || payload.phase !== "ready") return;
|
|
105803
105886
|
const kind = result?.kind ?? "schematic";
|
|
@@ -105819,6 +105902,52 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
105819
105902
|
setBusy(null);
|
|
105820
105903
|
});
|
|
105821
105904
|
}
|
|
105905
|
+
/**
|
|
105906
|
+
* Place the generated design into the host EDA editor via HQ Edge.
|
|
105907
|
+
*
|
|
105908
|
+
* A system design sends ONE request (the project zip; HQ Edge derives the
|
|
105909
|
+
* root from the `*.kicad_pro` name — the same convention as the preview).
|
|
105910
|
+
* A multi-sheet schematic sends one request per sheet so every sheet lands
|
|
105911
|
+
* in the editor. Failures are collected and reported as a one-line status;
|
|
105912
|
+
* a partial success is explicitly surfaced, not swallowed.
|
|
105913
|
+
*/
|
|
105914
|
+
function placeRequestsOf() {
|
|
105915
|
+
if (!result) return [];
|
|
105916
|
+
return result.artifacts.filter((a) => a.uri).map((a) => ({
|
|
105917
|
+
artifactUri: a.uri,
|
|
105918
|
+
filename: a.filename
|
|
105919
|
+
}));
|
|
105920
|
+
}
|
|
105921
|
+
async function onPlace() {
|
|
105922
|
+
if (busy) return;
|
|
105923
|
+
const support = placeSupportOf(props.getHqEdge, "schematic")?.();
|
|
105924
|
+
if (!support) return;
|
|
105925
|
+
const requests = placeRequestsOf();
|
|
105926
|
+
if (requests.length === 0) return;
|
|
105927
|
+
setBusy("place");
|
|
105928
|
+
setPlaceStatus(null);
|
|
105929
|
+
let placed = 0;
|
|
105930
|
+
const failures = [];
|
|
105931
|
+
for (const req of requests) try {
|
|
105932
|
+
await support.place({
|
|
105933
|
+
type: "schematic",
|
|
105934
|
+
artifactUri: req.artifactUri,
|
|
105935
|
+
...req.filename ? { filename: req.filename } : {}
|
|
105936
|
+
});
|
|
105937
|
+
placed++;
|
|
105938
|
+
} catch (err) {
|
|
105939
|
+
const detail = String(err?.message || err);
|
|
105940
|
+
console.warn("[hq-schematic-gen] place failed", detail);
|
|
105941
|
+
failures.push(detail);
|
|
105942
|
+
}
|
|
105943
|
+
setBusy(null);
|
|
105944
|
+
if (failures.length === 0) setPlaceStatus(t("card.place.done", { count: placed }));
|
|
105945
|
+
else if (placed > 0) setPlaceStatus(t("card.place.partial", {
|
|
105946
|
+
placed,
|
|
105947
|
+
failed: failures.length
|
|
105948
|
+
}) + " " + failures[0]);
|
|
105949
|
+
else setPlaceStatus(t("card.place.failed") + " " + failures[0]);
|
|
105950
|
+
}
|
|
105822
105951
|
if (state.phase === "needs_auth") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoginCard, {
|
|
105823
105952
|
toolName: props.toolName,
|
|
105824
105953
|
authState: props.authState,
|
|
@@ -105891,6 +106020,9 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
105891
106020
|
})
|
|
105892
106021
|
});
|
|
105893
106022
|
const canDownload = payload.phase === "ready" && (payload.source != null || payload.bytes != null);
|
|
106023
|
+
const placeSupport = placeSupportOf(props.getHqEdge, "schematic");
|
|
106024
|
+
const placeableCount = result.artifacts.filter((a) => a.uri).length;
|
|
106025
|
+
const canPlace = !!placeSupport?.() && placeableCount > 0;
|
|
105894
106026
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
105895
106027
|
className: "hq-sch",
|
|
105896
106028
|
children: [
|
|
@@ -105911,6 +106043,13 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
105911
106043
|
disabled: !canDownload || busy === "download",
|
|
105912
106044
|
children: ["⭳ ", busy === "download" ? t("card.action.downloading") : t("card.action.download")]
|
|
105913
106045
|
}),
|
|
106046
|
+
canPlace ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
106047
|
+
type: "button",
|
|
106048
|
+
className: "hq-sch__act",
|
|
106049
|
+
onClick: onPlace,
|
|
106050
|
+
disabled: busy === "place",
|
|
106051
|
+
children: ["⇥ ", busy === "place" ? t("card.action.placing") : t("card.action.place")]
|
|
106052
|
+
}) : null,
|
|
105914
106053
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
105915
106054
|
type: "button",
|
|
105916
106055
|
className: "hq-sch__act",
|
|
@@ -105925,7 +106064,11 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
105925
106064
|
children: t("card.action.inspect")
|
|
105926
106065
|
}) : null
|
|
105927
106066
|
]
|
|
105928
|
-
})
|
|
106067
|
+
}),
|
|
106068
|
+
placeStatus ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
106069
|
+
className: "hq-sch__note",
|
|
106070
|
+
children: placeStatus
|
|
106071
|
+
}) : null
|
|
105929
106072
|
]
|
|
105930
106073
|
});
|
|
105931
106074
|
});
|
|
@@ -106007,6 +106150,7 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
106007
106150
|
function apply(ctx) {
|
|
106008
106151
|
const disposers = [];
|
|
106009
106152
|
const useAuthState = createUseAuthState(ctx.get("huaqiuAuth")?.auth);
|
|
106153
|
+
const getHqEdge = () => ctx.get("hqEdge");
|
|
106010
106154
|
const sendPrompt = (sessionId, message) => {
|
|
106011
106155
|
const sessions = ctx.get("sessions");
|
|
106012
106156
|
if (!sessions || typeof sessions.binding !== "function" || !sessionId) return Promise.reject(/* @__PURE__ */ new Error("no session conversation channel"));
|
|
@@ -106026,7 +106170,8 @@ while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]
|
|
|
106026
106170
|
sessionId: props.sessionId,
|
|
106027
106171
|
callId: props.callId,
|
|
106028
106172
|
sendPrompt,
|
|
106029
|
-
authState: useAuthState()
|
|
106173
|
+
authState: useAuthState(),
|
|
106174
|
+
getHqEdge
|
|
106030
106175
|
});
|
|
106031
106176
|
for (const toolName of TOOLVIEW_KEYS) disposers.push(slots.inject("tool.call.toolview", () => slots.register({
|
|
106032
106177
|
name: "tool.call.toolview",
|