@bubblydoo/photoshop-mcp 0.0.2

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 (88) hide show
  1. package/README.md +138 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +7049 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist-readmes/README.md +383 -0
  6. package/dist-runtime/runtime-code.cjs +17124 -0
  7. package/dist-runtime/runtime-code.d.cts +9 -0
  8. package/dist-schemas/@adobe-uxp-types/photoshop/src/index.d.ts +16 -0
  9. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/all-types.d.ts +65 -0
  10. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Actions.d.ts +230 -0
  11. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Channel.d.ts +120 -0
  12. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/ColorSampler.d.ts +105 -0
  13. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Constants.d.ts +1648 -0
  14. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/CoreModules.d.ts +922 -0
  15. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/CountItem.d.ts +86 -0
  16. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Document.d.ts +931 -0
  17. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Guide.d.ts +105 -0
  18. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/HistoryState.d.ts +74 -0
  19. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/ImagingModule.d.ts +559 -0
  20. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Layer.d.ts +1073 -0
  21. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/LayerComp.d.ts +219 -0
  22. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Objects.d.ts +7 -0
  23. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/PathItem.d.ts +243 -0
  24. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/PathPoint.d.ts +78 -0
  25. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Photoshop.d.ts +317 -0
  26. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/Selection.d.ts +557 -0
  27. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/SubPathItem.d.ts +69 -0
  28. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/TextItem.d.ts +213 -0
  29. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/Channels.d.ts +81 -0
  30. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/ColorSamplers.d.ts +97 -0
  31. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/CountItems.d.ts +130 -0
  32. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/Documents.d.ts +95 -0
  33. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/Guides.d.ts +76 -0
  34. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/HistoryStates.d.ts +56 -0
  35. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/LayerComps.d.ts +92 -0
  36. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/Layers.d.ts +68 -0
  37. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/PathItems.d.ts +65 -0
  38. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/PathPoints.d.ts +50 -0
  39. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/SubPathItems.d.ts +50 -0
  40. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/collections/TextFonts.d.ts +43 -0
  41. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/Colors.d.ts +225 -0
  42. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/ConversionOptions.d.ts +213 -0
  43. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/ImagingBounds.d.ts +53 -0
  44. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/PathPointInfo.d.ts +84 -0
  45. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/SaveOptions.d.ts +376 -0
  46. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/SolidColor.d.ts +118 -0
  47. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/SubPathInfo.d.ts +47 -0
  48. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/TextFont.d.ts +49 -0
  49. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/objects/Tool.d.ts +23 -0
  50. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/Preferences.d.ts +121 -0
  51. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesBase.d.ts +9 -0
  52. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesCursors.d.ts +37 -0
  53. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesFileHandling.d.ts +58 -0
  54. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesGeneral.d.ts +77 -0
  55. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesGuidesGridsAndSlices.d.ts +51 -0
  56. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesHistory.d.ts +69 -0
  57. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesInterface.d.ts +46 -0
  58. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesPerformance.d.ts +42 -0
  59. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesTools.d.ts +44 -0
  60. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesTransparencyAndGamut.d.ts +38 -0
  61. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesType.d.ts +44 -0
  62. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/preferences/PreferencesUnitsAndRulers.d.ts +44 -0
  63. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/text/CharacterStyle.d.ts +254 -0
  64. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/text/ParagraphStyle.d.ts +114 -0
  65. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/text/TextWarpStyle.d.ts +48 -0
  66. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/ApplyImageTypes.d.ts +107 -0
  67. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/CalculationsTypes.d.ts +119 -0
  68. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/DocumentTypes.d.ts +80 -0
  69. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/LayerCompTypes.d.ts +91 -0
  70. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/LayerTypes.d.ts +153 -0
  71. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/SharedTypes.d.ts +6 -0
  72. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/dom/types/TextTypes.d.ts +218 -0
  73. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/util/colorTypes.d.ts +61 -0
  74. package/dist-schemas/@adobe-uxp-types/photoshop/src/internal/util/unit.d.ts +45 -0
  75. package/dist-schemas/@adobe-uxp-types/uxp/src/index.d.ts +21 -0
  76. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/all-types.d.ts +3 -0
  77. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/dialog.d.ts +26 -0
  78. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/entrypoints.d.ts +385 -0
  79. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/host.d.ts +28 -0
  80. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/os.d.ts +56 -0
  81. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/other.d.ts +7 -0
  82. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/shell.d.ts +54 -0
  83. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/storage.d.ts +1216 -0
  84. package/dist-schemas/@adobe-uxp-types/uxp/src/internal/versions.d.ts +18 -0
  85. package/dist-schemas/@bubblydoo/uxp-toolkit/dist/commands-library/index.d.ts +109 -0
  86. package/dist-schemas/@bubblydoo/uxp-toolkit/dist/index.d.ts +153 -0
  87. package/dist-schemas/@bubblydoo/uxp-toolkit/dist/psLayerRef-BJKcxKbm.d.ts +66 -0
  88. package/package.json +51 -0
