@huaqiu/dsh-tool-schematic-gen 0.3.13 → 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/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/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
|
-
"@huaqiu/dsh-plugin-log": "0.3.
|
|
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); }
|