dsh-image-gen 0.6.7 → 0.6.8

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 (40) hide show
  1. package/README.en.md +387 -375
  2. package/README.md +387 -375
  3. package/README.zh-CN.md +3 -3
  4. package/docs/assets/readme/chat-generate.webp +0 -0
  5. package/docs/assets/readme/other-features.webp +0 -0
  6. package/lib/client.js +146 -37
  7. package/lib/client.js.map +1 -1
  8. package/lib/index.js +200 -37
  9. package/lib/types/client/conversation-image-revisions.d.ts +2 -2
  10. package/lib/types/client/gallery-view.d.ts +4 -0
  11. package/lib/types/client/multi-model-compare.d.ts +3 -3
  12. package/lib/types/client/provider-pill.d.ts +1 -1
  13. package/lib/types/client/studio-chat-panel.d.ts +23 -0
  14. package/lib/types/client/studio-view.d.ts +4 -0
  15. package/lib/types/client/tl/diagram-landing.d.ts +75 -0
  16. package/lib/types/client/tl/diagram-layout.d.ts +76 -0
  17. package/lib/types/client/tl/diagram-measure.d.ts +40 -0
  18. package/lib/types/diagram.d.ts +42 -0
  19. package/lib/types/shared.d.ts +16 -4
  20. package/lib/types/studio-chat.d.ts +48 -0
  21. package/lib/types/studio.d.ts +3 -2
  22. package/lib/types/subscription/manager.d.ts +15 -0
  23. package/lib/types/subscription/vendors/antigravity.d.ts +10 -1
  24. package/lib/types/subscription/vendors/codex.d.ts +2 -0
  25. package/lib/types/subscription/vendors/grok.d.ts +2 -0
  26. package/lib/types/subscription.d.ts +7 -5
  27. package/package.json +10 -8
  28. package/skills/install-dsh-image-gen/SKILL.md +22 -22
  29. package/lib/types/client/inspiration-api.d.ts +0 -10
  30. package/lib/types/client/inspiration-detail.d.ts +0 -14
  31. package/lib/types/client/tldraw/generated/tldraw-assets.d.ts +0 -12
  32. package/lib/types/client/tldraw/generated/tldraw-css.d.ts +0 -1
  33. package/lib/types/client/tldraw/tldraw-style.d.ts +0 -1
  34. package/lib/types/client/tldraw/tldraw-workspace.d.ts +0 -1
  35. package/lib/types/inspiration/cache.d.ts +0 -20
  36. package/lib/types/inspiration/downloader.d.ts +0 -27
  37. package/lib/types/inspiration/routes.d.ts +0 -13
  38. package/lib/types/inspiration/sources.d.ts +0 -33
  39. package/lib/types/inspiration/types.d.ts +0 -65
  40. package/lib/types/inspiration/updater.d.ts +0 -7
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Land one create_diagram result onto a tldraw page.
3
+ *
4
+ * Shapes and their arrow bindings are created in a single editor.run
5
+ * transaction, and a history stopping point is marked BEFORE the batch:
6
+ * tldraw's HistoryManager pops diffs until the next stop mark on undo, so
7
+ * without the mark two diagrams landing back-to-back would undo together.
8
+ * With it, each diagram is one independent undo step (undo/redo verified
9
+ * against the HistoryManager source and on the real canvas).
10
+ *
11
+ * Arrows are ELBOW connectors with BOTH terminals bound. Each terminal's
12
+ * binding side is derived from dagre's polyline: the first/last segment's
13
+ * dominant axis says which node edge the route uses (back edges leave the
14
+ * source's top and re-enter the target's bottom through the corridor dagre
15
+ * reserved, instead of tldraw guessing a center-to-center route). tldraw
16
+ * then re-routes the middle segments itself from the bindings — the
17
+ * polyline is a per-terminal side hint, not a full path contract. Whether
18
+ * the final arrows avoid crossing nodes and whether labels sit clear of
19
+ * geometry is validated on the real canvas, not assumed here.
20
+ *
21
+ * Derived anchors are clamped to the middle band (0.2–0.8) of their edge:
22
+ * tldraw's getEdgeFromNormalizedAnchor resolves the side via |x-0.5| vs
23
+ * |y-0.5|, and a corner-ish anchor could resolve to the wrong side.
24
+ *
25
+ * Edge labels set labelPosition from dagre's arc-length ratio — a
26
+ * best-effort estimate, since tldraw applies the ratio to its own routed
27
+ * path.
28
+ *
29
+ * Self loops (empty dagre polyline) fall back to center bindings: tldraw
30
+ * draws bound self-loop arrows natively.
31
+ *
32
+ * Every created shape carries meta.diagramId, the same dedupe identity the
33
+ * landing reconcile uses for images' meta.galleryId.
34
+ */
35
+ import { type Editor } from 'tldraw';
36
+ import { type DiagramLayout, type DiagramLayoutEdge, type DiagramLayoutNode, type DiagramPoint } from './diagram-layout.js';
37
+ import type { TlDiagramLanding } from './tl-canvas-bridge.js';
38
+ /** Terminal binding plan: the precise anchor, or a center fallback. */
39
+ export interface TerminalPlan {
40
+ anchor: {
41
+ x: number;
42
+ y: number;
43
+ };
44
+ precise: boolean;
45
+ }
46
+ /**
47
+ * Derive one terminal's binding side + precise anchor from dagre's
48
+ * polyline. The boundary point sits ON the node outline (dagre guarantees
49
+ * this via its node-intersection pass), so the binding side is the OUTLINE
50
+ * EDGE CLOSEST TO THE BOUNDARY POINT — not the segment direction. The last
51
+ * segment often enters at an angle because dagre projects the corridor
52
+ * point onto the outline (e.g. a back edge entering the target's bottom
53
+ * with a final dx=57, dy=-48 segment), and direction-dominance would
54
+ * misread that as `right`. The segment direction is only used to break
55
+ * exact corner ties. The boundary point gives the cross-axis position,
56
+ * clamped to the anchor band.
57
+ */
58
+ export declare function terminalPlan(node: Pick<DiagramLayoutNode, 'x' | 'y' | 'w' | 'h'>, boundary: DiagramPoint, next: DiagramPoint): TerminalPlan;
59
+ /**
60
+ * Binding plans for one edge's two terminals. Self loops (no dagre
61
+ * polyline) get center plans: tldraw renders bound self loops natively.
62
+ */
63
+ export declare function edgeTerminalPlans(edge: DiagramLayoutEdge, fromNode: DiagramLayoutNode, toNode: DiagramLayoutNode): {
64
+ start: TerminalPlan;
65
+ end: TerminalPlan;
66
+ };
67
+ /**
68
+ * Land one diagram with its top-left at `origin`. The caller passes the
69
+ * precomputed layout (it needs the layout bounds to pick the origin, so the
70
+ * layout is computed once and shared). No-op on empty layouts.
71
+ */
72
+ export declare function landDiagram(editor: Editor, landing: TlDiagramLanding, layout: DiagramLayout, origin: {
73
+ x: number;
74
+ y: number;
75
+ }): void;
@@ -0,0 +1,76 @@
1
+ import type { DiagramNodeShape, DiagramSpec } from '../../shared.js';
2
+ /** One laid-out node: local id, label, outline, top-left position, size. */
3
+ export interface DiagramLayoutNode {
4
+ id: string;
5
+ label: string;
6
+ shape: DiagramNodeShape;
7
+ x: number;
8
+ y: number;
9
+ w: number;
10
+ h: number;
11
+ }
12
+ /** A point in graph space (same origin as the layout nodes). */
13
+ export interface DiagramPoint {
14
+ x: number;
15
+ y: number;
16
+ }
17
+ /** One laid-out edge between node local ids, with dagre's routing hint. */
18
+ export interface DiagramLayoutEdge {
19
+ from: string;
20
+ to: string;
21
+ label?: string;
22
+ /**
23
+ * dagre's polyline in graph space. points[0] lies on the source node's
24
+ * outline and points[last] on the target's. Self loops carry an empty
25
+ * array: dagre cannot route them, and the landing layer falls back to
26
+ * center bindings (tldraw draws bound self loops natively).
27
+ */
28
+ points: DiagramPoint[];
29
+ /**
30
+ * Where the label sits along the polyline, as an arc-length ratio in
31
+ * [0, 1] (tldraw's arrow labelPosition shares the ratio semantics). This
32
+ * is a best-effort initial estimate: tldraw applies the ratio to its own
33
+ * routed path, which may differ from dagre's polyline in the middle
34
+ * segments. The final label position is validated on the real canvas.
35
+ */
36
+ labelPosition?: number;
37
+ }
38
+ export interface DiagramLayout {
39
+ nodes: DiagramLayoutNode[];
40
+ edges: DiagramLayoutEdge[];
41
+ width: number;
42
+ height: number;
43
+ /** Growth direction of the layout, needed by the landing layer to pick
44
+ * binding anchors (TB connects bottom→top edges, LR right→left edges). */
45
+ direction: 'TB' | 'LR';
46
+ }
47
+ /** Node size in canvas units (top-left anchored, like tldraw shape props). */
48
+ export interface DiagramSize {
49
+ w: number;
50
+ h: number;
51
+ }
52
+ /** Measured sizes fed into the pure layout function. */
53
+ export interface DiagramMeasurements {
54
+ /** node id → measured node size. Missing entries fall back to the default. */
55
+ nodes: ReadonlyMap<string, DiagramSize>;
56
+ /**
57
+ * edge list index → measured label size. Only edges carrying a label are
58
+ * present; dagre reserves rank space for these labels.
59
+ */
60
+ edgeLabels?: ReadonlyMap<number, DiagramSize>;
61
+ }
62
+ /** Fallback size for nodes the caller did not measure (defensive only). */
63
+ export declare const DEFAULT_NODE_SIZE: DiagramSize;
64
+ /**
65
+ * Where a point sits along a polyline, as an arc-length ratio in [0, 1].
66
+ * The point is projected onto the nearest polyline segment. Degenerate
67
+ * polylines return 0.5.
68
+ */
69
+ export declare function arcRatioAlongPolyline(points: readonly DiagramPoint[], target: DiagramPoint): number;
70
+ /**
71
+ * Lay out a diagram spec with coordinates relative to (0, 0). The layout is
72
+ * deterministic: same spec + same measurements always produce the same
73
+ * coordinates (dagre is seeded by insertion order, which we keep stable by
74
+ * iterating the spec's arrays as given).
75
+ */
76
+ export declare function layoutDiagram(diagram: DiagramSpec, measurements: DiagramMeasurements): DiagramLayout;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Measure diagram node/edge-label sizes with tldraw's own DOM text measuring.
3
+ *
4
+ * This is the "real" half of the measurement/layout split: the editor's
5
+ * TextManager renders text with the same font family, size, line height and
6
+ * wrap width the landed geo shapes will use, so RECTANGLE node sizes track
7
+ * the rendered label 1:1 (no character-width heuristics).
8
+ *
9
+ * The measure parameters mirror tldraw's internal geo-shape constants for
10
+ * our landed shapes (font 'sans', size 'm'): theme.fontSize * 1.375,
11
+ * theme.lineHeight, label padding 16.
12
+ *
13
+ * Non-rectangular outlines are APPROXIMATE, not 1:1. tldraw re-wraps the
14
+ * label against the SHAPE's width (shape w - padding), and we size the
15
+ * shape from the text measured at the pre-inflation wrap width — so after
16
+ * inflation the label re-wraps into fewer, wider lines. For short labels
17
+ * (single line at the wrap width) the geometry below is exact. For long
18
+ * wrapped labels the re-wrapped block can grow past the outline's inscribed
19
+ * rectangle and crowd the diamond's slanted edges / the ellipse's arc:
20
+ * greedy text wrapping scales with shape width while the inscribed rectangle
21
+ * only halves it, so there is no closed-form fix. The create_diagram tool
22
+ * prompt steers long text to rectangles and keeps diamond labels short;
23
+ * whether a real label fits is ultimately a visual check on the real canvas
24
+ * (see the diagram-verify harness), not something this module can promise.
25
+ * - diamond: a single-line text rect (tw, th) fits exactly when
26
+ * tw/w + th/h <= 1, so doubling the text size (+ padding) is exact for
27
+ * unwrapped labels.
28
+ * - ellipse: a single-line corner point fits exactly when
29
+ * tw²/w² + th²/h² <= 1, so a √2 factor (+ padding) is exact for
30
+ * unwrapped labels.
31
+ */
32
+ import type { Editor } from 'tldraw';
33
+ import type { DiagramSpec } from '../../shared.js';
34
+ import type { DiagramMeasurements } from './diagram-layout.js';
35
+ /**
36
+ * Measure every node and edge label of a spec against the editor's live
37
+ * theme and fonts. Node sizes carry the outline inflation for diamond and
38
+ * ellipse; edge-label sizes let dagre reserve rank space for labels.
39
+ */
40
+ export declare function measureDiagram(editor: Editor, diagram: DiagramSpec): DiagramMeasurements;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * create_diagram: a structure-only tool whose results land on the workbench
3
+ * infinite canvas.
4
+ *
5
+ * The model outputs a declarative DSL (nodes + edges with local ids, never
6
+ * coordinates). The tool call succeeds immediately — exactly like image
7
+ * generation — and the diagram rides the same landing bus: an open canvas
8
+ * renders it at once, a closed one renders it the moment it opens. The canvas
9
+ * computes the layered layout, creates geo shapes, and binds every arrow to
10
+ * its endpoints so the user can drag nodes around with arrows following.
11
+ */
12
+ import type { Context } from '@deepseek-ai/cordis';
13
+ import { type DiagramDirection, type DiagramEdgeSpec, type DiagramNodeSpec } from './shared.js';
14
+ /** Value returned by create_diagram and echoed into the tool-result schema. */
15
+ export interface CreateDiagramValue {
16
+ diagramId: string;
17
+ title: string;
18
+ direction: DiagramDirection;
19
+ nodeCount: number;
20
+ edgeCount: number;
21
+ }
22
+ /** Untrusted create_diagram arguments as they arrive from the model. */
23
+ export interface CreateDiagramArgs {
24
+ title?: unknown;
25
+ direction?: unknown;
26
+ nodes?: unknown;
27
+ edges?: unknown;
28
+ }
29
+ /** Register the create_diagram tool on a host context. */
30
+ export declare function registerDiagramTool(ctx: Context): void;
31
+ /**
32
+ * Validate untrusted create_diagram arguments into a DiagramSpec. Returns
33
+ * undefined for anything structurally unusable (no nodes, duplicate ids,
34
+ * edges pointing at unknown nodes, over the caps) — the tool then fails with
35
+ * an actionable message and the model can retry with a corrected diagram.
36
+ */
37
+ export declare function diagramSpecFromArgs(args: CreateDiagramArgs): {
38
+ title?: string;
39
+ direction?: DiagramDirection;
40
+ nodes: DiagramNodeSpec[];
41
+ edges: DiagramEdgeSpec[];
42
+ } | undefined;
@@ -117,6 +117,18 @@ export declare function isSubscriptionProvider(provider: ImageProvider): provide
117
117
  /** Providers supported by the first browser workbench release. */
