dsh-image-gen 0.5.0 → 0.6.0

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 (42) hide show
  1. package/README.en.md +345 -344
  2. package/README.md +345 -344
  3. package/README.zh-CN.md +3 -3
  4. package/lib/client.js +115006 -228
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +2270 -601
  7. package/lib/types/canvas-state-route.d.ts +37 -0
  8. package/lib/types/canvas-state.d.ts +77 -0
  9. package/lib/types/canvas-tools.d.ts +44 -0
  10. package/lib/types/client/browser-image-utils.d.ts +4 -0
  11. package/lib/types/client/canvas/canvas-bridge.d.ts +10 -0
  12. package/lib/types/client/canvas/canvas-model.d.ts +129 -0
  13. package/lib/types/client/canvas/canvas-nodes.d.ts +23 -0
  14. package/lib/types/client/canvas/canvas-store.d.ts +29 -0
  15. package/lib/types/client/canvas/canvas-style.d.ts +1 -0
  16. package/lib/types/client/canvas/canvas-view.d.ts +8 -0
  17. package/lib/types/client/canvas/rf-base-css.d.ts +2 -0
  18. package/lib/types/client/gallery-store.d.ts +2 -0
  19. package/lib/types/client/gallery-view.d.ts +13 -2
  20. package/lib/types/client/image-result-node.d.ts +2 -0
  21. package/lib/types/client/index.d.ts +4 -2
  22. package/lib/types/client/studio-chat-panel.d.ts +23 -0
  23. package/lib/types/client/studio-style.d.ts +1 -1
  24. package/lib/types/client/studio-view.d.ts +8 -6
  25. package/lib/types/client/tl/canvas-sync.d.ts +22 -0
  26. package/lib/types/client/tl/studio-tl-canvas.d.ts +2 -0
  27. package/lib/types/client/tl/tl-canvas-bridge.d.ts +53 -0
  28. package/lib/types/client/tl/tl-css.d.ts +2 -0
  29. package/lib/types/index.d.ts +1 -0
  30. package/lib/types/reference-image.d.ts +1 -0
  31. package/lib/types/shared.d.ts +86 -0
  32. package/lib/types/studio-chat.d.ts +48 -0
  33. package/package.json +22 -15
  34. package/skills/install-dsh-image-gen/SKILL.md +22 -22
  35. package/lib/types/client/inspiration-api.d.ts +0 -10
  36. package/lib/types/client/inspiration-detail.d.ts +0 -14
  37. package/lib/types/inspiration/cache.d.ts +0 -20
  38. package/lib/types/inspiration/downloader.d.ts +0 -27
  39. package/lib/types/inspiration/routes.d.ts +0 -13
  40. package/lib/types/inspiration/sources.d.ts +0 -33
  41. package/lib/types/inspiration/types.d.ts +0 -65
  42. package/lib/types/inspiration/updater.d.ts +0 -7
@@ -1,11 +1,6 @@
1
1
  import { type FC } from 'react';
2
2
  import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
