@huaqiu/dsh-tool-schematic-gen 0.3.12 → 0.3.14
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 +54 -9
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +8 -8
- package/package.json +7 -7
- package/src/client/hit-card.tsx +68 -9
- package/src/client/i18n.ts +4 -0
- package/src/client/index.ts +1 -0
- package/src/client/theme.ts +2 -0
- package/src/index.ts +8 -3
- package/src/tools.ts +4 -4
package/lib/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
6
|
-
import {
|
|
6
|
+
import { getLogger } from "@huaqiu/dsh-plugin-log";
|
|
7
7
|
//#region src/config.ts
|
|
8
8
|
/**
|
|
9
9
|
* `@huaqiu/dsh-tool-schematic-gen` — config, agent identity, run-body and
|
|
@@ -710,7 +710,7 @@ async function exportModuleGraphZip(exportZipUrl, moduleGraph, config, account,
|
|
|
710
710
|
function asJson(value) {
|
|
711
711
|
return JSON.parse(JSON.stringify(value));
|
|
712
712
|
}
|
|
713
|
-
const log$1 =
|
|
713
|
+
const log$1 = getLogger("dsh-schematic-gen");
|
|
714
714
|
/** Agent-facing timeout hints. */
|
|
715
715
|
const TOOL_TIMEOUT_MS = {
|
|
716
716
|
generate_schematic_from_description: HTTP_TIMEOUT_MS,
|
|
@@ -733,7 +733,7 @@ async function resolveAccount(auth) {
|
|
|
733
733
|
};
|
|
734
734
|
return null;
|
|
735
735
|
} catch (err) {
|
|
736
|
-
log$1.warn({ error: String(err?.message || err) }
|
|
736
|
+
log$1.warn("could not resolve the eda.cn account", { error: String(err?.message || err) });
|
|
737
737
|
return null;
|
|
738
738
|
}
|
|
739
739
|
}
|
|
@@ -798,10 +798,10 @@ async function artifactUriOf(env, id) {
|
|
|
798
798
|
if (!env.artifacts || typeof env.artifacts.getDownloadUri !== "function") return null;
|
|
799
799
|
return await env.artifacts.getDownloadUri(id);
|
|
800
800
|
} catch (err) {
|
|
801
|
-
log$1.warn({
|
|
801
|
+
log$1.warn("getDownloadUri failed", {
|
|
802
802
|
id,
|
|
803
803
|
error: String(err?.message || err)
|
|
804
|
-
}
|
|
804
|
+
});
|
|
805
805
|
return null;
|
|
806
806
|
}
|
|
807
807
|
}
|
|
@@ -1405,7 +1405,7 @@ const inject = [
|
|
|
1405
1405
|
"huaqiuArtifacts",
|
|
1406
1406
|
"webServer"
|
|
1407
1407
|
];
|
|
1408
|
-
const log =
|
|
1408
|
+
const log = getLogger("dsh-schematic-gen");
|
|
1409
1409
|
/**
|
|
1410
1410
|
* Host plugin body — register the two generation tools.
|
|
1411
1411
|
*
|
|
@@ -1440,12 +1440,12 @@ function apply(ctx, config = {}) {
|
|
|
1440
1440
|
progress,
|
|
1441
1441
|
deps: {}
|
|
1442
1442
|
}).map((tool) => ctx.tools.register(tool));
|
|
1443
|
-
log.info({
|
|
1443
|
+
log.info("registered agent tools", {
|
|
1444
1444
|
tools: disposers.length,
|
|
1445
1445
|
copilotkitUrl: finalConfig.copilotkitUrl,
|
|
1446
1446
|
exportZipUrl: finalConfig.exportZipUrl,
|
|
1447
1447
|
auth: "huaqiuAuth"
|
|
1448
|
-
}
|
|
1448
|
+
});
|
|
1449
1449
|
return function dispose() {
|
|
1450
1450
|
for (const disposeTool of disposers) try {
|
|
1451
1451
|
disposeTool();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huaqiu/dsh-tool-schematic-gen",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.mjs",
|
|
6
6
|
"types": "./lib/index.d.mts",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
31
31
|
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.0",
|
|
32
32
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.0",
|
|
33
|
-
"@huaqiu/dsh-auth": "^0.3.
|
|
34
|
-
"@huaqiu/dsh-artifacts": "^0.3.
|
|
33
|
+
"@huaqiu/dsh-auth": "^0.3.14",
|
|
34
|
+
"@huaqiu/dsh-artifacts": "^0.3.14",
|
|
35
35
|
"react": "^18"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"@huaqiu/kicad-sexpr-parser": "^0.1.1",
|
|
40
40
|
"@types/react": "^18.3.31",
|
|
41
41
|
"react": "^18.3.1",
|
|
42
|
-
"@huaqiu/dsh-
|
|
43
|
-
"@huaqiu/dsh-tool-uncollapse": "0.3.
|
|
44
|
-
"@huaqiu/dsh-
|
|
42
|
+
"@huaqiu/dsh-auth": "0.3.14",
|
|
43
|
+
"@huaqiu/dsh-tool-uncollapse": "0.3.14",
|
|
44
|
+
"@huaqiu/dsh-artifacts": "0.3.14"
|
|
45
45
|
},
|
|
46
46
|
"files": [
|
|
47
47
|
"lib",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@
|
|
55
|
+
"@huaqiu/dsh-plugin-log": "0.3.14"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"typecheck": "tsc --noEmit",
|
package/src/client/hit-card.tsx
CHANGED
|
@@ -33,6 +33,22 @@ export interface AuthStateLike {
|
|
|
33
33
|
nickname?: string
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Structural view of the `huaqiuAuth` CLIENT service (declared structurally,
|
|
38
|
+
* never imported — each package must remain independently installable).
|
|
39
|
+
* `login()` in HQ Edge host mode triggers the EDA login dialog through
|
|
40
|
+
* hq-edge (`POST /api/v1/auth/login` → EDA `TriggerLoginDialog`) instead of
|
|
41
|
+
* the auth.eda.cn iframe; `isHostMode()` tells the card which surface to show.
|
|
42
|
+
*/
|
|
43
|
+
export interface AuthClientLike {
|
|
44
|
+
auth?: {
|
|
45
|
+
isAuthenticated(): boolean
|
|
46
|
+
isHostMode?(): boolean
|
|
47
|
+
login?(options?: { lang?: string; theme?: string }): Promise<void>
|
|
48
|
+
onAuthStateChanged(listener: (info: { nickname?: string } | null) => void): () => void
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
36
52
|
export type PromptSender = (sessionId: string | undefined, message: string) => Promise<unknown>
|
|
37
53
|
|
|
38
54
|
const TOOL_SCHEMATIC = 'generate_schematic_from_description'
|
|
@@ -53,6 +69,13 @@ export interface GenHitProps {
|
|
|
53
69
|
inspect?: () => void
|
|
54
70
|
authState?: AuthStateLike
|
|
55
71
|
sendPrompt?: PromptSender
|
|
72
|
+
/**
|
|
73
|
+
* Lazy accessor for the `huaqiuAuth` client service (auth plugin browser
|
|
74
|
+
* half). Absent/undefined in a broken install — the needs_auth card then
|
|
75
|
+
* falls back to the embedded auth.eda.cn iframe. Lazy (not captured once)
|
|
76
|
+
* so plugin load order resolves correctly at click time.
|
|
77
|
+
*/
|
|
78
|
+
getAuth?: () => AuthClientLike | undefined
|
|
56
79
|
/**
|
|
57
80
|
* Lazy accessor for the host's `hqEdge` service (edge-bridge browser half).
|
|
58
81
|
* Absent/undefined in standalone DSH — the Place button is then hidden.
|
|
@@ -186,9 +209,16 @@ function PreviewStage({ payload, t }: { payload: PreviewPayload; t: Translate })
|
|
|
186
209
|
|
|
187
210
|
// ── needs_auth login card ───────────────────────────────────────────────────
|
|
188
211
|
|
|
189
|
-
function LoginCard({ toolName, authState, t }: { toolName: string; authState?: AuthStateLike; t: Translate }): ReactElement {
|
|
212
|
+
function LoginCard({ toolName, authState, t, getAuth }: { toolName: string; authState?: AuthStateLike; t: Translate; getAuth?: () => AuthClientLike | undefined }): ReactElement {
|
|
190
213
|
const dark = useTheme()
|
|
191
214
|
const locale = useLocale()
|
|
215
|
+
const authClient = getAuth?.()?.auth
|
|
216
|
+
// HQ Edge host mode: EDA owns the credential — login must ask EDA to open
|
|
217
|
+
// its own TriggerLoginDialog (hq-edge POST /api/v1/auth/login), not the
|
|
218
|
+
// auth.eda.cn iframe (a browser-pushed token is ignored by the STRICT host
|
|
219
|
+
// resolver). Standalone DSH keeps the inline iframe.
|
|
220
|
+
const hostMode = authClient?.isHostMode?.() ?? false
|
|
221
|
+
|
|
192
222
|
// FILL mode (`fill=full`): this card IS the surface, so let the embed paint
|
|
193
223
|
// it edge-to-edge with its own `bg-background`. Without it the embed's
|
|
194
224
|
// `grid-rows-[20px_1fr_20px]` wrapper leaves two transparent strips above
|
|
@@ -202,6 +232,41 @@ function LoginCard({ toolName, authState, t }: { toolName: string; authState?: A
|
|
|
202
232
|
// its URL params once on mount), silently ignoring the new `fill`/`theme`.
|
|
203
233
|
const remountKey = `${locale}|${dark ? 'd' : 'l'}`
|
|
204
234
|
|
|
235
|
+
const statusLine = (
|
|
236
|
+
<p className="hq-sch__login-status" style={{ color: authState?.authenticated ? '#1677ff' : '#d4380d' }}>
|
|
237
|
+
{authState?.authenticated
|
|
238
|
+
? t('card.auth.loggedIn', {
|
|
239
|
+
nickname: authState.nickname ? t('card.nicknameSep', { nickname: authState.nickname }) : '',
|
|
240
|
+
})
|
|
241
|
+
: t('card.auth.loggedOut')}
|
|
242
|
+
</p>
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
if (hostMode) {
|
|
246
|
+
return (
|
|
247
|
+
<div className="hq-sch">
|
|
248
|
+
<div className="hq-sch__header">
|
|
249
|
+
<span className="hq-sch__icon">⇶</span>
|
|
250
|
+
<span className="hq-sch__title">{t('card.auth.title')}</span>
|
|
251
|
+
</div>
|
|
252
|
+
<div className="hq-sch__login">
|
|
253
|
+
<p className="hq-sch__login-desc">{t('card.auth.descHost', { tool: toolName })}</p>
|
|
254
|
+
{statusLine}
|
|
255
|
+
<button
|
|
256
|
+
type="button"
|
|
257
|
+
className="hq-sch__login-btn"
|
|
258
|
+
onClick={() => {
|
|
259
|
+
void authClient?.login?.({ lang: locale, theme: dark ? 'dark' : 'light' })
|
|
260
|
+
.catch(() => { /* login cancelled / dialog failed — card keeps showing the button */ })
|
|
261
|
+
}}
|
|
262
|
+
>
|
|
263
|
+
{t('card.auth.loginBtn')}
|
|
264
|
+
</button>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
205
270
|
return (
|
|
206
271
|
<div className="hq-sch">
|
|
207
272
|
<div className="hq-sch__header">
|
|
@@ -210,13 +275,7 @@ function LoginCard({ toolName, authState, t }: { toolName: string; authState?: A
|
|
|
210
275
|
</div>
|
|
211
276
|
<div className="hq-sch__login">
|
|
212
277
|
<p className="hq-sch__login-desc">{t('card.auth.desc', { tool: toolName })}</p>
|
|
213
|
-
|
|
214
|
-
{authState?.authenticated
|
|
215
|
-
? t('card.auth.loggedIn', {
|
|
216
|
-
nickname: authState.nickname ? t('card.nicknameSep', { nickname: authState.nickname }) : '',
|
|
217
|
-
})
|
|
218
|
-
: t('card.auth.loggedOut')}
|
|
219
|
-
</p>
|
|
278
|
+
{statusLine}
|
|
220
279
|
<iframe
|
|
221
280
|
key={remountKey}
|
|
222
281
|
src={src}
|
|
@@ -364,7 +423,7 @@ export const GenHit = memo(function GenHit(props: GenHitProps): ReactElement {
|
|
|
364
423
|
|
|
365
424
|
// needs_auth
|
|
366
425
|
if (state.phase === 'needs_auth') {
|
|
367
|
-
return <LoginCard toolName={props.toolName} authState={props.authState} t={t} />
|
|
426
|
+
return <LoginCard toolName={props.toolName} authState={props.authState} t={t} getAuth={props.getAuth} />
|
|
368
427
|
}
|
|
369
428
|
|
|
370
429
|
const headerKind = result?.kind ?? kindOf(props.toolName)
|
package/src/client/i18n.ts
CHANGED
|
@@ -59,6 +59,8 @@ const ZH = {
|
|
|
59
59
|
'card.auth.desc': '工具「{tool}」需要登录华秋 EDA AI 账号才能继续。请在下方的登录框完成登录(或点击左侧「华秋EDA AI登录」按钮);登录完成后,回复助手「已登录,请重试」,助手会自动重新调用该工具。',
|
|
60
60
|
'card.auth.loggedIn': '✓ 已登录{nickname}—— 现在可以回复助手「已登录,请重试」,助手会重新调用工具。',
|
|
61
61
|
'card.auth.loggedOut': '未登录 —— 请在上方登录华秋 EDA AI(eda.cn)账号,或点击左侧「华秋EDA AI 登录」按钮;登录完成后让助手重试。',
|
|
62
|
+
'card.auth.descHost': '工具「{tool}」需要登录华秋 EDA AI 账号才能继续。点击下方按钮后,EDA(KiCad)将弹出登录窗口,请在弹出的窗口中完成登录;登录完成后回复助手「已登录,请重试」,助手会自动重新调用该工具。',
|
|
63
|
+
'card.auth.loginBtn': '登录华秋 EDA AI',
|
|
62
64
|
// Substituted into `{nickname}` by `card.auth.loggedIn`. zh uses a
|
|
63
65
|
// full-width colon, en a half-width one plus a space — hardcoding ':'
|
|
64
66
|
// made the English card read "Logged in:John".
|
|
@@ -116,6 +118,8 @@ const EN: Record<CopyKey, string> = {
|
|
|
116
118
|
'card.auth.desc': 'Tool "{tool}" requires a Huaqiu EDA AI login. Complete the login below (or use the 华秋EDA AI sidebar button); then reply "I have logged in, please retry" so the assistant can retry the tool.',
|
|
117
119
|
'card.auth.loggedIn': '✓ Logged in{nickname} — reply "I have logged in, please retry" and the assistant will retry.',
|
|
118
120
|
'card.auth.loggedOut': 'Not logged in — complete the login above, or use the 华秋EDA AI sidebar button.',
|
|
121
|
+
'card.auth.descHost': 'Tool "{tool}" requires a Huaqiu EDA AI account. Click the button below — EDA (KiCad) will open its login dialog. Complete the login there, then reply "I have logged in, please retry" so the assistant can retry the tool.',
|
|
122
|
+
'card.auth.loginBtn': 'Sign in to Huaqiu EDA AI',
|
|
119
123
|
'card.nicknameSep': ': {nickname}',
|
|
120
124
|
}
|
|
121
125
|
|
package/src/client/index.ts
CHANGED
package/src/client/theme.ts
CHANGED
|
@@ -181,6 +181,8 @@ const CSS = `
|
|
|
181
181
|
.hq-sch__login-desc { margin: 0 0 10px; font: var(--dsw-font-xxs-12, 12px/1.4 system-ui, sans-serif); color: var(--dsw-alias-label-secondary, currentColor); line-height: 1.5; }
|
|
182
182
|
.hq-sch__login-status { margin: 0 0 10px; font: var(--dsw-font-xxs-12, 12px/1.4 system-ui, sans-serif); line-height: 1.5; }
|
|
183
183
|
.hq-sch__login-iframe { width: 100%; height: ${LOGIN_IFRAME_HEIGHT}px; border: 0; border-radius: 8px; display: block; }
|
|
184
|
+
.hq-sch__login-btn { display: inline-flex; align-items: center; gap: 4px; border: 1px solid var(--dsw-alias-border-l1, currentColor); border-radius: 6px; padding: 6px 16px; background: var(--dsw-alias-interactive-bg-hover, rgba(127,127,127,0.08)); color: var(--dsw-alias-label-primary, currentColor); font: var(--dsw-font-xxs-12, 12px/1.4 system-ui, sans-serif); cursor: pointer; }
|
|
185
|
+
.hq-sch__login-btn:hover { filter: brightness(1.08); }
|
|
184
186
|
|
|
185
187
|
/* ── live call stack (long-running generations) ───────────────────────────── */
|
|
186
188
|
.hq-sch__progress { display: flex; align-items: center; gap: 8px; padding: 0 12px 8px; font: var(--dsw-font-xxs-12, 12px/1.4 system-ui, sans-serif); color: var(--dsw-alias-label-secondary, currentColor); }
|
package/src/index.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { resolveConfig } from './config.js'
|
|
|
26
26
|
import { HTTP_TIMEOUT_MS } from './sse.js'
|
|
27
27
|
import { ProgressStore } from './progress.js'
|
|
28
28
|
import { createProgressHandler, PROGRESS_ROUTE_PREFIX } from './routes.js'
|
|
29
|
-
import {
|
|
29
|
+
import { getLogger } from '@huaqiu/dsh-plugin-log'
|
|
30
30
|
|
|
31
31
|
/** Plugin id — matches package.json. */
|
|
32
32
|
export const name = '@huaqiu/dsh-tool-schematic-gen'
|
|
@@ -42,7 +42,7 @@ export const inject = ['tools', 'huaqiuAuth', 'huaqiuArtifacts', 'webServer'] as
|
|
|
42
42
|
|
|
43
43
|
/** Shared component name for the unified DSH-plugin log. */
|
|
44
44
|
const COMPONENT = 'dsh-schematic-gen'
|
|
45
|
-
const log =
|
|
45
|
+
const log = getLogger(COMPONENT)
|
|
46
46
|
|
|
47
47
|
export interface SchematicGenPluginConfig {
|
|
48
48
|
/** Endpoint overrides, env-backed. */
|
|
@@ -107,7 +107,12 @@ export function apply(ctx: Context, config: SchematicGenPluginConfig = {}): () =
|
|
|
107
107
|
|
|
108
108
|
const disposers = createSchematicGenTools(env).map((tool) => ctx.tools.register(tool))
|
|
109
109
|
|
|
110
|
-
log.info(
|
|
110
|
+
log.info('registered agent tools', {
|
|
111
|
+
tools: disposers.length,
|
|
112
|
+
copilotkitUrl: finalConfig.copilotkitUrl,
|
|
113
|
+
exportZipUrl: finalConfig.exportZipUrl,
|
|
114
|
+
auth: 'huaqiuAuth',
|
|
115
|
+
})
|
|
111
116
|
|
|
112
117
|
return function dispose() {
|
|
113
118
|
for (const disposeTool of disposers) {
|
package/src/tools.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { join } from 'node:path'
|
|
|
23
23
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
24
24
|
import type { HuaqiuAuthService } from '@huaqiu/dsh-auth'
|
|
25
25
|
import type { CreateArtifactResult, HuaqiuArtifacts } from '@huaqiu/dsh-artifacts'
|
|
26
|
-
import {
|
|
26
|
+
import { getLogger } from '@huaqiu/dsh-plugin-log'
|
|
27
27
|
import {
|
|
28
28
|
agentIds,
|
|
29
29
|
buildHeaders,
|
|
@@ -47,7 +47,7 @@ function asJson<T>(value: T): Json {
|
|
|
47
47
|
|
|
48
48
|
/** Shared component name for the unified DSH-plugin log. */
|
|
49
49
|
const COMPONENT = 'dsh-schematic-gen'
|
|
50
|
-
const log =
|
|
50
|
+
const log = getLogger(COMPONENT)
|
|
51
51
|
|
|
52
52
|
/** Agent-facing timeout hints. */
|
|
53
53
|
export const TOOL_TIMEOUT_MS = {
|
|
@@ -98,7 +98,7 @@ async function resolveAccount(auth: HuaqiuAuthService['auth']): Promise<EdaAccou
|
|
|
98
98
|
}
|
|
99
99
|
return null
|
|
100
100
|
} catch (err) {
|
|
101
|
-
log.warn({ error: String((err as Error)?.message || err) }
|
|
101
|
+
log.warn('could not resolve the eda.cn account', { error: String((err as Error)?.message || err) })
|
|
102
102
|
return null
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -180,7 +180,7 @@ async function artifactUriOf(env: SchematicGenEnv, id: string): Promise<string |
|
|
|
180
180
|
if (!env.artifacts || typeof env.artifacts.getDownloadUri !== 'function') return null
|
|
181
181
|
return await env.artifacts.getDownloadUri(id)
|
|
182
182
|
} catch (err) {
|
|
183
|
-
log.warn({ id, error: String((err as Error)?.message || err) }
|
|
183
|
+
log.warn('getDownloadUri failed', { id, error: String((err as Error)?.message || err) })
|
|
184
184
|
return null
|
|
185
185
|
}
|
|
186
186
|
}
|