@skillbuilder/minitool-e2e 0.0.0-beta-20261027053041051

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/lib/gate.js ADDED
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * e2e 灰度闸口的后半段:把宿主给的快照收成可信结构 + 按 appKind 做最后一道判定。
4
+ * 前半段(用户维度)由控制面建任务时求值并固化 —— 只有它有身份与配置版本;形态维度只能等
5
+ * 出码侧的意图路由定出 appKind 才判。
6
+ *
7
+ * ⚠️ **fail-closed**:字段缺失、类型不对、老控制面没带这个字段,一律不放行 ——
8
+ * 宁可不开也不能在脏数据上误开,它会真起浏览器、烧 token。零依赖,不碰 playwright。
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.normalizeE2EGate = normalizeE2EGate;
12
+ exports.isE2EEnabledForKind = isE2EEnabledForKind;
13
+ exports.describeE2EGate = describeE2EGate;
14
+ function isStringArray(value) {
15
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
16
+ }
17
+ /** 不满足契约的输入一律收成 undefined,调用方按「不放行」处理。 */
18
+ function normalizeE2EGate(value) {
19
+ if (!value || typeof value !== "object" || Array.isArray(value))
20
+ return undefined;
21
+ const raw = value;
22
+ if (typeof raw.userEnabled !== "boolean")
23
+ return undefined;
24
+ if (!isStringArray(raw.appKinds))
25
+ return undefined;
26
+ return {
27
+ userEnabled: raw.userEnabled,
28
+ appKinds: raw.appKinds.map((kind) => kind.trim()).filter(Boolean),
29
+ reason: typeof raw.reason === "string" ? raw.reason : undefined,
30
+ bucket: typeof raw.bucket === "number" && Number.isFinite(raw.bucket) ? raw.bucket : undefined,
31
+ configRevision: typeof raw.configRevision === "string" ? raw.configRevision : undefined,
32
+ configSource: typeof raw.configSource === "string" ? raw.configSource : undefined,
33
+ };
34
+ }
35
+ /** 最终判定:用户维度放行 **且** 当前形态在允许清单内。 */
36
+ function isE2EEnabledForKind(gate, appKind) {
37
+ if (!gate?.userEnabled)
38
+ return false;
39
+ return gate.appKinds.includes(appKind);
40
+ }
41
+ /**
42
+ * 不放行时的一行归因摘要,由出码侧原样打进日志。
43
+ * 必须带上 appKinds:控制面那个输入框是自由 tag,形态名敲错不报错、只是永不命中,
44
+ * 对着这一行才看得出是拼写问题。
45
+ */
46
+ function describeE2EGate(gate) {
47
+ if (!gate)
48
+ return "e2e gate absent (closed)";
49
+ const parts = [
50
+ `userEnabled=${gate.userEnabled}`,
51
+ `appKinds=[${gate.appKinds.join(",")}]`,
52
+ gate.reason ? `reason=${gate.reason}` : "",
53
+ gate.bucket === undefined ? "" : `bucket=${gate.bucket}`,
54
+ gate.configRevision ? `revision=${gate.configRevision}` : "",
55
+ gate.configSource ? `source=${gate.configSource}` : "",
56
+ ].filter(Boolean);
57
+ return parts.join(" ");
58
+ }
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /**
7
+ * 闸口的 **fail-closed** 用例:误关只是少跑一次自检,误开会真起浏览器并烧 token ——
8
+ * 代价不对称,所以「读不出可信结构」与「显式关闭」必须都判不放行。
9
+ * 前 8 条打纯函数,后 3 条打 `resolveRun()`(出码侧真正调用的那一层)。
10
+ */
11
+ const strict_1 = __importDefault(require("node:assert/strict"));
12
+ const node_test_1 = __importDefault(require("node:test"));
13
+ const codegen_port_1 = require("./codegen-port");
14
+ const gate_1 = require("./gate");
15
+ (0, node_test_1.default)("归一化:非对象 / 缺字段 / 类型不对,一律收成 undefined", () => {
16
+ for (const bad of [
17
+ undefined,
18
+ null,
19
+ 0,
20
+ "",
21
+ "true",
22
+ [],
23
+ {},
24
+ { appKinds: ["game_2d"] }, // 缺 userEnabled
25
+ { userEnabled: true }, // 缺 appKinds
26
+ { userEnabled: "true", appKinds: ["game_2d"] }, // userEnabled 不是布尔
27
+ { userEnabled: true, appKinds: "game_2d" }, // appKinds 不是数组
28
+ { userEnabled: true, appKinds: ["game_2d", 1] }, // 数组元素不是字符串
29
+ ]) {
30
+ strict_1.default.equal((0, gate_1.normalizeE2EGate)(bad), undefined, `should reject: ${JSON.stringify(bad)}`);
31
+ }
32
+ });
33
+ (0, node_test_1.default)("归一化:合法输入保留归因字段,形态清单去空白去空项", () => {
34
+ const gate = (0, gate_1.normalizeE2EGate)({
35
+ userEnabled: true,
36
+ appKinds: ["game_2d", " game_3d ", "", " "],
37
+ reason: "allowlist_hit",
38
+ bucket: 3068,
39
+ configRevision: "1",
40
+ configSource: "published",
41
+ unknownField: "ignored",
42
+ });
43
+ strict_1.default.deepEqual(gate, {
44
+ userEnabled: true,
45
+ appKinds: ["game_2d", "game_3d"],
46
+ reason: "allowlist_hit",
47
+ bucket: 3068,
48
+ configRevision: "1",
49
+ configSource: "published",
50
+ });
51
+ });
52
+ (0, node_test_1.default)("归一化:bucket 非有限数值时丢弃(不因归因字段脏而整体判废)", () => {
53
+ const gate = (0, gate_1.normalizeE2EGate)({
54
+ userEnabled: false,
55
+ appKinds: ["game_2d"],
56
+ bucket: Number.NaN,
57
+ });
58
+ strict_1.default.equal(gate?.userEnabled, false);
59
+ strict_1.default.equal(gate?.bucket, undefined);
60
+ });
61
+ (0, node_test_1.default)("判定:闸口缺省等价于不放行", () => {
62
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(undefined, "game_2d"), false);
63
+ });
64
+ (0, node_test_1.default)("判定:用户维度未放行时,形态命中也不放行", () => {
65
+ const gate = { userEnabled: false, appKinds: ["game_2d"] };
66
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(gate, "game_2d"), false);
67
+ });
68
+ (0, node_test_1.default)("判定:用户维度放行但形态不在清单内时不放行", () => {
69
+ const gate = { userEnabled: true, appKinds: ["game_2d", "game_3d"] };
70
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(gate, "spa_vue"), false);
71
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(gate, "minitool_html"), false);
72
+ });
73
+ (0, node_test_1.default)("判定:用户维度放行且形态命中才放行", () => {
74
+ const gate = { userEnabled: true, appKinds: ["game_2d", "game_3d"] };
75
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(gate, "game_2d"), true);
76
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(gate, "game_3d"), true);
77
+ });
78
+ (0, node_test_1.default)("判定:形态清单为空等价于全关(即使用户维度放行)", () => {
79
+ const gate = { userEnabled: true, appKinds: [] };
80
+ strict_1.default.equal((0, gate_1.isE2EEnabledForKind)(gate, "game_2d"), false);
81
+ });
82
+ /** `createMinitoolE2EPort()` 只拼配置、不探测 chromium,所以这里不起任何进程。 */
83
+ const port = () => (0, codegen_port_1.createMinitoolE2EPort)();
84
+ (0, node_test_1.default)("resolveRun:闸口脏数据与「压根没下发」的原因必须能分开", () => {
85
+ const run = (gate) => port().resolveRun({
86
+ workspaceDir: "/work",
87
+ appKind: "game_2d",
88
+ hasGameBridge: true,
89
+ gate,
90
+ taskId: "wt-test",
91
+ });
92
+ // 下发了但结构不对 ⇒ 控制面 bug,原因里要带上原文才能定位是哪个字段坏了
93
+ const malformed = run({ userEnabled: "true", appKinds: ["game_2d"] });
94
+ strict_1.default.equal(malformed.allowed, false);
95
+ strict_1.default.match(malformed.allowed === false ? malformed.reason : "", /malformed/);
96
+ strict_1.default.match(malformed.allowed === false ? malformed.reason : "", /"userEnabled":"true"/);
97
+ // 压根没下发 ⇒ 老版本控制面,正常情况,不该报成 malformed
98
+ const absent = run(undefined);
99
+ strict_1.default.equal(absent.allowed, false);
100
+ strict_1.default.doesNotMatch(absent.allowed === false ? absent.reason : "", /malformed/);
101
+ });
102
+ (0, node_test_1.default)("resolveRun:形态不在清单内时不放行,原因里能看到实际清单", () => {
103
+ const decision = port().resolveRun({
104
+ workspaceDir: "/work",
105
+ appKind: "minitool_html",
106
+ hasGameBridge: false,
107
+ gate: { userEnabled: true, appKinds: ["game_2d", "game_3d"] },
108
+ taskId: "wt-test",
109
+ });
110
+ strict_1.default.equal(decision.allowed, false);
111
+ // 控制面那个输入框是自由 tag,形态名敲错不报错只是永不命中;原因里带清单才能一眼看出拼写问题
112
+ strict_1.default.match(decision.allowed === false ? decision.reason : "", /appKinds=\[game_2d,game_3d\]/);
113
+ });
114
+ (0, node_test_1.default)("resolveRun:放行时按有无游戏桥给出装配,且 prompt 里写死算好的产物目录", () => {
115
+ const gate = { userEnabled: true, appKinds: ["game_2d", "minitool_html"] };
116
+ const game = port().resolveRun({
117
+ workspaceDir: "/work",
118
+ appKind: "game_2d",
119
+ hasGameBridge: true,
120
+ gate,
121
+ taskId: "wt-game",
122
+ });
123
+ strict_1.default.equal(game.allowed, true);
124
+ if (!game.allowed)
125
+ return; // 让 TS 收窄,上面的断言已经保证走不到
126
+ strict_1.default.equal(game.plan.allowedToolNames.length, 14);
127
+ // MCP 子进程的 cwd 不是任务工作区,产物目录必须算好写进 prompt
128
+ strict_1.default.match(game.plan.instruction, /\/work\/dist/);
129
+ // 每任务一份 MCP 配置,env 必须带上本任务 taskId —— 截图上传回调宿主靠它把事件归流
130
+ strict_1.default.equal(game.plan.mcpServers[codegen_port_1.MINITOOL_E2E_MCP_SERVER_NAME]?.env?.MINITOOL_E2E_TASK_ID, "wt-game");
131
+ const generic = port().resolveRun({
132
+ workspaceDir: "/work",
133
+ appKind: "minitool_html",
134
+ hasGameBridge: false,
135
+ gate,
136
+ taskId: "wt-generic",
137
+ });
138
+ strict_1.default.equal(generic.allowed, true);
139
+ if (!generic.allowed)
140
+ return;
141
+ strict_1.default.equal(generic.plan.allowedToolNames.length, 8);
142
+ // 无桥那组开销小一个量级,回合预算必须跟着少给
143
+ strict_1.default.equal(generic.plan.extraTurns < game.plan.extraTurns, true);
144
+ });
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderHostPage = renderHostPage;
4
+ /** 页面侧事件缓冲上限:够排障,又不至于让长任务把页面内存吃满 */
5
+ const EVENT_BUFFER_LIMIT = 500;
6
+ function renderHostPage(opts) {
7
+ const { sdkEntry, serviceWorkerUrl, viewport } = opts;
8
+ return `<!doctype html>
9
+ <html lang="zh-CN">
10
+ <head>
11
+ <meta charset="utf-8" />
12
+ <title>minitool-e2e host</title>
13
+ <style>
14
+ html, body { margin: 0; padding: 0; background: #111; overflow: hidden; }
15
+ #stage { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; }
16
+ #preview { width: ${viewport.width}px; height: ${viewport.height}px; }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <div id="stage"><div id="preview"></div></div>
21
+ <script type="module">
22
+ import { createMiniAppSimulator } from "${sdkEntry}";
23
+
24
+ const events = [];
25
+ const push = (name, detail) => {
26
+ events.push({ name, at: Date.now(), detail });
27
+ if (events.length > ${EVENT_BUFFER_LIMIT}) events.splice(0, events.length - ${EVENT_BUFFER_LIMIT});
28
+ };
29
+ const safe = (value) => {
30
+ try { return JSON.parse(JSON.stringify(value)); } catch { return String(value); }
31
+ };
32
+
33
+ const simulator = createMiniAppSimulator({
34
+ mount: document.getElementById("preview"),
35
+ viewport: { width: ${viewport.width}, height: ${viewport.height} },
36
+ renderer: "iframe-service-worker",
37
+ serviceWorker: { scriptUrl: "${serviceWorkerUrl}" },
38
+ touchEmulation: true,
39
+ debug: true,
40
+ jsapi: { enabled: true, mode: "auto" },
41
+ });
42
+
43
+ for (const name of [
44
+ "ready", "load", "error", "console", "guestError",
45
+ "navigation", "renderDone", "network",
46
+ ]) {
47
+ simulator.on(name, (event) => push(name, safe(event)));
48
+ }
49
+
50
+ window.__MINITOOL_E2E__ = {
51
+ simulator,
52
+ events,
53
+ /** 取事件并清空已读部分,避免 Node 侧重复处理同一批 */
54
+ drainEvents(level) {
55
+ const picked = level
56
+ ? events.filter((item) => item.detail && item.detail.level === level)
57
+ : events.slice();
58
+ events.length = 0;
59
+ return picked;
60
+ },
61
+ viewport: { width: ${viewport.width}, height: ${viewport.height} },
62
+ };
63
+ window.__MINITOOL_E2E_READY__ = true;
64
+ </script>
65
+ </body>
66
+ </html>
67
+ `;
68
+ }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SDK_ROUTE_PREFIX = exports.SW_ROUTE = void 0;
37
+ exports.startHostServer = startHostServer;
38
+ /**
39
+ * 宿主页静态服务,三个路由全部同源,绑 127.0.0.1 随机端口:`/` 宿主页、`/miniapp-sw.js`
40
+ * 模拟器 SW、`/sdk/*` 模拟器 ESM runtime 整目录(chunk 是哈希名,不能只托管入口)。
41
+ *
42
+ * ★ SW 必须挂在**根路径**:它的最大作用域由脚本自身路径决定,而模拟器把小应用挂在虚拟前缀
43
+ * `/miniapp-simulator/<id>/` 下。放根路径时作用域天然是 `/`,**不需要
44
+ * `Service-Worker-Allowed` 响应头**(实测去掉照样注册);放 `/sdk/` 下就必须靠该头放宽。
45
+ */
46
+ const fs = __importStar(require("node:fs"));
47
+ const http = __importStar(require("node:http"));
48
+ const path = __importStar(require("node:path"));
49
+ const assets_1 = require("./assets");
50
+ const host_page_1 = require("./host-page");
51
+ const MIME = {
52
+ ".html": "text/html; charset=utf-8",
53
+ ".js": "text/javascript; charset=utf-8",
54
+ ".mjs": "text/javascript; charset=utf-8",
55
+ ".css": "text/css; charset=utf-8",
56
+ ".json": "application/json; charset=utf-8",
57
+ ".map": "application/json; charset=utf-8",
58
+ };
59
+ exports.SW_ROUTE = "/miniapp-sw.js";
60
+ exports.SDK_ROUTE_PREFIX = "/sdk/";
61
+ async function startHostServer(opts = {}) {
62
+ const assets = (0, assets_1.resolveSimulatorAssets)();
63
+ const html = (0, host_page_1.renderHostPage)({
64
+ sdkEntry: `${exports.SDK_ROUTE_PREFIX}index.js`,
65
+ serviceWorkerUrl: exports.SW_ROUTE,
66
+ viewport: opts.viewport ?? { width: 390, height: 844 },
67
+ });
68
+ const server = http.createServer((req, res) => {
69
+ const url = (req.url ?? "/").split("?")[0];
70
+ try {
71
+ if (url === "/" || url === "/index.html") {
72
+ return void send(res, 200, "text/html; charset=utf-8", Buffer.from(html, "utf8"));
73
+ }
74
+ if (url === exports.SW_ROUTE) {
75
+ return void send(res, 200, "text/javascript; charset=utf-8", fs.readFileSync(assets.serviceWorkerFile));
76
+ }
77
+ if (url.startsWith(exports.SDK_ROUTE_PREFIX)) {
78
+ const rel = url.slice(exports.SDK_ROUTE_PREFIX.length);
79
+ // 目录穿越防护:解析后必须仍在 libDir 内(这是本地回环服务,但仍不给自己留坑)
80
+ const file = path.resolve(assets.libDir, rel);
81
+ if (!file.startsWith(path.resolve(assets.libDir) + path.sep)) {
82
+ return void send(res, 403, "text/plain; charset=utf-8", Buffer.from("forbidden"));
83
+ }
84
+ if (!fs.existsSync(file) || fs.statSync(file).isDirectory()) {
85
+ return void send(res, 404, "text/plain; charset=utf-8", Buffer.from("not found"));
86
+ }
87
+ const mime = MIME[path.extname(file).toLowerCase()] ?? "application/octet-stream";
88
+ return void send(res, 200, mime, fs.readFileSync(file));
89
+ }
90
+ send(res, 404, "text/plain; charset=utf-8", Buffer.from("not found"));
91
+ }
92
+ catch (err) {
93
+ send(res, 500, "text/plain; charset=utf-8", Buffer.from(err instanceof Error ? err.message : String(err)));
94
+ }
95
+ });
96
+ await new Promise((resolve, reject) => {
97
+ server.once("error", reject);
98
+ server.listen(0, "127.0.0.1", () => resolve());
99
+ });
100
+ const address = server.address();
101
+ if (!address || typeof address === "string") {
102
+ server.close();
103
+ throw new Error("[minitool-e2e] 宿主页服务未能取得端口");
104
+ }
105
+ return {
106
+ baseUrl: `http://127.0.0.1:${address.port}`,
107
+ assets,
108
+ close: () => new Promise((resolve) => {
109
+ server.close(() => resolve());
110
+ }),
111
+ };
112
+ }
113
+ function send(res, status, contentType, body) {
114
+ res.writeHead(status, {
115
+ "Content-Type": contentType,
116
+ "Content-Length": body.byteLength,
117
+ // 沙箱内每个任务一套新服务,缓存只会带来「改了没生效」的困惑
118
+ "Cache-Control": "no-store",
119
+ });
120
+ res.end(body);
121
+ }
package/lib/index.js ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runMinitoolE2EStdioServer = exports.registerMinitoolE2ETools = exports.createMinitoolE2EMcpServer = exports.E2E_TOOL_NAMES = exports.E2E_GAME_TOOL_NAMES = exports.E2E_GENERIC_TOOL_NAMES = exports.toMcpToolName = exports.e2eExtraTurns = exports.e2eAllowedToolNames = exports.buildE2EInstruction = exports.MINITOOL_E2E_MCP_SERVER_NAME = exports.createMinitoolE2EPortIfAvailable = exports.createMinitoolE2EPort = exports.readDistDir = exports.MinitoolE2ESession = exports.renderHostPage = exports.SW_ROUTE = exports.SDK_ROUTE_PREFIX = exports.startHostServer = exports.resolveSimulatorAssets = exports.resolveChromiumPath = exports.probeChromium = exports.launchChromium = void 0;
4
+ /**
5
+ * @skillbuilder/minitool-e2e —— 小工具端到端验证能力。
6
+ * 游戏「试玩」只是第一种模式,别把包名理解成只能玩游戏。
7
+ *
8
+ * **工具只经 MCP 暴露,没有进程内形态。** 本包被加载两次、扮演两个角色:
9
+ * 控制面 `codegen-port.ts`(出码主进程里 require,纯计算不碰 chromium);
10
+ * 数据面 `mcp/stdio-entry.ts`(被 spawn 成独立子进程,14 个真工具 + chromium 都在这侧)。
11
+ * 工具名与 prompt 的权威定义都在 `contract.ts`,两个角色都从那里取,所以不会漂移。
12
+ *
13
+ * 接入:`initCodegenAgent({ ...ports.context, e2e: (await createMinitoolE2EPortIfAvailable()).port })`
14
+ *
15
+ * 运行前置:容器内预装发行版 chromium(见 browser.ts)、已完整构建 miniapp-simulator(见 assets.ts)。
16
+ */
17
+ var browser_1 = require("./browser");
18
+ Object.defineProperty(exports, "launchChromium", { enumerable: true, get: function () { return browser_1.launchChromium; } });
19
+ Object.defineProperty(exports, "probeChromium", { enumerable: true, get: function () { return browser_1.probeChromium; } });
20
+ Object.defineProperty(exports, "resolveChromiumPath", { enumerable: true, get: function () { return browser_1.resolveChromiumPath; } });
21
+ var assets_1 = require("./assets");
22
+ Object.defineProperty(exports, "resolveSimulatorAssets", { enumerable: true, get: function () { return assets_1.resolveSimulatorAssets; } });
23
+ var host_server_1 = require("./host-server");
24
+ Object.defineProperty(exports, "startHostServer", { enumerable: true, get: function () { return host_server_1.startHostServer; } });
25
+ Object.defineProperty(exports, "SDK_ROUTE_PREFIX", { enumerable: true, get: function () { return host_server_1.SDK_ROUTE_PREFIX; } });
26
+ Object.defineProperty(exports, "SW_ROUTE", { enumerable: true, get: function () { return host_server_1.SW_ROUTE; } });
27
+ var host_page_1 = require("./host-page");
28
+ Object.defineProperty(exports, "renderHostPage", { enumerable: true, get: function () { return host_page_1.renderHostPage; } });
29
+ var session_1 = require("./session");
30
+ Object.defineProperty(exports, "MinitoolE2ESession", { enumerable: true, get: function () { return session_1.MinitoolE2ESession; } });
31
+ Object.defineProperty(exports, "readDistDir", { enumerable: true, get: function () { return session_1.readDistDir; } });
32
+ var codegen_port_1 = require("./codegen-port");
33
+ Object.defineProperty(exports, "createMinitoolE2EPort", { enumerable: true, get: function () { return codegen_port_1.createMinitoolE2EPort; } });
34
+ Object.defineProperty(exports, "createMinitoolE2EPortIfAvailable", { enumerable: true, get: function () { return codegen_port_1.createMinitoolE2EPortIfAvailable; } });
35
+ Object.defineProperty(exports, "MINITOOL_E2E_MCP_SERVER_NAME", { enumerable: true, get: function () { return codegen_port_1.MINITOOL_E2E_MCP_SERVER_NAME; } });
36
+ var contract_1 = require("./contract");
37
+ Object.defineProperty(exports, "buildE2EInstruction", { enumerable: true, get: function () { return contract_1.buildE2EInstruction; } });
38
+ Object.defineProperty(exports, "e2eAllowedToolNames", { enumerable: true, get: function () { return contract_1.e2eAllowedToolNames; } });
39
+ Object.defineProperty(exports, "e2eExtraTurns", { enumerable: true, get: function () { return contract_1.e2eExtraTurns; } });
40
+ Object.defineProperty(exports, "toMcpToolName", { enumerable: true, get: function () { return contract_1.toMcpToolName; } });
41
+ Object.defineProperty(exports, "E2E_GENERIC_TOOL_NAMES", { enumerable: true, get: function () { return contract_1.E2E_GENERIC_TOOL_NAMES; } });
42
+ Object.defineProperty(exports, "E2E_GAME_TOOL_NAMES", { enumerable: true, get: function () { return contract_1.E2E_GAME_TOOL_NAMES; } });
43
+ Object.defineProperty(exports, "E2E_TOOL_NAMES", { enumerable: true, get: function () { return contract_1.E2E_TOOL_NAMES; } });
44
+ var server_1 = require("./mcp/server");
45
+ Object.defineProperty(exports, "createMinitoolE2EMcpServer", { enumerable: true, get: function () { return server_1.createMinitoolE2EMcpServer; } });
46
+ Object.defineProperty(exports, "registerMinitoolE2ETools", { enumerable: true, get: function () { return server_1.registerMinitoolE2ETools; } });
47
+ var stdio_1 = require("./mcp/stdio");
48
+ Object.defineProperty(exports, "runMinitoolE2EStdioServer", { enumerable: true, get: function () { return stdio_1.runMinitoolE2EStdioServer; } });