autodev-cli 1.4.150 → 1.4.152

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.
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // gimpPluginSource.ts — GENERATED. Do not edit by hand.
4
+ //
5
+ // Source of truth: media/gimp/gimp_mcp_server.py (GPL-3.0; see media/gimp/LICENSE).
6
+ // Regenerate with: node scripts/gen-gimp-plugin-source.mjs (runs in `npm run build`).
7
+ //
8
+ // Embeds the user-verified GIMP 3.x MCP server plug-in as a string so the installer works even when bundled
9
+ // (VS Code extension esbuild) with no media file on disk.
10
+ // ---------------------------------------------------------------------------
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.GIMP_PLUGIN_SOURCE = exports.GIMP_PLUGIN_SOURCE_HASH = void 0;
13
+ /** sha256 (first 12 hex) of the canonical media/gimp/gimp_mcp_server.py. */
14
+ exports.GIMP_PLUGIN_SOURCE_HASH = "c4b85cccece9";
15
+ /** Full body of the user-verified GIMP 3.x MCP server plug-in (media/gimp/gimp_mcp_server.py). */
16
+ exports.GIMP_PLUGIN_SOURCE = `#!/usr/bin/env python3
17
+ # ---------------------------------------------------------------------------
18
+ # gimp_mcp_server.py — vendored, USER-VERIFIED GIMP 3.2 MCP bridge (plug-in).
19
+ #
20
+ # Derived from libreearth/gimp-mcp (GPL-3.0; see media/gimp/LICENSE) and fixed by
21
+ # the user / AutoDev for GIMP 3.2 (Store / MSIX). Verified working on real GIMP
22
+ # 3.2.44: a menu-triggered PLUGIN (Tools -> MCP / Filters -> Development -> Start
23
+ # MCP Server) that listens on 127.0.0.1:9876 and drives GIMP. Keep the "GIMP MCP
24
+ # Server" window open — GLib.MainLoop() holds the out-of-process plug-in alive.
25
+ #
26
+ # This is the user's verified file; the body below is kept byte-for-byte. The
27
+ # lines in THIS block are a provenance comment only — do not edit the code below.
28
+ # ---------------------------------------------------------------------------
29
+
30
+ # GIMP MCP Server Plugin (GIMP 3.2)
31
+ # Listens on localhost:9876 so the libreearth gimp-mcp client can drive GIMP.
32
+
33
+ import gi
34
+ gi.require_version('Gimp', '3.0')
35
+ from gi.repository import Gimp
36
+ from gi.repository import GLib
37
+ from gi.repository import Gio
38
+ from gi.repository import GObject
39
+
40
+ import io
41
+ import json
42
+ import os
43
+ import socket
44
+ import sys
45
+ import threading
46
+ import traceback
47
+
48
+ HOST = '127.0.0.1'
49
+ PORT = 9876
50
+ # Store GIMP redirects GLib config dir into the MSIX LocalCache. Also write
51
+ # to the real roaming profile so the log is findable.
52
+ _LOG_PATHS = [
53
+ os.path.join(GLib.get_user_config_dir(), 'GIMP', '3.2', 'gimp_mcp_server.log'),
54
+ os.path.join(os.environ.get('APPDATA', ''), 'GIMP', '3.2', 'gimp_mcp_server.log'),
55
+ ]
56
+
57
+ _server_lock = threading.Lock()
58
+ _server_started = False
59
+ _exec_globals = None
60
+ _main_loop = None
61
+
62
+
63
+ def _log(msg):
64
+ line = msg.rstrip() + '\\n'
65
+ for path in _LOG_PATHS:
66
+ if not path:
67
+ continue
68
+ try:
69
+ os.makedirs(os.path.dirname(path), exist_ok=True)
70
+ with open(path, 'a', encoding='utf-8') as fh:
71
+ fh.write(line)
72
+ except Exception:
73
+ pass
74
+ print(msg, flush=True)
75
+
76
+
77
+ def N_(message):
78
+ return message
79
+
80
+
81
+ def _(message):
82
+ return GLib.dgettext(None, message)
83
+
84
+
85
+ def _serialize(obj):
86
+ if obj is None or isinstance(obj, (str, int, float, bool)):
87
+ return obj
88
+ if isinstance(obj, (list, tuple)):
89
+ return [_serialize(item) for item in obj]
90
+ if isinstance(obj, dict):
91
+ return {str(k): _serialize(v) for k, v in obj.items()}
92
+ data = {'type': obj.__class__.__name__}
93
+ if hasattr(obj, 'get_id'):
94
+ try:
95
+ data['id'] = int(obj.get_id())
96
+ except Exception:
97
+ pass
98
+ elif hasattr(obj, 'ID'):
99
+ data['id'] = obj.ID
100
+ if hasattr(obj, 'get_name'):
101
+ try:
102
+ data['name'] = obj.get_name()
103
+ except Exception:
104
+ pass
105
+ if 'id' not in data and len(data) == 1:
106
+ return str(obj)
107
+ return data
108
+
109
+
110
+ def _resolve_api(api_path):
111
+ parts = [p for p in str(api_path).split('.') if p]
112
+ if parts and parts[0] == 'Gimp':
113
+ parts = parts[1:]
114
+ elif len(parts) >= 3 and parts[0] == 'gi' and parts[1] == 'repository' and parts[2] == 'Gimp':
115
+ parts = parts[3:]
116
+
117
+ aliases = {
118
+ 'list_images': 'get_images',
119
+ 'list_fonts': 'get_fonts',
120
+ 'fonts_get_list': 'get_fonts',
121
+ }
122
+
123
+ if not parts:
124
+ return Gimp
125
+
126
+ obj = Gimp
127
+ for part in parts:
128
+ part = aliases.get(part, part)
129
+ obj = getattr(obj, part)
130
+ return obj
131
+
132
+
133
+ def _exec_namespace():
134
+ global _exec_globals
135
+ if _exec_globals is None:
136
+ ns = {
137
+ '__builtins__': __builtins__,
138
+ '__name__': '__main__',
139
+ 'Gimp': Gimp,
140
+ 'GLib': GLib,
141
+ 'Gio': Gio,
142
+ 'GObject': GObject,
143
+ 'sys': sys,
144
+ 'os': os,
145
+ 'json': json,
146
+ }
147
+ try:
148
+ gi.require_version('Gegl', '0.4')
149
+ from gi.repository import Gegl
150
+ ns['Gegl'] = Gegl
151
+ except Exception as exc:
152
+ _log(f'Gegl import failed: {exc}')
153
+ try:
154
+ gi.require_version('Babl', '0.1')
155
+ from gi.repository import Babl
156
+ ns['Babl'] = Babl
157
+ except Exception:
158
+ pass
159
+ _exec_globals = ns
160
+ return _exec_globals
161
+
162
+
163
+ def _extract_code(args, kwargs):
164
+ if kwargs.get('code'):
165
+ return str(kwargs['code'])
166
+ if not args:
167
+ return ''
168
+ if len(args) >= 2 and args[0] in ('exec', 'eval', 'pyGObject-console'):
169
+ payload = args[1]
170
+ if isinstance(payload, (list, tuple)):
171
+ return '\\n'.join(str(item) for item in payload)
172
+ return str(payload)
173
+ if isinstance(args[0], (list, tuple)):
174
+ return '\\n'.join(str(item) for item in args[0])
175
+ return str(args[0])
176
+
177
+
178
+ def _run_python(code):
179
+ ns = _exec_namespace()
180
+ stdout = io.StringIO()
181
+ old_stdout = sys.stdout
182
+ sys.stdout = stdout
183
+ try:
184
+ exec(code, ns)
185
+ finally:
186
+ sys.stdout = old_stdout
187
+ printed = stdout.getvalue()
188
+ result = ns.get('_result')
189
+ if result is not None:
190
+ return {'printed': printed, 'result': _serialize(result)}
191
+ return {'printed': printed, 'result': None}
192
+
193
+
194
+ class MCPPlugin(Gimp.PlugIn):
195
+ def do_set_i18n(self, name):
196
+ return False
197
+
198
+ def do_query_procedures(self):
199
+ return ['plug-in-mcp-server']
200
+
201
+ def do_create_procedure(self, name):
202
+ procedure = Gimp.Procedure.new(
203
+ self, name, Gimp.PDBProcType.PLUGIN, self.run, None
204
+ )
205
+ procedure.set_menu_label(_('Start MCP Server'))
206
+ procedure.set_documentation(
207
+ _('Starts an MCP server to control GIMP externally'),
208
+ _('Listens on 127.0.0.1:9876 for the GIMP MCP client'),
209
+ name,
210
+ )
211
+ procedure.set_attribution('GIMP MCP', 'GIMP MCP', '2026')
212
+ procedure.set_sensitivity_mask(Gimp.ProcedureSensitivityMask.ALWAYS)
213
+ procedure.add_enum_argument(
214
+ 'run-mode',
215
+ _('Run mode'),
216
+ _('The run mode'),
217
+ Gimp.RunMode,
218
+ Gimp.RunMode.INTERACTIVE,
219
+ GObject.ParamFlags.READWRITE,
220
+ )
221
+ procedure.add_menu_path('<Image>/Tools/MCP')
222
+ procedure.add_menu_path('<Image>/Filters/Development/')
223
+ return procedure
224
+
225
+ def run(self, procedure, config, data):
226
+ global _main_loop
227
+ started, message = self.ensure_server()
228
+ _log(message)
229
+ try:
230
+ Gimp.message(message)
231
+ except Exception:
232
+ pass
233
+ if not started:
234
+ return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR, GLib.Error(message))
235
+
236
+ # GIMP 3 launches Python plug-ins out of process. Returning from run()
237
+ # would exit that process and kill the socket thread. Stay alive and
238
+ # dispatch GLib.idle_add work (API calls) on this main loop.
239
+ # A visible window is required: otherwise "Start MCP Server" looks like
240
+ # it did not open anything.
241
+ try:
242
+ self._show_status_window(message)
243
+ except Exception as exc:
244
+ _log(f'Status window failed: {exc}\\n{traceback.format_exc()}')
245
+
246
+ _main_loop = GLib.MainLoop()
247
+ _log('Entering GLib.MainLoop to keep MCP server process alive')
248
+ try:
249
+ _main_loop.run()
250
+ except Exception as exc:
251
+ _log(f'MainLoop exited: {exc}')
252
+ return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
253
+
254
+ def _show_status_window(self, message):
255
+ gi.require_version('Gtk', '3.0')
256
+ gi.require_version('GimpUi', '3.0')
257
+ from gi.repository import Gtk
258
+ from gi.repository import GimpUi
259
+
260
+ GimpUi.init('gimp_mcp_server.py')
261
+ window = Gtk.Window(title='GIMP MCP Server')
262
+ window.set_default_size(420, 160)
263
+ window.set_keep_above(True)
264
+ box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
265
+ box.set_border_width(16)
266
+ label = Gtk.Label(label=message + '\\n\\nLeave this window open while Grok talks to GIMP.')
267
+ label.set_line_wrap(True)
268
+ box.pack_start(label, True, True, 0)
269
+ button = Gtk.Button(label='Stop server')
270
+ button.connect('clicked', lambda *_: window.destroy())
271
+ box.pack_start(button, False, False, 0)
272
+ window.add(box)
273
+ window.connect('destroy', self._on_status_closed)
274
+ window.show_all()
275
+ window.present()
276
+ _log('Status window opened')
277
+
278
+ def _on_status_closed(self, *_args):
279
+ global _main_loop
280
+ _log('Status window closed; stopping MCP server')
281
+ if _main_loop is not None:
282
+ _main_loop.quit()
283
+
284
+ def ensure_server(self):
285
+ global _server_started
286
+ with _server_lock:
287
+ if _server_started:
288
+ return True, f'MCP Server already listening on {HOST}:{PORT}'
289
+ try:
290
+ thread = threading.Thread(target=self.start_server, daemon=True)
291
+ thread.start()
292
+ _server_started = True
293
+ return True, f'MCP Server started on {HOST}:{PORT}'
294
+ except Exception as exc:
295
+ return False, f'Failed to start MCP Server: {exc}'
296
+
297
+ def start_server(self):
298
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
299
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
300
+ try:
301
+ sock.bind((HOST, PORT))
302
+ sock.listen(8)
303
+ _log(f'Server listening on {HOST}:{PORT}')
304
+ except Exception as exc:
305
+ _log(f'Bind/listen failed: {exc}')
306
+ return
307
+
308
+ while True:
309
+ try:
310
+ client, addr = sock.accept()
311
+ _log(f'Connected to {addr}')
312
+ threading.Thread(target=self.handle_client, args=(client,), daemon=True).start()
313
+ except Exception as exc:
314
+ _log(f'Server accept error: {exc}')
315
+ break
316
+ sock.close()
317
+
318
+ def handle_client(self, client):
319
+ buffer = b''
320
+ try:
321
+ client.settimeout(120)
322
+ while True:
323
+ chunk = client.recv(65536)
324
+ if not chunk:
325
+ break
326
+ buffer += chunk
327
+ while buffer:
328
+ try:
329
+ command = json.loads(buffer.decode('utf-8'))
330
+ buffer = b''
331
+ except json.JSONDecodeError:
332
+ break
333
+ GLib.idle_add(self.execute_command, command, client)
334
+ except Exception as exc:
335
+ _log(f'Client error: {exc}')
336
+ finally:
337
+ try:
338
+ client.close()
339
+ except Exception:
340
+ pass
341
+
342
+ def execute_command(self, command, client):
343
+ cmd_type = command.get('type')
344
+ params = command.get('params', {}) or {}
345
+ try:
346
+ if cmd_type == 'ping':
347
+ response = {'status': 'success', 'result': 'pong'}
348
+ elif cmd_type == 'exec':
349
+ code = _extract_code(params.get('args', []), params.get('kwargs', {}))
350
+ if not code:
351
+ code = str(params.get('code', ''))
352
+ response = {'status': 'success', 'result': _run_python(code)}
353
+ elif cmd_type == 'call_api':
354
+ api_path = params.get('api_path', '')
355
+ args = params.get('args', []) or []
356
+ kwargs = params.get('kwargs', {}) or {}
357
+ if api_path in ('exec', 'eval', '__exec__'):
358
+ response = {'status': 'success', 'result': _run_python(_extract_code(args, kwargs))}
359
+ else:
360
+ method = _resolve_api(api_path)
361
+ result = method(*args, **kwargs)
362
+ response = {'status': 'success', 'result': _serialize(result)}
363
+ else:
364
+ response = {'status': 'error', 'message': f'Unknown command: {cmd_type}'}
365
+ except Exception as exc:
366
+ response = {
367
+ 'status': 'error',
368
+ 'message': str(exc),
369
+ 'traceback': traceback.format_exc(),
370
+ }
371
+ _log(f'Command error: {response["message"]}\\n{response["traceback"]}')
372
+
373
+ try:
374
+ payload = json.dumps(response).encode('utf-8')
375
+ client.sendall(payload)
376
+ except Exception as exc:
377
+ _log(f'Response send failed: {exc}')
378
+ return False
379
+
380
+
381
+ Gimp.main(MCPPlugin.__gtype__, sys.argv)
382
+ `;
383
+ //# sourceMappingURL=gimpPluginSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gimpPluginSource.js","sourceRoot":"","sources":["../../src/core/gimpPluginSource.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,wDAAwD;AACxD,EAAE;AACF,oFAAoF;AACpF,wFAAwF;AACxF,EAAE;AACF,4GAA4G;AAC5G,0DAA0D;AAC1D,8EAA8E;;;AAE9E,4EAA4E;AAC/D,QAAA,uBAAuB,GAAG,cAAc,CAAC;AAEtD,kGAAkG;AACrF,QAAA,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8WjC,CAAC"}
@@ -20,22 +20,18 @@ export interface McpCatalogEntry {
20
20
  notes: string[];
21
21
  }
