@huaqiu/dsh-eda-host 0.4.6 → 0.4.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/index.d.mts +19 -10
- package/lib/index.mjs +35 -3
- package/package.json +2 -2
- package/src/client.ts +23 -10
- package/src/config.ts +19 -0
- package/src/index.ts +1 -1
- package/src/tools.ts +37 -2
- package/src/types.ts +6 -5
package/lib/index.d.mts
CHANGED
|
@@ -18,6 +18,8 @@ interface EdaHostConfig {
|
|
|
18
18
|
netlistPathPrefix?: string;
|
|
19
19
|
/** Path prefix for PCB selection; default "/api/v1/pcb-selection". */
|
|
20
20
|
pcbSelectionPathPrefix?: string;
|
|
21
|
+
/** Path prefix for the complete-board query; default "/api/v1/pcb-board". */
|
|
22
|
+
pcbBoardPathPrefix?: string;
|
|
21
23
|
/** Path prefix for host discovery; default "/api/v1/host". */
|
|
22
24
|
hostPathPrefix?: string;
|
|
23
25
|
/**
|
|
@@ -71,12 +73,13 @@ interface SchematicNetlist {
|
|
|
71
73
|
nets: ElectricalNet[];
|
|
72
74
|
}
|
|
73
75
|
/**
|
|
74
|
-
* Semantic PCB
|
|
76
|
+
* Semantic PCB snapshot types.
|
|
75
77
|
*
|
|
76
78
|
* Self-contained structural mirror of `hq.pcb.v1` (the hq-edge-owned semantic
|
|
77
|
-
* protobuf contract for `
|
|
78
|
-
*
|
|
79
|
-
*
|
|
79
|
+
* protobuf contract for `PcbQueryService.GetSelection` / `GetBoard`). The
|
|
80
|
+
* same PcbSnapshot shape backs both the current selection and the complete
|
|
81
|
+
* board. Units follow the hq.pcb.v1 convention: positions/sizes/lengths in mm,
|
|
82
|
+
* rotations in degrees, `id` is the KiCad native object identity.
|
|
80
83
|
*/
|
|
81
84
|
interface PcbPoint {
|
|
82
85
|
x: number;
|
|
@@ -174,7 +177,7 @@ interface PcbGroup {
|
|
|
174
177
|
id: string;
|
|
175
178
|
itemIds: string[];
|
|
176
179
|
}
|
|
177
|
-
interface
|
|
180
|
+
interface PcbSnapshot {
|
|
178
181
|
footprints: PcbFootprint[];
|
|
179
182
|
pads: PcbPad[];
|
|
180
183
|
tracks: PcbTrack[];
|
|
@@ -294,11 +297,17 @@ interface EdaHostClient {
|
|
|
294
297
|
/** Capabilities the host currently provides. */
|
|
295
298
|
getEdaHostCapabilities(options?: EdaHostRequestOptions): Promise<EdaHostCapability[]>;
|
|
296
299
|
/**
|
|
297
|
-
* Semantic PCB
|
|
298
|
-
*
|
|
299
|
-
* selection resolves to an all-empty `
|
|
300
|
+
* Semantic PCB snapshot of the current PCB editor selection (hq.pcb.v1
|
|
301
|
+
* PcbQueryService.GetSelection bridged through hq-edge). An empty
|
|
302
|
+
* selection resolves to an all-empty `PcbSnapshot` — never an error.
|
|
300
303
|
*/
|
|
301
|
-
getPcbSelection(options?: EdaHostRequestOptions): Promise<
|
|
304
|
+
getPcbSelection(options?: EdaHostRequestOptions): Promise<PcbSnapshot>;
|
|
305
|
+
/**
|
|
306
|
+
* Semantic PCB snapshot of the complete board (hq.pcb.v1
|
|
307
|
+
* PcbQueryService.GetBoard bridged through hq-edge). An empty board
|
|
308
|
+
* resolves to an all-empty `PcbSnapshot` — never an error.
|
|
309
|
+
*/
|
|
310
|
+
getPcbBoard(options?: EdaHostRequestOptions): Promise<PcbSnapshot>;
|
|
302
311
|
}
|
|
303
312
|
/**
|
|
304
313
|
* Extract the semantic `SchematicNetlist` from an hq-edge netlist body.
|
|
@@ -373,4 +382,4 @@ declare module '@deepseek-ai/cordis' {
|
|
|
373
382
|
*/
|
|
374
383
|
declare function apply(ctx: Context, config?: Partial<EdaHostConfig>): () => void;
|
|
375
384
|
//#endregion
|
|
376
|
-
export { type EdaHostCapability, type EdaHostClient, type EdaHostConfig, type EdaHostExecutable, type EdaHostIdentity, type EdaHostInfo, type EdaHostInstallation, type EdaHostRequestOptions, type EdaHostType, type ElectricalNet, type ElectricalType, NetlistError, type NetlistErrorKind, type PcbArc, type PcbDimension, type PcbFootprint, type PcbGroup, type PcbNetRef, type PcbPad, type PcbPoint, type PcbSegment, type
|
|
385
|
+
export { type EdaHostCapability, type EdaHostClient, type EdaHostConfig, type EdaHostExecutable, type EdaHostIdentity, type EdaHostInfo, type EdaHostInstallation, type EdaHostRequestOptions, type EdaHostType, type ElectricalNet, type ElectricalType, NetlistError, type NetlistErrorKind, type PcbArc, type PcbDimension, type PcbFootprint, type PcbGroup, type PcbNetRef, type PcbPad, type PcbPoint, type PcbSegment, type PcbShape, type PcbSnapshot, type PcbText, type PcbTrack, type PcbVia, type PcbZone, type PinDefinition, type PinReference, type SchematicComponent, type SchematicNetlist, apply, inject, name, parseNetlistBody };
|
package/lib/index.mjs
CHANGED
|
@@ -10,6 +10,7 @@ function resolveEdaHostConfig(config, env = process.env) {
|
|
|
10
10
|
const baseUrl = config?.hqEdgeBaseUrl ?? env.HQ_EDGE_BASE_URL ?? "";
|
|
11
11
|
const pathPrefix = config?.netlistPathPrefix ?? env.HQ_EDGE_NETLIST_PATH ?? "/api/v1/netlist";
|
|
12
12
|
const pcbSelectionPrefix = config?.pcbSelectionPathPrefix ?? env.HQ_EDGE_PCB_SELECTION_PATH ?? "/api/v1/pcb-selection";
|
|
13
|
+
const pcbBoardPrefix = config?.pcbBoardPathPrefix ?? env.HQ_EDGE_PCB_BOARD_PATH ?? "/api/v1/pcb-board";
|
|
13
14
|
const hostPrefix = config?.hostPathPrefix ?? env.HQ_EDGE_HOST_PATH ?? "/api/v1/host";
|
|
14
15
|
const timeoutRaw = config?.requestTimeoutMs ?? env.HQ_EDGE_REQUEST_TIMEOUT_MS;
|
|
15
16
|
const timeout = Number.parseInt(String(timeoutRaw ?? ""), 10);
|
|
@@ -17,6 +18,7 @@ function resolveEdaHostConfig(config, env = process.env) {
|
|
|
17
18
|
hqEdgeBaseUrl: baseUrl,
|
|
18
19
|
netlistPathPrefix: pathPrefix,
|
|
19
20
|
pcbSelectionPathPrefix: pcbSelectionPrefix,
|
|
21
|
+
pcbBoardPathPrefix: pcbBoardPrefix,
|
|
20
22
|
hostPathPrefix: hostPrefix,
|
|
21
23
|
requestTimeoutMs: Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_REQUEST_TIMEOUT_MS
|
|
22
24
|
};
|
|
@@ -33,6 +35,10 @@ function netlistUrlOf(config, scope) {
|
|
|
33
35
|
function pcbSelectionUrlOf(config) {
|
|
34
36
|
return `${(config.hqEdgeBaseUrl ?? "").replace(/\/+$/, "")}/${(config.pcbSelectionPathPrefix ?? "/api/v1/pcb-selection").replace(/^\/+|\/+$/g, "")}`;
|
|
35
37
|
}
|
|
38
|
+
/** Build the absolute URL for the complete-board query route. */
|
|
39
|
+
function pcbBoardUrlOf(config) {
|
|
40
|
+
return `${(config.hqEdgeBaseUrl ?? "").replace(/\/+$/, "")}/${(config.pcbBoardPathPrefix ?? "/api/v1/pcb-board").replace(/^\/+|\/+$/g, "")}`;
|
|
41
|
+
}
|
|
36
42
|
const HOST_ROUTE = {
|
|
37
43
|
info: "/info",
|
|
38
44
|
capabilities: "/capabilities"
|
|
@@ -191,8 +197,8 @@ function createEdaHostClient(config, deps = {}) {
|
|
|
191
197
|
async function fetchScope(scope, options) {
|
|
192
198
|
return parseNetlistBody(await getJson(netlistUrlOf(resolveConfig(), scope), options, "netlist"));
|
|
193
199
|
}
|
|
194
|
-
function
|
|
195
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw new NetlistError("INTERNAL",
|
|
200
|
+
function parsePcbSnapshot(value, what) {
|
|
201
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new NetlistError("INTERNAL", `eda-host: malformed ${what} response from hq-edge`);
|
|
196
202
|
const asArray = (v) => Array.isArray(v) ? v : [];
|
|
197
203
|
return {
|
|
198
204
|
footprints: asArray(value.footprints),
|
|
@@ -223,7 +229,10 @@ function createEdaHostClient(config, deps = {}) {
|
|
|
223
229
|
return body.capabilities.filter((c) => typeof c === "string");
|
|
224
230
|
},
|
|
225
231
|
getPcbSelection: async (options) => {
|
|
226
|
-
return
|
|
232
|
+
return parsePcbSnapshot(await getJson(pcbSelectionUrlOf(resolveConfig()), options, "pcb selection"), "PCB selection");
|
|
233
|
+
},
|
|
234
|
+
getPcbBoard: async (options) => {
|
|
235
|
+
return parsePcbSnapshot(await getJson(pcbBoardUrlOf(resolveConfig()), options, "pcb board"), "PCB board");
|
|
227
236
|
}
|
|
228
237
|
};
|
|
229
238
|
}
|
|
@@ -371,6 +380,29 @@ function createEdaHostTools(env) {
|
|
|
371
380
|
}
|
|
372
381
|
}
|
|
373
382
|
}),
|
|
383
|
+
defineTool({
|
|
384
|
+
name: "get_pcb_board",
|
|
385
|
+
description: "Read the COMPLETE semantic PCB board from the current PCB editor through hq-edge (DSH → dsh-eda-host → hq-edge → EDA host). Returns { ok, snapshot: { footprints[], pads[], tracks[], arcs[], vias[], zones[], shapes[], texts[], dimensions[], groups[], nets[] } } — the same shape as get_pcb_selection, but covering every object on the board regardless of selection. Each footprint has reference, value, footprint, position {x,y} in mm, rotationDeg and pads[] (pin, type, shape, position, widthMm, heightMm, rotationDeg, layer, net{name, code}); tracks have layer, start/end in mm, widthMm, lengthMm and net; vias have layers[], drillMm, viaType and start/end; zones have layer, net and outline segments. Every object carries id — the EDA-host native object identity. IMPORTANT: ok:true with all-empty arrays is a VALID empty board — do not treat it as a failure. " + ERROR_SEMANTICS,
|
|
386
|
+
parameters: {},
|
|
387
|
+
output: {
|
|
388
|
+
schema: { type: "json" },
|
|
389
|
+
render: renderJson
|
|
390
|
+
},
|
|
391
|
+
async execute(_args, exec) {
|
|
392
|
+
try {
|
|
393
|
+
const options = exec?.signal ? { signal: exec.signal } : {};
|
|
394
|
+
return asJson({
|
|
395
|
+
ok: true,
|
|
396
|
+
snapshot: await env.client.getPcbBoard(options)
|
|
397
|
+
});
|
|
398
|
+
} catch (err) {
|
|
399
|
+
return asJson({
|
|
400
|
+
ok: false,
|
|
401
|
+
error: failureOf(err)
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}),
|
|
374
406
|
defineTool({
|
|
375
407
|
name: "get_eda_host_capabilities",
|
|
376
408
|
description: "List the capabilities the CURRENT EDA host provides, using EDA-independent capability identifiers such as EDA_HOST_CAPABILITY_NETLIST, EDA_HOST_CAPABILITY_PCB or EDA_HOST_CAPABILITY_BOM. Returns { ok, capabilities: string[] }. This is DISCOVERY, not execution: it reports capabilities already provided by the connected EDA host. Treat the returned capability list as the authoritative runtime contract for the current host. Do not assume a capability is available merely because the EDA application is generally known to support it. Unknown capability identifiers MUST be treated as unsupported. " + ERROR_SEMANTICS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huaqiu/dsh-eda-host",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.mjs",
|
|
6
6
|
"types": "./lib/index.d.mts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.0"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@huaqiu/dsh-plugin-log": "0.4.
|
|
25
|
+
"@huaqiu/dsh-plugin-log": "0.4.8"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
28
|
"lib",
|
package/src/client.ts
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { DEFAULT_REQUEST_TIMEOUT_MS, hostUrlOf, netlistUrlOf, pcbSelectionUrlOf, type EdaHostConfig, type NetlistScope } from './config.js'
|
|
13
|
+
import { DEFAULT_REQUEST_TIMEOUT_MS, hostUrlOf, netlistUrlOf, pcbBoardUrlOf, pcbSelectionUrlOf, type EdaHostConfig, type NetlistScope } from './config.js'
|
|
14
14
|
import {
|
|
15
15
|
NetlistError,
|
|
16
16
|
type EdaHostCapability,
|
|
17
17
|
type EdaHostInfo,
|
|
18
|
-
type
|
|
18
|
+
type PcbSnapshot,
|
|
19
19
|
type SchematicNetlist,
|
|
20
20
|
} from './types.js'
|
|
21
21
|
|
|
@@ -53,11 +53,17 @@ export interface EdaHostClient {
|
|
|
53
53
|
/** Capabilities the host currently provides. */
|
|
54
54
|
getEdaHostCapabilities(options?: EdaHostRequestOptions): Promise<EdaHostCapability[]>
|
|
55
55
|
/**
|
|
56
|
-
* Semantic PCB
|
|
57
|
-
*
|
|
58
|
-
* selection resolves to an all-empty `
|
|
56
|
+
* Semantic PCB snapshot of the current PCB editor selection (hq.pcb.v1
|
|
57
|
+
* PcbQueryService.GetSelection bridged through hq-edge). An empty
|
|
58
|
+
* selection resolves to an all-empty `PcbSnapshot` — never an error.
|
|
59
59
|
*/
|
|
60
|
-
getPcbSelection(options?: EdaHostRequestOptions): Promise<
|
|
60
|
+
getPcbSelection(options?: EdaHostRequestOptions): Promise<PcbSnapshot>
|
|
61
|
+
/**
|
|
62
|
+
* Semantic PCB snapshot of the complete board (hq.pcb.v1
|
|
63
|
+
* PcbQueryService.GetBoard bridged through hq-edge). An empty board
|
|
64
|
+
* resolves to an all-empty `PcbSnapshot` — never an error.
|
|
65
|
+
*/
|
|
66
|
+
getPcbBoard(options?: EdaHostRequestOptions): Promise<PcbSnapshot>
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
/** HTTP status → semantic error kind (see routes/edaHostStatus.ts on hq-edge). */
|
|
@@ -267,11 +273,11 @@ export function createEdaHostClient(
|
|
|
267
273
|
return parseNetlistBody(await getJson(url, options, 'netlist'))
|
|
268
274
|
}
|
|
269
275
|
|
|
270
|
-
function
|
|
276
|
+
function parsePcbSnapshot(value: unknown, what: string): PcbSnapshot {
|
|
271
277
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
272
278
|
throw new NetlistError(
|
|
273
279
|
'INTERNAL',
|
|
274
|
-
|
|
280
|
+
`eda-host: malformed ${what} response from hq-edge`,
|
|
275
281
|
)
|
|
276
282
|
}
|
|
277
283
|
|
|
@@ -290,7 +296,7 @@ export function createEdaHostClient(
|
|
|
290
296
|
dimensions: asArray((value as Record<string, unknown>).dimensions),
|
|
291
297
|
groups: asArray((value as Record<string, unknown>).groups),
|
|
292
298
|
nets: asArray((value as Record<string, unknown>).nets),
|
|
293
|
-
} as
|
|
299
|
+
} as PcbSnapshot
|
|
294
300
|
}
|
|
295
301
|
|
|
296
302
|
return {
|
|
@@ -331,7 +337,14 @@ export function createEdaHostClient(
|
|
|
331
337
|
const resolved = resolveConfig()
|
|
332
338
|
const url = pcbSelectionUrlOf(resolved)
|
|
333
339
|
const body = (await getJson(url, options, 'pcb selection')) as unknown
|
|
334
|
-
return
|
|
340
|
+
return parsePcbSnapshot(body, 'PCB selection')
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
getPcbBoard: async (options) => {
|
|
344
|
+
const resolved = resolveConfig()
|
|
345
|
+
const url = pcbBoardUrlOf(resolved)
|
|
346
|
+
const body = (await getJson(url, options, 'pcb board')) as unknown
|
|
347
|
+
return parsePcbSnapshot(body, 'PCB board')
|
|
335
348
|
},
|
|
336
349
|
}
|
|
337
350
|
}
|
package/src/config.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface EdaHostConfig {
|
|
|
17
17
|
netlistPathPrefix?: string
|
|
18
18
|
/** Path prefix for PCB selection; default "/api/v1/pcb-selection". */
|
|
19
19
|
pcbSelectionPathPrefix?: string
|
|
20
|
+
/** Path prefix for the complete-board query; default "/api/v1/pcb-board". */
|
|
21
|
+
pcbBoardPathPrefix?: string
|
|
20
22
|
/** Path prefix for host discovery; default "/api/v1/host". */
|
|
21
23
|
hostPathPrefix?: string
|
|
22
24
|
/**
|
|
@@ -34,6 +36,8 @@ export const DEFAULT_NETLIST_PATH_PREFIX = '/api/v1/netlist'
|
|
|
34
36
|
|
|
35
37
|
export const DEFAULT_PCB_SELECTION_PATH_PREFIX = '/api/v1/pcb-selection'
|
|
36
38
|
|
|
39
|
+
export const DEFAULT_PCB_BOARD_PATH_PREFIX = '/api/v1/pcb-board'
|
|
40
|
+
|
|
37
41
|
export const DEFAULT_HOST_PATH_PREFIX = '/api/v1/host'
|
|
38
42
|
|
|
39
43
|
export const DEFAULT_REQUEST_TIMEOUT_MS = 30_000
|
|
@@ -58,6 +62,10 @@ export function resolveEdaHostConfig(
|
|
|
58
62
|
config?.pcbSelectionPathPrefix ??
|
|
59
63
|
env.HQ_EDGE_PCB_SELECTION_PATH ??
|
|
60
64
|
DEFAULT_PCB_SELECTION_PATH_PREFIX
|
|
65
|
+
const pcbBoardPrefix =
|
|
66
|
+
config?.pcbBoardPathPrefix ??
|
|
67
|
+
env.HQ_EDGE_PCB_BOARD_PATH ??
|
|
68
|
+
DEFAULT_PCB_BOARD_PATH_PREFIX
|
|
61
69
|
const hostPrefix =
|
|
62
70
|
config?.hostPathPrefix ?? env.HQ_EDGE_HOST_PATH ?? DEFAULT_HOST_PATH_PREFIX
|
|
63
71
|
const timeoutRaw = config?.requestTimeoutMs ?? env.HQ_EDGE_REQUEST_TIMEOUT_MS
|
|
@@ -66,6 +74,7 @@ export function resolveEdaHostConfig(
|
|
|
66
74
|
hqEdgeBaseUrl: baseUrl,
|
|
67
75
|
netlistPathPrefix: pathPrefix,
|
|
68
76
|
pcbSelectionPathPrefix: pcbSelectionPrefix,
|
|
77
|
+
pcbBoardPathPrefix: pcbBoardPrefix,
|
|
69
78
|
hostPathPrefix: hostPrefix,
|
|
70
79
|
requestTimeoutMs:
|
|
71
80
|
Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_REQUEST_TIMEOUT_MS,
|
|
@@ -94,6 +103,16 @@ export function pcbSelectionUrlOf(config: EdaHostConfig): string {
|
|
|
94
103
|
return `${base}/${prefix}`
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
/** Build the absolute URL for the complete-board query route. */
|
|
107
|
+
export function pcbBoardUrlOf(config: EdaHostConfig): string {
|
|
108
|
+
const base = (config.hqEdgeBaseUrl ?? '').replace(/\/+$/, '')
|
|
109
|
+
const prefix = (config.pcbBoardPathPrefix ?? DEFAULT_PCB_BOARD_PATH_PREFIX).replace(
|
|
110
|
+
/^\/+|\/+$/g,
|
|
111
|
+
'',
|
|
112
|
+
)
|
|
113
|
+
return `${base}/${prefix}`
|
|
114
|
+
}
|
|
115
|
+
|
|
97
116
|
/** Host discovery route suffix. */
|
|
98
117
|
export type HostRoute = 'info' | 'capabilities'
|
|
99
118
|
|
package/src/index.ts
CHANGED
package/src/tools.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
26
26
|
import type { EdaHostClient, EdaHostRequestOptions } from './client.js'
|
|
27
|
-
import { NetlistError, type EdaHostCapability, type EdaHostInfo, type
|
|
27
|
+
import { NetlistError, type EdaHostCapability, type EdaHostInfo, type PcbSnapshot, type SchematicNetlist } from './types.js'
|
|
28
28
|
|
|
29
29
|
/** Structural alias of the DSH `JsonValue`. */
|
|
30
30
|
type Json = string | number | boolean | null | Json[] | { [key: string]: Json }
|
|
@@ -63,7 +63,11 @@ type HostCapabilitiesResult =
|
|
|
63
63
|
| { ok: false; error: { kind: string; message: string } }
|
|
64
64
|
|
|
65
65
|
type PcbSelectionResult =
|
|
66
|
-
| { ok: true; selection:
|
|
66
|
+
| { ok: true; selection: PcbSnapshot }
|
|
67
|
+
| { ok: false; error: { kind: string; message: string } }
|
|
68
|
+
|
|
69
|
+
type PcbBoardResult =
|
|
70
|
+
| { ok: true; snapshot: PcbSnapshot }
|
|
67
71
|
| { ok: false; error: { kind: string; message: string } }
|
|
68
72
|
|
|
69
73
|
/**
|
|
@@ -229,6 +233,37 @@ export function createNetListTools(env: NetlistToolEnv) {
|
|
|
229
233
|
},
|
|
230
234
|
}),
|
|
231
235
|
|
|
236
|
+
defineTool({
|
|
237
|
+
name: 'get_pcb_board',
|
|
238
|
+
description:
|
|
239
|
+
`Read the COMPLETE semantic PCB board from the current PCB editor through hq-edge ` +
|
|
240
|
+
`(DSH → dsh-eda-host → hq-edge → EDA host). Returns { ok, snapshot: { footprints[], ` +
|
|
241
|
+
`pads[], tracks[], arcs[], vias[], zones[], shapes[], texts[], dimensions[], groups[], ` +
|
|
242
|
+
`nets[] } } — the same shape as get_pcb_selection, but covering every object on the ` +
|
|
243
|
+
`board regardless of selection. ` +
|
|
244
|
+
`Each footprint has reference, value, footprint, position {x,y} in mm, rotationDeg and ` +
|
|
245
|
+
`pads[] (pin, type, shape, position, widthMm, heightMm, rotationDeg, layer, net{name, ` +
|
|
246
|
+
`code}); tracks have layer, start/end in mm, widthMm, lengthMm and net; vias have ` +
|
|
247
|
+
`layers[], drillMm, viaType and start/end; zones have layer, net and outline segments. ` +
|
|
248
|
+
`Every object carries id — the EDA-host native object identity. ` +
|
|
249
|
+
`IMPORTANT: ok:true with all-empty arrays is a VALID empty board — do not treat it as ` +
|
|
250
|
+
`a failure. ` +
|
|
251
|
+
ERROR_SEMANTICS,
|
|
252
|
+
parameters: {},
|
|
253
|
+
output: { schema: { type: 'json' }, render: renderJson },
|
|
254
|
+
async execute(_args: unknown, exec: ToolExecLike): Promise<Json> {
|
|
255
|
+
try {
|
|
256
|
+
const options: EdaHostRequestOptions = exec?.signal
|
|
257
|
+
? { signal: exec.signal }
|
|
258
|
+
: {}
|
|
259
|
+
const snapshot = await env.client.getPcbBoard(options)
|
|
260
|
+
return asJson<PcbBoardResult>({ ok: true, snapshot })
|
|
261
|
+
} catch (err) {
|
|
262
|
+
return asJson<PcbBoardResult>({ ok: false, error: failureOf(err) })
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
}),
|
|
266
|
+
|
|
232
267
|
defineTool({
|
|
233
268
|
name: 'get_eda_host_capabilities',
|
|
234
269
|
description:
|
package/src/types.ts
CHANGED
|
@@ -55,12 +55,13 @@ export interface SchematicNetlist {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* Semantic PCB
|
|
58
|
+
* Semantic PCB snapshot types.
|
|
59
59
|
*
|
|
60
60
|
* Self-contained structural mirror of `hq.pcb.v1` (the hq-edge-owned semantic
|
|
61
|
-
* protobuf contract for `
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
* protobuf contract for `PcbQueryService.GetSelection` / `GetBoard`). The
|
|
62
|
+
* same PcbSnapshot shape backs both the current selection and the complete
|
|
63
|
+
* board. Units follow the hq.pcb.v1 convention: positions/sizes/lengths in mm,
|
|
64
|
+
* rotations in degrees, `id` is the KiCad native object identity.
|
|
64
65
|
*/
|
|
65
66
|
|
|
66
67
|
export interface PcbPoint {
|
|
@@ -172,7 +173,7 @@ export interface PcbGroup {
|
|
|
172
173
|
itemIds: string[]
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
export interface
|
|
176
|
+
export interface PcbSnapshot {
|
|
176
177
|
footprints: PcbFootprint[]
|
|
177
178
|
pads: PcbPad[]
|
|
178
179
|
tracks: PcbTrack[]
|