@dickpy/dsh-imagegen 1.0.2 → 1.0.3

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.js CHANGED
@@ -13,6 +13,8 @@ import { spawn } from "node:child_process";
13
13
  */
14
14
  /** Settings namespace this plugin owns (host settings seam + bridge). */
15
15
  const IMAGEGEN_SETTINGS_NAMESPACE = "dsh-imagegen";
16
+ /** Published package version shared by the host updater and the client UI. */
17
+ const PLUGIN_VERSION = "1.0.3";
16
18
  /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
17
19
  const SETTINGS_API = {
18
20
  describe: "/api/dsh-imagegen/settings/describe",
@@ -438,7 +440,7 @@ async function readHistoryImage(file) {
438
440
  //#region src/updater.ts
439
441
  /** GitHub Release discovery and explicit, user-triggered plugin updates. */
440
442
  /** Keep this in sync with package.json for each published release. */
441
- const CURRENT_VERSION = "1.0.2";
443
+ const CURRENT_VERSION = PLUGIN_VERSION;
442
444
  const PACKAGE_NAME = "@dickpy/dsh-imagegen";
443
445
  const RELEASES_URL = "https://api.github.com/repos/dickpy/dsh-imagegen/releases/latest";
444
446
  const CHECK_TIMEOUT_MS = 1e4;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dickpy/dsh-imagegen",
3
3
  "description": "AI 生图 (image generation) plugin for the dsh web GUI: text-to-image and image-to-image through a configurable OpenAI-compatible endpoint (gpt-image-2 / gpt-image-1 / dall-e-3), with a settings card for api_url / api_key and a sidebar entry opening a split-pane generation studio.",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -50,6 +50,13 @@ function useConfig(scope: ImageGenScope): ImageGenConfig | undefined {
50
50
  return value
51
51
  }
52
52
 
53
+ /** Track the redacted api-key presence bit exposed by the settings bridge. */
54
+ function useKeySet(scope: ImageGenScope): boolean {
55
+ const [keySet, setKeySet] = useState(scope.getKeySetSnapshot())
56
+ useEffect(() => scope.subscribeKeySet(() => { setKeySet(scope.getKeySetSnapshot()) }), [scope])
57
+ return keySet
58
+ }
59
+
53
60
  /** Tick a seconds counter while `running`. */
54
61
  function useElapsed(running: boolean, startedAt: number | null): number {
55
62
  const [elapsed, setElapsed] = useState(0)
@@ -108,6 +115,8 @@ export function ImageGenPanel(props: {
108
115
  const enabled = config?.enabled ?? true
109
116
  const apiUrl = config?.apiUrl ?? ''
110
117
  const configured = apiUrl.trim() !== ''
118
+ const keySet = useKeySet(scope)
119
+ const connected = enabled && configured && keySet
111
120
 
112
121
  const [mode, setMode] = useState<GenerateMode>('text')
113
122
  const [prompt, setPrompt] = useState('')
@@ -316,16 +325,21 @@ export function ImageGenPanel(props: {
316
325
  return (
317
326
  <div className={css.panel}>
318
327
  <header className={css.panelHeader}>
319
- <h2 className={css.panelTitle}>{tt('panel.title')}</h2>
320
- <span className={css.panelSubtitle}>{tt('panel.subtitle')}</span>
328
+ <span className={css.panelHeading}>
329
+ <h2 className={css.panelTitle}>{tt('panel.title')}</h2>
330
+ <span className={css.panelSubtitle}>{tt('panel.subtitle')}</span>
331
+ </span>
332
+ <button
333
+ type="button"
334
+ className={css.connectionStatus}
335
+ data-connected={connected ? 'true' : 'false'}
336
+ aria-label={tt(connected ? 'connection.connected' : 'connection.disconnected')}
337
+ >
338
+ <span className={css.connectionDot} aria-hidden="true" />
339
+ {tt(connected ? 'connection.connected' : 'connection.disconnected')}
340
+ </button>
321
341
  </header>
322
342
 
323
- {!enabled
324
- ? <div className={css.banner} data-kind="warn">{tt('config.disabled')}</div>
325
- : !configured
326
- ? <div className={css.banner} data-kind="warn">{tt('config.missing')}</div>
327
- : <div className={css.banner} data-kind="ok">{tt('config.configured', { url: apiUrl })}</div>}
328
-
329
343
  {update !== null ? (
330
344
  <div className={css.updateBanner} data-kind={updateResult === 'success' ? 'ok' : 'warn'}>
331
345
  <span className={css.updateText}>
@@ -11,6 +11,7 @@ import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-cli
11
11
  import { createSnapshotStore, type SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'
12
12
  import { CardForm, booleanField, secretField, textField, type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts'
13
13
  import type { ImageGenScope } from './settings-scope.ts'
14
+ import { PLUGIN_VERSION } from '../protocol.ts'
14
15
  import css from './settings-card.module.css'
15
16
 
16
17
  /** The fields this card edits (the namespace's full schema). */
@@ -161,6 +162,10 @@ export function ImageGenSettingsCard(props: ImageGenSettingsCardProps) {
161
162
  ? (
162
163
  <div className={css.body}>
163
164
  {!state.writable ? <p className={css.readOnly} role="status">{t('settings.readOnly')}</p> : null}
165
+ <div className={css.versionRow}>
166
+ <span className={css.versionLabel}>{t('settings.currentVersion')}</span>
167
+ <code className={css.versionValue}>v{PLUGIN_VERSION}</code>
168
+ </div>
164
169
  <ValueField
165
170
  id="dsh-imagegen-settings-apikey"
166
171
  label={t('settings.apiKey')}
@@ -76,6 +76,8 @@ export const zh = {
76
76
  'config.missing': '尚未配置 API:请前往「设置 → 插件 → 可配置」为 AI 生图填写 api_url 与 api_key。',
77
77
  'config.configured': '已连接 {url}',
78
78
  'config.disabled': '插件已停用,请在设置中重新启用。',
79
+ 'connection.connected': '已连接',
80
+ 'connection.disconnected': '未连接',
79
81
  // plugin update
80
82
  'update.available': '检测到新版本:{version}',
81
83
  'update.install': '在线更新',
@@ -86,6 +88,7 @@ export const zh = {
86
88
  // settings card
87
89
  'settings.title': 'AI 生图(dsh-imagegen)',
88
90
  'settings.description': '配置图像生成 API 地址与密钥',
91
+ 'settings.currentVersion': '当前版本',
89
92
  'settings.apiUrl': 'API 地址(api_url)',
90
93
  'settings.apiUrlHint': 'OpenAI 兼容接口基址,如 https://api.openai.com/v1;将自动拼接 /images/generations 与 /images/edits',
91
94
  'settings.apiKey': 'API 密钥(api_key)',
@@ -178,6 +181,8 @@ export const en: Record<keyof typeof zh, string> = {
178
181
  'config.missing': 'API not configured: open "Settings → Plugins → Configurable" and fill in api_url and api_key for AI Image.',
179
182
  'config.configured': 'Connected to {url}',
180
183
  'config.disabled': 'The plugin is disabled — re-enable it in Settings.',
184
+ 'connection.connected': 'Connected',
185
+ 'connection.disconnected': 'Disconnected',
181
186
  'update.available': 'A new version is available: {version}',
182
187
  'update.install': 'Update online',
183
188
  'update.installing': 'Updating…',
@@ -186,6 +191,7 @@ export const en: Record<keyof typeof zh, string> = {
186
191
  'update.release': 'View Release',
187
192
  'settings.title': 'AI Image (dsh-imagegen)',
188
193
  'settings.description': 'Configure the image generation API endpoint and key',
194
+ 'settings.currentVersion': 'Current version',
189
195
  'settings.apiUrl': 'API URL (api_url)',
190
196
  'settings.apiUrlHint': 'OpenAI-compatible base URL, e.g. https://api.openai.com/v1; /images/generations and /images/edits are appended',
191
197
  'settings.apiKey': 'API Key (api_key)',
@@ -121,10 +121,18 @@ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ss
121
121
  }
122
122
 
123
123
  .panelHeader {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: space-between;
127
+ gap: 12px;
128
+ flex: none;
129
+ }
130
+
131
+ .panelHeading {
124
132
  display: flex;
125
133
  align-items: baseline;
126
134
  gap: 10px;
127
- flex: none;
135
+ min-width: 0;
128
136
  }
129
137
 
130
138
  .panelTitle {
@@ -143,27 +151,35 @@ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ss
143
151
  text-overflow: ellipsis;
144
152
  }
145
153
 
146
- /* --- banners ------------------------------------------------------------------ */
154
+ /* --- connection status and update notice -------------------------------------- */
147
155
 
148
- .banner {
156
+ .connectionStatus {
157
+ display: inline-flex;
158
+ align-items: center;
159
+ gap: 6px;
149
160
  flex: none;
150
- padding: 7px 12px;
161
+ height: 28px;
162
+ padding: 0 10px;
163
+ border: 1px solid var(--dsw-alias-label-error);
164
+ border-radius: 8px;
165
+ background: transparent;
166
+ color: var(--dsw-alias-label-error);
167
+ font: inherit;
151
168
  font-size: 12px;
152
- line-height: 1.5;
153
- border-radius: 10px;
154
- border: 1px solid var(--dsw-alias-border-l2);
155
- color: var(--dsw-alias-label-secondary);
156
- overflow-wrap: anywhere;
169
+ line-height: 1;
170
+ white-space: nowrap;
157
171
  }
158
172
 
159
- .banner[data-kind='ok'] {
160
- color: var(--dsw-alias-state-success-primary);
173
+ .connectionStatus[data-connected='true'] {
161
174
  border-color: var(--dsw-alias-state-success-primary);
175
+ color: var(--dsw-alias-state-success-primary);
162
176
  }
163
177
 
164
- .banner[data-kind='warn'] {
165
- color: var(--dsw-alias-state-warn-primary);
166
- border-color: var(--dsw-alias-state-warn-primary);
178
+ .connectionDot {
179
+ width: 6px;
180
+ height: 6px;
181
+ border-radius: 50%;
182
+ background: currentColor;
167
183
  }
168
184
 
169
185
  .updateBanner {
@@ -205,6 +221,16 @@ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ss
205
221
  }
206
222
 
207
223
  @media (max-width: 700px) {
224
+ .panelHeader {
225
+ align-items: flex-start;
226
+ }
227
+
228
+ .panelHeading {
229
+ align-items: flex-start;
230
+ flex-direction: column;
231
+ gap: 2px;
232
+ }
233
+
208
234
  .updateBanner {
209
235
  align-items: flex-start;
210
236
  flex-direction: column;
@@ -95,6 +95,32 @@
95
95
  padding-bottom: 8px;
96
96
  }
97
97
 
98
+ .versionRow {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: space-between;
102
+ gap: 12px;
103
+ padding: 12px 0;
104
+ border-bottom: 1px solid var(--dsw-alias-border-l2);
105
+ }
106
+
107
+ .versionLabel {
108
+ font-size: 13px;
109
+ font-weight: 500;
110
+ line-height: 1.5;
111
+ color: var(--dsw-alias-label-primary);
112
+ }
113
+
114
+ .versionValue {
115
+ padding: 1px 8px;
116
+ border-radius: 999px;
117
+ background: var(--dsw-alias-bg-module-platform);
118
+ color: var(--dsw-alias-label-secondary);
119
+ font-family: var(--dsw-font-family-mono, monospace);
120
+ font-size: 12px;
121
+ line-height: 1.5;
122
+ }
123
+
98
124
  /* --- fields (mirror of the official plugin-config fields) --------------------- */
99
125
 
100
126
  .field {
package/src/protocol.ts CHANGED
@@ -7,6 +7,9 @@
7
7
  /** Settings namespace this plugin owns (host settings seam + bridge). */
8
8
  export const IMAGEGEN_SETTINGS_NAMESPACE = 'dsh-imagegen'
9
9
 
10
+ /** Published package version shared by the host updater and the client UI. */
11
+ export const PLUGIN_VERSION = '1.0.3'
12
+
10
13
  /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
11
14
  export const SETTINGS_API = {
12
15
  describe: '/api/dsh-imagegen/settings/describe',
package/src/updater.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  /** GitHub Release discovery and explicit, user-triggered plugin updates. */
2
2
 
3
3
  import { spawn, type ChildProcess } from 'node:child_process'
4
+ import { PLUGIN_VERSION } from './protocol.ts'
4
5
 
5
6
  /** Keep this in sync with package.json for each published release. */
6
- export const CURRENT_VERSION = '1.0.2'
7
+ export const CURRENT_VERSION = PLUGIN_VERSION
7
8
  export const PACKAGE_NAME = '@dickpy/dsh-imagegen'
8
9
  export const RELEASES_URL = 'https://api.github.com/repos/dickpy/dsh-imagegen/releases/latest'
9
10