22
22
  /**
23
- * Legacy placeholder the OLD GIMP stub carried until the user pointed it at a
24
- * local checkout. No longer the default (see serverSpecFor/gimp below) — kept
25
- * ONLY so the migration can recognise + upgrade pre-git-based stubs.
23
+ * Display placeholder for the gimp client path BEFORE install (path unknown).
24
+ * `serverSpecFor('gimp', …)` with no resolved client path emits this so the
25
+ * catalog/detect JSON never bakes in a machine-specific path — and, crucially,
26
+ * never the broken raw-github upstream client. It also lets the migration
27
+ * recognise a not-yet-resolved gimp entry and upgrade it once GIMP is detected.
26
28
  */
27
- export declare const GIMP_CLIENT_PLACEHOLDER = "<GIMP_MCP_CLIENT_PY>";
29
+ export declare const GIMP_CLIENT_PLACEHOLDER = "<GIMP config>/mcp/gimp_mcp_client.py";
28
30
  /**
29
- * The GIMP MCP client, run straight from git by `uv` — no manual clone. Pinned
30
- * to a specific upstream commit + `mcp==1.2.0` for reproducibility: `uv run`
31
- * fetches this raw script, installs the PINNED mcp SDK, and launches the FastMCP
32
- * stdio server (it lazily connects to GIMP on localhost:9876, so it starts even
33
- * without GIMP running). Verified end-to-end (valid MCP initialize handshake,
34
- * clean exit). `mcp==1.2.0` is load-bearing — current mcp releases break this
35
- * client on a removed `description=` kwarg.
31
+ * The pinned mcp SDK version the client runs under. Load-bearing — current mcp
32
+ * releases break the client on a removed `description=` kwarg. `uv run --with
33
+ * mcp==1.2.0 <client>` installs exactly this into an ephemeral env.
36
34
  */