118
118
  export declare const CLOUD_IMAGE_PROVIDERS: readonly ["google", "openai", "openai-compat", "seedream", "dashscope", "xai", "zhipu"];
119
119
  export type CloudImageProvider = typeof CLOUD_IMAGE_PROVIDERS[number];
120
+ /**
121
+ * Providers the browser workbench can drive: the BYOK cloud set plus the
122
+ * logged-in subscription channels. ComfyUI stays out; it has its own workflow
123
+ * pipeline and no shared request shape.
124
+ */
125
+ export declare const STUDIO_PROVIDERS: readonly ["google", "openai", "openai-compat", "seedream", "dashscope", "xai", "zhipu", "chatgpt-sub", "grok-sub", "google-sub"];
126
+ export type StudioProvider = CloudImageProvider | SubscriptionProvider;
127
+ /** True when the provider is selectable in the browser workbench. */
128
+ export declare function isStudioProvider(provider: ImageProvider): provider is StudioProvider;
129
+ /** Timeout for one subscription image call, shared by the tool path and the
130
+ * studio route so neither drifts from the other. */
131
+ export declare const SUBSCRIPTION_TIMEOUT_MS = 300000;
120
132
  /**
121
133
  * Credential references resolved through the DSH Credentials service (BYOK).
122
134
  * These are POSIX-style reference names, not environment variables: the host
@@ -155,7 +167,7 @@ export interface StudioOption {
155
167
  }
156
168
  /** Browser-safe provider description. Credentials and endpoints never cross this boundary. */
