@dickpy/dsh-imagegen 1.4.0 → 1.5.1

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 (54) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +270 -124
  3. package/cordis.patch.yml +8 -8
  4. package/docs/images/ecommerce-mode.png +0 -0
  5. package/docs/images/image-generation-studio-three-column.png +0 -0
  6. package/docs/images/imagegen-overview.png +0 -0
  7. package/docs/videos/agent-chat-edit.gif +0 -0
  8. package/docs/videos/agent-chat-edit.mp4 +0 -0
  9. package/lib/client.js +1873 -431
  10. package/lib/client.js.map +1 -1
  11. package/lib/index.js +355 -116
  12. package/package.json +77 -70
  13. package/src/agent-image-tools.ts +447 -418
  14. package/src/client/ImageGenPanel.tsx +1243 -348
  15. package/src/client/SettingsCard.tsx +936 -936
  16. package/src/client/TemplateLibrary.tsx +336 -336
  17. package/src/client/api.ts +203 -193
  18. package/src/client/channels-form.ts +263 -263
  19. package/src/client/controller.ts +46 -46
  20. package/src/client/conversation-sync.ts +14 -14
  21. package/src/client/css-modules.d.ts +5 -5
  22. package/src/client/helpers.ts +33 -33
  23. package/src/client/image-toolview.module.css +73 -73
  24. package/src/client/image-toolview.tsx +34 -28
  25. package/src/client/index.ts +25 -24
  26. package/src/client/locales.ts +156 -28
  27. package/src/client/mount.tsx +117 -117
  28. package/src/client/panel.module.css +1243 -455
  29. package/src/client/settings-card.module.css +1023 -1023
  30. package/src/client/settings-form.ts +337 -336
  31. package/src/client/settings-scope.ts +302 -298
  32. package/src/client/sidebar-entry.ts +190 -190
  33. package/src/client/templates.module.css +453 -453
  34. package/src/edit-image-command.ts +110 -0
  35. package/src/engine.ts +520 -520
  36. package/src/gallery-store.ts +306 -286
  37. package/src/generation-runtime.ts +84 -79
  38. package/src/history-store.ts +270 -250
  39. package/src/image-format.ts +11 -11
  40. package/src/image-models.ts +19 -19
  41. package/src/index.ts +337 -318
  42. package/src/model-catalog.ts +115 -115
  43. package/src/presets.ts +71 -71
  44. package/src/prompt-enhancer.ts +137 -137
  45. package/src/protocol.ts +380 -338
  46. package/src/routes.ts +966 -916
  47. package/src/settings-compat.ts +60 -0
  48. package/src/task-queue.ts +113 -113
  49. package/src/templates/cases.json +10196 -10196
  50. package/src/templates-store.ts +278 -278
  51. package/src/updater.ts +117 -117
  52. package/docs/images/agent-chat-edit.png +0 -0
  53. package/docs/images/agent-chat-generate.png +0 -0
  54. package/docs/images/agent-chat-poster-workflow.png +0 -0