37
- export declare const GIMP_MCP_COMMIT = "49c46dd6146cb7393b42a9ecda630583b3117b33";
38
- export declare const GIMP_MCP_CLIENT_URL = "https://raw.githubusercontent.com/libreearth/gimp-mcp/49c46dd6146cb7393b42a9ecda630583b3117b33/gimp_mcp_client.py";
39
35
  export declare const GIMP_MCP_PIN = "mcp==1.2.0";
40
36
  /** Per-platform install hint for the `uv`/`uvx` toolchain (never `pip install uv`). */
41
37
  export declare function uvInstallHint(platform: NodeJS.Platform): string;
@@ -60,14 +56,26 @@ export declare const BLENDER_LAB_FROM = "git+https://projects.blender.org/lab/bl
60
56
  * from Blender Lab" add-on. NEVER bare `uvx blender-mcp` (no --from) — that
61
57
  * pulls the incompatible community PyPI package. (The exact launcher form is
62
58
  * under review; the args are the load-bearing part the migration re-resolves.)
63
- * - GIMP: the git-based client run by bare `uv` (`uv run --with mcp==1.2.0
64
- * <raw github url>`) on every platform — runnable now, so written ENABLED
65
- * (no disabled stub). `opts.gimpClientPath` is an OPTIONAL override for users
66
- * who cloned the repo locally → `python[3] <that path>`. Still experimental.
59
+ * - GIMP: the LOCALLY-INSTALLED, user-verified client run by bare `uv`
60
+ * (`uv run --with mcp==1.2.0 <clientPath>`) on every platform. `clientPath`
61
+ * is the client installGimpPlugin() writes to <GIMP-config>/<ver>/mcp/. Pass
62
+ * the resolved path via `opts.gimpClientPath`; without it we emit the display
63
+ * placeholder (never the broken raw-github upstream client). Experimental.
67
64
  */
