@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
@@ -1,190 +1,190 @@
1
- /**
2
- * Replace the shell's standalone New Session affordance with a two-tab entry:
3
- * New Session and Image Generation. When image generation is active, the
4
- * plugin also uses the shell's region area as a dedicated history surface;
5
- * the original workspace/session tree remains underneath and is restored when
6
- * the panel closes.
7
- */
8
-
9
- import type { ImageGenController } from './controller.ts'
10
- import css from './panel.module.css'
11
-
12
- /** Stable selector for the injected two-tab host. */
13
- export const ENTRY_SELECTOR = '[data-dsh-imagegen-session-tabs]'
14
- /** Stable selector for the history surface in the shell region area. */
15
- export const HISTORY_HOST_SELECTOR = '[data-dsh-imagegen-history-host]'
16
-
17
- /** Inline picture glyph kept deliberately small for the sidebar rail. */
18
- const IMAGE_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2.5" width="12" height="11" rx="1.5"/><circle cx="5.6" cy="5.8" r="1"/><path d="M2.5 12.5l3.6-3.4 2.4 2.2 3-3 2 2.4"/></svg>'
19
-
20
- /** Inline plus glyph for the new-session tab. */
21
- const NEW_SESSION_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>'
22
-
23
- /** Find the sidebar shell root, or undefined while it is not mounted. */
24
- function sidebarRoot(): HTMLElement | undefined {
25
- const column = document.querySelector<HTMLElement>('[data-pane="sidebar"], [class*="sidebarCol"]')
26
- if (column === null) return undefined
27
- const logoOwner = column.querySelector<HTMLElement>('[class*="logoRow"]')?.parentElement
28
- return logoOwner ?? (column.firstElementChild as HTMLElement | undefined)
29
- }
30
-
31
- /** The shell-owned New Session button across current and legacy shells. */
32
- function newSessionButton(root: HTMLElement): HTMLButtonElement | undefined {
33
- return root.querySelector<HTMLButtonElement>(
34
- 'button[data-dsh-part="new-session"], button[class*="newSession"]',
35
- ) ?? Array.from(root.children).find(
36
- (child): child is HTMLButtonElement => child instanceof HTMLElement && child.tagName === 'BUTTON',
37
- )
38
- }
39
-
40
- /** Locate the shell region that normally contains workspaces and sessions. */
41
- function regionArea(root: HTMLElement): HTMLElement | undefined {
42
- return root.querySelector<HTMLElement>('[class*="regionArea"]') ?? undefined
43
- }
44
-
45
- function makeTab(
46
- label: string,
47
- tooltip: string,
48
- icon: string,
49
- onClick: () => void,
50
- ): HTMLButtonElement {
51
- const tab = document.createElement('button')
52
- tab.type = 'button'
53
- tab.className = css.sessionTab
54
- tab.setAttribute('aria-label', label)
55
- tab.setAttribute('title', tooltip)
56
- tab.innerHTML = `<span class="${css.sessionTabIcon}">${icon}</span><span class="${css.sessionTabLabel}">${label}</span>`
57
- tab.addEventListener('click', onClick)
58
- return tab
59
- }
60
-
61
- function hideShellButton(button: HTMLButtonElement): void {
62
- button.dataset.dshImagegenOriginal = ''
63
- button.setAttribute('aria-hidden', 'true')
64
- button.tabIndex = -1
65
- button.style.display = 'none'
66
- }
67
-
68
- function restoreShellButton(button: HTMLButtonElement): void {
69
- button.style.removeProperty('display')
70
- button.removeAttribute('aria-hidden')
71
- button.removeAttribute('tabindex')
72
- delete button.dataset.dshImagegenOriginal
73
- }
74
-
75
- /** Mount or repair the two-tab host at the shell's New Session position. */
76
- function placeTabs(
77
- root: HTMLElement,
78
- controller: ImageGenController,
79
- newSessionLabel: string,
80
- newSessionTooltip: string,
81
- imageLabel: string,
82
- imageTooltip: string,
83
- ): HTMLDivElement | undefined {
84
- const button = newSessionButton(root)
85
- if (button === undefined) return undefined
86
-
87
- const existing = root.querySelector<HTMLDivElement>(ENTRY_SELECTOR)
88
- if (existing !== null && existing.parentElement === button.parentElement) {
89
- hideShellButton(button)
90
- return existing
91
- }
92
-
93
- existing?.remove()
94
- const tabs = document.createElement('div')
95
- tabs.dataset.dshImagegenSessionTabs = ''
96
- tabs.className = css.sessionTabs
97
- tabs.setAttribute('role', 'tablist')
98
- tabs.setAttribute('aria-label', imageTooltip)
99
-
100
- const newSessionTab = makeTab(newSessionLabel, newSessionTooltip, NEW_SESSION_ICON, () => {
101
- controller.close()
102
- button.click()
103
- })
104
- const imageTab = makeTab(imageLabel, imageTooltip, IMAGE_ICON, () => {
105
- controller.open()
106
- })
107
- newSessionTab.dataset.dshImagegenTab = 'new-session'
108
- imageTab.dataset.dshImagegenTab = 'image'
109
- tabs.append(newSessionTab, imageTab)
110
-
111
- button.parentElement?.insertBefore(tabs, button)
112
- hideShellButton(button)
113
- return tabs
114
- }
115
-
116
- /** Mount an overlay host over the workspace/session tree for image history. */
117
- function placeHistoryHost(root: HTMLElement): HTMLDivElement | undefined {
118
- const region = regionArea(root)
119
- if (region === undefined) return undefined
120
- const existing = region.querySelector<HTMLDivElement>(HISTORY_HOST_SELECTOR)
121
- if (existing !== null) return existing
122
- const host = document.createElement('div')
123
- host.dataset.dshImagegenHistoryHost = ''
124
- host.className = css.sidebarHistoryHost
125
- region.append(host)
126
- return host
127
- }
128
-
129
- /**
130
- * Mount the two tabs and self-heal after React rebuilds the sidebar. The
131
- * shell-owned button is restored by the disposer so unloading the plugin
132
- * leaves the host unchanged.
133
- */
134
- export function mountSidebarEntry(
135
- controller: ImageGenController,
136
- newSessionLabel: string,
137
- newSessionTooltip: string,
138
- imageLabel: string,
139
- imageTooltip: string,
140
- ): () => void {
141
- let root: HTMLElement | undefined
142
- let tabs: HTMLDivElement | undefined
143
- let historyHost: HTMLDivElement | undefined
144
- let originalButton: HTMLButtonElement | undefined
145
-
146
- const syncActive = (): void => {
147
- if (tabs === undefined) return
148
- const newTab = tabs.querySelector<HTMLElement>('[data-dsh-imagegen-tab="new-session"]')
149
- const imageTab = tabs.querySelector<HTMLElement>('[data-dsh-imagegen-tab="image"]')
150
- if (controller.getSnapshot().panelOpen) {
151
- if (newTab !== null) delete newTab.dataset.active
152
- if (imageTab !== null) imageTab.dataset.active = ''
153
- } else {
154
- if (newTab !== null) newTab.dataset.active = ''
155
- if (imageTab !== null) delete imageTab.dataset.active
156
- }
157
- }
158
-
159
- const ensure = (): void => {
160
- if (root !== undefined && !root.isConnected) {
161
- root = undefined
162
- tabs = undefined
163
- historyHost = undefined
164
- originalButton = undefined
165
- }
166
- root ??= sidebarRoot()
167
- if (root === undefined) return
168
- root.dataset.dshImagegenSidebarRoot = ''
169
- const button = newSessionButton(root)
170
- if (button === undefined) return
171
- originalButton ??= button
172
- tabs = placeTabs(root, controller, newSessionLabel, newSessionTooltip, imageLabel, imageTooltip)
173
- historyHost = placeHistoryHost(root)
174
- syncActive()
175
- }
176
-
177
- const bodyObserver = new MutationObserver(ensure)
178
- bodyObserver.observe(document.body, { childList: true, subtree: true })
179
- const unsubscribe = controller.subscribe(syncActive)
180
- ensure()
181
-
182
- return () => {
183
- bodyObserver.disconnect()
184
- unsubscribe()
185
- tabs?.remove()
186
- historyHost?.remove()
187
- if (originalButton !== undefined && originalButton.isConnected) restoreShellButton(originalButton)
188
- if (root !== undefined) delete root.dataset.dshImagegenSidebarRoot
189
- }
190
- }
1
+ /**
2
+ * Replace the shell's standalone New Session affordance with a two-tab entry:
3
+ * New Session and Image Generation. When image generation is active, the
4
+ * plugin also uses the shell's region area as a dedicated history surface;
5
+ * the original workspace/session tree remains underneath and is restored when
6
+ * the panel closes.
7
+ */
8
+
9
+ import type { ImageGenController } from './controller.ts'
10
+ import css from './panel.module.css'
11
+
12
+ /** Stable selector for the injected two-tab host. */
13
+ export const ENTRY_SELECTOR = '[data-dsh-imagegen-session-tabs]'
14
+ /** Stable selector for the history surface in the shell region area. */
15
+ export const HISTORY_HOST_SELECTOR = '[data-dsh-imagegen-history-host]'
16
+
17
+ /** Inline picture glyph kept deliberately small for the sidebar rail. */
18
+ const IMAGE_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2.5" width="12" height="11" rx="1.5"/><circle cx="5.6" cy="5.8" r="1"/><path d="M2.5 12.5l3.6-3.4 2.4 2.2 3-3 2 2.4"/></svg>'
19
+
20
+ /** Inline plus glyph for the new-session tab. */
21
+ const NEW_SESSION_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>'
22
+
23
+ /** Find the sidebar shell root, or undefined while it is not mounted. */
24
+ function sidebarRoot(): HTMLElement | undefined {
25
+ const column = document.querySelector<HTMLElement>('[data-pane="sidebar"], [class*="sidebarCol"]')
26
+ if (column === null) return undefined
27
+ const logoOwner = column.querySelector<HTMLElement>('[class*="logoRow"]')?.parentElement
28
+ return logoOwner ?? (column.firstElementChild as HTMLElement | undefined)
29
+ }
30
+
31
+ /** The shell-owned New Session button across current and legacy shells. */
32
+ function newSessionButton(root: HTMLElement): HTMLButtonElement | undefined {
33
+ return root.querySelector<HTMLButtonElement>(
34
+ 'button[data-dsh-part="new-session"], button[class*="newSession"]',
35
+ ) ?? Array.from(root.children).find(
36
+ (child): child is HTMLButtonElement => child instanceof HTMLElement && child.tagName === 'BUTTON',
37
+ )
38
+ }
39
+
40
+ /** Locate the shell region that normally contains workspaces and sessions. */
41
+ function regionArea(root: HTMLElement): HTMLElement | undefined {
42
+ return root.querySelector<HTMLElement>('[class*="regionArea"]') ?? undefined
43
+ }
44
+
45
+ function makeTab(
46
+ label: string,
47
+ tooltip: string,
48
+ icon: string,
49
+ onClick: () => void,
50
+ ): HTMLButtonElement {
51
+ const tab = document.createElement('button')
52
+ tab.type = 'button'
53
+ tab.className = css.sessionTab
54
+ tab.setAttribute('aria-label', label)
55
+ tab.setAttribute('title', tooltip)
56
+ tab.innerHTML = `<span class="${css.sessionTabIcon}">${icon}</span><span class="${css.sessionTabLabel}">${label}</span>`
57
+ tab.addEventListener('click', onClick)
58
+ return tab
59
+ }
60
+
61
+ function hideShellButton(button: HTMLButtonElement): void {
62
+ button.dataset.dshImagegenOriginal = ''
63
+ button.setAttribute('aria-hidden', 'true')
64
+ button.tabIndex = -1
65
+ button.style.display = 'none'
66
+ }
67
+
68
+ function restoreShellButton(button: HTMLButtonElement): void {
69
+ button.style.removeProperty('display')
70
+ button.removeAttribute('aria-hidden')
71
+ button.removeAttribute('tabindex')
72
+ delete button.dataset.dshImagegenOriginal
73
+ }
74
+
75
+ /** Mount or repair the two-tab host at the shell's New Session position. */
76
+ function placeTabs(
77
+ root: HTMLElement,
78
+ controller: ImageGenController,
79
+ newSessionLabel: string,
80
+ newSessionTooltip: string,
81
+ imageLabel: string,
82
+ imageTooltip: string,
83
+ ): HTMLDivElement | undefined {
84
+ const button = newSessionButton(root)
85
+ if (button === undefined) return undefined
86
+
87
+ const existing = root.querySelector<HTMLDivElement>(ENTRY_SELECTOR)
88
+ if (existing !== null && existing.parentElement === button.parentElement) {
89
+ hideShellButton(button)
90
+ return existing
91
+ }
92
+
93
+ existing?.remove()
94
+ const tabs = document.createElement('div')
95
+ tabs.dataset.dshImagegenSessionTabs = ''
96
+ tabs.className = css.sessionTabs
97
+ tabs.setAttribute('role', 'tablist')
98
+ tabs.setAttribute('aria-label', imageTooltip)
99
+
100
+ const newSessionTab = makeTab(newSessionLabel, newSessionTooltip, NEW_SESSION_ICON, () => {
101
+ controller.close()
102
+ button.click()
103
+ })
104
+ const imageTab = makeTab(imageLabel, imageTooltip, IMAGE_ICON, () => {
105
+ controller.open()
106
+ })
107
+ newSessionTab.dataset.dshImagegenTab = 'new-session'
108
+ imageTab.dataset.dshImagegenTab = 'image'
109
+ tabs.append(newSessionTab, imageTab)
110
+
111
+ button.parentElement?.insertBefore(tabs, button)
112
+ hideShellButton(button)
113
+ return tabs
114
+ }
115
+
116
+ /** Mount an overlay host over the workspace/session tree for image history. */
117
+ function placeHistoryHost(root: HTMLElement): HTMLDivElement | undefined {
118
+ const region = regionArea(root)
119
+ if (region === undefined) return undefined
120
+ const existing = region.querySelector<HTMLDivElement>(HISTORY_HOST_SELECTOR)
121
+ if (existing !== null) return existing
122
+ const host = document.createElement('div')
123
+ host.dataset.dshImagegenHistoryHost = ''
124
+ host.className = css.sidebarHistoryHost
125
+ region.append(host)
126
+ return host
127
+ }
128
+
129
+ /**
130
+ * Mount the two tabs and self-heal after React rebuilds the sidebar. The
131
+ * shell-owned button is restored by the disposer so unloading the plugin
132
+ * leaves the host unchanged.
133
+ */
134
+ export function mountSidebarEntry(
135
+ controller: ImageGenController,
136
+ newSessionLabel: string,
137
+ newSessionTooltip: string,
138
+ imageLabel: string,
139
+ imageTooltip: string,
140
+ ): () => void {
141
+ let root: HTMLElement | undefined
142
+ let tabs: HTMLDivElement | undefined
143
+ let historyHost: HTMLDivElement | undefined
144
+ let originalButton: HTMLButtonElement | undefined
145
+
146
+ const syncActive = (): void => {
147
+ if (tabs === undefined) return
148
+ const newTab = tabs.querySelector<HTMLElement>('[data-dsh-imagegen-tab="new-session"]')
149
+ const imageTab = tabs.querySelector<HTMLElement>('[data-dsh-imagegen-tab="image"]')
150
+ if (controller.getSnapshot().panelOpen) {
151
+ if (newTab !== null) delete newTab.dataset.active
152
+ if (imageTab !== null) imageTab.dataset.active = ''
153
+ } else {
154
+ if (newTab !== null) newTab.dataset.active = ''
155
+ if (imageTab !== null) delete imageTab.dataset.active
156
+ }
157
+ }
158
+
159
+ const ensure = (): void => {
160
+ if (root !== undefined && !root.isConnected) {
161
+ root = undefined
162
+ tabs = undefined
163
+ historyHost = undefined
164
+ originalButton = undefined
165
+ }
166
+ root ??= sidebarRoot()
167
+ if (root === undefined) return
168
+ root.dataset.dshImagegenSidebarRoot = ''
169
+ const button = newSessionButton(root)
170
+ if (button === undefined) return
171
+ originalButton ??= button
172
+ tabs = placeTabs(root, controller, newSessionLabel, newSessionTooltip, imageLabel, imageTooltip)
173
+ historyHost = placeHistoryHost(root)
174
+ syncActive()
175
+ }
176
+
177
+ const bodyObserver = new MutationObserver(ensure)
178
+ bodyObserver.observe(document.body, { childList: true, subtree: true })
179
+ const unsubscribe = controller.subscribe(syncActive)
180
+ ensure()
181
+
182
+ return () => {
183
+ bodyObserver.disconnect()
184
+ unsubscribe()
185
+ tabs?.remove()
186
+ historyHost?.remove()
187
+ if (originalButton !== undefined && originalButton.isConnected) restoreShellButton(originalButton)
188
+ if (root !== undefined) delete root.dataset.dshImagegenSidebarRoot
189
+ }
190
+ }