3
- export interface LocaleService {
4
- subscribe(cb: () => void): () => void;
5
- getSnapshot(): {
6
- active?: string;
7
- };
8
- }
3
+ import type { LocaleService } from './gallery-view.js';
9
4
  export interface StudioReferenceItem {
10
5
  id: string;
11
6
  attachment?: ImageAttachmentRef;
@@ -22,6 +17,13 @@ export declare const StudioView: FC<{
22
17
  locale?: LocaleService | undefined;
23
18
  workspace?: StudioWorkspaceProps | null | undefined;
24
19
  initialPrompt?: string | undefined;
20
+ /**
21
+ * Canvas surface opened first: 'preview' (single-image viewer, the default)
22
+ * or 'infinite' (the tldraw editor). The right-sidebar variant opens the
23
+ * infinite canvas directly - mirroring chat-generated images while the
24
+ * native conversation runs beside it is the point of the split.
25
+ */
26
+ initialCanvasSurface?: 'preview' | 'infinite' | undefined;
25
27
  onInitialPromptApplied?(): void;
26
28
  onOpenInspiration?(): void;
27
29
  }>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Live canvas-state sync from one tldraw surface to the host mirror.
3
+ *
4
+ * The conversation agent runs in the host process and cannot see the browser
5
+ * canvas, so this module is the canvas's voice: it watches the editor store,
6
+ * summarizes the page (shape inventory + selection) and pushes a compact
7
+ * snapshot to the canvas-state route. When the selection settles on content
8
+ * the conversation cannot already see — hand-drawn strokes, text, pasted
9
+ * images — it also exports a PNG screenshot of the selection, which the host
10
+ * turns into a durable attachment (view_canvas / edit_image
11
+ * source=canvas_selection read exactly that).
12
+ *
13
+ * Pushes are fire-and-forget: failures warn in the console and the next
14
+ * change retries. Duplicate snapshots (e.g. camera pans that change nothing
15
+ * in the summary) never hit the network.
16
+ */
17
+ import type { Editor } from 'tldraw';
18
+ /**
19
+ * Start mirroring one editor into the host canvas-state route.
20
+ * Returns a disposer that stops listening and marks the instance offline.
21
+ */
22
+ export declare function startCanvasSync(editor: Editor): () => void;
@@ -0,0 +1,2 @@
1
+ import { type FC } from 'react';
2
+ export declare const StudioTlCanvas: FC;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Landing bus between studio generation results and the tldraw canvases.
3
+ *
4
+ * Generation paths (single, multi-image, multi-model comparison, chat tool
5
+ * cards) push items here; every mounted tldraw surface reconciles against the
6
+ * full list. More than one canvas can be mounted at once (the conversation-view
7
+ * gallery tab and the right-sidebar studio tab), so the bus broadcasts instead
8
+ * of draining: each canvas lands the items its own page does not carry yet
9
+ * (per-canvas galleryId dedupe) and re-reads on every push. If no canvas is
10
+ * mounted, items wait in memory and land on the next mount. Nothing here or on
11
+ * any canvas survives a restart: the tldraw surfaces run without
12
+ * persistenceKey, so unsaved generations vanish on reload - the gallery
13
+ * remains the only durable store (save-first philosophy).
14
+ */
15
+ import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
16
+ export interface TlLandingItem {
17
+ /** Gallery item id; also used to dedupe shapes via shape.meta.galleryId. */
18
+ galleryId: string;
19
+ attachment: ImageAttachmentRef;
20
+ /**
21
+ * True when this attachment is part of the current conversation messages
22
+ * (chat tool results): the host can then resolve its full-resolution
23
+ * original directly, and a canvas screenshot of it would be redundant.
24
+ * Form generations never enter the conversation, so their selections must
25
+ * keep the screenshot fallback — the host has no other way to see them.
26
+ */
27
+ fromConversation?: boolean;
28
+ /**
29
+ * Generation provenance copied onto the landed shape's meta: the canvas
30
+ * digest then tells the model how each image was made, so "regenerate this"
31
+ * or "vary this" reuses the original prompt and model instead of guessing.
32
+ * All optional; shapes landed from older paths simply carry none.
33
+ */
34
+ prompt?: string;
35
+ provider?: string;
36
+ model?: string;
37
+ }
38
+ type TlLandingListener = () => void;
39
+ /** Queue freshly generated images for the tldraw canvases. Safe to call anywhere. */
40
+ export declare function pushTlLandings(newItems: readonly TlLandingItem[]): void;
41
+ /**
42
+ * Read every item landed so far in this browser session.
43
+ *
44
+ * The list is the in-memory session-scratch record shared by all canvases:
45
+ * reading never removes items, so a canvas mounted later (or a second canvas
46
+ * mounted beside the first) reconciles the same set. The list dies with the
47
+ * page, which is exactly the "unsaved content does not survive a restart"
48
+ * semantic the studio canvas keeps.
49
+ */
50
+ export declare function getTlLandings(): readonly TlLandingItem[];
51
+ /** Subscribe to queue pushes. Returns an unsubscribe function. */
52
+ export declare function subscribeTlLandings(listener: TlLandingListener): () => void;
53
+ export {};
@@ -0,0 +1,2 @@
1
+ /** Bundled tldraw styles (tldraw 5.3.0, tldraw SDK license; the "Made with tldraw" watermark is part of the licensed default UI). Generated from tldraw/tldraw.css - do not edit by hand. */
2
+ export declare const TL_CSS: string;
@@ -6,6 +6,7 @@ export { IMAGE_ROUTE, DELETE_ROUTE, SAVE_WORKSPACE_ROUTE, imageAttachmentFromMet
6
6
  export { STUDIO_ROUTE } from './shared.js';
7
7
  export { INSPIRATION_ROUTE } from './shared.js';
8
8
  export { TEST_CONNECTION_ROUTE } from './shared.js';
9
+ export { CANVAS_STATE_ROUTE } from './shared.js';
9
10
  export declare const name = "dsh-image-gen";
10
11
  export declare const inject: string[];
11
12
  export declare function apply(ctx: Context, config?: Config): void;
@@ -53,3 +53,4 @@ export declare function findReferenceImages(messages: readonly Message[], source
53
53
  export declare function findReferenceImage(messages: readonly Message[], sourceAttachmentId?: string): ImageAttachmentRef | undefined;
54
54
  /** Validate an untrusted serialized image reference at an HTTP/UI boundary. */
55
55
  export declare function parseImageAttachmentRef(value: unknown): ImageAttachmentRef | undefined;
56
+ export declare function detectImageMediaType(data: Uint8Array): ImageMediaType | undefined;
@@ -12,6 +12,92 @@ export declare const INSPIRATION_ROUTE = "/plugins/dsh-image-gen/inspiration";
12
12
  export declare const SAVE_WORKSPACE_ROUTE = "/plugins/dsh-image-gen/save-workspace";
13
13
  /** Browser route the settings card probes provider connectivity through. */
14
14
  export declare const TEST_CONNECTION_ROUTE = "/plugins/dsh-image-gen/test";
15
+ /** Browser route the workbench infinite canvas pushes live state through. */
16
+ export declare const CANVAS_STATE_ROUTE = "/plugins/dsh-image-gen/canvas-state";
17
+ /** Coarse model-facing kind of one shape on the workbench infinite canvas. */
18
+ export type CanvasNodeKind = 'image' | 'draw' | 'text' | 'note' | 'geo' | 'arrow' | 'frame' | 'other';
19
+ /** Every accepted canvas node kind, for validating untrusted pushes. */
20
+ export declare const CANVAS_NODE_KINDS: readonly CanvasNodeKind[];
21
+ /**
22
+ * Cap on the selection identity list: the client trims `selection.items` to
23
+ * this size and the canvas-state route rejects pushes carrying more, so the
24
+ * two ends can never drift apart.
25
+ */
26
+ export declare const CANVAS_MAX_SELECTION_ITEMS = 16;
27
+ /**
28
+ * Cap on the node inventory: the client trims `nodes` to this size and the
29
+ * canvas-state route rejects pushes carrying more, so the two ends can never
30
+ * drift apart. Sized to keep the model-facing digest compact.
31
+ */
32
+ export declare const CANVAS_MAX_NODES = 48;
33
+ /** Same shared-cap contract as CANVAS_MAX_NODES, for the selection kind list. */
34
+ export declare const CANVAS_MAX_SELECTION_KINDS = 8;
35
+ /**
36
+ * Cap on the generation prompt copied onto canvas image shapes and into the
37
+ * model-facing summaries. The landing path truncates to this and the
38
+ * canvas-state route rejects longer values, so the two ends can never drift.
39
+ * The gallery keeps the full prompt; this is only the canvas-side digest view.
40
+ */
41
+ export declare const CANVAS_MAX_PROMPT_CHARS = 120;
42
+ /** One shape on the workbench infinite canvas, summarized for the model. */
43
+ export interface CanvasNodeSummary {
44
+ kind: CanvasNodeKind;
45
+ /** Gallery id when the shape is a generated image landed from the bus. */
46
+ galleryId?: string;
47
+ /** Conversation attachment id for generated images; edit_image can target it directly. */
48
+ attachmentId?: string;
49
+ /** Human-facing label: image name, geo variant, or similar. */
50
+ name?: string;
51
+ width?: number;
52
+ height?: number;
53
+ /** Short text preview for text-bearing shapes. */
54
+ text?: string;
55
+ /**
56
+ * Truncated generation prompt for landed generated images: the model can
57
+ * reproduce or precisely vary a canvas image instead of guessing from pixels.
58
+ */
59
+ prompt?: string;
60
+ /** Provider id (e.g. "google") the landed image was generated with. */
61
+ provider?: string;
62
+ /** Model (or ComfyUI workflow label) the landed image was generated with. */
63
+ model?: string;
64
+ }
65
+ /** What is currently selected on the canvas. */
66
+ export interface CanvasSelectionSummary {
67
+ count: number;
68
+ kinds: readonly CanvasNodeKind[];
69
+ /**
70
+ * Capped identity list of the selected shapes, using the same summary shape
71
+ * as canvas nodes: the model learns WHICH images or strokes are selected
72
+ * (name, attachment id, dimensions), not just how many. Without this, two
73
+ * selections of the same size and kind are indistinguishable.
74
+ */
75
+ items?: readonly CanvasNodeSummary[];
76
+ }
77
+ /**
78
+ * One live state push from a browser tldraw instance of the workbench canvas.
79
+ * The browser owns the canvas; the host keeps only this compact mirror, so
80
+ * the conversation agent can reason about (and look at) what the user sees.
81
+ */
82
+ export interface CanvasStatePush {
83
+ /** Tldraw editor id; distinguishes simultaneously mounted canvases. */
84
+ clientInstance: string;
85
+ /** False on the final push right before a canvas unmounts. */
86
+ connected: boolean;
87
+ /** Total shape count on the current page (the node list may be capped). */
88
+ nodeCount: number;
89
+ /** Capped shape inventory, capped client-side before transport. */
90
+ nodes?: readonly CanvasNodeSummary[];
91
+ selection?: CanvasSelectionSummary;
92
+ /**
93
+ * PNG data-URL screenshot of the current selection, pushed whenever a
94
+ * selection settles. It shows the selection as it looks on the canvas —
95
+ * including annotations drawn over generated images — so the model sees the
96
+ * live canvas state, not just the original conversation attachment.
97
+ */
98
+ selectionImage?: string;
99
+ updatedAt: number;
100
+ }
15
101
  /** Namespace persisted through DSH Settings. */
16
102
  export declare const IMAGE_GENERATION_NAMESPACE = "image-generation";
17
103
  /** Supported providers. */
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Dedicated DSH agent session backing the workbench chat panel.
3
+ *
4
+ * The panel is a real DSH conversation driven from the plugin, not a parallel
5
+ * chat implementation: on first use the host creates an agent through
6
+ * ctx.agents.create (the same factory the sidebar uses), then archives the
7
+ * session through ctx.workspaceRegistry so it never appears in the sidebar
8
+ * history list while remaining fully usable. The plugin never calls
9
+ * sessions.open - archiving the selected session would clear the user's
10
+ * current selection - and drives turns purely through agent.followup().
11
+ *
12
+ * Session events are projected into a small lossless-enough StudioChatEvent
13
+ * feed (text turns, tool summaries, generated-image references) and served to
14
+ * the browser through CHAT_ROUTE. The browser pulls increments with
15
+ * ?since=<seq>; images land on the tldraw canvas from the browser side via
16
+ * the existing IMAGE_ROUTE + landing-queue path.
17
+ */
18
+ import type { IncomingMessage, ServerResponse } from 'node:http';
19
+ import type { Context } from '@deepseek-ai/cordis';
20
+ import { type StudioChatEvent } from './shared.js';
21
+ /** Wire responses for CHAT_ROUTE. */
22
+ export interface StudioChatStateResponse {
23
+ ok: true;
24
+ latestSeq: number;
25
+ events: StudioChatEvent[];
26
+ /** Why the backing agent is missing, when creation failed; absent otherwise. */
27
+ unavailable?: string;
28
+ }
29
+ export interface StudioChatSendResponse {
30
+ ok: true;
31
+ }
32
+ export interface StudioChatErrorResponse {
33
+ error: string;
34
+ }
35
+ export interface StudioChatDeps {
36
+ maxBodyBytes: number;
37
+ }
38
+ /**
39
+ * Install the studio chat: ensure the dedicated agent session, subscribe to
40
+ * its events, and return the CHAT_ROUTE handler plus a disposer. Creation
41
+ * failures never break the plugin load - the route reports the error and the
42
+ * panel shows it, so a host without agent services degrades visibly instead
43
+ * of fatally.
44
+ */
45
+ export declare function createStudioChat(ctx: Context, deps: StudioChatDeps): {
46
+ serve: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
47
+ dispose(): void;
48
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-image-gen",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Bring ChatGPT-like image generation to DeepSeek Harness — Gemini, OpenAI, Seedream, DashScope, local ComfyUI & more.",
5
5
  "type": "module",
6
6
  "author": "shanliuling",
@@ -49,6 +49,7 @@
49
49
  "@deepseek-ai/dsh-client-ui-conversation",
50
50
  "@deepseek-ai/dsh-client-ui-settings",
51
51
  "@deepseek-ai/dsh-client-ui-settings-plugins",
52
+ "@deepseek-ai/dsh-client-ui-sidebar-right",
52
53
  "@deepseek-ai/dsh-client-ui-tool",
53
54
  "@deepseek-ai/dsh-client-locale"
54
55
  ],
@@ -99,30 +100,36 @@
99
100
  },
100
101
  "devDependencies": {
101
102
  "@deepseek-ai/cordis": "4.0.1",
102
- "@deepseek-ai/dsh-api-remotes": "0.1.1-rc.2",
103
- "@deepseek-ai/dsh-attachment": "0.1.1-rc.2",
104
- "@deepseek-ai/dsh-client-connection": "0.1.1-rc.2",
105
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.1-rc.2",
106
- "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
107
- "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.1-rc.2",
108
- "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
109
- "@deepseek-ai/dsh-client-ui-tool": "0.1.1-rc.2",
110
- "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
111
- "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
112
- "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
113
- "@deepseek-ai/dsh-settings": "0.1.2-alpha.2",
114
- "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
103
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.1",
104
+ "@deepseek-ai/dsh-api-remotes": "0.1.5-rc.1",
105
+ "@deepseek-ai/dsh-attachment": "0.1.5-rc.1",
106
+ "@deepseek-ai/dsh-client-connection": "0.1.5-rc.1",
107
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.1",
108
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
109
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.5-rc.1",
110
+ "@deepseek-ai/dsh-client-ui-sidebar-right": "0.1.5-rc.1",
111
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
112
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.5-rc.1",
113
+ "@deepseek-ai/dsh-credentials": "0.1.5-rc.1",
114
+ "@deepseek-ai/dsh-host-webserver": "0.1.5-rc.1",
115
+ "@deepseek-ai/dsh-llm": "0.1.5-rc.1",
116
+ "@deepseek-ai/dsh-session": "0.1.5-rc.1",
117
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
118
+ "@deepseek-ai/dsh-tools": "0.1.5-rc.1",
119
+ "@deepseek-ai/dsh-workspace": "0.1.5-rc.1",
115
120
  "@deepseek-ai/schemastery": "3.18.1",
116
121
  "@types/node": "^22.20.0",
117
122
  "@types/react": "~18.3.1",
118
123
  "react": "^18.2.0",
124
+ "react-dom": "18.3.1",
119
125
  "tsdown": "^0.22.2",
120
126
  "typescript": "^6.0.3",
121
127
  "unrun": "^0.3.1",
122
128
  "vitest": "^4.1.8"
123
129
  },
124
130
  "dependencies": {
125
- "lucide-react": "^1.38.0"
131
+ "lucide-react": "^1.38.0",
132
+ "tldraw": "5.3.0"
126
133
  },
127
134
  "scripts": {
128
135
  "typecheck": "tsc --noEmit",
@@ -1,22 +1,22 @@
1
- ---
2
- name: install-dsh-image-gen
3
- description: Install, configure, verify, or remove the dsh-image-gen Bundle in a DeepSeek Harness Web profile. Use when a user wants Google, OpenAI-compatible relay, Seedream, DashScope, or local ComfyUI image generation in DSH, cannot find the Image generation settings card, or needs help testing generate_image.
4
- ---
5
-
6
- # Install DSH Image Gen
7
-
8
- 1. Confirm `dsh` runs and record `dsh --version`.
9
- 2. Ask which Web profile to change if the user did not name one. Default to `web` only when that profile already exists.
10
- 3. Install the pinned package or repository spec the user provides:
11
-
12
- ```sh
13
- dsh plugin --profile <profile> add <package-or-git-spec>
14
- ```
15
-
16
- 4. If pnpm blocks the Git dependency's `prepare` script, explain that the allowance executes repository code during installation. Add only the exact package key pnpm reports to the profile's `pnpm-workspace.yaml`, then retry after the user approves.
17
- 5. Verify `dsh --profile <profile> --dump-config` contains the `dsh-image-gen` layer and `image-gen` row.
18
- 6. Start the profile. If port 3080 is already in use, identify the existing DSH process before stopping anything.
19
- 7. In Settings > Plugins > Plugin configuration > Image generation, select a cloud Provider and save its API key, or select Local ComfyUI, enter its URL, and import a ComfyUI API Format workflow JSON containing `{{prompt}}`. Never print, read back, or commit a key.
20
- 8. Test with “生成一张戴墨镜的赛博朋克猫图片”. Confirm one `generate_image` call succeeds and its image renders in the conversation.
21
-
22
- For removal, run `dsh plugin --profile <profile> remove dsh-image-gen`. Do not delete the user's credentials unless they explicitly request it.
1
+ ---
2
+ name: install-dsh-image-gen
3
+ description: Install, configure, verify, or remove the dsh-image-gen Bundle in a DeepSeek Harness Web profile. Use when a user wants Google, OpenAI-compatible relay, Seedream, DashScope, or local ComfyUI image generation in DSH, cannot find the Image generation settings card, or needs help testing generate_image.
4
+ ---
5
+
6
+ # Install DSH Image Gen
7
+
8
+ 1. Confirm `dsh` runs and record `dsh --version`.
9
+ 2. Ask which Web profile to change if the user did not name one. Default to `web` only when that profile already exists.
10
+ 3. Install the pinned package or repository spec the user provides:
11
+
12
+ ```sh
13
+ dsh plugin --profile <profile> add <package-or-git-spec>
14
+ ```
15
+
16
+ 4. If pnpm blocks the Git dependency's `prepare` script, explain that the allowance executes repository code during installation. Add only the exact package key pnpm reports to the profile's `pnpm-workspace.yaml`, then retry after the user approves.
17
+ 5. Verify `dsh --profile <profile> --dump-config` contains the `dsh-image-gen` layer and `image-gen` row.
18
+ 6. Start the profile. If port 3080 is already in use, identify the existing DSH process before stopping anything.
19
+ 7. In Settings > Plugins > Plugin configuration > Image generation, select a cloud Provider and save its API key, or select Local ComfyUI, enter its URL, and import a ComfyUI API Format workflow JSON containing `{{prompt}}`. Never print, read back, or commit a key.
20
+ 8. Test with “生成一张戴墨镜的赛博朋克猫图片”. Confirm one `generate_image` call succeeds and its image renders in the conversation.
21
+
22
+ For removal, run `dsh plugin --profile <profile> remove dsh-image-gen`. Do not delete the user's credentials unless they explicitly request it.
@@ -1,10 +0,0 @@
1
- import type { InspirationCasesResponse } from '../inspiration/types.js';
2
- export declare function getInspirationImageUrl(sourceId: string, caseId: string): string;
3
- export declare function fetchInspirationCases(): Promise<InspirationCasesResponse | null>;
4
- export interface UpdateResponse {
5
- updated: boolean;
6
- currentCount: number;
7
- newCount?: number;
8
- message: string;
9
- }
10
- export declare function triggerInspirationUpdate(): Promise<UpdateResponse | null>;
@@ -1,14 +0,0 @@
1
- /**
2
- * Modal detail view for a specific Inspiration Library case.
3
- */
4
- import { type FC } from 'react';
5
- import type { PromptCase, PromptSource } from '../inspiration/types.js';
6
- export interface InspirationDetailProps {
7
- promptCase: PromptCase;
8
- source: PromptSource;
9
- lang?: 'zh' | 'en';
10
- onClose: () => void;
11
- onUsePrompt: (prompt: string) => void;
12
- onToast: (msg: string) => void;
13
- }
14
- export declare const InspirationDetail: FC<InspirationDetailProps>;
@@ -1,20 +0,0 @@
1
- export declare const DEFAULT_MAX_CACHE_BYTES: number;
2
- export declare function setInspirationCacheDir(dir: string): void;
3
- export declare function getInspirationCacheDir(): string;
4
- export declare function cacheKey(sourceId: string, caseId: string): string;
5
- export interface CachedImageMetadata {
6
- contentType: string;
7
- sourceId: string;
8
- caseId: string;
9
- savedAt: number;
10
- }
11
- export declare function getCachedImagePath(key: string): string | null;
12
- export declare function readCachedImage(key: string): {
13
- data: Buffer;
14
- contentType: string;
15
- } | null;
16
- export declare function writeCachedImage(key: string, data: Buffer, contentType: string, sourceId: string, caseId: string, maxBytes?: number): void;
17
- /**
18
- * Enforce max cache size constraint by evicting oldest accessed files.
19
- */
20
- export declare function evictCacheIfNeeded(maxBytes?: number): void;
@@ -1,27 +0,0 @@
1
- import type { PromptCase, PromptSource } from './types.js';
2
- export declare const MAX_IMAGE_BYTES: number;
3
- export declare const FETCH_TIMEOUT_MS = 6000;
4
- /**
5
- * Validate that an IP or hostname is not private/loopback (SSRF protection).
6
- */
7
- export declare function isPrivateOrLocalAddress(hostname: string): boolean;
8
- /**
9
- * Check binary magic bytes to verify genuine image type.
10
- * Rejects SVGs, HTML, scripts, executables.
11
- */
12
- export declare function sniffImageMimeType(buf: Buffer): 'image/jpeg' | 'image/png' | 'image/webp' | null;
13
- /**
14
- * Safely fetch a single URL with strict checks.
15
- */
16
- export declare function fetchSingleImageUrl(urlStr: string, allowedDomains: string[]): Promise<{
17
- data: Buffer;
18
- contentType: string;
19
- } | null>;
20
- /**
21
- * Multi-tier racing / fallback fetcher:
22
- * Tries candidate URLs in order until a valid image is retrieved.
23
- */
24
- export declare function fetchInspirationImage(source: PromptSource, promptCase: PromptCase): Promise<{
25
- data: Buffer;
26
- contentType: string;
27
- } | null>;
@@ -1,13 +0,0 @@
1
- /**
2
- * Server-side route handlers for the Inspiration Library.
3
- */
4
- import type { IncomingMessage, ServerResponse } from 'node:http';
5
- export declare function serveInspirationCases(_req: IncomingMessage, res: ServerResponse): Promise<void>;
6
- /**
7
- * Handle GET /plugins/dsh-image-gen/inspiration/image/:sourceId/:caseId
8
- */
9
- export declare function serveInspirationImage(req: IncomingMessage, res: ServerResponse): Promise<void>;
10
- /**
11
- * Handle POST /plugins/dsh-image-gen/inspiration/update
12
- */
13
- export declare function serveInspirationUpdate(req: IncomingMessage, res: ServerResponse): Promise<void>;
@@ -1,33 +0,0 @@
1
- import type { PromptCase, PromptSource } from './types.js';
2
- /**
3
- * Find the path to the inspiration snapshots folder.
4
- * Supports both development (src/) and built distribution (root / lib).
5
- */
6
- export declare function getSnapshotsDir(): string;
7
- /**
8
- * Load built-in prompt sources from packaged JSON snapshots.
9
- */
10
- export declare function loadBuiltinSources(): PromptSource[];
11
- /**
12
- * Clear cached sources to allow reloading upon update.
13
- */
14
- export declare function invalidateSourcesCache(): void;
15
- /**
16
- * Get a specific prompt source by ID.
17
- */
18
- export declare function getPromptSource(sourceId: string): PromptSource | undefined;
19
- /**
20
- * Find a specific case within a source.
21
- */
22
- export declare function getPromptCase(sourceId: string, caseId: string): {
23
- source: PromptSource;
24
- promptCase: PromptCase;
25
- } | undefined;
26
- /**
27
- * Resolve candidate URLs for downloading an inspiration case's image.
28
- * Uses a prioritized multi-tier fallback:
29
- * 1. Fast, reliable global CDN (fastly.jsdelivr.net) - free, doesn't load author's server
30
- * 2. Canghe.ai official website static origin (fast in mainland China)
31
- * 3. GitHub raw official fallback
32
- */
33
- export declare function resolveCaseImageCandidateUrls(source: PromptSource, promptCase: PromptCase): string[];
@@ -1,65 +0,0 @@
1
- /**
2
- * Type definitions and contracts for the Prompt Library / Inspiration system.
3
- */
4
- export interface PromptCase {
5
- /** Unique case ID within the source (e.g. "544" or "case-544") */
6
- id: string;
7
- /** Human-readable title */
8
- title: string;
9
- /** The full prompt text to be reused */
10
- prompt: string;
11
- /** Image identifier or path (e.g. "/images/case544.jpg" or "case544.jpg") */
12
- image?: string | undefined;
13
- /** Primary category (e.g. "UI & Interfaces", "Products & E-commerce") */
14
- category?: string | undefined;
15
- /** Visual styles (e.g. ["UI", "Poster", "Realistic"]) */
16
- styles?: string[] | undefined;
17
- /** Application scenarios (e.g. ["Tech", "Commerce"]) */
18
- scenes?: string[] | undefined;
19
- /** Original creator or source platform display name */
20
- sourceLabel?: string | undefined;
21
- /** Link to original social post or source article */
22
- sourceUrl?: string | undefined;
23
- /** Original author name if known */
24
- author?: string | undefined;
25
- /** Author homepage or profile */
26
- authorUrl?: string | undefined;
27
- /** License name if explicitly declared */
28
- license?: string | undefined;
29
- /** License URL if explicitly declared */
30
- licenseUrl?: string | undefined;
31
- /** Recommended model hint if available */
32
- modelHint?: string | undefined;
33
- /** Whether the case is marked as featured / staff pick */
34
- featured?: boolean | undefined;
35
- /** Direct link back to upstream repository documentation */
36
- githubUrl?: string | undefined;
37
- }
38
- export interface PromptSource {
39
- id: string;
40
- name: string;
41
- homepage?: string | undefined;
42
- version: string;
43
- schemaVersion: number;
44
- /** Domain whitelist allowed for fetching images for this source */
45
- allowedDomains: string[];
46
- /** Array of prompt cases */
47
- cases: PromptCase[];
48
- /** Available categories extracted from cases */
49
- categories?: string[] | undefined;
50
- /** Available styles extracted from cases */
51
- styles?: string[] | undefined;
52
- /** Available scenes extracted from cases */
53
- scenes?: string[] | undefined;
54
- }
55
- export interface InspirationManifest {
56
- schemaVersion: number;
57
- sourceVersion: string;
58
- updatedAt: string;
59
- sha256: string;
60
- totalCases: number;
61
- }
62
- export interface InspirationCasesResponse {
63
- sources: PromptSource[];
64
- activeSourceId: string;
65
- }
@@ -1,7 +0,0 @@
1
- export interface UpdateCheckResult {
2
- updated: boolean;
3
- currentCount: number;
4
- newCount?: number;
5
- message: string;
6
- }
7
- export declare function checkAndApplyInspirationUpdate(): Promise<UpdateCheckResult>;