157
169
  export interface StudioProviderProfile {
158
- provider: CloudImageProvider;
170
+ provider: StudioProvider;
159
171
  label: string;
160
172
  model: string;
161
173
  configured: boolean;
@@ -175,7 +187,7 @@ export interface StudioWorkspaceInfo {
175
187
  /** Read model and capability state for the workbench without exposing secrets. */
176
188
  export interface StudioConfigResponse {
177
189
  providers: StudioProviderProfile[];
178
- activeProvider: CloudImageProvider;
190
+ activeProvider: StudioProvider;
179
191
  workspaceRoot?: string | undefined;
180
192
  workspaces?: StudioWorkspaceInfo[] | undefined;
181
193
  }
@@ -193,7 +205,7 @@ export type StudioReference = StudioEncodedReference | StudioAttachmentReference
193
205
  /** One browser workbench generation or editing request. */
194
206
  export interface StudioGenerateRequest {
195
207
  mode: 'generate' | 'edit';
196
- provider: CloudImageProvider;
208
+ provider: StudioProvider;
197
209
  model: string;
198
210
  prompt: string;
199
211
  ratio: string;
@@ -211,7 +223,7 @@ export interface StudioGeneratedItem {
211
223
  }
212
224
  /** One completed workbench request. */
213
225
  export interface StudioGenerateResponse extends StudioGeneratedItem {
214
- provider: CloudImageProvider;
226
+ provider: StudioProvider;
215
227
  model: string;
216
228
  prompt: string;
217
229
  createdAt: number;
@@ -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
+ };
@@ -1,9 +1,10 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import { type Config } from './config.js';
3
+ import { type SubscriptionManager } from './subscription.js';
3
4
  import { type CloudImageProvider, type StudioConfigResponse, type StudioGenerateRequest, type StudioGenerateResponse, type StudioProviderProfile } from './shared.js';
4
5
  /** Return only browser-safe capability data. */
5
- export declare function describeStudio(ctx: Context, config: Config): Promise<StudioConfigResponse>;
6
+ export declare function describeStudio(ctx: Context, config: Config, subscriptions?: SubscriptionManager | undefined): Promise<StudioConfigResponse>;
6
7
  /** Execute one validated browser workbench request using the existing provider adapters. */
7
- export declare function generateFromStudio(ctx: Context, config: Config, input: StudioGenerateRequest, signal: AbortSignal, fallbackWorkspaceRoot?: string | undefined): Promise<StudioGenerateResponse>;
8
+ export declare function generateFromStudio(ctx: Context, config: Config, input: StudioGenerateRequest, signal: AbortSignal, fallbackWorkspaceRoot?: string | undefined, subscriptions?: SubscriptionManager | undefined): Promise<StudioGenerateResponse>;
8
9
  export declare function runPool<T>(tasks: Array<() => Promise<T>>, concurrency?: number): Promise<PromiseSettledResult<T>[]>;
9
10
  export declare function studioProfile(config: Config, provider: CloudImageProvider, configured: boolean): StudioProviderProfile;
@@ -21,12 +21,26 @@ import { type SubscriptionBlob } from './blob.js';
21
21
  import { type SubscriptionProvider } from '../shared.js';
22
22
  /** Vendor ids used by the credential refs and the wire calls. */
23
23
  export type SubscriptionVendor = 'codex' | 'grok' | 'antigravity';
24
+ /**
25
+ * Reference image passed to edit calls. Structural so callers can pass their
26
+ * own resolved types without importing from the plugin root.
27
+ */
28
+ export interface SubscriptionReferenceImage {
29
+ data: Uint8Array;
30
+ mediaType: string;
31
+ }
24
32
  /** The vendor each dsh-image-gen subscription provider maps onto. */
25
33
  export declare function vendorOf(provider: SubscriptionProvider): SubscriptionVendor;
26
34
  /** Credential ref one vendor's OAuth blob is stored under (index fixed at 1). */
27
35
  export declare function subscriptionOauthRef(vendor: SubscriptionVendor): CredentialRef;
28
36
  /** Sizes both vendors understand. */
29
37
  export declare const SUBSCRIPTION_SIZES: readonly ["1024x1024", "1024x1536", "1536x1024", "auto"];
38
+ /**
39
+ * Reference images per edit call. Every subscription channel accepts at
40
+ * least this many (Codex edits up to 16, Grok up to 5, Antigravity up to 10),
41
+ * so 5 keeps one shared guard in line with the Studio UI's upload cap.
42
+ */
43
+ export declare const SUBSCRIPTION_MAX_REFERENCE_IMAGES = 5;
30
44
  /** Login status the settings card renders as a badge. */
31
45
  export type SubscriptionLoginStatus = {
32
46
  state: 'logged-in';
@@ -80,6 +94,7 @@ export declare class SubscriptionManager {
80
94
  prompt: string;
81
95
  size?: string;
82
96
  quality?: string;
97
+ referenceImages?: ReadonlyArray<SubscriptionReferenceImage>;
83
98
  signal?: AbortSignal;
84
99
  }): Promise<Array<{
85
100
  b64_json: string;
@@ -37,12 +37,17 @@ export declare function antigravityResolveProject(blob: SubscriptionBlob): Promi
37
37
  * Build the streamGenerateContent request body for one image generation.
38
38
  * Ported from the reference buildImageRequest + the wrapping envelope: no
39
39
  * tools, no systemInstruction, no thinkingConfig; responseModalities asks
40
- * for TEXT+IMAGE.
40
+ * for TEXT+IMAGE. Reference images (edits) ride along as inlineData parts
41
+ * before the text part, mirroring the reference implementation.
41
42
  */
42
43
  export declare function antigravityImageBody(options: {
43
44
  prompt: string;
44
45
  aspectRatio?: string;
45
46
  hd?: boolean;
47
+ referenceImages?: ReadonlyArray<{
48
+ data: Uint8Array;
49
+ mediaType: string;
50
+ }>;
46
51
  }): Record<string, unknown>;
47
52
  /** Wrap the inner request in the Antigravity agent envelope. */
48
53
  export declare function antigravityEnvelope(projectId: string, request: Record<string, unknown>): Record<string, unknown>;
@@ -62,5 +67,9 @@ export declare function antigravityGenerateImage(options: {
62
67
  prompt: string;
63
68
  aspectRatio?: string;
64
69
  hd?: boolean;
70
+ referenceImages?: ReadonlyArray<{
71
+ data: Uint8Array;
72
+ mediaType: string;
73
+ }>;
65
74
  signal?: AbortSignal;
66
75
  }): Promise<AntigravityImageResult>;
@@ -12,6 +12,8 @@ export declare const CODEX_AUTH = "https://auth.openai.com/oauth/authorize";
12
12
  export declare const CODEX_TOKEN = "https://auth.openai.com/oauth/token";
13
13
  /** Where the ChatGPT subscription image request goes. */
14
14
  export declare const CODEX_IMAGE_URL = "https://chatgpt.com/backend-api/codex/images/generations";
15
+ /** Where the ChatGPT subscription image edit request goes. */
16
+ export declare const CODEX_IMAGE_EDIT_URL = "https://chatgpt.com/backend-api/codex/images/edits";
15
17
  /** The model served by this endpoint (probed live: gpt-image-2.5-flare works
16
18
  * on the ChatGPT internal generations route as of 2026-09-14). */
17
19
  export declare const CODEX_IMAGE_MODEL = "gpt-image-2.5-flare";
@@ -10,6 +10,8 @@ import { type Pkce } from '../oauth.js';
10
10
  import type { SubscriptionBlob } from '../blob.js';
11
11
  /** Where the Grok subscription image request goes. */
12
12
  export declare const GROK_IMAGE_URL = "https://api.x.ai/v1/images/generations";
13
+ /** Where the Grok subscription image edit request goes. */
14
+ export declare const GROK_IMAGE_EDIT_URL = "https://api.x.ai/v1/images/edits";
13
15
  /** The model served by this endpoint. */
14
16
  export declare const GROK_IMAGE_MODEL = "grok-imagine-image-2.0";
15
17
  /** Public client id of the grok-cli; vendor-fixed redirect on 127.0.0.1:56121. */
@@ -18,12 +18,12 @@ import { SubscriptionManager } from './subscription/manager.js';
18
18
  import { type SubscriptionProvider } from './shared.js';
19
19
  export { SubscriptionManager, vendorOf } from './subscription/manager.js';
20
20
  export { registerSubscriptionRoutes } from './subscription/subscription-route.js';
21
- /** Timeout for one subscription image call, mirroring the other adapters. */
22
- export declare const SUBSCRIPTION_TIMEOUT_MS = 300000;
21
+ export { SUBSCRIPTION_TIMEOUT_MS } from './shared.js';
23
22
  /**
24
23
  * Generate one image through a logged-in subscription account. Returns the
25
24
  * same `{ data, mediaType }` contract as the API-key adapters so the caller
26
- * can feed it straight into `saveGenerated`.
25
+ * can feed it straight into `saveGenerated`. With sourceImages the call is
26
+ * an edit: the vendor layer picks the channel's edit endpoint.
27
27
  */
28
28
  export declare function generateSubscriptionImage(options: {
29
29
  manager: SubscriptionManager;
@@ -31,6 +31,10 @@ export declare function generateSubscriptionImage(options: {
31
31
  prompt: string;
32
32
  size?: string;
33
33
  quality?: string;
34
+ sourceImages?: ReadonlyArray<{
35
+ data: Uint8Array;
36
+ mediaType: ImageMediaType;
37
+ }>;
34
38
  maxBytes: number;
35
39
  signal: AbortSignal;
36
40
  }): Promise<{
@@ -38,5 +42,3 @@ export declare function generateSubscriptionImage(options: {
38
42
  mediaType: ImageMediaType;
39
43
  revisedPrompt?: string;
40
44
  }>;
41
- /** Subscription channels are prompt-only today; edit_image is rejected outright. */
42
- export declare function assertSubscriptionEditUnsupported(provider: SubscriptionProvider): never;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-image-gen",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
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",
@@ -56,6 +56,13 @@
56
56
  "platform": "web"
57
57
  }
58
58
  },
59
+ "scripts": {
60
+ "typecheck": "tsc --noEmit",
61
+ "build": "tsc && tsdown",
62
+ "prepare": "pnpm run build",
63
+ "test": "vitest run",
64
+ "pack:check": "pnpm pack --dry-run"
65
+ },
59
66
  "engines": {
60
67
  "node": "^22.19.0 || >=24.0.0"
61
68
  },
@@ -127,14 +134,9 @@
127
134
  "unrun": "^0.3.1",
128
135
  "vitest": "^4.1.8"
129
136
  },
137
+ "packageManager": "pnpm@11.7.0",
130
138
  "dependencies": {
131
139
  "lucide-react": "^1.38.0",
132
140
  "tldraw": "5.3.0"
133
- },
134
- "scripts": {
135
- "typecheck": "tsc --noEmit",
136
- "build": "tsc && tsdown",
137
- "test": "vitest run",
138
- "pack:check": "pnpm pack --dry-run"
139
141
  }
140
- }
142
+ }
@@ -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,12 +0,0 @@
1
- export declare const TLDRAW_ASSET_URLS: {
2
- fonts: Record<string, string>;
3
- icons: Record<string, string>;
4
- translations: Record<string, string>;
5
- };
6
- export declare const TLDRAW_ASSETS_META: {
7
- version: string;
8
- fonts: number;
9
- icons: number;
10
- translations: number;
11
- generatedAt: string;
12
- };