@gtkx/cli 0.20.0 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -0
- package/bin/gtkx-dev-runner.js +9 -0
- package/dist/builder.d.ts +2 -50
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +22 -48
- package/dist/builder.js.map +1 -1
- package/dist/cli.d.ts +1 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -124
- package/dist/cli.js.map +1 -1
- package/dist/codegen/freshness.d.ts +11 -0
- package/dist/codegen/freshness.d.ts.map +1 -0
- package/dist/codegen/freshness.js +42 -0
- package/dist/codegen/freshness.js.map +1 -0
- package/dist/codegen/report.d.ts +3 -0
- package/dist/codegen/report.d.ts.map +1 -0
- package/dist/codegen/report.js +16 -0
- package/dist/codegen/report.js.map +1 -0
- package/dist/codegen/run-codegen.d.ts +35 -0
- package/dist/codegen/run-codegen.d.ts.map +1 -0
- package/dist/codegen/run-codegen.js +133 -0
- package/dist/codegen/run-codegen.js.map +1 -0
- package/dist/codegen/store-resolver.d.ts +21 -0
- package/dist/codegen/store-resolver.d.ts.map +1 -0
- package/dist/codegen/store-resolver.js +52 -0
- package/dist/codegen/store-resolver.js.map +1 -0
- package/dist/commands/build.d.ts +9 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +33 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/codegen.d.ts +9 -0
- package/dist/commands/codegen.d.ts.map +1 -0
- package/dist/commands/codegen.js +40 -0
- package/dist/commands/codegen.js.map +1 -0
- package/dist/commands/dev.d.ts +5 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +21 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/docs.d.ts +19 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +59 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/dev/icon-dir.d.ts +2 -0
- package/dist/dev/icon-dir.d.ts.map +1 -0
- package/dist/dev/icon-dir.js +13 -0
- package/dist/dev/icon-dir.js.map +1 -0
- package/dist/dev/refresh-tracker.d.ts +6 -0
- package/dist/dev/refresh-tracker.d.ts.map +1 -0
- package/dist/dev/refresh-tracker.js +18 -0
- package/dist/dev/refresh-tracker.js.map +1 -0
- package/dist/dev/runner-deps.d.ts +3 -0
- package/dist/dev/runner-deps.d.ts.map +1 -0
- package/dist/dev/runner-deps.js +39 -0
- package/dist/dev/runner-deps.js.map +1 -0
- package/dist/dev/runner-main.d.ts +2 -0
- package/dist/dev/runner-main.d.ts.map +1 -0
- package/dist/dev/runner-main.js +28 -0
- package/dist/dev/runner-main.js.map +1 -0
- package/dist/dev/runner.d.ts +23 -0
- package/dist/dev/runner.d.ts.map +1 -0
- package/dist/dev/runner.js +88 -0
- package/dist/dev/runner.js.map +1 -0
- package/dist/dev/schema-dir.d.ts +2 -0
- package/dist/dev/schema-dir.d.ts.map +1 -0
- package/dist/dev/schema-dir.js +10 -0
- package/dist/dev/schema-dir.js.map +1 -0
- package/dist/dev/supervisor.d.ts +17 -0
- package/dist/dev/supervisor.d.ts.map +1 -0
- package/dist/dev/supervisor.js +142 -0
- package/dist/dev/supervisor.js.map +1 -0
- package/dist/dev/vite-dev-server.d.ts +21 -0
- package/dist/dev/vite-dev-server.d.ts.map +1 -0
- package/dist/dev/vite-dev-server.js +12 -0
- package/dist/dev/vite-dev-server.js.map +1 -0
- package/dist/internal/banner.d.ts +3 -0
- package/dist/internal/banner.d.ts.map +1 -0
- package/dist/internal/banner.js +8 -0
- package/dist/internal/banner.js.map +1 -0
- package/dist/internal/data-dir.d.ts +3 -0
- package/dist/internal/data-dir.d.ts.map +1 -0
- package/dist/internal/data-dir.js +37 -0
- package/dist/internal/data-dir.js.map +1 -0
- package/dist/internal/entry-arg.d.ts +19 -0
- package/dist/internal/entry-arg.d.ts.map +1 -0
- package/dist/internal/entry-arg.js +33 -0
- package/dist/internal/entry-arg.js.map +1 -0
- package/dist/internal/errors.d.ts +4 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +27 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/list-files.d.ts +6 -0
- package/dist/internal/list-files.d.ts.map +1 -0
- package/dist/internal/list-files.js +13 -0
- package/dist/internal/list-files.js.map +1 -0
- package/dist/internal/resolve-cli-tool.d.ts +2 -0
- package/dist/internal/resolve-cli-tool.d.ts.map +1 -0
- package/dist/internal/resolve-cli-tool.js +20 -0
- package/dist/internal/resolve-cli-tool.js.map +1 -0
- package/dist/internal/staging-dir.d.ts +3 -0
- package/dist/internal/staging-dir.d.ts.map +1 -0
- package/dist/internal/staging-dir.js +16 -0
- package/dist/internal/staging-dir.js.map +1 -0
- package/dist/internal/xdg-data-dirs.d.ts +2 -0
- package/dist/internal/xdg-data-dirs.d.ts.map +1 -0
- package/dist/internal/xdg-data-dirs.js +8 -0
- package/dist/internal/xdg-data-dirs.js.map +1 -0
- package/dist/mcp/client.d.ts +23 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +157 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/handlers.d.ts +8 -0
- package/dist/mcp/handlers.d.ts.map +1 -0
- package/dist/mcp/handlers.js +119 -0
- package/dist/mcp/handlers.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +17 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/serialize-widget.d.ts +10 -0
- package/dist/mcp/serialize-widget.d.ts.map +1 -0
- package/dist/mcp/serialize-widget.js +20 -0
- package/dist/mcp/serialize-widget.js.map +1 -0
- package/dist/mcp/testing-loader.d.ts +6 -0
- package/dist/mcp/testing-loader.d.ts.map +1 -0
- package/dist/mcp/testing-loader.js +25 -0
- package/dist/mcp/testing-loader.js.map +1 -0
- package/dist/mcp/widget-registry.d.ts +13 -0
- package/dist/mcp/widget-registry.d.ts.map +1 -0
- package/dist/mcp/widget-registry.js +38 -0
- package/dist/mcp/widget-registry.js.map +1 -0
- package/dist/refresh-runtime.d.ts +10 -20
- package/dist/refresh-runtime.d.ts.map +1 -1
- package/dist/refresh-runtime.js +12 -36
- package/dist/refresh-runtime.js.map +1 -1
- package/dist/settings/compile.d.ts +2 -0
- package/dist/settings/compile.d.ts.map +1 -0
- package/dist/settings/compile.js +19 -0
- package/dist/settings/compile.js.map +1 -0
- package/dist/settings/parser.d.ts +23 -0
- package/dist/settings/parser.d.ts.map +1 -0
- package/dist/settings/parser.js +117 -0
- package/dist/settings/parser.js.map +1 -0
- package/dist/settings/render.d.ts +4 -0
- package/dist/settings/render.d.ts.map +1 -0
- package/dist/settings/render.js +148 -0
- package/dist/settings/render.js.map +1 -0
- package/dist/settings/schema.d.ts +13 -0
- package/dist/settings/schema.d.ts.map +1 -0
- package/dist/settings/schema.js +103 -0
- package/dist/settings/schema.js.map +1 -0
- package/dist/vite-plugins/asset-extensions.d.ts +4 -0
- package/dist/vite-plugins/asset-extensions.d.ts.map +1 -0
- package/dist/vite-plugins/asset-extensions.js +27 -0
- package/dist/vite-plugins/asset-extensions.js.map +1 -0
- package/dist/vite-plugins/built-url.d.ts +3 -0
- package/dist/vite-plugins/built-url.d.ts.map +1 -0
- package/dist/{vite-plugin-gtkx-built-url.js → vite-plugins/built-url.js} +4 -17
- package/dist/vite-plugins/built-url.js.map +1 -0
- package/dist/vite-plugins/css.d.ts +3 -0
- package/dist/vite-plugins/css.d.ts.map +1 -0
- package/dist/vite-plugins/css.js +30 -0
- package/dist/vite-plugins/css.js.map +1 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +7 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.js +15 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +5 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.js +66 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -0
- package/dist/vite-plugins/icons.d.ts +3 -0
- package/dist/vite-plugins/icons.d.ts.map +1 -0
- package/dist/vite-plugins/icons.js +47 -0
- package/dist/vite-plugins/icons.js.map +1 -0
- package/dist/vite-plugins/index.d.ts +3 -0
- package/dist/vite-plugins/index.d.ts.map +1 -0
- package/dist/vite-plugins/index.js +21 -0
- package/dist/vite-plugins/index.js.map +1 -0
- package/dist/vite-plugins/native.d.ts +3 -0
- package/dist/vite-plugins/native.d.ts.map +1 -0
- package/dist/vite-plugins/native.js +60 -0
- package/dist/vite-plugins/native.js.map +1 -0
- package/dist/vite-plugins/react-compiler.d.ts +4 -0
- package/dist/vite-plugins/react-compiler.d.ts.map +1 -0
- package/dist/vite-plugins/react-compiler.js +56 -0
- package/dist/vite-plugins/react-compiler.js.map +1 -0
- package/dist/vite-plugins/react-dom-prebundle.d.ts +3 -0
- package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -0
- package/dist/vite-plugins/react-dom-prebundle.js +11 -0
- package/dist/vite-plugins/react-dom-prebundle.js.map +1 -0
- package/dist/vite-plugins/resource-init-module.d.ts +5 -0
- package/dist/vite-plugins/resource-init-module.d.ts.map +1 -0
- package/dist/vite-plugins/resource-init-module.js +50 -0
- package/dist/vite-plugins/resource-init-module.js.map +1 -0
- package/dist/vite-plugins/resource-shared.d.ts +6 -0
- package/dist/vite-plugins/resource-shared.d.ts.map +1 -0
- package/dist/vite-plugins/resource-shared.js +21 -0
- package/dist/vite-plugins/resource-shared.js.map +1 -0
- package/dist/vite-plugins/resources.d.ts +4 -0
- package/dist/vite-plugins/resources.d.ts.map +1 -0
- package/dist/vite-plugins/resources.js +220 -0
- package/dist/vite-plugins/resources.js.map +1 -0
- package/dist/vite-plugins/settings-worker-env.d.ts +3 -0
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -0
- package/dist/vite-plugins/settings-worker-env.js +21 -0
- package/dist/vite-plugins/settings-worker-env.js.map +1 -0
- package/dist/vite-plugins/settings.d.ts +3 -0
- package/dist/vite-plugins/settings.d.ts.map +1 -0
- package/dist/vite-plugins/settings.js +190 -0
- package/dist/vite-plugins/settings.js.map +1 -0
- package/dist/vite-plugins/undeclared-library.d.ts +3 -0
- package/dist/vite-plugins/undeclared-library.d.ts.map +1 -0
- package/dist/vite-plugins/undeclared-library.js +47 -0
- package/dist/vite-plugins/undeclared-library.js.map +1 -0
- package/dist/vite-plugins/virtual-module.d.ts +22 -0
- package/dist/vite-plugins/virtual-module.d.ts.map +1 -0
- package/dist/vite-plugins/virtual-module.js +18 -0
- package/dist/vite-plugins/virtual-module.js.map +1 -0
- package/dist/vitest-plugin.d.ts +10 -0
- package/dist/vitest-plugin.d.ts.map +1 -0
- package/dist/vitest-plugin.js +12 -0
- package/dist/vitest-plugin.js.map +1 -0
- package/env.d.ts +131 -3
- package/package.json +32 -38
- package/src/babel-modules.d.ts +13 -0
- package/src/builder.ts +28 -76
- package/src/cli.ts +22 -0
- package/src/codegen/freshness.ts +52 -0
- package/src/codegen/report.ts +20 -0
- package/src/codegen/run-codegen.ts +185 -0
- package/src/codegen/store-resolver.ts +75 -0
- package/src/commands/build.ts +37 -0
- package/src/commands/codegen.ts +44 -0
- package/src/commands/dev.ts +25 -0
- package/src/commands/docs.ts +66 -0
- package/src/dev/icon-dir.ts +11 -0
- package/src/dev/refresh-tracker.ts +21 -0
- package/src/dev/runner-deps.ts +42 -0
- package/src/dev/runner-main.ts +33 -0
- package/src/dev/runner.ts +126 -0
- package/src/dev/schema-dir.ts +11 -0
- package/src/dev/supervisor.ts +178 -0
- package/src/dev/vite-dev-server.ts +34 -0
- package/src/internal/banner.ts +9 -0
- package/src/internal/data-dir.ts +39 -0
- package/src/internal/entry-arg.ts +38 -0
- package/src/internal/errors.ts +28 -0
- package/src/internal/list-files.ts +17 -0
- package/src/internal/resolve-cli-tool.ts +21 -0
- package/src/internal/staging-dir.ts +16 -0
- package/src/internal/xdg-data-dirs.ts +7 -0
- package/src/mcp/client.ts +177 -0
- package/src/mcp/handlers.ts +156 -0
- package/src/mcp/index.ts +22 -0
- package/src/mcp/serialize-widget.ts +34 -0
- package/src/mcp/testing-loader.ts +32 -0
- package/src/mcp/widget-registry.ts +43 -0
- package/src/refresh-runtime.ts +12 -41
- package/src/settings/compile.ts +19 -0
- package/src/settings/parser.ts +154 -0
- package/src/settings/render.ts +167 -0
- package/src/settings/schema.ts +115 -0
- package/src/vite-plugins/asset-extensions.ts +28 -0
- package/src/{vite-plugin-gtkx-built-url.ts → vite-plugins/built-url.ts} +3 -16
- package/src/vite-plugins/css.ts +38 -0
- package/src/vite-plugins/fast-refresh/refresh-filter.ts +18 -0
- package/src/vite-plugins/fast-refresh/swc-refresh.ts +79 -0
- package/src/vite-plugins/icons.ts +58 -0
- package/src/vite-plugins/index.ts +22 -0
- package/src/vite-plugins/native.ts +74 -0
- package/src/vite-plugins/react-compiler.ts +70 -0
- package/src/vite-plugins/react-dom-prebundle.ts +14 -0
- package/src/vite-plugins/resource-init-module.ts +54 -0
- package/src/vite-plugins/resource-shared.ts +27 -0
- package/src/vite-plugins/resources.ts +272 -0
- package/src/vite-plugins/settings-worker-env.ts +25 -0
- package/src/vite-plugins/settings.ts +221 -0
- package/src/vite-plugins/undeclared-library.ts +69 -0
- package/src/vite-plugins/virtual-module.ts +37 -0
- package/src/vitest-plugin.ts +14 -0
- package/dist/create.d.ts +0 -54
- package/dist/create.d.ts.map +0 -1
- package/dist/create.js +0 -221
- package/dist/create.js.map +0 -1
- package/dist/dev-server.d.ts +0 -38
- package/dist/dev-server.d.ts.map +0 -1
- package/dist/dev-server.js +0 -128
- package/dist/dev-server.js.map +0 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -31
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -430
- package/dist/mcp-client.js.map +0 -1
- package/dist/templates.d.ts +0 -9
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js +0 -16
- package/dist/templates.js.map +0 -1
- package/dist/vite-plugin-gtkx-assets.d.ts +0 -20
- package/dist/vite-plugin-gtkx-assets.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-assets.js +0 -57
- package/dist/vite-plugin-gtkx-assets.js.map +0 -1
- package/dist/vite-plugin-gtkx-built-url.d.ts +0 -18
- package/dist/vite-plugin-gtkx-built-url.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-built-url.js.map +0 -1
- package/dist/vite-plugin-gtkx-native.d.ts +0 -14
- package/dist/vite-plugin-gtkx-native.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-native.js +0 -53
- package/dist/vite-plugin-gtkx-native.js.map +0 -1
- package/dist/vite-plugin-gtkx-refresh.d.ts +0 -8
- package/dist/vite-plugin-gtkx-refresh.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-refresh.js +0 -37
- package/dist/vite-plugin-gtkx-refresh.js.map +0 -1
- package/dist/vite-plugin-swc-ssr-refresh.d.ts +0 -8
- package/dist/vite-plugin-swc-ssr-refresh.d.ts.map +0 -1
- package/dist/vite-plugin-swc-ssr-refresh.js +0 -46
- package/dist/vite-plugin-swc-ssr-refresh.js.map +0 -1
- package/src/cli.tsx +0 -154
- package/src/create.ts +0 -310
- package/src/dev-server.tsx +0 -162
- package/src/index.ts +0 -3
- package/src/mcp-client.ts +0 -518
- package/src/templates.ts +0 -26
- package/src/vite-plugin-gtkx-assets.ts +0 -69
- package/src/vite-plugin-gtkx-native.ts +0 -64
- package/src/vite-plugin-gtkx-refresh.ts +0 -54
- package/src/vite-plugin-swc-ssr-refresh.ts +0 -61
- package/templates/claude/EXAMPLES.md.ejs +0 -744
- package/templates/claude/SKILL.md.ejs +0 -93
- package/templates/claude/WIDGETS.md.ejs +0 -820
- package/templates/config/vitest.config.ts.ejs +0 -11
- package/templates/gitignore.ejs +0 -4
- package/templates/package.json.ejs +0 -16
- package/templates/src/app.tsx.ejs +0 -32
- package/templates/src/dev.tsx.ejs +0 -5
- package/templates/src/gtkx-env.d.ts.ejs +0 -1
- package/templates/src/index.tsx.ejs +0 -5
- package/templates/tests/app.test.tsx.ejs +0 -16
- package/templates/tsconfig.json.ejs +0 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-arg.js","sourceRoot":"","sources":["../../src/internal/entry-arg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,kBAAkB,GAAG,WAAW,CAAC;AACvC,MAAM,wBAAwB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAChE,MAAM,aAAa,GAAG,GAAG,kBAAkB,IAAI,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAErF,MAAM,CAAC,MAAM,MAAM,GAA0B;IACzC,GAAG,EAAE;QACD,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,mDAAmD;KACnE;CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAmD;IACpE,KAAK,EAAE;QACH,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,wBAAwB,aAAa,GAAG;QACrD,QAAQ,EAAE,KAAK;KAClB;IACD,GAAG,MAAM;CACZ,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAsB,EAAU,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAE7G,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAU,EAAE;IAChD,KAAK,MAAM,SAAS,IAAI,wBAAwB,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,kBAAkB,GAAG,SAAS,EAAE,CAAC,CAAC;QACpE,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAChD,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,kBAAkB,GAAG,wBAAwB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAsC,EAAkC,EAAE;IACnG,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;AAC5F,CAAC,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { PositionalArgDef, StringArgDef } from \"citty\";\n\nconst DEFAULT_ENTRY_BASE = \"src/index\";\nconst DEFAULT_ENTRY_EXTENSIONS = [\".tsx\", \".jsx\", \".ts\", \".js\"];\nconst DEFAULT_ENTRY = `${DEFAULT_ENTRY_BASE}{${DEFAULT_ENTRY_EXTENSIONS.join(\",\")}}`;\n\nexport const cwdArg: { cwd: StringArgDef } = {\n cwd: {\n type: \"string\",\n description: \"Project root (default: current working directory)\",\n },\n};\n\nexport const entryArg: { entry: PositionalArgDef; cwd: StringArgDef } = {\n entry: {\n type: \"positional\",\n description: `Entry file (default: ${DEFAULT_ENTRY})`,\n required: false,\n },\n ...cwdArg,\n};\n\nexport const resolveCwd = (args: { cwd?: string }): string => (args.cwd ? resolve(args.cwd) : process.cwd());\n\nconst resolveDefaultEntry = (cwd: string): string => {\n for (const extension of DEFAULT_ENTRY_EXTENSIONS) {\n const candidate = resolve(cwd, `${DEFAULT_ENTRY_BASE}${extension}`);\n if (existsSync(candidate)) return candidate;\n }\n return resolve(cwd, `${DEFAULT_ENTRY_BASE}${DEFAULT_ENTRY_EXTENSIONS[0]}`);\n};\n\nexport const resolveEntry = (args: { entry?: string; cwd?: string }): { cwd: string; entry: string } => {\n const cwd = resolveCwd(args);\n return { cwd, entry: args.entry ? resolve(cwd, args.entry) : resolveDefaultEntry(cwd) };\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAIjD,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAO3C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,OAAO,WAAW,UAAU,CAAC,CAAC,CAAC,KAAG,UAAU,CAAC,CAAC,CAazF,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { logger } from "@gtkx/utils";
|
|
2
|
+
const ERROR_EXIT_CODE = 1;
|
|
3
|
+
export const printError = (cause) => {
|
|
4
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
5
|
+
logger.error(message);
|
|
6
|
+
if (cause instanceof Error && cause.stack !== undefined) {
|
|
7
|
+
logger.debug(cause.stack);
|
|
8
|
+
}
|
|
9
|
+
process.exit(ERROR_EXIT_CODE);
|
|
10
|
+
};
|
|
11
|
+
export const withErrorBoundary = (command) => {
|
|
12
|
+
const run = command.run;
|
|
13
|
+
if (run === undefined)
|
|
14
|
+
return command;
|
|
15
|
+
return {
|
|
16
|
+
...command,
|
|
17
|
+
run: async (context) => {
|
|
18
|
+
try {
|
|
19
|
+
return await run(context);
|
|
20
|
+
}
|
|
21
|
+
catch (cause) {
|
|
22
|
+
printError(cause);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAc,EAAS,EAAE;IAChD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtB,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAoB,OAAsB,EAAiB,EAAE;IAC1F,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACtC,OAAO;QACH,GAAG,OAAO;QACV,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACnB,IAAI,CAAC;gBACD,OAAO,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,UAAU,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACL,CAAC;KACJ,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { logger } from \"@gtkx/utils\";\nimport type { ArgsDef, CommandDef } from \"citty\";\n\nconst ERROR_EXIT_CODE = 1;\n\nexport const printError = (cause: unknown): never => {\n const message = cause instanceof Error ? cause.message : String(cause);\n logger.error(message);\n if (cause instanceof Error && cause.stack !== undefined) {\n logger.debug(cause.stack);\n }\n process.exit(ERROR_EXIT_CODE);\n};\n\nexport const withErrorBoundary = <T extends ArgsDef>(command: CommandDef<T>): CommandDef<T> => {\n const run = command.run;\n if (run === undefined) return command;\n return {\n ...command,\n run: async (context) => {\n try {\n return await run(context);\n } catch (cause) {\n printError(cause);\n }\n },\n };\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-files.d.ts","sourceRoot":"","sources":["../../src/internal/list-files.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,MAAM,cAAc,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,KAAG,UAAU,EAQjG,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
export const listFilesRecursive = (dir, predicate) => {
|
|
4
|
+
if (!existsSync(dir))
|
|
5
|
+
return [];
|
|
6
|
+
return readdirSync(dir, { recursive: true, withFileTypes: true })
|
|
7
|
+
.filter((entry) => entry.isFile() && (predicate === undefined || predicate(entry.name)))
|
|
8
|
+
.map((entry) => {
|
|
9
|
+
const absPath = join(entry.parentPath, entry.name);
|
|
10
|
+
return { absPath, rel: relative(dir, absPath) };
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=list-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-files.js","sourceRoot":"","sources":["../../src/internal/list-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAO3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAE,SAAqC,EAAgB,EAAE;IACnG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC5D,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;SACvF,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACX,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;IACpD,CAAC,CAAC,CAAC;AACX,CAAC,CAAC","sourcesContent":["import { existsSync, readdirSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\n\nexport type ListedFile = {\n absPath: string;\n rel: string;\n};\n\nexport const listFilesRecursive = (dir: string, predicate?: (name: string) => boolean): ListedFile[] => {\n if (!existsSync(dir)) return [];\n return readdirSync(dir, { recursive: true, withFileTypes: true })\n .filter((entry) => entry.isFile() && (predicate === undefined || predicate(entry.name)))\n .map((entry) => {\n const absPath = join(entry.parentPath, entry.name);\n return { absPath, rel: relative(dir, absPath) };\n });\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-cli-tool.d.ts","sourceRoot":"","sources":["../../src/internal/resolve-cli-tool.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,cAAc,eAGH,MAAM,KAAG,MAc7B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import { delimiter, join } from "node:path";
|
|
3
|
+
export const resolveCliTool = (() => {
|
|
4
|
+
const cache = new Map();
|
|
5
|
+
return (executable) => {
|
|
6
|
+
const cached = cache.get(executable);
|
|
7
|
+
if (cached)
|
|
8
|
+
return cached;
|
|
9
|
+
const dirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
10
|
+
for (const dir of dirs) {
|
|
11
|
+
const candidate = join(dir, executable);
|
|
12
|
+
if (existsSync(candidate) && statSync(candidate).isFile()) {
|
|
13
|
+
cache.set(executable, candidate);
|
|
14
|
+
return candidate;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`${executable} not found in PATH`);
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
//# sourceMappingURL=resolve-cli-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-cli-tool.js","sourceRoot":"","sources":["../../src/internal/resolve-cli-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE;IAChC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAExC,OAAO,CAAC,UAAkB,EAAU,EAAE;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAE1B,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YACxC,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBACxD,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBACjC,OAAO,SAAS,CAAC;YACrB,CAAC;QACL,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,oBAAoB,CAAC,CAAC;IACvD,CAAC,CAAC;AACN,CAAC,CAAC,EAAE,CAAC","sourcesContent":["import { existsSync, statSync } from \"node:fs\";\nimport { delimiter, join } from \"node:path\";\n\nexport const resolveCliTool = (() => {\n const cache = new Map<string, string>();\n\n return (executable: string): string => {\n const cached = cache.get(executable);\n if (cached) return cached;\n\n const dirs = (process.env.PATH ?? \"\").split(delimiter).filter(Boolean);\n for (const dir of dirs) {\n const candidate = join(dir, executable);\n if (existsSync(candidate) && statSync(candidate).isFile()) {\n cache.set(executable, candidate);\n return candidate;\n }\n }\n throw new Error(`${executable} not found in PATH`);\n };\n})();\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging-dir.d.ts","sourceRoot":"","sources":["../../src/internal/staging-dir.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,aAAa,QAAS,MAAM,KAAG,IAE3C,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,CAAC,UAAU,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,KAAG,CAO/E,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export const removeTempDir = (dir) => {
|
|
5
|
+
rmSync(dir, { recursive: true, force: true, maxRetries: 5 });
|
|
6
|
+
};
|
|
7
|
+
export const withStagingDir = (prefix, produce) => {
|
|
8
|
+
const dir = mkdtempSync(join(tmpdir(), `gtkx-${prefix}-`));
|
|
9
|
+
try {
|
|
10
|
+
return produce(dir);
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
removeTempDir(dir);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=staging-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging-dir.js","sourceRoot":"","sources":["../../src/internal/staging-dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAQ,EAAE;IAC/C,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAI,MAAc,EAAE,OAA2B,EAAK,EAAE;IAChF,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,QAAQ,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,IAAI,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;YAAS,CAAC;QACP,aAAa,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { mkdtempSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const removeTempDir = (dir: string): void => {\n rmSync(dir, { recursive: true, force: true, maxRetries: 5 });\n};\n\nexport const withStagingDir = <T>(prefix: string, produce: (dir: string) => T): T => {\n const dir = mkdtempSync(join(tmpdir(), `gtkx-${prefix}-`));\n try {\n return produce(dir);\n } finally {\n removeTempDir(dir);\n }\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xdg-data-dirs.d.ts","sourceRoot":"","sources":["../../src/internal/xdg-data-dirs.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,QAAS,MAAM,YAAY,MAAM,GAAG,SAAS,KAAG,MAI7E,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const XDG_DATA_DIRS_DEFAULT = "/usr/local/share:/usr/share";
|
|
2
|
+
export const prependXdgDataDir = (dir, existing) => {
|
|
3
|
+
const base = existing === undefined || existing.length === 0 ? XDG_DATA_DIRS_DEFAULT : existing;
|
|
4
|
+
if (base.split(":").includes(dir))
|
|
5
|
+
return base;
|
|
6
|
+
return `${dir}:${base}`;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=xdg-data-dirs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xdg-data-dirs.js","sourceRoot":"","sources":["../../src/internal/xdg-data-dirs.ts"],"names":[],"mappings":"AAAA,MAAM,qBAAqB,GAAG,6BAA6B,CAAC;AAE5D,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAE,QAA4B,EAAU,EAAE;IACnF,MAAM,IAAI,GAAG,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC;IAChG,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;AAC5B,CAAC,CAAC","sourcesContent":["const XDG_DATA_DIRS_DEFAULT = \"/usr/local/share:/usr/share\";\n\nexport const prependXdgDataDir = (dir: string, existing: string | undefined): string => {\n const base = existing === undefined || existing.length === 0 ? XDG_DATA_DIRS_DEFAULT : existing;\n if (base.split(\":\").includes(dir)) return base;\n return `${dir}:${base}`;\n};\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type McpClientOptions = {
|
|
2
|
+
socketPath?: string;
|
|
3
|
+
applicationId: string;
|
|
4
|
+
};
|
|
5
|
+
export declare class McpClient {
|
|
6
|
+
private socket;
|
|
7
|
+
private connection;
|
|
8
|
+
private socketPath;
|
|
9
|
+
private applicationId;
|
|
10
|
+
private reconnectTimer;
|
|
11
|
+
private hasConnected;
|
|
12
|
+
private isStopping;
|
|
13
|
+
private pendingConnectReject;
|
|
14
|
+
private registry;
|
|
15
|
+
constructor(options: McpClientOptions);
|
|
16
|
+
connect(): Promise<void>;
|
|
17
|
+
disconnect(): void;
|
|
18
|
+
private attemptConnect;
|
|
19
|
+
private scheduleReconnect;
|
|
20
|
+
private register;
|
|
21
|
+
private handleRequest;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,gBAAgB,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAKF,qBAAa,SAAS;IAClB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,oBAAoB,CAAyC;IACrE,OAAO,CAAC,QAAQ,CAAwB;IAExC,YAAY,OAAO,EAAE,gBAAgB,EAGpC;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAc7B;IAED,UAAU,IAAI,IAAI,CAkBjB;IAED,OAAO,CAAC,cAAc;IA0DtB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,QAAQ;YAeF,aAAa;CA2B9B"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import * as net from "node:net";
|
|
2
|
+
import * as Gio from "@gtkx/gi/gio";
|
|
3
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
|
+
import { DEFAULT_SOCKET_PATH, ErrorCode, ProtocolConnection, ProtocolError } from "@gtkx/mcp/internal";
|
|
5
|
+
import { error, errorMessage, info, normalizeError, warn } from "@gtkx/utils";
|
|
6
|
+
import { dispatch } from "./handlers.js";
|
|
7
|
+
import { WidgetRegistry } from "./widget-registry.js";
|
|
8
|
+
const RECONNECT_DELAY_MS = 2000;
|
|
9
|
+
const REGISTER_TIMEOUT_MS = 30000;
|
|
10
|
+
export class McpClient {
|
|
11
|
+
socket = null;
|
|
12
|
+
connection = null;
|
|
13
|
+
socketPath;
|
|
14
|
+
applicationId;
|
|
15
|
+
reconnectTimer = null;
|
|
16
|
+
hasConnected = false;
|
|
17
|
+
isStopping = false;
|
|
18
|
+
pendingConnectReject = null;
|
|
19
|
+
registry = new WidgetRegistry();
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;
|
|
22
|
+
this.applicationId = options.applicationId;
|
|
23
|
+
}
|
|
24
|
+
async connect() {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
this.pendingConnectReject = reject;
|
|
27
|
+
this.attemptConnect(() => {
|
|
28
|
+
this.pendingConnectReject = null;
|
|
29
|
+
resolve();
|
|
30
|
+
}, (error) => {
|
|
31
|
+
this.pendingConnectReject = null;
|
|
32
|
+
reject(error);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
disconnect() {
|
|
37
|
+
this.isStopping = true;
|
|
38
|
+
if (this.pendingConnectReject) {
|
|
39
|
+
this.pendingConnectReject(new Error("Client disconnected before connection registered"));
|
|
40
|
+
this.pendingConnectReject = null;
|
|
41
|
+
}
|
|
42
|
+
if (this.reconnectTimer) {
|
|
43
|
+
clearTimeout(this.reconnectTimer);
|
|
44
|
+
this.reconnectTimer = null;
|
|
45
|
+
}
|
|
46
|
+
this.connection?.rejectPending(new Error("Client disconnected"));
|
|
47
|
+
if (this.socket) {
|
|
48
|
+
this.connection?.write({ id: crypto.randomUUID(), method: "app.unregister" });
|
|
49
|
+
this.socket.destroy();
|
|
50
|
+
this.socket = null;
|
|
51
|
+
}
|
|
52
|
+
this.connection = null;
|
|
53
|
+
this.hasConnected = false;
|
|
54
|
+
}
|
|
55
|
+
attemptConnect(onSuccess, onError) {
|
|
56
|
+
let settled = false;
|
|
57
|
+
const settle = (callback, ...args) => {
|
|
58
|
+
if (settled)
|
|
59
|
+
return;
|
|
60
|
+
settled = true;
|
|
61
|
+
callback?.(...args);
|
|
62
|
+
};
|
|
63
|
+
const socket = net.createConnection(this.socketPath, () => {
|
|
64
|
+
info(`Connected to MCP server at ${this.socketPath}`);
|
|
65
|
+
this.hasConnected = true;
|
|
66
|
+
this.register()
|
|
67
|
+
.then(() => {
|
|
68
|
+
info("Registered with MCP server");
|
|
69
|
+
settle(onSuccess);
|
|
70
|
+
})
|
|
71
|
+
.catch((cause) => {
|
|
72
|
+
error("Failed to register with MCP server:", cause.message);
|
|
73
|
+
settle(onError, normalizeError(cause));
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
const connection = ProtocolConnection.fromSocket(socket, {
|
|
77
|
+
onClose: () => {
|
|
78
|
+
if (this.hasConnected) {
|
|
79
|
+
info("Disconnected from MCP server");
|
|
80
|
+
this.hasConnected = false;
|
|
81
|
+
}
|
|
82
|
+
this.socket = null;
|
|
83
|
+
this.connection = null;
|
|
84
|
+
this.scheduleReconnect();
|
|
85
|
+
},
|
|
86
|
+
onError: (socketError) => {
|
|
87
|
+
const code = socketError.code;
|
|
88
|
+
const isDisconnectError = code === "ENOENT" || code === "ECONNREFUSED" || code === "EPIPE" || code === "ECONNRESET";
|
|
89
|
+
if (isDisconnectError) {
|
|
90
|
+
this.scheduleReconnect();
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
error("Socket error:", socketError.message);
|
|
94
|
+
}
|
|
95
|
+
settle(onError, socketError);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
connection.on("request", (request) => {
|
|
99
|
+
this.handleRequest(request).catch((cause) => {
|
|
100
|
+
error("Error handling request:", cause);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
connection.on("invalid", ({ error: parseError }) => {
|
|
104
|
+
warn(`Received invalid JSON from MCP server: ${parseError.message}`);
|
|
105
|
+
});
|
|
106
|
+
this.socket = socket;
|
|
107
|
+
this.connection = connection;
|
|
108
|
+
}
|
|
109
|
+
scheduleReconnect() {
|
|
110
|
+
if (this.reconnectTimer || this.isStopping)
|
|
111
|
+
return;
|
|
112
|
+
this.reconnectTimer = setTimeout(() => {
|
|
113
|
+
this.reconnectTimer = null;
|
|
114
|
+
this.attemptConnect();
|
|
115
|
+
}, RECONNECT_DELAY_MS);
|
|
116
|
+
}
|
|
117
|
+
register() {
|
|
118
|
+
if (!this.connection) {
|
|
119
|
+
return Promise.reject(new Error("Connection not initialized"));
|
|
120
|
+
}
|
|
121
|
+
return this.connection.send("app.register", {
|
|
122
|
+
applicationId: this.applicationId,
|
|
123
|
+
pid: process.pid,
|
|
124
|
+
projectRoot: process.cwd(),
|
|
125
|
+
}, REGISTER_TIMEOUT_MS);
|
|
126
|
+
}
|
|
127
|
+
async handleRequest(request) {
|
|
128
|
+
const { id, method, params } = request;
|
|
129
|
+
const connection = this.connection;
|
|
130
|
+
if (!connection)
|
|
131
|
+
return;
|
|
132
|
+
try {
|
|
133
|
+
const defaultApp = Gio.Application.getDefault();
|
|
134
|
+
if (!(defaultApp instanceof Gtk.Application)) {
|
|
135
|
+
throw new TypeError("Application not initialized");
|
|
136
|
+
}
|
|
137
|
+
this.registry.refresh();
|
|
138
|
+
const result = await dispatch(method, params, { app: defaultApp, registry: this.registry });
|
|
139
|
+
connection.write({ id, result });
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof ProtocolError) {
|
|
143
|
+
connection.write({ id, error: error.toErrorObject() });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
connection.write({
|
|
147
|
+
id,
|
|
148
|
+
error: {
|
|
149
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
150
|
+
message: errorMessage(error),
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"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","sourcesContent":["import * as net from \"node:net\";\nimport * as Gio from \"@gtkx/gi/gio\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { DEFAULT_SOCKET_PATH, ErrorCode, ProtocolConnection, ProtocolError, type Request } from \"@gtkx/mcp/internal\";\nimport { error, errorMessage, info, normalizeError, warn } from \"@gtkx/utils\";\nimport { dispatch } from \"./handlers.js\";\nimport { WidgetRegistry } from \"./widget-registry.js\";\n\nexport type McpClientOptions = {\n socketPath?: string;\n applicationId: string;\n};\n\nconst RECONNECT_DELAY_MS = 2000;\nconst REGISTER_TIMEOUT_MS = 30000;\n\nexport class McpClient {\n private socket: net.Socket | null = null;\n private connection: ProtocolConnection | null = null;\n private socketPath: string;\n private applicationId: string;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private hasConnected = false;\n private isStopping = false;\n private pendingConnectReject: ((error: Error) => void) | null = null;\n private registry = new WidgetRegistry();\n\n constructor(options: McpClientOptions) {\n this.socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;\n this.applicationId = options.applicationId;\n }\n\n async connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.pendingConnectReject = reject;\n this.attemptConnect(\n () => {\n this.pendingConnectReject = null;\n resolve();\n },\n (error) => {\n this.pendingConnectReject = null;\n reject(error);\n },\n );\n });\n }\n\n disconnect(): void {\n this.isStopping = true;\n if (this.pendingConnectReject) {\n this.pendingConnectReject(new Error(\"Client disconnected before connection registered\"));\n this.pendingConnectReject = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.connection?.rejectPending(new Error(\"Client disconnected\"));\n if (this.socket) {\n this.connection?.write({ id: crypto.randomUUID(), method: \"app.unregister\" });\n this.socket.destroy();\n this.socket = null;\n }\n this.connection = null;\n this.hasConnected = false;\n }\n\n private attemptConnect(onSuccess?: () => void, onError?: (error: Error) => void): void {\n let settled = false;\n\n const settle = <T extends unknown[]>(callback: ((...args: T) => void) | undefined, ...args: T) => {\n if (settled) return;\n settled = true;\n callback?.(...args);\n };\n\n const socket = net.createConnection(this.socketPath, () => {\n info(`Connected to MCP server at ${this.socketPath}`);\n this.hasConnected = true;\n this.register()\n .then(() => {\n info(\"Registered with MCP server\");\n settle(onSuccess);\n })\n .catch((cause) => {\n error(\"Failed to register with MCP server:\", cause.message);\n settle(onError, normalizeError(cause));\n });\n });\n\n const connection = ProtocolConnection.fromSocket(socket, {\n onClose: () => {\n if (this.hasConnected) {\n info(\"Disconnected from MCP server\");\n this.hasConnected = false;\n }\n this.socket = null;\n this.connection = null;\n this.scheduleReconnect();\n },\n onError: (socketError) => {\n const code = (socketError as NodeJS.ErrnoException).code;\n const isDisconnectError =\n code === \"ENOENT\" || code === \"ECONNREFUSED\" || code === \"EPIPE\" || code === \"ECONNRESET\";\n if (isDisconnectError) {\n this.scheduleReconnect();\n } else {\n error(\"Socket error:\", socketError.message);\n }\n settle(onError, socketError);\n },\n });\n connection.on(\"request\", (request) => {\n this.handleRequest(request).catch((cause) => {\n error(\"Error handling request:\", cause);\n });\n });\n connection.on(\"invalid\", ({ error: parseError }) => {\n warn(`Received invalid JSON from MCP server: ${parseError.message}`);\n });\n\n this.socket = socket;\n this.connection = connection;\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer || this.isStopping) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.attemptConnect();\n }, RECONNECT_DELAY_MS);\n }\n\n private register(): Promise<unknown> {\n if (!this.connection) {\n return Promise.reject(new Error(\"Connection not initialized\"));\n }\n return this.connection.send(\n \"app.register\",\n {\n applicationId: this.applicationId,\n pid: process.pid,\n projectRoot: process.cwd(),\n },\n REGISTER_TIMEOUT_MS,\n );\n }\n\n private async handleRequest(request: Request): Promise<void> {\n const { id, method, params } = request;\n const connection = this.connection;\n if (!connection) return;\n\n try {\n const defaultApp = Gio.Application.getDefault();\n if (!(defaultApp instanceof Gtk.Application)) {\n throw new TypeError(\"Application not initialized\");\n }\n this.registry.refresh();\n const result = await dispatch(method, params, { app: defaultApp, registry: this.registry });\n connection.write({ id, result });\n } catch (error) {\n if (error instanceof ProtocolError) {\n connection.write({ id, error: error.toErrorObject() });\n } else {\n connection.write({\n id,\n error: {\n code: ErrorCode.INTERNAL_ERROR,\n message: errorMessage(error),\n },\n });\n }\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import type { WidgetRegistry } from "./widget-registry.js";
|
|
3
|
+
export type HandlerContext = {
|
|
4
|
+
app: Gtk.Application;
|
|
5
|
+
registry: WidgetRegistry;
|
|
6
|
+
};
|
|
7
|
+
export declare const dispatch: (method: string, params: unknown, ctx: HandlerContext) => Promise<unknown>;
|
|
8
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAYpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,cAAc,GAAG;IACzB,GAAG,EAAE,GAAG,CAAC,WAAW,CAAC;IACrB,QAAQ,EAAE,cAAc,CAAC;CAC5B,CAAC;AAmIF,eAAO,MAAM,QAAQ,WAAkB,MAAM,UAAU,OAAO,OAAO,cAAc,KAAG,OAAO,CAAC,OAAO,CAKpG,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
|
+
import { invalidRequestError, methodNotFoundError, ServerRequestParamsSchemas, widgetNotFoundError, } from "@gtkx/mcp/internal";
|
|
5
|
+
import { serializeWidget } from "./serialize-widget.js";
|
|
6
|
+
import { loadTestingModule } from "./testing-loader.js";
|
|
7
|
+
const validated = (schema, handler) => {
|
|
8
|
+
return (ctx, params) => {
|
|
9
|
+
const parsed = schema.safeParse(params ?? {});
|
|
10
|
+
if (!parsed.success) {
|
|
11
|
+
throw invalidRequestError(parsed.error.message);
|
|
12
|
+
}
|
|
13
|
+
return handler(ctx, parsed.data);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
const requireWidget = (registry, widgetId) => {
|
|
17
|
+
if (widgetId === undefined) {
|
|
18
|
+
throw widgetNotFoundError("undefined");
|
|
19
|
+
}
|
|
20
|
+
const widget = registry.get(widgetId);
|
|
21
|
+
if (!widget) {
|
|
22
|
+
throw widgetNotFoundError(widgetId);
|
|
23
|
+
}
|
|
24
|
+
return widget;
|
|
25
|
+
};
|
|
26
|
+
const extractSignalArg = (arg) => {
|
|
27
|
+
const isTypedArg = typeof arg === "object" && arg !== null && "type" in arg && "value" in arg;
|
|
28
|
+
return isTypedArg ? arg.value : arg;
|
|
29
|
+
};
|
|
30
|
+
const handleQuery = async ({ app, registry }, params) => {
|
|
31
|
+
const testing = await loadTestingModule();
|
|
32
|
+
let widgets = [];
|
|
33
|
+
switch (params.by) {
|
|
34
|
+
case "role": {
|
|
35
|
+
const roleValue = typeof params.value === "string"
|
|
36
|
+
? Gtk.AccessibleRole[params.value]
|
|
37
|
+
: params.value;
|
|
38
|
+
widgets = await testing.findAllByRole(app, roleValue, params.options);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case "text":
|
|
42
|
+
widgets = await testing.findAllByText(app, String(params.value), params.options);
|
|
43
|
+
break;
|
|
44
|
+
case "name":
|
|
45
|
+
widgets = await testing.findAllByName(app, String(params.value), params.options);
|
|
46
|
+
break;
|
|
47
|
+
case "labelText":
|
|
48
|
+
widgets = await testing.findAllByLabelText(app, String(params.value), params.options);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
return { widgets: widgets.map((w) => serializeWidget(w, (widget) => registry.idFor(widget), testing)) };
|
|
52
|
+
};
|
|
53
|
+
const defaultScreenshotTarget = (registry) => {
|
|
54
|
+
const [toplevel] = registry.toplevels();
|
|
55
|
+
if (!toplevel) {
|
|
56
|
+
throw new Error("No windows available for screenshot");
|
|
57
|
+
}
|
|
58
|
+
return toplevel;
|
|
59
|
+
};
|
|
60
|
+
const handleScreenshot = async ({ registry }, params) => {
|
|
61
|
+
const testing = await loadTestingModule();
|
|
62
|
+
const target = params.windowId ? requireWidget(registry, params.windowId) : defaultScreenshotTarget(registry);
|
|
63
|
+
const result = await testing.screenshot(target);
|
|
64
|
+
if (params.path) {
|
|
65
|
+
mkdirSync(dirname(params.path), { recursive: true });
|
|
66
|
+
writeFileSync(params.path, Buffer.from(result.data, "base64"));
|
|
67
|
+
return { data: result.data, mimeType: result.mimeType, savedPath: params.path };
|
|
68
|
+
}
|
|
69
|
+
return { data: result.data, mimeType: result.mimeType };
|
|
70
|
+
};
|
|
71
|
+
const HANDLERS = {
|
|
72
|
+
"app.getWindows": validated(ServerRequestParamsSchemas["app.getWindows"], async ({ registry }) => ({
|
|
73
|
+
windows: registry.toplevels().map((window) => ({
|
|
74
|
+
id: registry.idFor(window),
|
|
75
|
+
title: window.getTitle(),
|
|
76
|
+
})),
|
|
77
|
+
})),
|
|
78
|
+
"widget.getTree": validated(ServerRequestParamsSchemas["widget.getTree"], async ({ app, registry }) => {
|
|
79
|
+
const testing = await loadTestingModule();
|
|
80
|
+
return { tree: testing.prettyWidget(app, { getId: (w) => registry.idFor(w), highlight: false }) };
|
|
81
|
+
}),
|
|
82
|
+
"widget.query": validated(ServerRequestParamsSchemas["widget.query"], handleQuery),
|
|
83
|
+
"widget.getProps": validated(ServerRequestParamsSchemas["widget.getProps"], async ({ registry }, params) => {
|
|
84
|
+
const testing = await loadTestingModule();
|
|
85
|
+
const widget = requireWidget(registry, params.widgetId);
|
|
86
|
+
return serializeWidget(widget, (target) => registry.idFor(target), testing);
|
|
87
|
+
}),
|
|
88
|
+
"widget.click": validated(ServerRequestParamsSchemas["widget.click"], async ({ registry }, params) => {
|
|
89
|
+
const testing = await loadTestingModule();
|
|
90
|
+
const widget = requireWidget(registry, params.widgetId);
|
|
91
|
+
await testing.userEvent.click(widget);
|
|
92
|
+
return { success: true };
|
|
93
|
+
}),
|
|
94
|
+
"widget.type": validated(ServerRequestParamsSchemas["widget.type"], async ({ registry }, params) => {
|
|
95
|
+
const testing = await loadTestingModule();
|
|
96
|
+
const widget = requireWidget(registry, params.widgetId);
|
|
97
|
+
if (params.clear) {
|
|
98
|
+
await testing.userEvent.clear(widget);
|
|
99
|
+
}
|
|
100
|
+
await testing.userEvent.type(widget, params.text);
|
|
101
|
+
return { success: true };
|
|
102
|
+
}),
|
|
103
|
+
"widget.fireEvent": validated(ServerRequestParamsSchemas["widget.fireEvent"], async ({ registry }, params) => {
|
|
104
|
+
const testing = await loadTestingModule();
|
|
105
|
+
const widget = requireWidget(registry, params.widgetId);
|
|
106
|
+
const signalArgs = (params.args ?? []).map(extractSignalArg);
|
|
107
|
+
await testing.fireEvent(widget, params.signal, ...signalArgs);
|
|
108
|
+
return { success: true };
|
|
109
|
+
}),
|
|
110
|
+
"widget.screenshot": validated(ServerRequestParamsSchemas["widget.screenshot"], handleScreenshot),
|
|
111
|
+
};
|
|
112
|
+
const isServerInitiatedMethod = (method) => Object.hasOwn(ServerRequestParamsSchemas, method);
|
|
113
|
+
export const dispatch = async (method, params, ctx) => {
|
|
114
|
+
if (!isServerInitiatedMethod(method)) {
|
|
115
|
+
throw methodNotFoundError(method);
|
|
116
|
+
}
|
|
117
|
+
return HANDLERS[method](ctx, params);
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/mcp/handlers.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport {\n invalidRequestError,\n methodNotFoundError,\n type ParamsSchema,\n type ServerInitiatedMethod,\n type ServerRequestParams,\n ServerRequestParamsSchemas,\n widgetNotFoundError,\n} from \"@gtkx/mcp/internal\";\nimport { serializeWidget } from \"./serialize-widget.js\";\nimport { loadTestingModule } from \"./testing-loader.js\";\nimport type { WidgetRegistry } from \"./widget-registry.js\";\n\nexport type HandlerContext = {\n app: Gtk.Application;\n registry: WidgetRegistry;\n};\n\ntype ValidatedHandler = (ctx: HandlerContext, params: unknown) => Promise<unknown>;\n\nconst validated = <Params>(\n schema: ParamsSchema<Params>,\n handler: (ctx: HandlerContext, params: Params) => Promise<unknown>,\n): ValidatedHandler => {\n return (ctx, params) => {\n const parsed = schema.safeParse(params ?? {});\n if (!parsed.success) {\n throw invalidRequestError(parsed.error.message);\n }\n return handler(ctx, parsed.data);\n };\n};\n\nconst requireWidget = (registry: WidgetRegistry, widgetId: string | undefined): Gtk.Widget => {\n if (widgetId === undefined) {\n throw widgetNotFoundError(\"undefined\");\n }\n const widget = registry.get(widgetId);\n if (!widget) {\n throw widgetNotFoundError(widgetId);\n }\n return widget;\n};\n\nconst extractSignalArg = (arg: unknown): unknown => {\n const isTypedArg = typeof arg === \"object\" && arg !== null && \"type\" in arg && \"value\" in arg;\n return isTypedArg ? (arg as { value: unknown }).value : arg;\n};\n\nconst handleQuery = async (\n { app, registry }: HandlerContext,\n params: ServerRequestParams<\"widget.query\">,\n): Promise<unknown> => {\n const testing = await loadTestingModule();\n let widgets: Gtk.Widget[] = [];\n\n switch (params.by) {\n case \"role\": {\n const roleValue =\n typeof params.value === \"string\"\n ? Gtk.AccessibleRole[params.value as keyof typeof Gtk.AccessibleRole]\n : params.value;\n widgets = await testing.findAllByRole(app, roleValue as Gtk.AccessibleRole, params.options);\n break;\n }\n case \"text\":\n widgets = await testing.findAllByText(app, String(params.value), params.options);\n break;\n case \"name\":\n widgets = await testing.findAllByName(app, String(params.value), params.options);\n break;\n case \"labelText\":\n widgets = await testing.findAllByLabelText(app, String(params.value), params.options);\n break;\n }\n\n return { widgets: widgets.map((w) => serializeWidget(w, (widget) => registry.idFor(widget), testing)) };\n};\n\nconst defaultScreenshotTarget = (registry: WidgetRegistry): Gtk.Widget => {\n const [toplevel] = registry.toplevels();\n if (!toplevel) {\n throw new Error(\"No windows available for screenshot\");\n }\n return toplevel;\n};\n\nconst handleScreenshot = async (\n { registry }: HandlerContext,\n params: ServerRequestParams<\"widget.screenshot\">,\n): Promise<unknown> => {\n const testing = await loadTestingModule();\n const target = params.windowId ? requireWidget(registry, params.windowId) : defaultScreenshotTarget(registry);\n const result = await testing.screenshot(target);\n if (params.path) {\n mkdirSync(dirname(params.path), { recursive: true });\n writeFileSync(params.path, Buffer.from(result.data, \"base64\"));\n return { data: result.data, mimeType: result.mimeType, savedPath: params.path };\n }\n return { data: result.data, mimeType: result.mimeType };\n};\n\nconst HANDLERS: Record<ServerInitiatedMethod, ValidatedHandler> = {\n \"app.getWindows\": validated(ServerRequestParamsSchemas[\"app.getWindows\"], async ({ registry }) => ({\n windows: registry.toplevels().map((window) => ({\n id: registry.idFor(window),\n title: window.getTitle(),\n })),\n })),\n \"widget.getTree\": validated(ServerRequestParamsSchemas[\"widget.getTree\"], async ({ app, registry }) => {\n const testing = await loadTestingModule();\n return { tree: testing.prettyWidget(app, { getId: (w) => registry.idFor(w), highlight: false }) };\n }),\n \"widget.query\": validated(ServerRequestParamsSchemas[\"widget.query\"], handleQuery),\n \"widget.getProps\": validated(ServerRequestParamsSchemas[\"widget.getProps\"], async ({ registry }, params) => {\n const testing = await loadTestingModule();\n const widget = requireWidget(registry, params.widgetId);\n return serializeWidget(widget, (target) => registry.idFor(target), testing);\n }),\n \"widget.click\": validated(ServerRequestParamsSchemas[\"widget.click\"], async ({ registry }, params) => {\n const testing = await loadTestingModule();\n const widget = requireWidget(registry, params.widgetId);\n await testing.userEvent.click(widget);\n return { success: true };\n }),\n \"widget.type\": validated(ServerRequestParamsSchemas[\"widget.type\"], async ({ registry }, params) => {\n const testing = await loadTestingModule();\n const widget = requireWidget(registry, params.widgetId);\n if (params.clear) {\n await testing.userEvent.clear(widget);\n }\n await testing.userEvent.type(widget, params.text);\n return { success: true };\n }),\n \"widget.fireEvent\": validated(ServerRequestParamsSchemas[\"widget.fireEvent\"], async ({ registry }, params) => {\n const testing = await loadTestingModule();\n const widget = requireWidget(registry, params.widgetId);\n const signalArgs = (params.args ?? []).map(extractSignalArg);\n await testing.fireEvent(widget, params.signal, ...signalArgs);\n return { success: true };\n }),\n \"widget.screenshot\": validated(ServerRequestParamsSchemas[\"widget.screenshot\"], handleScreenshot),\n};\n\nconst isServerInitiatedMethod = (method: string): method is ServerInitiatedMethod =>\n Object.hasOwn(ServerRequestParamsSchemas, method);\n\nexport const dispatch = async (method: string, params: unknown, ctx: HandlerContext): Promise<unknown> => {\n if (!isServerInitiatedMethod(method)) {\n throw methodNotFoundError(method);\n }\n return HANDLERS[method](ctx, params);\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,eAAO,MAAM,cAAc,kBAAyB,MAAM,KAAG,OAAO,CAAC,SAAS,CAU7E,CAAC;AAEF,eAAO,MAAM,aAAa,QAAO,IAKhC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { McpClient } from "./client.js";
|
|
2
|
+
let globalClient = null;
|
|
3
|
+
export const startMcpClient = async (applicationId) => {
|
|
4
|
+
if (globalClient) {
|
|
5
|
+
return globalClient;
|
|
6
|
+
}
|
|
7
|
+
globalClient = new McpClient({ applicationId });
|
|
8
|
+
await globalClient.connect().catch(() => { });
|
|
9
|
+
return globalClient;
|
|
10
|
+
};
|
|
11
|
+
export const stopMcpClient = () => {
|
|
12
|
+
if (globalClient) {
|
|
13
|
+
globalClient.disconnect();
|
|
14
|
+
globalClient = null;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,IAAI,YAAY,GAAqB,IAAI,CAAC;AAE1C,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,aAAqB,EAAsB,EAAE;IAC9E,IAAI,YAAY,EAAE,CAAC;QACf,OAAO,YAAY,CAAC;IACxB,CAAC;IAED,YAAY,GAAG,IAAI,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;IAEhD,MAAM,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE7C,OAAO,YAAY,CAAC;AACxB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,GAAS,EAAE;IACpC,IAAI,YAAY,EAAE,CAAC;QACf,YAAY,CAAC,UAAU,EAAE,CAAC;QAC1B,YAAY,GAAG,IAAI,CAAC;IACxB,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { McpClient } from \"./client.js\";\n\nlet globalClient: McpClient | null = null;\n\nexport const startMcpClient = async (applicationId: string): Promise<McpClient> => {\n if (globalClient) {\n return globalClient;\n }\n\n globalClient = new McpClient({ applicationId });\n\n await globalClient.connect().catch(() => {});\n\n return globalClient;\n};\n\nexport const stopMcpClient = (): void => {\n if (globalClient) {\n globalClient.disconnect();\n globalClient = null;\n }\n};\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import type { SerializedWidget } from "@gtkx/mcp/internal";
|
|
3
|
+
type WidgetIdResolver = (widget: Gtk.Widget) => string;
|
|
4
|
+
export type WidgetFormatting = {
|
|
5
|
+
formatRole(role: Gtk.AccessibleRole): string;
|
|
6
|
+
getWidgetNodeText(widget: Gtk.Widget): string | null;
|
|
7
|
+
};
|
|
8
|
+
export declare const serializeWidget: (widget: Gtk.Widget, idFor: WidgetIdResolver, testing: WidgetFormatting) => SerializedWidget;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=serialize-widget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize-widget.d.ts","sourceRoot":"","sources":["../../src/mcp/serialize-widget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,KAAK,gBAAgB,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC;AAEvD,MAAM,MAAM,gBAAgB,GAAG;IAC3B,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC;IAC7C,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;AAEF,eAAO,MAAM,eAAe,WAChB,GAAG,CAAC,MAAM,SACX,gBAAgB,WACd,gBAAgB,KAC1B,gBAmBF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const serializeWidget = (widget, idFor, testing) => {
|
|
2
|
+
const children = [];
|
|
3
|
+
let child = widget.getFirstChild();
|
|
4
|
+
while (child) {
|
|
5
|
+
children.push(serializeWidget(child, idFor, testing));
|
|
6
|
+
child = child.getNextSibling();
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
id: idFor(widget),
|
|
10
|
+
type: widget.constructor.name,
|
|
11
|
+
role: testing.formatRole(widget.getAccessibleRole()),
|
|
12
|
+
name: widget.getName() || null,
|
|
13
|
+
text: testing.getWidgetNodeText(widget),
|
|
14
|
+
sensitive: widget.getSensitive(),
|
|
15
|
+
visible: widget.getVisible(),
|
|
16
|
+
cssClasses: widget.getCssClasses(),
|
|
17
|
+
children,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=serialize-widget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize-widget.js","sourceRoot":"","sources":["../../src/mcp/serialize-widget.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,eAAe,GAAG,CAC3B,MAAkB,EAClB,KAAuB,EACvB,OAAyB,EACT,EAAE;IAClB,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,IAAI,KAAK,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;IACnC,OAAO,KAAK,EAAE,CAAC;QACX,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QACtD,KAAK,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;IACnC,CAAC;IAED,OAAO;QACH,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI;QAC7B,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACpD,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI;QAC9B,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC;QACvC,SAAS,EAAE,MAAM,CAAC,YAAY,EAAE;QAChC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE;QAC5B,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE;QAClC,QAAQ;KACX,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { SerializedWidget } from \"@gtkx/mcp/internal\";\n\ntype WidgetIdResolver = (widget: Gtk.Widget) => string;\n\nexport type WidgetFormatting = {\n formatRole(role: Gtk.AccessibleRole): string;\n getWidgetNodeText(widget: Gtk.Widget): string | null;\n};\n\nexport const serializeWidget = (\n widget: Gtk.Widget,\n idFor: WidgetIdResolver,\n testing: WidgetFormatting,\n): SerializedWidget => {\n const children: SerializedWidget[] = [];\n let child = widget.getFirstChild();\n while (child) {\n children.push(serializeWidget(child, idFor, testing));\n child = child.getNextSibling();\n }\n\n return {\n id: idFor(widget),\n type: widget.constructor.name,\n role: testing.formatRole(widget.getAccessibleRole()),\n name: widget.getName() || null,\n text: testing.getWidgetNodeText(widget),\n sensitive: widget.getSensitive(),\n visible: widget.getVisible(),\n cssClasses: widget.getCssClasses(),\n children,\n };\n};\n"]}
|