68
65
  export declare function serverSpecFor(app: CreativeAppId, platform: NodeJS.Platform, opts?: {
69
66
  gimpClientPath?: string;
70
67
  }): McpJsonEntry;
68
+ /** The client-path argument carried by a gimp .mcp.json entry, whatever the command form. */
69
+ export declare function gimpClientArgOf(entry: {
70
+ command?: string;
71
+ args?: string[];
72
+ }): string | undefined;
73
+ /**
74
+ * Is `arg` a CONCRETE local client path — a real filesystem path we must not
75
+ * clobber (a user's own checkout, or the client we already installed)? False for
76
+ * the display placeholder and for ANY URL (incl. the broken raw-github client).
77
+ */
78
+ export declare function isConcreteGimpClientArg(arg: string | undefined): boolean;
71
79
  /** Build the catalog for a given platform (install hints are platform-specific). */
72
80
  export declare function getCatalog(platform: NodeJS.Platform): McpCatalogEntry[];
73
81
  /** Lookup a single catalog entry. */
@@ -10,32 +10,29 @@
10
10
  // flagged experimental because upstream ships no packaged launcher — see below.
11
11
  // ---------------------------------------------------------------------------
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.BLENDER_LAB_FROM = exports.GIMP_MCP_PIN = exports.GIMP_MCP_CLIENT_URL = exports.GIMP_MCP_COMMIT = exports.GIMP_CLIENT_PLACEHOLDER = void 0;
13
+ exports.BLENDER_LAB_FROM = exports.GIMP_MCP_PIN = exports.GIMP_CLIENT_PLACEHOLDER = void 0;
14
14
  exports.uvInstallHint = uvInstallHint;