@@ -0,0 +1,383 @@
1
+ ![NPM Version](https://img.shields.io/npm/v/@bubblydoo/uxp-toolkit)
2
+
3
+ # UXP Toolkit
4
+
5
+ This is a toolkit for building UXP extensions for Adobe Photoshop. It has been created because the experience building extensions for Adobe Photoshop is pretty terrible: nothing works as expected and the documentation is lacking.
6
+
7
+ With the code in this repo, we fix a few things:
8
+ - A large amount of functions, including automated tests, for common actions in Photoshop, like interacting with layers and files.
9
+ - A way to interact with batchPlay in a typesafe way, with Zod schemas for the output.
10
+ - A unified way to represent layers in your code, without using document.layers (which gets very slow, see below)
11
+ - A testing framework for UXP, which you can also use for your own tests.
12
+ - Vitest integration for running unit tests without Photoshop, with CI/CD support.
13
+ - Typescript types for the `uxp` and `photoshop` modules.
14
+ - A fixed CLI for UXP.
15
+
16
+ ```bash
17
+ pnpm add @bubblydoo/uxp-toolkit
18
+ pnpm add -D @adobe-uxp-types/uxp @adobe-uxp-types/photoshop
19
+ ```
20
+
21
+ ## What is wrong with UXP?
22
+
23
+ We were very hopeful when in 2021 Adobe announced they would revamp their Photoshop API. However, after 2 years they seem to have given up, and the API is barely updated.
24
+
25
+ There are a lot of issues with the API:
26
+
27
+ - The Typescript types are more often wrong than not.
28
+ - It extends web APIs, but is incompatible with a lot of them.
29
+ - For most actions, you still have to use `batchPlay`, and in order to figure out what to do, you need to record the action with Alchemist and convert it into code. But even then, that code often does not work.
30
+ - When using the DOM API, e.g. `document.layers[0].name`, it looks synchronous, but under the hood it makes several IPC calls to the Photoshop process. If you have a lot of layers, this can get very slow.
31
+ - The amount of documentation is very lacking, often outdated or just plain wrong.
32
+
33
+ ## What we did
34
+
35
+ We made functions for building typesafe UXP projects. Instead of just running `batchPlay`, and trusting what the output is, we verify what the output is.
36
+
37
+ ### Core Functions
38
+
39
+ #### `createCommand` and `batchPlayCommand`
40
+
41
+ ```ts
42
+ // Before
43
+
44
+ // ActionDescriptor (any)
45
+ // ^
46
+ const result = await batchPlay([
47
+ {
48
+ _obj: "get",
49
+ _target: [
50
+ { _ref: "layer", _id: 123 }
51
+ ]
52
+ }
53
+ ]);
54
+
55
+ // After
56
+
57
+ // { name: string }
58
+ // ^
59
+ const result = await batchPlayCommand(
60
+ createCommand({
61
+ modifying: false,
62
+ descriptor: {
63
+ _obj: "get",
64
+ _target: [
65
+ { _ref: "layer", _id: 123 }
66
+ ]
67
+ },
68
+ schema: z.object({
69
+ name: z.string(),
70
+ }),
71
+ })
72
+ );
73
+ ```
74
+
75
+ This is only possible with non-modifiying commands. If you want to run a modifying command, this needs to happen in a modal context:
76
+
77
+ ```ts
78
+ await executeAsModal(commandName, async (ctx) => {
79
+ await ctx.batchPlayCommand(createCommand({
80
+ modifying: true,
81
+ descriptor: {
82
+ _obj: "set",
83
+ _target: [
84
+ { _ref: "layer", _id: 123 }
85
+ ],
86
+ name: "New Layer Name",
87
+ },
88
+ schema: z.unknown(),
89
+ }));
90
+ });
91
+ ```
92
+
93
+ There is also `batchPlayCommands` for running multiple commands at once, with correct typing.
94
+
95
+ #### `executeAsModal`
96
+
97
+ For better ergonomics, we put the name first, and then the function.
98
+ The ctx has new attributes:
99
+ - `signal`
100
+ - `batchPlayCommand` and `batchPlayCommands` for running commands
101
+
102
+ ```ts
103
+ await executeAsModal("Do something cancellable", async (ctx) => {
104
+ ctx.signal.throwIfAborted();
105
+ });
106
+ ```
107
+
108
+ #### `suspendHistory`
109
+
110
+ For better ergonomics, we put the document first, then the name, and then the function.
111
+
112
+ ```ts
113
+ await suspendHistory(document, "Action that suspends history", async (ctx) => {
114
+ await ctx.batchPlayCommand(createRenameLayerCommand({ id: 123, docId: document.id }, "New Name"));
115
+ });
116
+ ```
117
+
118
+ #### `executeAsModalAndSuspendHistory`
119
+
120
+ A combination of the two above:
121
+
122
+ ```ts
123
+ await executeAsModalAndSuspendHistory("Combined action", document, async (ctx, suspendHistoryContext) => {
124
+ ctx.reportProgress({ value: 0.5 });
125
+ });
126
+ ```
127
+
128
+ ### `UTLayer`
129
+
130
+ As `document.layers` can get slow, we provide a parser for a layer tree, built on `batchPlay` commands.
131
+
132
+ ```ts
133
+ // LayerDescriptor[]
134
+ // ^
135
+ const descriptors = await getDocumentLayerDescriptors(document.id);
136
+
137
+ // UTLayer[]
138
+ // ^
139
+ const layers = photoshopLayerDescriptorsToUTLayers(descriptors);
140
+ ```
141
+
142
+ ### `utLayersToText`
143
+
144
+ Convert a `UTLayer` tree to a human-readable text representation. This is useful for debugging, logging, and AI/LLM use cases where you need to represent the layer structure as text.
145
+
146
+ ```ts
147
+ import { utLayersToText } from '@bubblydoo/uxp-toolkit';
148
+
149
+ const text = utLayersToText(layers);
150
+ console.log(text);
151
+ ```
152
+
153
+ Output:
154
+ ```
155
+ ◯ Background
156
+ ◯ ▾ Header Group
157
+ ◯ Logo ƒ
158
+ ◯ ⬐ Title
159
+ ⊘ Subtitle ⁕
160
+ ◯ ▾ Content
161
+ ◯ Image
162
+ ```
163
+
164
+ Icons:
165
+ - `◯` visible / `⊘` hidden
166
+ - `▾` group
167
+ - `⬐` clipping mask
168
+ - `ƒ` has layer effects
169
+ - `⁕` non-default blend mode
170
+
171
+ ### Types packages
172
+
173
+ We publish our own types for the `uxp` and `photoshop` modules, which are based on other community efforts but adapted to be more accurate:
174
+
175
+ ```bash
176
+ pnpm add -D @adobe-uxp-types/uxp @adobe-uxp-types/photoshop
177
+ ```
178
+
179
+ `tsconfig.json`:
180
+ ```json
181
+ {
182
+ "compilerOptions": {
183
+ "types": ["photoshop", "uxp"],
184
+ "typeRoots": [
185
+ "./node_modules/@adobe-uxp-types",
186
+ "./node_modules/@types"
187
+ ]
188
+ }
189
+ }
190
+ ```
191
+
192
+ ### Commands library
193
+
194
+ We have a library of commands for common actions in Photoshop, which you can import from `@bubblydoo/uxp-toolkit/commands`.
195
+
196
+ Examples are `createRenameLayerCommand` and `createSelectLayerCommand`.
197
+
198
+ See the [commands library](./packages/uxp-toolkit/src/commands-library/index.ts) index file for a complete list.
199
+
200
+ ### Error sourcemaps
201
+
202
+ We have a function to parse error sourcemaps, which is very useful for debugging errors in your code.
203
+
204
+ ```ts
205
+ function throwError() {
206
+ throw new Error("Test error");
207
+ }
208
+
209
+ try {
210
+ throwError();
211
+ } catch (error) {
212
+ // [{ fileName: "test.ts", lineNumber: 2, columnNumber: 8 }]
213
+ // ^
214
+ const parsedError = await parseUxpErrorSourcemaps(error);
215
+
216
+ // "/Users/you/project/src/test.ts:2:8"
217
+ // ^
218
+ const absolutePath = await getBasicStackFrameAbsoluteFilePath(parsedError[0]);
219
+
220
+ await copyToClipboard(absolutePath);
221
+ }
222
+ ```
223
+
224
+ ### Testing
225
+
226
+ #### Vitest Integration
227
+
228
+ We now support Vitest for unit testing TypeScript code without Photoshop:
229
+
230
+ ```bash
231
+ pnpm test
232
+ ```
233
+
234
+ The test suite includes:
235
+ - Unit tests (`.test.ts`) for pure TypeScript functions
236
+ - Type tests (`.test-d.ts`) for compile-time type checking
237
+ - Photoshop builtin module aliases for testing code that imports `photoshop` or `uxp` modules
238
+
239
+ Tests run in CI via GitHub Actions with JUnit reporting.
240
+
241
+ #### UXP Testing Framework and Plugin
242
+
243
+ ```bash
244
+ pnpm add @bubblydoo/uxp-test-framework
245
+ ```
246
+
247
+ For integration tests that require Photoshop, we have developed a plugin specifically for testing UXP plugins. It allows you to run tests inside of Photoshop, and see the results in a panel.
248
+
249
+ <img src="res/screenshot-test-plugin.png" alt="Screenshot of the test plugin" width="400" />
250
+
251
+ You can run tests using the `create-uxp-test-plugin` command.
252
+
253
+ `uxp-tests.json`:
254
+ ```json
255
+ {
256
+ "$schema": "./node_modules/@bubblydoo/uxp-test-framework/uxp-tests-json-schema.json",
257
+ "testsFile": "test/index.ts",
258
+ "testFixturesDir": "test/fixtures",
259
+ "plugin": {
260
+ "id": "co.bubblydoo.uxp-toolkit-test-plugin",
261
+ "name": "UXP Toolkit Tests"
262
+ }
263
+ }
264
+ ```
265
+
266
+ `test/index.ts`:
267
+ ```ts
268
+ import type { Test } from "@bubblydoo/uxp-test-framework";
269
+ import { expect } from "chai";
270
+ import { app } from "photoshop";
271
+
272
+ const renameLayerTest: Test = {
273
+ name: "Should rename layer",
274
+ async run() {
275
+ const doc = await openFileByPath("plugin:/fixtures/one-layer.psd");
276
+ const descriptors = await getDocumentLayerDescriptors(doc.id);
277
+ const firstLayer = descriptors[0];
278
+
279
+ expect(firstLayer.name).to.equal("Layer 1");
280
+
281
+ await executeAsModal("Rename Layer", async (ctx) => {
282
+ await ctx.batchPlayCommand(
283
+ createRenameLayerCommand({ id: firstLayer.layerID, docId: firstLayer.docId }, "New Name")
284
+ );
285
+ });
286
+
287
+ const updatedDescriptors = await getDocumentLayerDescriptors(doc.id);
288
+ expect(updatedDescriptors[0].name).to.equal("New Name");
289
+ },
290
+ };
291
+
292
+ export const tests: Test[] = [
293
+ renameLayerTest,
294
+ ];
295
+ ```
296
+
297
+ ```json
298
+ {
299
+ "name": "your-plugin",
300
+ "scripts": {
301
+ "uxp-test:build": "uxp-test build",
302
+ "uxp-test:dev": "uxp-test dev"
303
+ }
304
+ }
305
+ ```
306
+
307
+ Then you can run:
308
+ ```bash
309
+ pnpm uxp-test:dev
310
+ ```
311
+
312
+ And you will get a plugin in the `uxp-tests-plugin` directory, which you can load using UXP Developer Tools, and then you can run the tests inside of Photoshop.
313
+
314
+ In the future, we'd like to get Vitest to work natively with a UXP runner or pool, but for now, this is a good compromise.
315
+
316
+ The plugin also sourcemaps the errors, so you can find the error much more easily:
317
+
318
+ <img src="res/screenshot-test-plugin-error.png" alt="Screenshot of the test plugin with an error" width="800" />
319
+
320
+ ### React integration
321
+
322
+ ```bash
323
+ pnpm add @bubblydoo/uxp-toolkit-react
324
+ ```
325
+
326
+ We have a React integration for the toolkit. It allows you to use the toolkit in a React application. Many functions use React Query under the hood.
327
+
328
+ ```ts
329
+ import { useActiveDocument } from "@bubblydoo/uxp-toolkit-react";
330
+
331
+ function App() {
332
+ const activeDocument = useActiveDocument();
333
+ return <div>Active document: {activeDocument.name}</div>;
334
+ }
335
+ ```
336
+
337
+ This package provides the following hooks:
338
+
339
+ - `useActiveDocument` – Sync external store for the current active document
340
+ - `useOnDocumentEdited` – Run a callback when the given document is edited (select, delete, make, set, move, close, show, hide, etc.)
341
+ - `useOnDocumentLayersEdited` – Run a callback when layers change (delete, make, set, move, close)
342
+ - `useOnDocumentLayersSelection` – Run a callback when layer selection changes (select, deselect)
343
+ - `useOnEvent` – Run a callback for arbitrary Photoshop action events on a given document
344
+ - `useOpenDocuments` – Sync external store for the list of open documents
345
+ - `useIsPluginPanelVisible` and `useIsAnyPluginPanelVisible` – Whether a plugin panel is visible
346
+ - `useApplicationInfoQuery` – React Query for Photoshop application info (e.g. panel list)
347
+ - `useEventListenerSkippable` - Generic hook to subscribe to events with optional skip/filter so triggers can be queued or ignored
348
+
349
+ ### CLI
350
+
351
+ We fixed the [official devtools package](https://github.com/adobe-uxp/devtools-cli), which had a lot of issues. You can find the fixed repo [here](https://github.com/bubblydoo/adobe-fixed-uxp-devtools).
352
+
353
+ Based on this, we created our own CLI. You can run this without installing anything, just `pnpm`.
354
+
355
+ This can replace UXP Developer Tools.
356
+
357
+ Open devtools with a "fake" plugin (doesn't have any functionality)
358
+
359
+ ```bash
360
+ pnpm --allow-build=@adobe-fixed-uxp/uxp-devtools-helper dlx @bubblydoo/uxp-cli open-devtools
361
+ ```
362
+
363
+ Open devtools with a custom plugin
364
+
365
+ ```bash
366
+ pnpm --allow-build=@adobe-fixed-uxp/uxp-devtools-helper dlx @bubblydoo/uxp-cli open-devtools --plugin-path ./my-plugin
367
+ ```
368
+
369
+ You can also just install it:
370
+
371
+ ```bash
372
+ pnpm add -D @bubblydoo/uxp-cli
373
+ ```
374
+
375
+ If you're using approved builds in pnpm, make sure to add `@adobe-fixed-uxp/uxp-devtools-helper` to the `onlyBuiltDependencies` in your `pnpm-workspace.yaml`. The postinstall script just unzips some binary proprietary Adobe files.
376
+
377
+ ### Photoshop MCP
378
+
379
+ We have a MCP server for Photoshop automation via Chrome DevTools Protocol. It allows AI assistants to execute JavaScript code directly in Adobe Photoshop's UXP environment, but it also has access to UXP Toolkit and its commands, to the TypeScript schemas and these readmes.
380
+
381
+ ```bash
382
+ pnpm --allow-build=@adobe-fixed-uxp/uxp-devtools-helper dlx @bubblydoo/photoshop-mcp
383
+ ```