@huaqiu/dsh-hqsch 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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -0
  3. package/cordis.patch.yml +13 -0
  4. package/lib/index.d.mts +98 -0
  5. package/lib/index.mjs +159 -0
  6. package/package.json +40 -0
  7. package/skills/hqsch-scenario-b/AGENTS.md +209 -0
  8. package/skills/hqsch-scenario-b/CLAUDE.md +209 -0
  9. package/skills/hqsch-scenario-b/INSTALL.md +140 -0
  10. package/skills/hqsch-scenario-b/SKILL.md +107 -0
  11. package/skills/hqsch-scenario-b/SYSTEM-PROMPT.md +209 -0
  12. package/skills/hqsch-scenario-b/docs/circuit-pattern-layout.md +304 -0
  13. package/skills/hqsch-scenario-b/docs/editing-a-circuit.md +167 -0
  14. package/skills/hqsch-scenario-b/docs/part-search.md +244 -0
  15. package/skills/hqsch-scenario-b/docs/placement-conventions.md +714 -0
  16. package/skills/hqsch-scenario-b/docs/property-conventions.md +225 -0
  17. package/skills/hqsch-scenario-b/docs/quickstart.md +99 -0
  18. package/skills/hqsch-scenario-b/docs/reading-a-circuit.md +317 -0
  19. package/skills/hqsch-scenario-b/docs/rpc/canvas-auto-connect-objects-by-id.md +98 -0
  20. package/skills/hqsch-scenario-b/docs/rpc/canvas-delete-objects-by-ids.md +94 -0
  21. package/skills/hqsch-scenario-b/docs/rpc/canvas-find-object-by-property.md +101 -0
  22. package/skills/hqsch-scenario-b/docs/rpc/canvas-list-wire-segments.md +94 -0
  23. package/skills/hqsch-scenario-b/docs/rpc/canvas-mirror-objects-by-ids.md +96 -0
  24. package/skills/hqsch-scenario-b/docs/rpc/canvas-rotate-objects-by-ids.md +94 -0
  25. package/skills/hqsch-scenario-b/docs/rpc/canvas-set-object-property.md +99 -0
  26. package/skills/hqsch-scenario-b/docs/rpc/canvas-zoom-all.md +92 -0
  27. package/skills/hqsch-scenario-b/docs/rpc/find-find-object.md +96 -0
  28. package/skills/hqsch-scenario-b/docs/rpc/kernel-get-snapshot.md +104 -0
  29. package/skills/hqsch-scenario-b/docs/rpc/netlist-get-active-page-net-list.md +87 -0
  30. package/skills/hqsch-scenario-b/docs/rpc/netlist-get-port-pairing.md +34 -0
  31. package/skills/hqsch-scenario-b/docs/rpc/obj-place-place-pin-stub-wire-and-net-alias.md +114 -0
  32. package/skills/hqsch-scenario-b/docs/rpc/pattern-layout-apply-circuit-pattern.md +125 -0
  33. package/skills/hqsch-scenario-b/docs/rpc/pattern-layout-get-page-occupancy.md +100 -0
  34. package/skills/hqsch-scenario-b/docs/rpc/pattern-layout-list-circuit-patterns.md +97 -0
  35. package/skills/hqsch-scenario-b/docs/rpc/placement-list-part-libraries.md +94 -0
  36. package/skills/hqsch-scenario-b/docs/rpc/placement-list-symbol-libraries.md +94 -0
  37. package/skills/hqsch-scenario-b/docs/rpc/placement-place-kicad-symbol.md +105 -0
  38. package/skills/hqsch-scenario-b/docs/rpc/placement-place-part-from-library.md +106 -0
  39. package/skills/hqsch-scenario-b/docs/rpc/placement-place-symbol-from-library.md +108 -0
  40. package/skills/hqsch-scenario-b/docs/rpc/project-get-active-project.md +96 -0
  41. package/skills/hqsch-scenario-b/docs/rpc/project-list-open-projects.md +99 -0
  42. package/skills/hqsch-scenario-b/docs/rpc-availability.md +97 -0
  43. package/skills/hqsch-scenario-b/docs/rpc-index/canvas.md +81 -0
  44. package/skills/hqsch-scenario-b/docs/rpc-index/find.md +36 -0
  45. package/skills/hqsch-scenario-b/docs/rpc-index/kernel.md +36 -0
  46. package/skills/hqsch-scenario-b/docs/rpc-index/netlist.md +38 -0
  47. package/skills/hqsch-scenario-b/docs/rpc-index/obj-place.md +76 -0
  48. package/skills/hqsch-scenario-b/docs/rpc-index/pattern-layout.md +38 -0
  49. package/skills/hqsch-scenario-b/docs/rpc-index/placement.md +48 -0
  50. package/skills/hqsch-scenario-b/docs/rpc-index/project.md +47 -0
  51. package/skills/hqsch-scenario-b/docs/serialization.md +60 -0
  52. package/skills/hqsch-scenario-b/docs/skill-dependencies.md +93 -0
  53. package/skills/hqsch-scenario-b/skill.json +13 -0
  54. package/skills/hqsch-scenario-b/template/package.json +16 -0
  55. package/skills/hqsch-scenario-b/template/scripts/edit-property-by-ref.ts +44 -0
  56. package/skills/hqsch-scenario-b/template/scripts/fix-designators.ts +52 -0
  57. package/skills/hqsch-scenario-b/template/scripts/hello.ts +46 -0
  58. package/skills/hqsch-scenario-b/template/scripts/read-circuit.ts +357 -0
  59. package/skills/hqsch-scenario-b/template/scripts/replace-part-by-ref.ts +44 -0
  60. package/skills/hqsch-scenario-b/template/scripts/rewire-pin-by-ref.ts +42 -0
  61. package/skills/hqsch-scenario-b/template/tsconfig.json +11 -0
  62. package/src/config.ts +25 -0
  63. package/src/index.ts +186 -0
  64. package/src/paths.ts +48 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 深圳华秋智联股份有限公司
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # @huaqiu/dsh-hqsch
2
+
3
+ HQSCH scenario-b agent skill for DeepSeek Harness, shipped as one DSH plugin.
4
+ Installing the Huaqiu DSH PCB/EDA bundle makes the `hqsch-scenario-b` skill
5
+ available without a separate skill installation step.
6
+
7
+ ## What You Get
8
+
9
+ ```
10
+ @huaqiu/dsh-hqsch
11
+ └── Skills hqsch-scenario-b - SKILL.md + SYSTEM-PROMPT.md + docs/ + template/
12
+ ```
13
+
14
+ This package intentionally registers no DSH tools. The bundled skill teaches the
15
+ agent to generate TypeScript scripts from `template/` and execute them locally
16
+ against HQ EDA.
17
+
18
+ ## How The Plugin Is Wired
19
+
20
+ ```yaml
21
+ - insert:
22
+ - id: huaqiu-dsh-hqsch
23
+ name: '@huaqiu/dsh-hqsch'
24
+ inject: ['skills']
25
+ ```
26
+
27
+ `skills` is the DSH runtime's plugin-bundled skill registry. `apply()` registers
28
+ the `hqsch-scenario-b` skill and returns a disposer.
29
+
30
+ The skill is resolved relative to the loaded module:
31
+
32
+ ```
33
+ <package>/lib/index.mjs -> <package>/skills/hqsch-scenario-b
34
+ ```
35
+
36
+ That is why `files[]` contains `skills`; otherwise npm would strip the bundled
37
+ skill from the published artifact.
38
+
39
+ ## Runtime Requirements
40
+
41
+ The skill's own instructions apply: HQ EDA desktop must be running with a
42
+ schematic project open, and the agent runs generated TypeScript scripts from the
43
+ bundled `template/` directory.
@@ -0,0 +1,13 @@
1
+ # DSH bundle patch: inserts the Huaqiu HQSCH scenario-b bundled skill plugin.
2
+ #
3
+ # This package registers the `hqsch-scenario-b` skill at load time via
4
+ # `ctx.skills.register()`. It intentionally registers no tools: scenario-b
5
+ # teaches the agent to generate and execute local TypeScript scripts against
6
+ # HQ EDA.
7
+ #
8
+ # The entry `inject` MUST match the node-half module contract (`src/index.ts`
9
+ # `export const inject`): `skills`.
10
+ - insert:
11
+ - id: huaqiu-dsh-hqsch
12
+ name: '@huaqiu/dsh-hqsch'
13
+ inject: ['skills']
@@ -0,0 +1,98 @@
1
+ import { Context } from "@deepseek-ai/cordis";
2
+ //#region src/config.d.ts
3
+ /**
4
+ * Configuration for `@huaqiu/dsh-hqsch`.
5
+ *
6
+ * This plugin only bundles and registers the HQSCH scenario-b skill. The skill
7
+ * itself guides the agent to generate and run local TypeScript scripts against
8
+ * HQ EDA, so there is no host connection configured here.
9
+ *
10
+ * @module
11
+ */
12
+ /** Canonical skill directory name shipped by this package. */
13
+ declare const HQSCH_SKILL_NAME = "hqsch-scenario-b";
14
+ /** Configuration accepted by the plugin's `apply()`. */
15
+ interface HqschConfig {
16
+ /** Bundled skill directory override (defaults to this package's skills/). */
17
+ skillsDir?: string;
18
+ }
19
+ type HqschConfigInput = Partial<HqschConfig>;
20
+ //#endregion
21
+ //#region src/paths.d.ts
22
+ /**
23
+ * Absolute path of the bundled HQSCH scenario-b skill directory.
24
+ *
25
+ * Resolution order: explicit override, `DSH_HQSCH_SKILLS_DIR`, then the
26
+ * package-relative location.
27
+ */
28
+ declare function resolveSkillDir(moduleUrl: string, override?: string): string;
29
+ /**
30
+ * Resolve the skill directory and assert the skill is actually present.
31
+ *
32
+ * @throws when `SKILL.md` is missing.
33
+ */
34
+ declare function requireSkillDir(moduleUrl: string, override?: string): string;
35
+ //#endregion
36
+ //#region src/index.d.ts
37
+ /** Plugin id - matches package.json. */
38
+ declare const name = "@huaqiu/dsh-hqsch";
39
+ /**
40
+ * `skills` is REQUIRED: it is the DSH runtime's plugin-bundled skill registry.
41
+ */
42
+ declare const inject: readonly ["skills"];
43
+ /** The `skills` service shape consumed by this plugin. */
44
+ interface SkillRegistration {
45
+ /** Skill id - must match DSH's discoverable skill id format. */
46
+ name: string;
47
+ /** Catalog description shown to the model. */
48
+ description: string;
49
+ /** Full SKILL.md body. */
50
+ content: string;
51
+ /** Discovery source for plugin-bundled skills. */
52
+ source: 'runtime';
53
+ /** Where docs/ and template/ live for progressive disclosure. */
54
+ resourceBase: {
55
+ kind: 'directory';
56
+ path: string;
57
+ };
58
+ }
59
+ declare module '@deepseek-ai/cordis' {
60
+ interface Context {
61
+ /** DSH skill registry, provided by the runtime skill service. */
62
+ skills: {
63
+ /** Register a plugin-bundled skill; returns its unregister disposer. */
64
+ register(skill: SkillRegistration): () => void;
65
+ };
66
+ }
67
+ }
68
+ /**
69
+ * Extract the `description` field from SKILL.md YAML frontmatter.
70
+ *
71
+ * Supports both single-line values and the folded block form used by
72
+ * hqeda-scenario-b (`description: >-` followed by indented lines).
73
+ */
74
+ declare function skillDescription(markdown: string): string | undefined;
75
+ /** Read the bundled HQSCH scenario-b SKILL.md. */
76
+ declare function readBundledSkill(moduleUrl: string, override?: string): {
77
+ dir: string;
78
+ name: string;
79
+ description: string;
80
+ content: string;
81
+ };
82
+ /**
83
+ * Read the bundled skill, or `null` when the installed package does not carry
84
+ * one. A missing skill is a packaging failure, but it should degrade this
85
+ * plugin instead of killing the whole DSH process.
86
+ */
87
+ declare function tryReadBundledSkill(moduleUrl: string, override?: string): {
88
+ dir: string;
89
+ name: string;
90
+ description: string;
91
+ content: string;
92
+ } | null;
93
+ /**
94
+ * Host plugin body - register the bundled HQSCH scenario-b skill.
95
+ */
96
+ declare function apply(ctx: Context, config?: HqschConfigInput): () => void;
97
+ //#endregion
98
+ export { HQSCH_SKILL_NAME, type HqschConfig, type HqschConfigInput, SkillRegistration, apply, inject, name, readBundledSkill, requireSkillDir, resolveSkillDir, skillDescription, tryReadBundledSkill };
package/lib/index.mjs ADDED
@@ -0,0 +1,159 @@
1
+ import { getLogger } from "@huaqiu/dsh-plugin-log";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ //#region src/config.ts
6
+ /**
7
+ * Configuration for `@huaqiu/dsh-hqsch`.
8
+ *
9
+ * This plugin only bundles and registers the HQSCH scenario-b skill. The skill
10
+ * itself guides the agent to generate and run local TypeScript scripts against
11
+ * HQ EDA, so there is no host connection configured here.
12
+ *
13
+ * @module
14
+ */
15
+ /** Canonical skill directory name shipped by this package. */
16
+ const HQSCH_SKILL_NAME = "hqsch-scenario-b";
17
+ /** Whether any host configuration was supplied (used for startup logging). */
18
+ function hasHostConfig(input = {}) {
19
+ return Boolean(input.skillsDir ?? process.env["DSH_HQSCH_SKILLS_DIR"]);
20
+ }
21
+ //#endregion
22
+ //#region src/paths.ts
23
+ /**
24
+ * Resolution of the bundled HQSCH scenario-b skill directory at runtime.
25
+ *
26
+ * The skill ships inside the installed package
27
+ * (`<pkg>/skills/hqsch-scenario-b/`), not beside a separate checkout. Resolving
28
+ * relative to the loaded module works for source tests, built artifacts and npm
29
+ * installs.
30
+ *
31
+ * @module
32
+ */
33
+ /**
34
+ * Absolute path of the bundled HQSCH scenario-b skill directory.
35
+ *
36
+ * Resolution order: explicit override, `DSH_HQSCH_SKILLS_DIR`, then the
37
+ * package-relative location.
38
+ */
39
+ function resolveSkillDir(moduleUrl, override) {
40
+ if (override && override.trim().length > 0) return resolve(override);
41
+ const envOverride = process.env["DSH_HQSCH_SKILLS_DIR"];
42
+ if (envOverride && envOverride.trim().length > 0) return resolve(envOverride);
43
+ const here = dirname(fileURLToPath(moduleUrl));
44
+ return resolve(here, "..", "skills", HQSCH_SKILL_NAME);
45
+ }
46
+ /**
47
+ * Resolve the skill directory and assert the skill is actually present.
48
+ *
49
+ * @throws when `SKILL.md` is missing.
50
+ */
51
+ function requireSkillDir(moduleUrl, override) {
52
+ const dir = resolveSkillDir(moduleUrl, override);
53
+ const skillFile = join(dir, "SKILL.md");
54
+ if (!existsSync(skillFile)) throw new Error(`@huaqiu/dsh-hqsch: bundled skill missing at ${skillFile}. The installed package is incomplete; reinstall @huaqiu/dsh-hqsch so that its skills/ directory is present.`);
55
+ return dir;
56
+ }
57
+ //#endregion
58
+ //#region src/index.ts
59
+ /** Plugin id - matches package.json. */
60
+ const name = "@huaqiu/dsh-hqsch";
61
+ /**
62
+ * `skills` is REQUIRED: it is the DSH runtime's plugin-bundled skill registry.
63
+ */
64
+ const inject = ["skills"];
65
+ const log = getLogger("dsh-hqsch");
66
+ log.info("dsh-hqsch: module loaded (waiting for the skills service)");
67
+ const FALLBACK_SKILL_DESCRIPTION = "HQSCH scenario-b automation skill for HQ EDA schematic drawing, reading and local surgical edits through generated TypeScript scripts.";
68
+ /**
69
+ * Extract the `description` field from SKILL.md YAML frontmatter.
70
+ *
71
+ * Supports both single-line values and the folded block form used by
72
+ * hqeda-scenario-b (`description: >-` followed by indented lines).
73
+ */
74
+ function skillDescription(markdown) {
75
+ const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---/.exec(markdown);
76
+ if (!frontmatter?.[1]) return void 0;
77
+ const lines = frontmatter[1].split(/\r?\n/);
78
+ const lineIndex = lines.findIndex((candidate) => /^\s*description\s*:/.test(candidate));
79
+ if (lineIndex < 0) return void 0;
80
+ const raw = lines[lineIndex].slice(lines[lineIndex].indexOf(":") + 1).trim();
81
+ if (raw === ">-" || raw === ">" || raw === "|-" || raw === "|") {
82
+ const block = [];
83
+ for (const line of lines.slice(lineIndex + 1)) {
84
+ if (/^\s+\S/.test(line)) {
85
+ block.push(line.trim());
86
+ continue;
87
+ }
88
+ if (line.trim().length === 0) continue;
89
+ break;
90
+ }
91
+ const text = block.join(" ").trim();
92
+ return text.length > 0 ? text : void 0;
93
+ }
94
+ const unquoted = raw.replace(/^["']/, "").replace(/["']$/, "");
95
+ return unquoted.length > 0 ? unquoted : void 0;
96
+ }
97
+ /** Read the bundled HQSCH scenario-b SKILL.md. */
98
+ function readBundledSkill(moduleUrl, override) {
99
+ const dir = requireSkillDir(moduleUrl, override);
100
+ const content = readFileSync(join(dir, "SKILL.md"), "utf8");
101
+ return {
102
+ dir,
103
+ name: HQSCH_SKILL_NAME,
104
+ description: skillDescription(content) ?? FALLBACK_SKILL_DESCRIPTION,
105
+ content
106
+ };
107
+ }
108
+ /**
109
+ * Read the bundled skill, or `null` when the installed package does not carry
110
+ * one. A missing skill is a packaging failure, but it should degrade this
111
+ * plugin instead of killing the whole DSH process.
112
+ */
113
+ function tryReadBundledSkill(moduleUrl, override) {
114
+ try {
115
+ return readBundledSkill(moduleUrl, override);
116
+ } catch (err) {
117
+ log.error("dsh-hqsch: bundled skill unavailable - continuing degraded without skill registration", {
118
+ expectedDir: resolveSkillDir(moduleUrl, override),
119
+ error: String(err?.message ?? err)
120
+ });
121
+ return null;
122
+ }
123
+ }
124
+ /**
125
+ * Host plugin body - register the bundled HQSCH scenario-b skill.
126
+ */
127
+ function apply(ctx, config = {}) {
128
+ if (!ctx.skills || typeof ctx.skills.register !== "function") throw new Error("@huaqiu/dsh-hqsch requires the DSH `skills` service (ctx.skills.register).");
129
+ const skill = tryReadBundledSkill(import.meta.url, config.skillsDir);
130
+ log.info("applying dsh-hqsch node half", {
131
+ hasConfigHost: hasHostConfig(config),
132
+ skillDir: skill?.dir ?? resolveSkillDir(import.meta.url, config.skillsDir),
133
+ skillPresent: skill !== null
134
+ });
135
+ const disposers = [];
136
+ if (skill) disposers.push(ctx.skills.register({
137
+ name: skill.name,
138
+ description: skill.description,
139
+ content: skill.content,
140
+ source: "runtime",
141
+ resourceBase: {
142
+ kind: "directory",
143
+ path: skill.dir
144
+ }
145
+ }));
146
+ log.info("dsh-hqsch node half ready", {
147
+ skill: skill?.name ?? null,
148
+ degraded: skill === null
149
+ });
150
+ return () => {
151
+ for (const dispose of disposers.reverse()) try {
152
+ dispose();
153
+ } catch (err) {
154
+ log.warn("dsh-hqsch disposer failed", { error: String(err?.message ?? err) });
155
+ }
156
+ };
157
+ }
158
+ //#endregion
159
+ export { HQSCH_SKILL_NAME, apply, inject, name, readBundledSkill, requireSkillDir, resolveSkillDir, skillDescription, tryReadBundledSkill };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@huaqiu/dsh-hqsch",
3
+ "version": "0.4.8",
4
+ "type": "module",
5
+ "main": "./lib/index.mjs",
6
+ "types": "./lib/index.d.mts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./lib/index.d.mts",
10
+ "default": "./lib/index.mjs"
11
+ },
12
+ "./cordis.patch.yml": "./cordis.patch.yml",
13
+ "./package.json": "./package.json"
14
+ },
15
+ "dsh": {
16
+ "bundle": {
17
+ "patch": "./cordis.patch.yml"
18
+ }
19
+ },
20
+ "peerDependencies": {
21
+ "@deepseek-ai/cordis": "^4.0.1"
22
+ },
23
+ "dependencies": {
24
+ "@huaqiu/dsh-plugin-log": "0.4.8"
25
+ },
26
+ "files": [
27
+ "lib",
28
+ "src",
29
+ "skills",
30
+ "cordis.patch.yml"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "scripts": {
36
+ "typecheck": "tsc --noEmit",
37
+ "build": "tsdown",
38
+ "test": "vitest run"
39
+ }
40
+ }
@@ -0,0 +1,209 @@
1
+ # HQ EDA 原理图自动化 — System Prompt / 项目指令
2
+
3
+ > **默认语言:中文。** 安装说明见 [INSTALL.md](./INSTALL.md)。
4
+ >
5
+ > | 平台 | 用法 |
6
+ > | --- | --- |
7
+ > | **Codex CLI** | 复制到项目根 `AGENTS.md`,或 `.codex/instructions.md` |
8
+ > | **Work Buddy** | 粘贴到平台 System Prompt UI,或合并进项目 `AGENTS.md` |
9
+ > | **Claude Project** | Custom Instructions 粘贴全文;Project Knowledge 上传 `docs/` |
10
+
11
+ ---
12
+
13
+ 你是 HQ EDA 原理图自动化助手。你**不直接连接**编辑器;你在用户工作区内生成 TypeScript 脚本,并**在终端自动执行** `npx tsx scripts/xxx.ts`,读取 stdout/stderr 并根据结果修正脚本。
14
+
15
+ ## 必读文档(按顺序,路径相对本 skill 包根目录)
16
+
17
+ 1. `docs/placement-conventions.md` — 坐标、布局、**routing mode gate**(短→autoConnect,长→stub+alias)
18
+ 2. `docs/circuit-pattern-layout.md` — 优先用 pattern(pull_resistor、reset_circuit、decoupling_cap)
19
+ 3. `docs/part-search.md` — searchParts → getEdaModels → PlaceKicadSymbol
20
+ 4. `docs/quickstart.md` — connect、createProjectContext
21
+ 5. `docs/property-conventions.md` — 位号、引脚坐标
22
+ 6. `docs/reading-a-circuit.md` — 读电路 / GetSnapshot 三表联结 / 邻域 / 串联穿透
23
+ 7. `docs/editing-a-circuit.md` — **局部改电路(Flow C)** / 确认 diff / 修改集 / 验收
24
+ 8. `docs/rpc-availability.md` — 接口可用性、禁建列表、耗时基线
25
+ 9. `docs/serialization.md` — toJsonString 与 BigInt
26
+ 10. `docs/rpc/*.md` — 仅当需要某个 RPC 的精确字段名时查阅
27
+
28
+ ## 硬性规则
29
+
30
+ - 器件(R/C/Q/U):在线搜索 + `client.componentPlace.placeKicadSymbol`;**禁止**手写 `json_part` / `PlacePart`
31
+ - 电源符号:`ListSymbolLibraries` → `PlaceSymbolFromLibrary`
32
+ - `kind`:电源/地用 **`LibrarySymbolKind.GLOBAL`(=1)**;`OFF_PAGE=2`,`PORT=3`
33
+ - **`symbolName`** = 库里的**图形符号名**(模糊匹配库符号)
34
+ - **`netName`** = 写入实例 **"Name"** 用户属性的网络名;传空则 Name 沿用 `symbolName` —— **勿把图形名和网络名混为一谈**
35
+ - `autoConnect` 时电源符号引脚用 pin **0**
36
+ - **先 pattern 后 hand-wire**;`connections[].routed=true` 的 net 不要重连
37
+ - **每条 net 先跑 routing gate**:量距离 → 短(≤300 ext、交叉<3)用 `autoConnect`;长/拥挤用双端 `placePinStubWireAndNetAlias`(同一 `netName`)
38
+ - 字母引脚(CC1、A5):用 `pinName` / `pinNumber` **字符串**,禁止 `Number("A5")`
39
+ - **pattern 的 host 电源引脚必须用 `pinName` 绑定**(如 `pinName:"VIN"`);用 `pinNum` 会返回 `PIN_RESOLVE_FAILED`
40
+ - **放置后必须等对象注册再 apply**:轮询 `getPageOccupancy` 直到所有新 id 出现,否则 apply 报 `OBJECT_NOT_FOUND` 或假 `PARTIAL`
41
+ - **读取导线段字段是 `wires`**(`listWireSegments().wires`),**不是** `wireSegments`
42
+ - 打印 protobuf 响应用 `toJsonString`;禁止对 RPC 结果裸 `JSON.stringify()`。遍历快照 `position.x/y`(bigint)时见 `docs/serialization.md` replacer
43
+ - 耗时基线(区间,非 SLA):快照约 **1.6–3.2s**;单次 pattern/放置脚本约 **15–20s**(抖动正常)。勿用超时反推「未实现」
44
+
45
+ ## Agent 执行流程(必须遵守)
46
+
47
+ **先判任务类型**:
48
+ - **画电路** → 按「流程 A」执行;不可跳过 pattern 规划直接写放置/接线代码。
49
+ - **读电路 / 理解已有设计**(如"VR201 有什么作用"、"这个网络为什么叫 +3.3V")→ 按「流程 B」,**只读不改**。
50
+ - **改部分电路**(如"把 C201 改成 1µF"、"把 R5 改接到 +3.3V"、"换掉 U3")→ 按「流程 C」,**外科手术式**;禁止清页重画。
51
+
52
+ ### 流程 A — 画电路
53
+
54
+ 1. **连通性检查**(首次任务前):在 `template/` 执行 `npm install`(若未安装),然后 `npx tsx scripts/hello.ts`;失败则停止并提示用户打开 HQ EDA 与原理图工程。
55
+
56
+ 2. **Pattern 规划**(生成脚本前,必做):
57
+ - 先调 `client.patternLayout.listCircuitPatterns({ context: ctx })` 刷新目录(RPC 是权威来源)。
58
+ - 读 `docs/circuit-pattern-layout.md`,对照用户需求列出适用的 pattern。
59
+ - 在脚本设计说明里**先写**将用哪些 pattern、host 器件、各 pattern 的 roles / anchor。
60
+ - 若无适用 pattern,在设计说明中**显式声明**「本任务无 pattern,原因:…」,再进入 hand-wire。
61
+
62
+ **Pattern 触发词表**(需求中出现 → 先想 pattern,不许直接手画):
63
+
64
+ | 需求特征 | pattern | apply 次数 |
65
+ | --- | --- | --- |
66
+ | LDO / 稳压 / 输入输出滤波 / 去耦 / 旁路电容 | `decoupling_cap` | 每个电源引脚一次 |
67
+ | 上拉 / 下拉电阻 | `pull_resistor` | 同极性同 rail 合并一次 |
68
+ | 复位电路 / reset 按键 | `reset_circuit` | 一次 |
69
+ | I2C + 上拉 | `i2c_bus` | 一次 |
70
+ | SPI 主从 | `spi_bus` | 一次(route_mode=NONE) |
71
+ | 晶振 + 负载电容 | `crystal` | 一次 |
72
+
73
+ 3. **生成脚本**(脚本内电路步骤顺序固定):
74
+ ```
75
+ connect → getActiveProject → createProjectContext
76
+ → 放置 host / 独立器件(part-search → placeKicadSymbol;电源符号 → PlaceSymbolFromLibrary)
77
+ → 【等待注册】轮询 getPageOccupancy 直到所有新 id 出现(关键!否则 apply 失败)
78
+ → 规范位号 / 容值(覆盖引擎自动分配的 C1..C4)
79
+ → applyCircuitPattern(每个适用 pattern 一次;先 planOnly 可选,再正式 apply)
80
+ → 仅对 pattern 未覆盖的 net 做 hand-wire(每条 net 先跑 routing gate)
81
+ → zoomAll + 验收输出(netlist + listWireSegments().wires)
82
+ ```
83
+ 写入 `template/scripts/<名称>.ts`(或用户指定的 scripts 目录)。
84
+ **禁止**跳过 `applyCircuitPattern` 直接 `autoConnect` 全图;**禁止**重连 `connections[].routed=true` 的 net。
85
+
86
+ 4. **自动执行**:立即在脚本所在目录运行 `npx tsx scripts/<名称>.ts`,读取 stdout/stderr。
87
+
88
+ 5. **失败重试**:若脚本报错,根据 stderr 修正后重试,**最多 3 次**。
89
+
90
+ 6. **验收**(脚本成功后必做):
91
+ - 检查每个 pattern 的 `status` / `connections`(是否 `routed=true`)。
92
+ - 用 `netList.getActivePageNetList` 核对关键 net(**注意访问器是 `netList`,大写 L**)。
93
+ - 用 `canvasOps.listWireSegments` 统计导线段 —— **字段是 `wires`**,`wireSegments` 会恒为 undefined。
94
+ - 调用 `client.canvasOps.zoomAll({ context: ctx })` 便于用户目视检查。
95
+ - ERC 在部分构建中未实现(`RunChecks not implemented`),不要把它当验收依赖。
96
+
97
+ ### 流程 B — 读电路 / 理解已有设计
98
+
99
+ **只读**:不放置、不删除、不改属性。详见 `docs/reading-a-circuit.md`。
100
+
101
+ 1. `client.project.getActiveProject` → **打印 projectId**;不要跨任务缓存(用户可能切换工程,编辑器也可能重启)。
102
+ 2. `client.kernel.getSnapshot({ context: ctx })` —— **一次调用覆盖全工程**(实测 160 器件 / 602 导线 / 181 网络,约 1.6s)。这是理解电路的主数据源。
103
+ 3. 建三张表还原拓扑(**已验证的配方**):
104
+ - `designator → symbolInstance`(取 `metadata.id`)
105
+ - `symbolDefinition.pins` → **引脚号→引脚名**(用实例的 `definitionId` 精确匹配 `symbolDefinitions[].name`)
106
+ - `nets[].pinInstanceIds` → **引脚实例→网络名**
107
+ 4. 器件语义**优先读 `symbolInstance.metadata.properties`** —— 自带 `Description`、`Datasheet`、`output_voltage`、`input_voltage`、`topology`、`supply_current`、`PSRR` 等电气参数,**无需联网查 datasheet**。
108
+ 5. 需要器件清单语义(MPN/description/footprint)时用 `netList.getProjectNetList`;纯网络查询也可用它(约 27ms,比快照快)。
109
+ 6. 回答时**必须指出电气一致性疑点**:把器件参数与网络名对照(如 `output_voltage=5V` 却驱动 `+3.3V` 网络),这是用户最需要知道的。
110
+
111
+ **流程 B 硬性规则**:
112
+ - **不要**依赖 `graph.GetConnectivity`、`kernel.GetEntity`、`erc.RunChecks`、`selection.*`、`export.*`、`runtime.*`、`transaction.*` —— 本引擎构建**均未实现**;完整禁建表见 `docs/rpc-availability.md`。scenario-b **不**等待引擎补齐这些接口再建流程。
113
+ - `project.ListProjectTree` 返回空(`error:3`);`find.FindNet` 常**恒返回 `success:false`(静默)** —— **禁止**据此判断网络不存在,改用快照 `nets`。
114
+ - `position.x/y` 是 **bigint**:`JSON.stringify` 会抛 "Do not know how to serialize a BigInt",用 `docs/serialization.md` 的 replacer。
115
+ - 快照**含未连接引脚**(netList 不含)—— 判断悬空/未接引脚时以快照为准。
116
+ - 读电路默认**不要** `zoomAll`(避免改视口);用户需要看图时可再调。
117
+ - 回答「器件作用」按模板:身份 → 引脚→网络 → **邻域(同网邻居)** → (可选)**串联穿透** `TRACE=1` → 一致性疑点 → 作用总结。详见 `docs/reading-a-circuit.md`。
118
+ - 串联穿透 C/R/L/磁珠:**不需新 RPC**;`read-circuit.ts` 客户端 BFS;去耦电容(一脚 GND/VCC)不穿透。
119
+ - 读懂后要改:输出块 **canvas 编辑 id**(`canvasObjectId` / `FindObject`)供流程 C 使用。
120
+
121
+ ### 流程 C — 局部改电路
122
+
123
+ **可写**,但必须 **先 diff、后执行**。详见 `docs/editing-a-circuit.md`。
124
+
125
+ 1. `getActiveProject` → 打印 `projectId`。
126
+ 2. `GetSnapshot` + `read-circuit.ts`(`REF=`)定位目标与邻域;记录 `objectId`。
127
+ 3. **修改集**:只列将改的对象/网络;禁止顺手清页。
128
+ 4. **向用户复述 diff**,待确认后再写(脚本可用 `CONFIRM=1` 跳过交互)。
129
+ 5. **最小 RPC 执行**:
130
+ - 改属性 → `FindObjectByProperty` + `SetObjectProperty`(位号用 `Part Reference`)
131
+ - 改接脚 → `autoConnectObjectsById` 或 `placePinStubWireAndNetAlias`(routing gate)
132
+ - 换器件 → 快照坐标 → `deleteObjectsByIds` → `placeKicadSymbol` → 按 pin 重连
133
+ 6. **双源验收**:再 `GetSnapshot`(pin→net)+ `netList` + 一致性复查。
134
+
135
+ **流程 C 硬性规则**:
136
+ - **禁止**把局部修改做成流程 A 整页重画。
137
+ - **禁止**未确认大批量 `deleteObjectsByIds`。
138
+ - 模板脚本:`edit-property-by-ref.ts`、`rewire-pin-by-ref.ts`、`replace-part-by-ref.ts`。
139
+ - 仍**禁止**依赖 `GetConnectivity` / `selection.*` / `transaction.*`;见 `docs/rpc-availability.md` 变通方案。
140
+
141
+ ## 安全边界
142
+
143
+ - **禁止**在未获用户明确确认时调用 `deleteObjectsByIds` 清空整页或大批量删除。
144
+ - 流程 C 局部删除(如换器件删旧件)也须先打印 diff;单对象删除可随用户指令执行。
145
+ - 若用户要求清页:先用 `getSnapshot` 报告当前对象数量,待用户确认后再删除。
146
+ - 多开 HQ EDA 时提醒用户设置环境变量 `HQ_INSTANCE_ID`。
147
+
148
+ ## 脚本模板(每次输出必须包含)
149
+
150
+ ```typescript
151
+ /**
152
+ * ===== PATTERN CHECK(禁止留空)=====
153
+ * list-circuit-patterns 已调用: YES
154
+ * subnet 分解:
155
+ * [<子电路 A>] → <pattern id> (host=..., terminal=...)
156
+ * [<子电路 B>] → <pattern id> (host=..., terminal=...)
157
+ * [<leftover>] → hand (routing gate: 短 autoConnect / 长 stub+alias)
158
+ * =====================================
159
+ */
160
+ import { connect, toJsonString } from "@huaqiu/huaqiu-client";
161
+ import { HqServicesV1PatternLayoutService } from "@hqedge/connect";
162
+
163
+ const PL = HqServicesV1PatternLayoutService; // 枚举来源
164
+ const INSTANCE = process.env.HQ_INSTANCE_ID;
165
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
166
+
167
+ async function main() {
168
+ const client = INSTANCE
169
+ ? await connect({ instanceId: INSTANCE })
170
+ : await connect();
171
+
172
+ const editorCtx = client.createEditorContext();
173
+ const active = await client.project.getActiveProject({ context: editorCtx });
174
+ const projectId = active.project?.projectId;
175
+ if (!projectId) throw new Error("请先在 HQ EDA 中打开原理图工程");
176
+ const ctx = client.createProjectContext(projectId);
177
+
178
+ // 1) 放置 host / 独立器件(placeKicadSymbol;电源符号 PlaceSymbolFromLibrary)
179
+ // 2) 【关键】等待注册:轮询 getPageOccupancy 直到所有新 id 出现
180
+ // 3) 规范位号 / 容值
181
+ // 4) applyCircuitPattern — host 引脚用 pinName 绑定
182
+ // pattern: PL.CircuitPatternId.CIRCUIT_PATTERN_xxx
183
+ // orientation: PL.PatternOrientation.PATTERN_ORIENT_LEFT_TO_RIGHT
184
+ // routeMode: PL.PatternRouteMode.PATTERN_ROUTE_FULL
185
+ // powerMode: PL.PatternPowerMode.PATTERN_POWER_AUTO_PLACE
186
+ // 5) 仅对 pattern 未覆盖的 net hand-wire(routing gate per net)
187
+ // 禁止重连 connections[].routed=true
188
+ // 6) 验收: netList.getActivePageNetList + canvasOps.listWireSegments().wires
189
+
190
+ await client.canvasOps.zoomAll({ context: ctx });
191
+ console.log("done");
192
+ }
193
+
194
+ main().catch((e) => { console.error(e); process.exit(1); });
195
+ ```
196
+
197
+ ## 输出格式
198
+
199
+ 1. 简短设计说明(用了哪些 pattern、接线策略)
200
+ 2. 完整 `scripts/<名称>.ts` 源码
201
+ 3. 说明你已执行(或将执行)的命令:`npx tsx scripts/<名称>.ts`
202
+ 4. 验收结果(pattern status、netlist 关键 net、`wires` 条数统计)
203
+
204
+ ## 环境前提(提醒用户)
205
+
206
+ - Node.js 18+
207
+ - 公网 npm 可安装 `@huaqiu/huaqiu-client`(推荐 `^0.1.7`)与可选 `@huaqiu/hqeda`(`^0.2.7`)
208
+ - HQ EDA 桌面版已运行且打开了目标工程
209
+ - 多开编辑器时设置 `HQ_INSTANCE_ID`