15
15
  exports.pythonInstallHint = pythonInstallHint;
16
16
  exports.gitInstallHint = gitInstallHint;
17
17
  exports.serverSpecFor = serverSpecFor;
18
+ exports.gimpClientArgOf = gimpClientArgOf;
19
+ exports.isConcreteGimpClientArg = isConcreteGimpClientArg;
18
20
  exports.getCatalog = getCatalog;
19
21
  exports.catalogEntry = catalogEntry;
20
22
  /**
21
- * Legacy placeholder the OLD GIMP stub carried until the user pointed it at a
22
- * local checkout. No longer the default (see serverSpecFor/gimp below) — kept
23
- * ONLY so the migration can recognise + upgrade pre-git-based stubs.
23
+ * Display placeholder for the gimp client path BEFORE install (path unknown).
24
+ * `serverSpecFor('gimp', …)` with no resolved client path emits this so the
25
+ * catalog/detect JSON never bakes in a machine-specific path — and, crucially,
26
+ * never the broken raw-github upstream client. It also lets the migration
27
+ * recognise a not-yet-resolved gimp entry and upgrade it once GIMP is detected.
24
28
  */
25
- exports.GIMP_CLIENT_PLACEHOLDER = '<GIMP_MCP_CLIENT_PY>';
29
+ exports.GIMP_CLIENT_PLACEHOLDER = '<GIMP config>/mcp/gimp_mcp_client.py';
26
30
  /**
27
- * The GIMP MCP client, run straight from git by `uv` — no manual clone. Pinned
28
- * to a specific upstream commit + `mcp==1.2.0` for reproducibility: `uv run`
29
- * fetches this raw script, installs the PINNED mcp SDK, and launches the FastMCP
30
- * stdio server (it lazily connects to GIMP on localhost:9876, so it starts even
31
- * without GIMP running). Verified end-to-end (valid MCP initialize handshake,
32
- * clean exit). `mcp==1.2.0` is load-bearing — current mcp releases break this
33
- * client on a removed `description=` kwarg.
31
+ * The pinned mcp SDK version the client runs under. Load-bearing — current mcp
32
+ * releases break the client on a removed `description=` kwarg. `uv run --with
33
+ * mcp==1.2.0 <client>` installs exactly this into an ephemeral env.
34
34
  */