@@ -0,0 +1,60 @@
1
+ /** Compatibility helpers for the dsh-settings API transition. */
2
+
3
+ import type { Context } from '@deepseek-ai/cordis'
4
+ import * as settingsModule from '@deepseek-ai/dsh-settings'
5
+ import type { SettingsNamespace, SettingsSectionHooks } from '@deepseek-ai/dsh-settings'
6
+ import type z from 'schemastery'
7
+
8
+ type SettingsModuleCompat = {
9
+ settingsNamespace?: (value: string) => SettingsNamespace
10
+ installSettingsSection?: <T>(
11
+ ctx: Context,
12
+ ns: SettingsNamespace,
13
+ schema: z<T>,
14
+ entry: T,
15
+ hooks: SettingsSectionHooks<T>,
16
+ ) => void
17
+ }
18
+
19
+ interface SettingsProviderCompat {
20
+ installSection?: <T>(
21
+ owner: Context,
22
+ ns: SettingsNamespace,
23
+ schema: z<T>,
24
+ entry: T,
25
+ hooks: SettingsSectionHooks<T>,
26
+ ) => void
27
+ }
28
+
29
+ const compatModule = settingsModule as unknown as SettingsModuleCompat
30
+
31
+ /** Brand namespaces where the installed settings package still exposes it. */
32
+ export function settingsNamespaceCompat(value: string): SettingsNamespace {
33
+ return compatModule.settingsNamespace?.(value) ?? value as SettingsNamespace
34
+ }
35
+
36
+ /**
37
+ * Register an optional settings section across the rc.7 and alpha.2 APIs.
38
+ * rc.7 exposes a module helper; alpha.2 moves the helper onto the provider.
39
+ */
40
+ export function installSettingsSectionCompat<T>(
41
+ ctx: Context,
42
+ ns: SettingsNamespace,
43
+ schema: z<T>,
44
+ entry: T,
45
+ hooks: SettingsSectionHooks<T>,
46
+ ): void {
47
+ const legacyInstaller = compatModule.installSettingsSection
48
+ if (legacyInstaller !== undefined) {
49
+ legacyInstaller(ctx, ns, schema, entry, hooks)
50
+ return
51
+ }
52
+
53
+ ctx.inject(['settings'], (sctx) => {
54
+ const provider = sctx.get('settings') as unknown as SettingsProviderCompat
55
+ if (provider.installSection === undefined) {
56
+ throw new TypeError('dsh-settings does not expose installSection')
57
+ }
58
+ provider.installSection(ctx, ns, schema, entry, hooks)
59
+ })
60
+ }
package/src/task-queue.ts CHANGED
@@ -1,113 +1,113 @@
1
- /** In-memory, host-resident image generation queue. */
2
-
3
- import { randomUUID } from 'node:crypto'
4
- import type { GenerateRequest, GenerateResult, GenerationTask } from './protocol.ts'
5
-
6
- export type GenerationTaskListener = (task: GenerationTask) => void
7
-
8
- export class GenerationTaskQueue {
9
- private readonly tasks: GenerationTask[] = []
10
- private readonly controllers = new Map<string, AbortController>()
11
- private readonly listeners = new Set<GenerationTaskListener>()
12
- private running = 0
13
- private serialRunning = false
14
-
15
- constructor(
16
- private readonly run: (request: GenerateRequest, signal: AbortSignal) => Promise<GenerateResult>,
17
- private readonly concurrency = 1,
18
- ) {}
19
-
20
- list(): GenerationTask[] {
21
- return this.tasks.map(task => this.snapshot(task))
22
- }
23
-
24
- /** Observe queue state changes. Listener failures never disrupt generation. */
25
- subscribe(listener: GenerationTaskListener): () => void {
26
- this.listeners.add(listener)
27
- return () => { this.listeners.delete(listener) }
28
- }
29
-
30
- submit(request: GenerateRequest): GenerationTask {
31
- const task: GenerationTask = { id: randomUUID(), request: { ...request }, status: 'queued', createdAt: Date.now() }
32
- this.tasks.unshift(task)
33
- this.publish(task)
34
- this.drain()
35
- return this.snapshot(task)
36
- }
37
-
38
- cancel(id: string): GenerationTask | undefined {
39
- const task = this.tasks.find(item => item.id === id)
40
- if (task === undefined || task.status === 'completed' || task.status === 'failed' || task.status === 'cancelled') return task
41
- task.status = 'cancelled'
42
- task.finishedAt = Date.now()
43
- this.controllers.get(id)?.abort()
44
- this.publish(task)
45
- this.drain()
46
- return this.snapshot(task)
47
- }
48
-
49
- retry(id: string): GenerationTask | undefined {
50
- const previous = this.tasks.find(item => item.id === id)
51
- return previous === undefined ? undefined : this.submit(previous.request)
52
- }
53
-
54
- private drain(): void {
55
- while (this.running < Math.max(1, this.concurrency)) {
56
- const task = this.tasks.find(item => item.status === 'queued'
57
- && (this.running === 0 || (item.request.comparisonId !== undefined && !this.serialRunning)))
58
- if (task === undefined) return
59
- this.running += 1
60
- if (task.request.comparisonId === undefined) this.serialRunning = true
61
- void this.runTask(task).finally(() => {
62
- this.running -= 1
63
- if (task.request.comparisonId === undefined) this.serialRunning = false
64
- this.drain()
65
- })
66
- }
67
- }
68
-
69
- private async runTask(task: GenerationTask): Promise<void> {
70
- task.status = 'running'
71
- task.startedAt = Date.now()
72
- this.publish(task)
73
- const controller = new AbortController()
74
- this.controllers.set(task.id, controller)
75
- try {
76
- const result = await this.run(task.request, controller.signal)
77
- if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
78
- task.status = 'completed'
79
- task.result = result
80
- task.finishedAt = Date.now()
81
- this.publish(task)
82
- }
83
- } catch (error) {
84
- if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
85
- task.status = 'failed'
86
- task.error = error instanceof Error ? error.message : String(error)
87
- task.finishedAt = Date.now()
88
- this.publish(task)
89
- }
90
- } finally {
91
- this.controllers.delete(task.id)
92
- }
93
- }
94
-
95
- private publish(task: GenerationTask): void {
96
- const snapshot = this.snapshot(task)
97
- for (const listener of this.listeners) {
98
- try {
99
- listener(snapshot)
100
- } catch {
101
- // Observers must not be able to interrupt the queue pump.
102
- }
103
- }
104
- }
105
-
106
- private snapshot(task: GenerationTask): GenerationTask {
107
- return {
108
- ...task,
109
- request: { ...task.request },
110
- ...task.result === undefined ? {} : { result: task.result },
111
- }
112
- }
113
- }
1
+ /** In-memory, host-resident image generation queue. */
2
+
3
+ import { randomUUID } from 'node:crypto'
4
+ import type { GenerateRequest, GenerateResult, GenerationTask } from './protocol.ts'
5
+
6
+ export type GenerationTaskListener = (task: GenerationTask) => void
7
+
8
+ export class GenerationTaskQueue {
9
+ private readonly tasks: GenerationTask[] = []
10
+ private readonly controllers = new Map<string, AbortController>()
11
+ private readonly listeners = new Set<GenerationTaskListener>()
12
+ private running = 0
13
+ private serialRunning = false
14
+
15
+ constructor(
16
+ private readonly run: (request: GenerateRequest, signal: AbortSignal) => Promise<GenerateResult>,
17
+ private readonly concurrency = 1,
18
+ ) {}
19
+
20
+ list(): GenerationTask[] {
21
+ return this.tasks.map(task => this.snapshot(task))
22
+ }
23
+
24
+ /** Observe queue state changes. Listener failures never disrupt generation. */
25
+ subscribe(listener: GenerationTaskListener): () => void {
26
+ this.listeners.add(listener)
27
+ return () => { this.listeners.delete(listener) }
28
+ }
29
+
30
+ submit(request: GenerateRequest): GenerationTask {
31
+ const task: GenerationTask = { id: randomUUID(), request: { ...request }, status: 'queued', createdAt: Date.now() }
32
+ this.tasks.unshift(task)
33
+ this.publish(task)
34
+ this.drain()
35
+ return this.snapshot(task)
36
+ }
37
+
38
+ cancel(id: string): GenerationTask | undefined {
39
+ const task = this.tasks.find(item => item.id === id)
40
+ if (task === undefined || task.status === 'completed' || task.status === 'failed' || task.status === 'cancelled') return task
41
+ task.status = 'cancelled'
42
+ task.finishedAt = Date.now()
43
+ this.controllers.get(id)?.abort()
44
+ this.publish(task)
45
+ this.drain()
46
+ return this.snapshot(task)
47
+ }
48
+
49
+ retry(id: string): GenerationTask | undefined {
50
+ const previous = this.tasks.find(item => item.id === id)
51
+ return previous === undefined ? undefined : this.submit(previous.request)
52
+ }
53
+
54
+ private drain(): void {
55
+ while (this.running < Math.max(1, this.concurrency)) {
56
+ const task = this.tasks.find(item => item.status === 'queued'
57
+ && (this.running === 0 || (item.request.comparisonId !== undefined && !this.serialRunning)))
58
+ if (task === undefined) return
59
+ this.running += 1
60
+ if (task.request.comparisonId === undefined) this.serialRunning = true
61
+ void this.runTask(task).finally(() => {
62
+ this.running -= 1
63
+ if (task.request.comparisonId === undefined) this.serialRunning = false
64
+ this.drain()
65
+ })
66
+ }
67
+ }
68
+
69
+ private async runTask(task: GenerationTask): Promise<void> {
70
+ task.status = 'running'
71
+ task.startedAt = Date.now()
72
+ this.publish(task)
73
+ const controller = new AbortController()
74
+ this.controllers.set(task.id, controller)
75
+ try {
76
+ const result = await this.run(task.request, controller.signal)
77
+ if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
78
+ task.status = 'completed'
79
+ task.result = result
80
+ task.finishedAt = Date.now()
81
+ this.publish(task)
82
+ }
83
+ } catch (error) {
84
+ if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
85
+ task.status = 'failed'
86
+ task.error = error instanceof Error ? error.message : String(error)
87
+ task.finishedAt = Date.now()
88
+ this.publish(task)
89
+ }
90
+ } finally {
91
+ this.controllers.delete(task.id)
92
+ }
93
+ }
94
+
95
+ private publish(task: GenerationTask): void {
96
+ const snapshot = this.snapshot(task)
97
+ for (const listener of this.listeners) {
98
+ try {
99
+ listener(snapshot)
100
+ } catch {
101
+ // Observers must not be able to interrupt the queue pump.
102
+ }
103
+ }
104
+ }
105
+
106
+ private snapshot(task: GenerationTask): GenerationTask {
107
+ return {
108
+ ...task,
109
+ request: { ...task.request },
110
+ ...task.result === undefined ? {} : { result: task.result },
111
+ }
112
+ }
113
+ }