@gtkx/cli 1.0.0-rc.1 → 1.0.0-rc.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.
- package/dist/builder.d.ts +3 -2
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -1
- package/dist/builder.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -6
- package/dist/cli.js.map +1 -1
- package/dist/codegen/freshness.d.ts +5 -5
- package/dist/codegen/freshness.d.ts.map +1 -1
- package/dist/codegen/freshness.js +26 -23
- package/dist/codegen/freshness.js.map +1 -1
- package/dist/codegen/report.d.ts +2 -1
- package/dist/codegen/report.d.ts.map +1 -1
- package/dist/codegen/report.js +4 -2
- package/dist/codegen/report.js.map +1 -1
- package/dist/codegen/run-codegen.d.ts +8 -8
- package/dist/codegen/run-codegen.d.ts.map +1 -1
- package/dist/codegen/run-codegen.js +72 -43
- package/dist/codegen/run-codegen.js.map +1 -1
- package/dist/codegen/store-resolver.d.ts +8 -5
- package/dist/codegen/store-resolver.d.ts.map +1 -1
- package/dist/codegen/store-resolver.js +26 -6
- package/dist/codegen/store-resolver.js.map +1 -1
- package/dist/commands/build.d.ts +4 -3
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +2 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/codegen.d.ts +2 -1
- package/dist/commands/codegen.d.ts.map +1 -1
- package/dist/commands/codegen.js +6 -4
- package/dist/commands/codegen.js.map +1 -1
- package/dist/commands/dev.d.ts +2 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +2 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/docs.d.ts +2 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +22 -7
- package/dist/commands/docs.js.map +1 -1
- package/dist/dev/icon-dir.d.ts +2 -1
- package/dist/dev/icon-dir.d.ts.map +1 -1
- package/dist/dev/icon-dir.js +6 -3
- package/dist/dev/icon-dir.js.map +1 -1
- package/dist/dev/refresh-tracker.d.ts +5 -4
- package/dist/dev/refresh-tracker.d.ts.map +1 -1
- package/dist/dev/refresh-tracker.js +6 -5
- package/dist/dev/refresh-tracker.js.map +1 -1
- package/dist/dev/runner-deps.d.ts +2 -1
- package/dist/dev/runner-deps.d.ts.map +1 -1
- package/dist/dev/runner-deps.js +20 -4
- package/dist/dev/runner-deps.js.map +1 -1
- package/dist/dev/runner-main.d.ts +2 -1
- package/dist/dev/runner-main.d.ts.map +1 -1
- package/dist/dev/runner-main.js +3 -2
- package/dist/dev/runner-main.js.map +1 -1
- package/dist/dev/runner.d.ts +6 -5
- package/dist/dev/runner.d.ts.map +1 -1
- package/dist/dev/runner.js +69 -38
- package/dist/dev/runner.js.map +1 -1
- package/dist/dev/schema-dir.d.ts +2 -1
- package/dist/dev/schema-dir.d.ts.map +1 -1
- package/dist/dev/schema-dir.js +4 -2
- package/dist/dev/schema-dir.js.map +1 -1
- package/dist/dev/supervisor.d.ts +7 -6
- package/dist/dev/supervisor.d.ts.map +1 -1
- package/dist/dev/supervisor.js +107 -67
- package/dist/dev/supervisor.js.map +1 -1
- package/dist/dev/vite-dev-server.d.ts +3 -3
- package/dist/dev/vite-dev-server.d.ts.map +1 -1
- package/dist/dev/vite-dev-server.js +2 -1
- package/dist/dev/vite-dev-server.js.map +1 -1
- package/dist/internal/banner.d.ts +2 -1
- package/dist/internal/banner.d.ts.map +1 -1
- package/dist/internal/banner.js +2 -1
- package/dist/internal/banner.js.map +1 -1
- package/dist/internal/data-dir.d.ts +3 -2
- package/dist/internal/data-dir.d.ts.map +1 -1
- package/dist/internal/data-dir.js +29 -14
- package/dist/internal/data-dir.js.map +1 -1
- package/dist/internal/entry-arg.d.ts +5 -4
- package/dist/internal/entry-arg.d.ts.map +1 -1
- package/dist/internal/entry-arg.js +10 -7
- package/dist/internal/entry-arg.js.map +1 -1
- package/dist/internal/errors.d.ts +3 -2
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +7 -5
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/list-files.d.ts +3 -2
- package/dist/internal/list-files.d.ts.map +1 -1
- package/dist/internal/list-files.js +5 -3
- package/dist/internal/list-files.js.map +1 -1
- package/dist/internal/resolve-cli-tool.d.ts +2 -1
- package/dist/internal/resolve-cli-tool.d.ts.map +1 -1
- package/dist/internal/resolve-cli-tool.js +17 -10
- package/dist/internal/resolve-cli-tool.js.map +1 -1
- package/dist/internal/staging-dir.d.ts +3 -2
- package/dist/internal/staging-dir.d.ts.map +1 -1
- package/dist/internal/staging-dir.js +3 -2
- package/dist/internal/staging-dir.js.map +1 -1
- package/dist/internal/xdg-data-dirs.d.ts +2 -1
- package/dist/internal/xdg-data-dirs.d.ts.map +1 -1
- package/dist/internal/xdg-data-dirs.js +4 -2
- package/dist/internal/xdg-data-dirs.js.map +1 -1
- package/dist/mcp/client.d.ts +9 -4
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +106 -81
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/handlers.d.ts +3 -2
- package/dist/mcp/handlers.d.ts.map +1 -1
- package/dist/mcp/handlers.js +89 -61
- package/dist/mcp/handlers.js.map +1 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +30 -13
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/serialize-widget.d.ts +3 -3
- package/dist/mcp/serialize-widget.d.ts.map +1 -1
- package/dist/mcp/serialize-widget.js +9 -6
- package/dist/mcp/serialize-widget.js.map +1 -1
- package/dist/mcp/testing-loader.d.ts +3 -4
- package/dist/mcp/testing-loader.d.ts.map +1 -1
- package/dist/mcp/testing-loader.js +43 -21
- package/dist/mcp/testing-loader.js.map +1 -1
- package/dist/mcp/widget-registry.d.ts +3 -2
- package/dist/mcp/widget-registry.d.ts.map +1 -1
- package/dist/mcp/widget-registry.js +4 -3
- package/dist/mcp/widget-registry.js.map +1 -1
- package/dist/refresh-globals.d.ts +2 -0
- package/dist/refresh-globals.d.ts.map +1 -0
- package/dist/refresh-globals.js +8 -0
- package/dist/refresh-globals.js.map +1 -0
- package/dist/refresh-runtime.d.ts +5 -11
- package/dist/refresh-runtime.d.ts.map +1 -1
- package/dist/refresh-runtime.js +16 -14
- package/dist/refresh-runtime.js.map +1 -1
- package/dist/settings/compile.d.ts +2 -1
- package/dist/settings/compile.d.ts.map +1 -1
- package/dist/settings/compile.js +6 -4
- package/dist/settings/compile.js.map +1 -1
- package/dist/settings/parser.d.ts +6 -5
- package/dist/settings/parser.d.ts.map +1 -1
- package/dist/settings/parser.js +26 -22
- package/dist/settings/parser.js.map +1 -1
- package/dist/settings/render.d.ts +3 -2
- package/dist/settings/render.d.ts.map +1 -1
- package/dist/settings/render.js +38 -64
- package/dist/settings/render.js.map +1 -1
- package/dist/settings/schema.d.ts +8 -8
- package/dist/settings/schema.d.ts.map +1 -1
- package/dist/settings/schema.js +61 -43
- package/dist/settings/schema.js.map +1 -1
- package/dist/vite-plugins/asset-extensions.d.ts +4 -3
- package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
- package/dist/vite-plugins/asset-extensions.js +4 -3
- package/dist/vite-plugins/asset-extensions.js.map +1 -1
- package/dist/vite-plugins/built-url.d.ts +2 -1
- package/dist/vite-plugins/built-url.d.ts.map +1 -1
- package/dist/vite-plugins/built-url.js +19 -13
- package/dist/vite-plugins/built-url.js.map +1 -1
- package/dist/vite-plugins/css.d.ts +2 -1
- package/dist/vite-plugins/css.d.ts.map +1 -1
- package/dist/vite-plugins/css.js +23 -15
- package/dist/vite-plugins/css.js.map +1 -1
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +5 -4
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -1
- package/dist/vite-plugins/fast-refresh/refresh-filter.js +11 -7
- package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -1
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +4 -3
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -1
- package/dist/vite-plugins/fast-refresh/swc-refresh.js +45 -41
- package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -1
- package/dist/vite-plugins/icons.d.ts +2 -1
- package/dist/vite-plugins/icons.d.ts.map +1 -1
- package/dist/vite-plugins/icons.js +24 -20
- package/dist/vite-plugins/icons.js.map +1 -1
- package/dist/vite-plugins/index.d.ts +2 -1
- package/dist/vite-plugins/index.d.ts.map +1 -1
- package/dist/vite-plugins/index.js +3 -2
- package/dist/vite-plugins/index.js.map +1 -1
- package/dist/vite-plugins/native.d.ts +2 -1
- package/dist/vite-plugins/native.d.ts.map +1 -1
- package/dist/vite-plugins/native.js +6 -4
- package/dist/vite-plugins/native.js.map +1 -1
- package/dist/vite-plugins/react-compiler.d.ts +3 -2
- package/dist/vite-plugins/react-compiler.d.ts.map +1 -1
- package/dist/vite-plugins/react-compiler.js +26 -20
- package/dist/vite-plugins/react-compiler.js.map +1 -1
- package/dist/vite-plugins/react-dom-prebundle.d.ts +2 -1
- package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -1
- package/dist/vite-plugins/react-dom-prebundle.js +2 -1
- package/dist/vite-plugins/react-dom-prebundle.js.map +1 -1
- package/dist/vite-plugins/resource-init-module.d.ts +2 -1
- package/dist/vite-plugins/resource-init-module.d.ts.map +1 -1
- package/dist/vite-plugins/resource-init-module.js +39 -38
- package/dist/vite-plugins/resource-init-module.js.map +1 -1
- package/dist/vite-plugins/resource-shared.d.ts +7 -5
- package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
- package/dist/vite-plugins/resource-shared.js +17 -10
- package/dist/vite-plugins/resource-shared.js.map +1 -1
- package/dist/vite-plugins/resources.d.ts +3 -2
- package/dist/vite-plugins/resources.d.ts.map +1 -1
- package/dist/vite-plugins/resources.js +94 -54
- package/dist/vite-plugins/resources.js.map +1 -1
- package/dist/vite-plugins/settings-worker-env.d.ts +2 -1
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
- package/dist/vite-plugins/settings-worker-env.js +4 -2
- package/dist/vite-plugins/settings-worker-env.js.map +1 -1
- package/dist/vite-plugins/settings.d.ts +2 -1
- package/dist/vite-plugins/settings.d.ts.map +1 -1
- package/dist/vite-plugins/settings.js +56 -32
- package/dist/vite-plugins/settings.js.map +1 -1
- package/dist/vite-plugins/strip-query.d.ts +3 -0
- package/dist/vite-plugins/strip-query.d.ts.map +1 -0
- package/dist/vite-plugins/strip-query.js +6 -0
- package/dist/vite-plugins/strip-query.js.map +1 -0
- package/dist/vite-plugins/undeclared-library.d.ts +2 -1
- package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
- package/dist/vite-plugins/undeclared-library.js +8 -5
- package/dist/vite-plugins/undeclared-library.js.map +1 -1
- package/dist/vite-plugins/virtual-module.d.ts +2 -2
- package/dist/vite-plugins/virtual-module.d.ts.map +1 -1
- package/dist/vite-plugins/virtual-module.js +5 -3
- package/dist/vite-plugins/virtual-module.js.map +1 -1
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js.map +1 -1
- package/env.d.ts +21 -61
- package/package.json +12 -14
- package/src/babel-modules.d.ts +0 -2
- package/src/builder.ts +7 -6
- package/src/cli.ts +26 -6
- package/src/codegen/freshness.ts +38 -25
- package/src/codegen/report.ts +10 -2
- package/src/codegen/run-codegen.ts +135 -60
- package/src/codegen/store-resolver.ts +56 -15
- package/src/commands/build.ts +3 -2
- package/src/commands/codegen.ts +9 -4
- package/src/commands/dev.ts +3 -4
- package/src/commands/docs.ts +36 -7
- package/src/dev/icon-dir.ts +13 -3
- package/src/dev/refresh-tracker.ts +12 -8
- package/src/dev/runner-deps.ts +30 -7
- package/src/dev/runner-main.ts +4 -3
- package/src/dev/runner.ts +100 -41
- package/src/dev/schema-dir.ts +7 -2
- package/src/dev/supervisor.ts +169 -71
- package/src/dev/vite-dev-server.ts +4 -2
- package/src/internal/banner.ts +5 -1
- package/src/internal/data-dir.ts +47 -16
- package/src/internal/entry-arg.ts +16 -8
- package/src/internal/errors.ts +15 -7
- package/src/internal/list-files.ts +10 -4
- package/src/internal/resolve-cli-tool.ts +28 -12
- package/src/internal/staging-dir.ts +5 -2
- package/src/internal/xdg-data-dirs.ts +8 -2
- package/src/mcp/client.ts +143 -85
- package/src/mcp/handlers.ts +126 -69
- package/src/mcp/index.ts +38 -14
- package/src/mcp/serialize-widget.ts +15 -8
- package/src/mcp/testing-loader.ts +64 -23
- package/src/mcp/widget-registry.ts +11 -5
- package/src/refresh-globals.ts +10 -0
- package/src/refresh-runtime.ts +20 -16
- package/src/settings/compile.ts +7 -4
- package/src/settings/parser.ts +69 -30
- package/src/settings/render.ts +66 -66
- package/src/settings/schema.ts +100 -46
- package/src/vite-plugins/asset-extensions.ts +4 -3
- package/src/vite-plugins/built-url.ts +30 -15
- package/src/vite-plugins/css.ts +35 -20
- package/src/vite-plugins/fast-refresh/refresh-filter.ts +18 -10
- package/src/vite-plugins/fast-refresh/swc-refresh.ts +60 -47
- package/src/vite-plugins/icons.ts +40 -24
- package/src/vite-plugins/index.ts +6 -3
- package/src/vite-plugins/native.ts +14 -5
- package/src/vite-plugins/react-compiler.ts +44 -30
- package/src/vite-plugins/react-dom-prebundle.ts +4 -1
- package/src/vite-plugins/resource-init-module.ts +41 -38
- package/src/vite-plugins/resource-shared.ts +27 -14
- package/src/vite-plugins/resources.ts +153 -59
- package/src/vite-plugins/settings-worker-env.ts +7 -2
- package/src/vite-plugins/settings.ts +107 -42
- package/src/vite-plugins/strip-query.ts +7 -0
- package/src/vite-plugins/undeclared-library.ts +21 -12
- package/src/vite-plugins/virtual-module.ts +9 -2
- package/src/vitest-plugin.ts +1 -2
package/src/mcp/handlers.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
1
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
2
|
import {
|
|
5
3
|
invalidRequestError,
|
|
@@ -10,147 +8,206 @@ import {
|
|
|
10
8
|
ServerRequestParamsSchemas,
|
|
11
9
|
widgetNotFoundError,
|
|
12
10
|
} from "@gtkx/mcp/internal";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { dirname } from "node:path";
|
|
15
13
|
import type { WidgetRegistry } from "./widget-registry.js";
|
|
14
|
+
import { serializeWidget } from "./serialize-widget.js";
|
|
15
|
+
import { loadTestingModule, type TestingModule } from "./testing-loader.js";
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
type HandlerContext = {
|
|
18
18
|
app: Gtk.Application;
|
|
19
19
|
registry: WidgetRegistry;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
type ValidatedHandler = (ctx: HandlerContext, params: unknown) => Promise<unknown>;
|
|
23
|
+
type WidgetTarget = { testing: TestingModule; widget: Gtk.Widget };
|
|
23
24
|
|
|
24
|
-
const
|
|
25
|
+
const HANDLERS: Record<ServerInitiatedMethod, ValidatedHandler> = {
|
|
26
|
+
"app.getWindows": validated(ServerRequestParamsSchemas["app.getWindows"], ({ registry }) =>
|
|
27
|
+
Promise.resolve({
|
|
28
|
+
windows: registry.toplevels().map((window) => ({
|
|
29
|
+
id: registry.getOrCreateId(window),
|
|
30
|
+
title: window.getTitle(),
|
|
31
|
+
})),
|
|
32
|
+
})),
|
|
33
|
+
"widget.getTree": validated(ServerRequestParamsSchemas["widget.getTree"], async ({ app, registry }, params) => {
|
|
34
|
+
const testing = await loadTestingModule();
|
|
35
|
+
const container = params.rootId === undefined ? app : requireWidget(registry, params.rootId);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
tree: testing.prettyWidget(container, {
|
|
39
|
+
getId: (w) => registry.getOrCreateId(w),
|
|
40
|
+
highlight: false,
|
|
41
|
+
...((params.maxDepth !== undefined) && { maxDepth: params.maxDepth }),
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
"widget.query": validated(ServerRequestParamsSchemas["widget.query"], handleQuery),
|
|
46
|
+
"widget.getProps": validated(ServerRequestParamsSchemas["widget.getProps"], async ({ registry }, params) => {
|
|
47
|
+
const { testing, widget } = await widgetTarget(registry, params.widgetId);
|
|
48
|
+
|
|
49
|
+
return serializeWidget(widget, (target) => registry.getOrCreateId(target), testing);
|
|
50
|
+
}),
|
|
51
|
+
"widget.click": validated(ServerRequestParamsSchemas["widget.click"], async ({ registry }, params) => {
|
|
52
|
+
const { testing, widget } = await widgetTarget(registry, params.widgetId);
|
|
53
|
+
await testing.userEvent.click(widget);
|
|
54
|
+
|
|
55
|
+
return { success: true };
|
|
56
|
+
}),
|
|
57
|
+
"widget.type": validated(ServerRequestParamsSchemas["widget.type"], async ({ registry }, params) => {
|
|
58
|
+
const { testing, widget } = await widgetTarget(registry, params.widgetId);
|
|
59
|
+
|
|
60
|
+
if (params.clear) {
|
|
61
|
+
await testing.userEvent.clear(widget);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await testing.userEvent.type(widget, params.text);
|
|
65
|
+
|
|
66
|
+
return { success: true };
|
|
67
|
+
}),
|
|
68
|
+
"widget.fireEvent": validated(ServerRequestParamsSchemas["widget.fireEvent"], async ({ registry }, params) => {
|
|
69
|
+
const { testing, widget } = await widgetTarget(registry, params.widgetId);
|
|
70
|
+
const signalArgs = (params.args ?? []).map((arg) => extractSignalArg(arg));
|
|
71
|
+
await testing.fireEvent(widget, params.signal, ...signalArgs);
|
|
72
|
+
|
|
73
|
+
return { success: true };
|
|
74
|
+
}),
|
|
75
|
+
"widget.screenshot": validated(ServerRequestParamsSchemas["widget.screenshot"], handleScreenshot),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
function validated<Params>(
|
|
25
79
|
schema: ParamsSchema<Params>,
|
|
26
80
|
handler: (ctx: HandlerContext, params: Params) => Promise<unknown>,
|
|
27
|
-
): ValidatedHandler
|
|
81
|
+
): ValidatedHandler {
|
|
28
82
|
return (ctx, params) => {
|
|
29
83
|
const parsed = schema.safeParse(params ?? {});
|
|
84
|
+
|
|
30
85
|
if (!parsed.success) {
|
|
31
86
|
throw invalidRequestError(parsed.error.message);
|
|
32
87
|
}
|
|
88
|
+
|
|
33
89
|
return handler(ctx, parsed.data);
|
|
34
90
|
};
|
|
35
|
-
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const widgetTarget = async (registry: WidgetRegistry, widgetId: string | undefined): Promise<WidgetTarget> => ({
|
|
94
|
+
testing: await loadTestingModule(),
|
|
95
|
+
widget: requireWidget(registry, widgetId),
|
|
96
|
+
});
|
|
36
97
|
|
|
37
98
|
const requireWidget = (registry: WidgetRegistry, widgetId: string | undefined): Gtk.Widget => {
|
|
38
99
|
if (widgetId === undefined) {
|
|
39
100
|
throw widgetNotFoundError("undefined");
|
|
40
101
|
}
|
|
102
|
+
|
|
41
103
|
const widget = registry.get(widgetId);
|
|
104
|
+
|
|
42
105
|
if (!widget) {
|
|
43
106
|
throw widgetNotFoundError(widgetId);
|
|
44
107
|
}
|
|
108
|
+
|
|
45
109
|
return widget;
|
|
46
110
|
};
|
|
47
111
|
|
|
48
112
|
const extractSignalArg = (arg: unknown): unknown => {
|
|
49
113
|
const isTypedArg = typeof arg === "object" && arg !== null && "type" in arg && "value" in arg;
|
|
114
|
+
|
|
50
115
|
return isTypedArg ? (arg as { value: unknown }).value : arg;
|
|
51
116
|
};
|
|
52
117
|
|
|
53
|
-
const
|
|
118
|
+
const resolveRole = (value: string | number): Gtk.AccessibleRole | undefined => {
|
|
119
|
+
if (typeof value === "number") {
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const resolved = Gtk.AccessibleRole[value.toUpperCase() as keyof typeof Gtk.AccessibleRole];
|
|
124
|
+
|
|
125
|
+
return typeof resolved === "number" ? resolved : undefined;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const matchesOrEmpty = async (find: () => Promise<Gtk.Widget[]>): Promise<Gtk.Widget[]> => {
|
|
129
|
+
try {
|
|
130
|
+
return await find();
|
|
131
|
+
} catch {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
async function handleQuery(
|
|
54
137
|
{ app, registry }: HandlerContext,
|
|
55
138
|
params: ServerRequestParams<"widget.query">,
|
|
56
|
-
): Promise<unknown>
|
|
139
|
+
): Promise<unknown> {
|
|
57
140
|
const testing = await loadTestingModule();
|
|
58
141
|
let widgets: Gtk.Widget[] = [];
|
|
59
142
|
|
|
60
143
|
switch (params.by) {
|
|
61
144
|
case "role": {
|
|
62
|
-
const roleValue =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
145
|
+
const roleValue = resolveRole(params.value);
|
|
146
|
+
|
|
147
|
+
if (roleValue === undefined) {
|
|
148
|
+
throw invalidRequestError(
|
|
149
|
+
`Unknown accessible role "${String(params.value)}"; use the lowercase role shown in the ` +
|
|
150
|
+
"widget tree, e.g. \"button\", \"list\", \"list_item\", or \"checkbox\".",
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
widgets = await matchesOrEmpty(() => testing.findAllByRole(app, roleValue, params.options));
|
|
67
155
|
break;
|
|
68
156
|
}
|
|
69
|
-
case "text":
|
|
70
|
-
widgets = await testing.findAllByText(app, String(params.value), params.options);
|
|
157
|
+
case "text": {
|
|
158
|
+
widgets = await matchesOrEmpty(() => testing.findAllByText(app, String(params.value), params.options));
|
|
71
159
|
break;
|
|
72
|
-
|
|
73
|
-
|
|
160
|
+
}
|
|
161
|
+
case "name": {
|
|
162
|
+
widgets = await matchesOrEmpty(() => testing.findAllByName(app, String(params.value), params.options));
|
|
74
163
|
break;
|
|
75
|
-
|
|
76
|
-
|
|
164
|
+
}
|
|
165
|
+
case "labelText": {
|
|
166
|
+
widgets = await matchesOrEmpty(() => testing.findAllByLabelText(app, String(params.value), params.options));
|
|
77
167
|
break;
|
|
168
|
+
}
|
|
78
169
|
}
|
|
79
170
|
|
|
80
|
-
return { widgets: widgets.map((w) => serializeWidget(w, (widget) => registry.
|
|
81
|
-
}
|
|
171
|
+
return { widgets: widgets.map((w) => serializeWidget(w, (widget) => registry.getOrCreateId(widget), testing, 0)) };
|
|
172
|
+
}
|
|
82
173
|
|
|
83
174
|
const defaultScreenshotTarget = (registry: WidgetRegistry): Gtk.Widget => {
|
|
84
175
|
const [toplevel] = registry.toplevels();
|
|
176
|
+
|
|
85
177
|
if (!toplevel) {
|
|
86
178
|
throw new Error("No windows available for screenshot");
|
|
87
179
|
}
|
|
180
|
+
|
|
88
181
|
return toplevel;
|
|
89
182
|
};
|
|
90
183
|
|
|
91
|
-
|
|
184
|
+
async function handleScreenshot(
|
|
92
185
|
{ registry }: HandlerContext,
|
|
93
186
|
params: ServerRequestParams<"widget.screenshot">,
|
|
94
|
-
): Promise<unknown>
|
|
187
|
+
): Promise<unknown> {
|
|
95
188
|
const testing = await loadTestingModule();
|
|
96
189
|
const target = params.windowId ? requireWidget(registry, params.windowId) : defaultScreenshotTarget(registry);
|
|
97
190
|
const result = await testing.screenshot(target);
|
|
191
|
+
|
|
98
192
|
if (params.path) {
|
|
99
193
|
mkdirSync(dirname(params.path), { recursive: true });
|
|
100
194
|
writeFileSync(params.path, Buffer.from(result.data, "base64"));
|
|
195
|
+
|
|
101
196
|
return { data: result.data, mimeType: result.mimeType, savedPath: params.path };
|
|
102
197
|
}
|
|
103
|
-
return { data: result.data, mimeType: result.mimeType };
|
|
104
|
-
};
|
|
105
198
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
windows: registry.toplevels().map((window) => ({
|
|
109
|
-
id: registry.idFor(window),
|
|
110
|
-
title: window.getTitle(),
|
|
111
|
-
})),
|
|
112
|
-
})),
|
|
113
|
-
"widget.getTree": validated(ServerRequestParamsSchemas["widget.getTree"], async ({ app, registry }) => {
|
|
114
|
-
const testing = await loadTestingModule();
|
|
115
|
-
return { tree: testing.prettyWidget(app, { getId: (w) => registry.idFor(w), highlight: false }) };
|
|
116
|
-
}),
|
|
117
|
-
"widget.query": validated(ServerRequestParamsSchemas["widget.query"], handleQuery),
|
|
118
|
-
"widget.getProps": validated(ServerRequestParamsSchemas["widget.getProps"], async ({ registry }, params) => {
|
|
119
|
-
const testing = await loadTestingModule();
|
|
120
|
-
const widget = requireWidget(registry, params.widgetId);
|
|
121
|
-
return serializeWidget(widget, (target) => registry.idFor(target), testing);
|
|
122
|
-
}),
|
|
123
|
-
"widget.click": validated(ServerRequestParamsSchemas["widget.click"], async ({ registry }, params) => {
|
|
124
|
-
const testing = await loadTestingModule();
|
|
125
|
-
const widget = requireWidget(registry, params.widgetId);
|
|
126
|
-
await testing.userEvent.click(widget);
|
|
127
|
-
return { success: true };
|
|
128
|
-
}),
|
|
129
|
-
"widget.type": validated(ServerRequestParamsSchemas["widget.type"], async ({ registry }, params) => {
|
|
130
|
-
const testing = await loadTestingModule();
|
|
131
|
-
const widget = requireWidget(registry, params.widgetId);
|
|
132
|
-
if (params.clear) {
|
|
133
|
-
await testing.userEvent.clear(widget);
|
|
134
|
-
}
|
|
135
|
-
await testing.userEvent.type(widget, params.text);
|
|
136
|
-
return { success: true };
|
|
137
|
-
}),
|
|
138
|
-
"widget.fireEvent": validated(ServerRequestParamsSchemas["widget.fireEvent"], async ({ registry }, params) => {
|
|
139
|
-
const testing = await loadTestingModule();
|
|
140
|
-
const widget = requireWidget(registry, params.widgetId);
|
|
141
|
-
const signalArgs = (params.args ?? []).map(extractSignalArg);
|
|
142
|
-
await testing.fireEvent(widget, params.signal, ...signalArgs);
|
|
143
|
-
return { success: true };
|
|
144
|
-
}),
|
|
145
|
-
"widget.screenshot": validated(ServerRequestParamsSchemas["widget.screenshot"], handleScreenshot),
|
|
146
|
-
};
|
|
199
|
+
return { data: result.data, mimeType: result.mimeType };
|
|
200
|
+
}
|
|
147
201
|
|
|
148
202
|
const isServerInitiatedMethod = (method: string): method is ServerInitiatedMethod =>
|
|
149
203
|
Object.hasOwn(ServerRequestParamsSchemas, method);
|
|
150
204
|
|
|
151
|
-
|
|
205
|
+
const dispatch = async (method: string, params: unknown, ctx: HandlerContext): Promise<unknown> => {
|
|
152
206
|
if (!isServerInitiatedMethod(method)) {
|
|
153
207
|
throw methodNotFoundError(method);
|
|
154
208
|
}
|
|
209
|
+
|
|
155
210
|
return HANDLERS[method](ctx, params);
|
|
156
211
|
};
|
|
212
|
+
|
|
213
|
+
export { dispatch, type HandlerContext };
|
package/src/mcp/index.ts
CHANGED
|
@@ -1,22 +1,46 @@
|
|
|
1
1
|
import { McpClient } from "./client.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type McpClientController = {
|
|
4
|
+
start: (applicationId: string) => Promise<McpClient>;
|
|
5
|
+
stop: () => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const { start: startMcpClient, stop: stopMcpClient } = createMcpClientController();
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
async function connectQuietly(client: McpClient): Promise<boolean> {
|
|
11
|
+
try {
|
|
12
|
+
await client.connect();
|
|
13
|
+
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
8
17
|
}
|
|
18
|
+
}
|
|
9
19
|
|
|
10
|
-
|
|
20
|
+
function createMcpClientController(): McpClientController {
|
|
21
|
+
let current: McpClient | null = null;
|
|
11
22
|
|
|
12
|
-
|
|
23
|
+
return {
|
|
24
|
+
start: async (applicationId: string): Promise<McpClient> => {
|
|
25
|
+
if (current) {
|
|
26
|
+
return current;
|
|
27
|
+
}
|
|
13
28
|
|
|
14
|
-
|
|
15
|
-
|
|
29
|
+
const client = new McpClient({ applicationId });
|
|
30
|
+
current = client;
|
|
31
|
+
await connectQuietly(client);
|
|
16
32
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
33
|
+
return client;
|
|
34
|
+
},
|
|
35
|
+
stop: (): void => {
|
|
36
|
+
if (!current) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
current.disconnect();
|
|
41
|
+
current = null;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { startMcpClient, stopMcpClient };
|
|
@@ -3,25 +3,30 @@ import type { SerializedWidget } from "@gtkx/mcp/internal";
|
|
|
3
3
|
|
|
4
4
|
type WidgetIdResolver = (widget: Gtk.Widget) => string;
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type WidgetFormatting = {
|
|
7
7
|
formatRole(role: Gtk.AccessibleRole): string;
|
|
8
8
|
getWidgetNodeText(widget: Gtk.Widget): string | null;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const serializeWidget = (
|
|
12
12
|
widget: Gtk.Widget,
|
|
13
|
-
|
|
13
|
+
resolveId: WidgetIdResolver,
|
|
14
14
|
testing: WidgetFormatting,
|
|
15
|
+
maxDepth = Infinity,
|
|
15
16
|
): SerializedWidget => {
|
|
16
17
|
const children: SerializedWidget[] = [];
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
|
|
19
|
+
if (maxDepth > 0) {
|
|
20
|
+
let child = widget.getFirstChild();
|
|
21
|
+
|
|
22
|
+
while (child) {
|
|
23
|
+
children.push(serializeWidget(child, resolveId, testing, maxDepth - 1));
|
|
24
|
+
child = child.getNextSibling();
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
return {
|
|
24
|
-
id:
|
|
29
|
+
id: resolveId(widget),
|
|
25
30
|
type: widget.constructor.name,
|
|
26
31
|
role: testing.formatRole(widget.getAccessibleRole()),
|
|
27
32
|
name: widget.getName() || null,
|
|
@@ -32,3 +37,5 @@ export const serializeWidget = (
|
|
|
32
37
|
children,
|
|
33
38
|
};
|
|
34
39
|
};
|
|
40
|
+
|
|
41
|
+
export { serializeWidget, type WidgetFormatting };
|
|
@@ -1,32 +1,73 @@
|
|
|
1
1
|
type TestingModule = typeof import("@gtkx/testing");
|
|
2
|
+
type TestingModuleLoader = () => Promise<TestingModule>;
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
type TestingModuleCache = {
|
|
5
|
+
setLoader: (next: TestingModuleLoader | null) => void;
|
|
6
|
+
load: () => Promise<TestingModule>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type TestingModuleState = {
|
|
10
|
+
loader: TestingModuleLoader;
|
|
11
|
+
testingModule: TestingModule | null;
|
|
12
|
+
testingLoadError: Error | null;
|
|
13
|
+
};
|
|
4
14
|
|
|
5
|
-
const
|
|
15
|
+
const { setLoader: setTestingModuleLoader, load: loadTestingModule } = createTestingModuleCache();
|
|
6
16
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
function defaultLoader(): Promise<TestingModule> {
|
|
18
|
+
return import("@gtkx/testing");
|
|
19
|
+
}
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
21
|
+
function missingTestingPackageError(cause: unknown): Error {
|
|
22
|
+
return new Error(
|
|
23
|
+
"@gtkx/testing is not installed, install it to enable MCP widget interactions: " +
|
|
24
|
+
`pnpm add -D @gtkx/testing (import failed: ${String(cause)})`,
|
|
25
|
+
{ cause },
|
|
26
|
+
);
|
|
27
|
+
}
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
function replaceLoader(state: TestingModuleState, next: TestingModuleLoader | null): void {
|
|
30
|
+
state.loader = next ?? defaultLoader;
|
|
31
|
+
state.testingModule = null;
|
|
32
|
+
state.testingLoadError = null;
|
|
33
|
+
}
|
|
20
34
|
|
|
35
|
+
async function importTestingModule(state: TestingModuleState): Promise<TestingModule> {
|
|
21
36
|
try {
|
|
22
|
-
testingModule = await loader();
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{ cause },
|
|
29
|
-
);
|
|
30
|
-
throw testingLoadError;
|
|
37
|
+
state.testingModule = await state.loader();
|
|
38
|
+
|
|
39
|
+
return state.testingModule;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
state.testingLoadError = missingTestingPackageError(error);
|
|
42
|
+
throw state.testingLoadError;
|
|
31
43
|
}
|
|
32
|
-
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function loadCachedTestingModule(state: TestingModuleState): Promise<TestingModule> {
|
|
47
|
+
if (state.testingModule) {
|
|
48
|
+
return Promise.resolve(state.testingModule);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (state.testingLoadError) {
|
|
52
|
+
return Promise.reject(state.testingLoadError);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return importTestingModule(state);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createTestingModuleCache(): TestingModuleCache {
|
|
59
|
+
const state: TestingModuleState = {
|
|
60
|
+
loader: defaultLoader,
|
|
61
|
+
testingModule: null,
|
|
62
|
+
testingLoadError: null,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
setLoader: (next: TestingModuleLoader | null): void => {
|
|
67
|
+
replaceLoader(state, next);
|
|
68
|
+
},
|
|
69
|
+
load: (): Promise<TestingModule> => loadCachedTestingModule(state),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { setTestingModuleLoader, loadTestingModule, type TestingModule, type TestingModuleLoader };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
private idByWidget
|
|
3
|
+
class WidgetRegistry {
|
|
4
|
+
private idByWidget: WeakMap<Gtk.Widget, string> = new WeakMap();
|
|
5
5
|
private nextId = 0;
|
|
6
|
-
private widgetById
|
|
6
|
+
private widgetById: Map<string, Gtk.Widget> = new Map();
|
|
7
7
|
private toplevelWindows: Gtk.Window[] = [];
|
|
8
8
|
|
|
9
9
|
refresh(): void {
|
|
10
10
|
this.widgetById.clear();
|
|
11
11
|
this.toplevelWindows = Gtk.Window.listToplevels() as Gtk.Window[];
|
|
12
|
+
|
|
12
13
|
for (const window of this.toplevelWindows) {
|
|
13
14
|
this.register(window);
|
|
14
15
|
}
|
|
@@ -19,21 +20,24 @@ export class WidgetRegistry {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
register(widget: Gtk.Widget): void {
|
|
22
|
-
const id = this.
|
|
23
|
+
const id = this.getOrCreateId(widget);
|
|
23
24
|
this.widgetById.set(id, widget);
|
|
24
25
|
let child = widget.getFirstChild();
|
|
26
|
+
|
|
25
27
|
while (child) {
|
|
26
28
|
this.register(child);
|
|
27
29
|
child = child.getNextSibling();
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
getOrCreateId(widget: Gtk.Widget): string {
|
|
32
34
|
let id = this.idByWidget.get(widget);
|
|
35
|
+
|
|
33
36
|
if (!id) {
|
|
34
37
|
id = String(this.nextId++);
|
|
35
38
|
this.idByWidget.set(widget, id);
|
|
36
39
|
}
|
|
40
|
+
|
|
37
41
|
return id;
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -41,3 +45,5 @@ export class WidgetRegistry {
|
|
|
41
45
|
return this.widgetById.get(id);
|
|
42
46
|
}
|
|
43
47
|
}
|
|
48
|
+
|
|
49
|
+
export { WidgetRegistry };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import RefreshRuntime from "react-refresh/runtime";
|
|
2
|
+
|
|
3
|
+
const identity = (type: unknown): unknown => type;
|
|
4
|
+
|
|
5
|
+
RefreshRuntime.injectIntoGlobalHook(globalThis);
|
|
6
|
+
|
|
7
|
+
Object.assign(globalThis, {
|
|
8
|
+
$RefreshReg$: (): void => undefined,
|
|
9
|
+
$RefreshSig$: () => identity,
|
|
10
|
+
});
|
package/src/refresh-runtime.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import RefreshRuntime from "react-refresh/runtime";
|
|
2
|
+
import "./refresh-globals.js";
|
|
2
3
|
|
|
3
4
|
type ComponentType = (...args: unknown[]) => unknown;
|
|
4
5
|
|
|
5
|
-
RefreshRuntime.injectIntoGlobalHook(globalThis);
|
|
6
|
-
globalThis.$RefreshReg$ = () => {};
|
|
7
|
-
globalThis.$RefreshSig$ = () => (type: unknown) => type;
|
|
8
|
-
|
|
9
6
|
/**
|
|
10
7
|
* Builds the per-module `$RefreshReg$` and `$RefreshSig$` hooks that React Refresh
|
|
11
8
|
* transformed code expects, scoping every registered component to the given module.
|
|
@@ -13,7 +10,7 @@ globalThis.$RefreshSig$ = () => (type: unknown) => type;
|
|
|
13
10
|
* @param moduleId Identifier used to namespace registered component types so they are unique across modules.
|
|
14
11
|
* @returns An object with `$RefreshReg$` and `$RefreshSig$` to install as module-local globals.
|
|
15
12
|
*/
|
|
16
|
-
|
|
13
|
+
function createModuleRegistration(moduleId: string): {
|
|
17
14
|
$RefreshReg$: (type: ComponentType, id: string) => void;
|
|
18
15
|
$RefreshSig$: typeof RefreshRuntime.createSignatureFunctionForTransform;
|
|
19
16
|
} {
|
|
@@ -32,21 +29,26 @@ export function createModuleRegistration(moduleId: string): {
|
|
|
32
29
|
* @param moduleExports The module's export object to inspect.
|
|
33
30
|
* @returns `true` when the module qualifies as a refresh boundary, `false` otherwise.
|
|
34
31
|
*/
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
32
|
+
const isComponentExport = (key: string, value: unknown): boolean =>
|
|
33
|
+
key === "__esModule" || RefreshRuntime.isLikelyComponentType(value);
|
|
39
34
|
|
|
35
|
+
const areAllExportsComponents = (moduleExports: Record<string, unknown>): boolean => {
|
|
40
36
|
for (const key in moduleExports) {
|
|
41
|
-
if (key
|
|
42
|
-
|
|
37
|
+
if (!isComponentExport(key, moduleExports[key])) {
|
|
38
|
+
return false;
|
|
43
39
|
}
|
|
40
|
+
}
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
function isRefreshBoundary(moduleExports: Record<string, unknown>): boolean {
|
|
46
|
+
if (RefreshRuntime.isLikelyComponentType(moduleExports)) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!areAllExportsComponents(moduleExports)) {
|
|
51
|
+
return false;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
return Object.keys(moduleExports).some((k) => k !== "__esModule");
|
|
@@ -55,6 +57,8 @@ export function isRefreshBoundary(moduleExports: Record<string, unknown>): boole
|
|
|
55
57
|
/**
|
|
56
58
|
* Applies all pending React Refresh updates, re-rendering components whose modules have changed.
|
|
57
59
|
*/
|
|
58
|
-
|
|
60
|
+
function performRefresh(): void {
|
|
59
61
|
RefreshRuntime.performReactRefresh();
|
|
60
62
|
}
|
|
63
|
+
|
|
64
|
+
export { createModuleRegistration, isRefreshBoundary, performRefresh };
|
package/src/settings/compile.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
1
|
import { formatChildProcessError } from "@gtkx/utils";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
3
|
import { resolveCliTool } from "../internal/resolve-cli-tool.js";
|
|
4
4
|
|
|
5
5
|
const SCHEMA_COMPILER = "glib-compile-schemas";
|
|
6
6
|
const SCHEMA_COMPILE_TIMEOUT_MS = 30_000;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const compileSchemas = (dir: string): void => {
|
|
9
9
|
try {
|
|
10
10
|
execFileSync(resolveCliTool(SCHEMA_COMPILER), ["--strict", dir], {
|
|
11
11
|
stdio: ["ignore", "pipe", "pipe"],
|
|
12
12
|
timeout: SCHEMA_COMPILE_TIMEOUT_MS,
|
|
13
|
-
encoding: "
|
|
13
|
+
encoding: "utf8",
|
|
14
14
|
});
|
|
15
15
|
} catch (error) {
|
|
16
16
|
const details = formatChildProcessError(error);
|
|
17
|
-
|
|
17
|
+
const suffix = details ? `:\n${details}` : "";
|
|
18
|
+
throw new Error(`glib-compile-schemas failed for ${dir}${suffix}`, { cause: error });
|
|
18
19
|
}
|
|
19
20
|
};
|
|
21
|
+
|
|
22
|
+
export { compileSchemas };
|