35
- exports.GIMP_MCP_COMMIT = '49c46dd6146cb7393b42a9ecda630583b3117b33';
36
- exports.GIMP_MCP_CLIENT_URL = `https://raw.githubusercontent.com/libreearth/gimp-mcp/${exports.GIMP_MCP_COMMIT}/gimp_mcp_client.py`;
37
35
  exports.GIMP_MCP_PIN = 'mcp==1.2.0';
38
- const GIMP_GIT_ARGS = ['run', '--with', exports.GIMP_MCP_PIN, exports.GIMP_MCP_CLIENT_URL];
39
36
  /** Per-platform install hint for the `uv`/`uvx` toolchain (never `pip install uv`). */
40
37
  function uvInstallHint(platform) {
41
38
  if (platform === 'win32') {
@@ -84,10 +81,11 @@ const BLENDER_LAB_ARGS = ['--from', exports.BLENDER_LAB_FROM, '--with', 'mcp<2',
84
81
  * from Blender Lab" add-on. NEVER bare `uvx blender-mcp` (no --from) — that
85
82
  * pulls the incompatible community PyPI package. (The exact launcher form is
86
83
  * under review; the args are the load-bearing part the migration re-resolves.)
87
- * - GIMP: the git-based client run by bare `uv` (`uv run --with mcp==1.2.0
88
- * <raw github url>`) on every platform — runnable now, so written ENABLED
89
- * (no disabled stub). `opts.gimpClientPath` is an OPTIONAL override for users
90
- * who cloned the repo locally → `python[3] <that path>`. Still experimental.
84
+ * - GIMP: the LOCALLY-INSTALLED, user-verified client run by bare `uv`
85
+ * (`uv run --with mcp==1.2.0 <clientPath>`) on every platform. `clientPath`
86
+ * is the client installGimpPlugin() writes to <GIMP-config>/<ver>/mcp/. Pass
87
+ * the resolved path via `opts.gimpClientPath`; without it we emit the display
88
+ * placeholder (never the broken raw-github upstream client). Experimental.
91
89
  */
92
90
  function serverSpecFor(app, platform, opts) {
93
91
  if (app === 'blender') {
@@ -95,15 +93,41 @@ function serverSpecFor(app, platform, opts) {
95
93
  // official Blender Lab `--from git+…lab…` client.
96
94
  return { command: 'uvx', args: [...BLENDER_LAB_ARGS] };
97
95
  }
98
- // gimp — OPTIONAL local override: a user who cloned the repo points us at their
99
- // gimp_mcp_client.py and we run it via python (enabled — it's a real path).
100
- const local = opts?.gimpClientPath && opts.gimpClientPath.trim();
101
- if (local && local !== exports.GIMP_CLIENT_PLACEHOLDER) {
102
- return { command: platform === 'win32' ? 'python' : 'python3', args: [local] };
96
+ // gimp — run the locally-installed client via `uv` with the pinned mcp SDK.
97
+ // Same command shape on every platform; only the client path differs.
98
+ const client = (opts?.gimpClientPath && opts.gimpClientPath.trim()) || exports.GIMP_CLIENT_PLACEHOLDER;
99
+ return { command: 'uv', args: ['run', '--with', exports.GIMP_MCP_PIN, client] };
100
+ }
101
+ /** The client-path argument carried by a gimp .mcp.json entry, whatever the command form. */
102
+ function gimpClientArgOf(entry) {
103
+ const args = Array.isArray(entry.args) ? entry.args : [];
104
+ if (entry.command === 'python' || entry.command === 'python3') {
105
+ return args[0];
106
+ }
107
+ if (entry.command === 'uv') {
108
+ return args[args.length - 1];
109
+ }
110
+ return undefined;
111
+ }
112
+ /**
113
+ * Is `arg` a CONCRETE local client path — a real filesystem path we must not
114
+ * clobber (a user's own checkout, or the client we already installed)? False for
115
+ * the display placeholder and for ANY URL (incl. the broken raw-github client).
116
+ */
117
+ function isConcreteGimpClientArg(arg) {
118
+ if (typeof arg !== 'string' || arg.length === 0) {
119
+ return false;
103
120
  }
104
- // Default: the git-based client, fetched + launched by `uv run`. Same on every
105
- // platform. Enabled by default — it launches even without GIMP present.
106
- return { command: 'uv', args: [...GIMP_GIT_ARGS] };
121
+ if (arg === exports.GIMP_CLIENT_PLACEHOLDER) {
122
+ return false;
123
+ }
124
+ if (/^https?:\/\//i.test(arg)) {
125
+ return false;
126
+ }
127
+ if (/raw\.githubusercontent\.com/i.test(arg)) {
128
+ return false;
129
+ }
130
+ return true;
107
131
  }
108
132
  /** Build the catalog for a given platform (install hints are platform-specific). */
109
133
  function getCatalog(platform) {
@@ -135,25 +159,33 @@ function getCatalog(platform) {
135
159
  serverName: 'gimp',
136
160
  prerequisites: [{ id: 'uv', installHint: uvInstallHint(platform) }],
137
161
  postSetup: [
138
- 'The MCP client runs from git automatically (uv fetches it) — no manual download of the client.',
139
- `The GIMP-side AUTO-START plugin is installed for you into your GIMP 3.x plug-ins folder (${gimpPluginDir(platform)}) — just restart GIMP and the server auto-starts on localhost:9876 (no menu click). Re-run any time with: autodev mcp gimp-install-plugin`,
140
- 'Requires GIMP 3.0+ (the plugin uses the GIMP 3.0 API).',
162
+ `Plugin + client are installed automatically into your GIMP 3.x config (${gimpPluginDir(platform)}) — you copy nothing. Re-run any time with: autodev mcp gimp-install-plugin`,
163
+ "In GIMP: Tools → MCP → Start MCP Server (or Filters → Development → Start MCP Server), and KEEP the 'GIMP MCP Server' window open — it holds the plug-in process alive and the :9876 socket. One click per GIMP session (the window may hide behind other apps; use the taskbar).",
164
+ 'Requires GIMP 3.x (the plugin uses the GIMP 3.0 Python API).',
141
165
  "Port 9876 collides with Blender — don't run both MCP servers at once.",
142
166
  ],
143
167
  notes: [
144
- 'Experimental prototype: upstream is a prototype and its README contradicts its own code — expect rough edges.',
145
- `The client is pinned to a specific commit (${exports.GIMP_MCP_COMMIT.slice(0, 7)}…) and ${exports.GIMP_MCP_PIN} for reproducibility (current mcp releases break the client on a removed description= kwarg).`,
168
+ `Log: ${gimpLogPath(platform)} (Store/MSIX GIMP also mirrors a copy inside its sandbox LocalCache).`,
169
+ `The client runs via \`uv run --with ${exports.GIMP_MCP_PIN} <installed client>\`; the ${exports.GIMP_MCP_PIN} pin is load-bearing (current mcp releases break the client on a removed description= kwarg).`,
146
170
  ],
147
171
  },
148
172
  ];
149
173
  }
150
- /** GIMP 3.0 plug-ins directory, per OS (where the server-side plugin lives). */
174
+ /** GIMP 3.x config directory, per OS (where plug-ins/ and mcp/ get installed). */
151
175
  function gimpPluginDir(platform) {
152
176
  return platform === 'win32'
153
- ? '%APPDATA%\\GIMP\\3.x\\plug-ins\\'
177
+ ? '%APPDATA%\\GIMP\\3.x\\'
178
+ : platform === 'darwin'
179
+ ? '~/Library/Application Support/GIMP/3.x/'
180
+ : '~/.config/GIMP/3.x/';
181
+ }
182
+ /** GIMP MCP server log path, per OS (dual-written by the plug-in). */
183
+ function gimpLogPath(platform) {
184
+ return platform === 'win32'
185
+ ? '%APPDATA%\\GIMP\\3.x\\gimp_mcp_server.log'
154
186
  : platform === 'darwin'
155
- ? '~/Library/Application Support/GIMP/3.x/plug-ins/'
156
- : '~/.config/GIMP/3.x/plug-ins/';
187
+ ? '~/Library/Application Support/GIMP/3.x/gimp_mcp_server.log'
188
+ : '~/.config/GIMP/3.x/gimp_mcp_server.log';
157
189
  }
158
190
  /** Lookup a single catalog entry. */
159
191
  function catalogEntry(app, platform) {
@@ -1 +1 @@
1
- {"version":3,"file":"mcpCatalog.js","sourceRoot":"","sources":["../../src/core/mcpCatalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcpCatalog.js","sourceRoot":"","sources":["../../src/core/mcpCatalog.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,14 @@
1
+ export interface MigrateOpts {
2
+ /**
3
+ * Resolve the local gimp client path for this machine, or null when GIMP 3.x is
4
+ * absent. Defaults to resolveGimpClientPath() (real detection). Injectable for
5
+ * tests. When null, a gimp entry that needs upgrading is left as-is.
6
+ */
7
+ resolveGimpClient?: () => string | null;
8
+ }
1
9
  /**
2
10
  * Re-resolve stale creative-app user entries in <root>/.mcp.json from the current
3
11
  * catalog. Persists the upgraded set back to .mcp.json when anything changed and
4
12
  * logs each upgrade. Returns true iff at least one entry was migrated.
5
13
  */
6
- export declare function migrateCreativeMcpEntries(root: string, platform: NodeJS.Platform, log?: (m: string) => void): boolean;
14
+ export declare function migrateCreativeMcpEntries(root: string, platform: NodeJS.Platform, log?: (m: string) => void, opts?: MigrateOpts): boolean;