@adep/vite-plugin 0.1.5 → 0.1.6

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.
@@ -56,3 +56,16 @@ export declare function createAdepFnProxyScriptMiddleware(): (req: IncomingMessa
56
56
  * Web IDE 预览路径用(CLI 模式下脚本自检 window.parent === window 不激活,无害)。
57
57
  */
58
58
  export declare function injectFnProxyScriptTag(html: string): string;
59
+ /**
60
+ * 构造中间件:serve `/@adep/automation.js`(返回自动化中继脚本)。
61
+ * 与 `createAdepFnProxyScriptMiddleware` 同构——Nodebox 路径凭 3 个静态 URL 注入,
62
+ * 不往沙箱里塞业务代码(注入插件只写 `<script src>`,见 `ide-nodebox-preview.ts`)。
63
+ */
64
+ export declare function createAdepAutomationScriptMiddleware(): (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
65
+ /**
66
+ * 把自动化中继 script 标签注入 index.html 的 </head> 前(幂等)。
67
+ *
68
+ * 注入位置排在三段脚本的最后:中继脚本会再包一层 `console.*`(记环形缓冲),
69
+ * 排在控制台中继之后才能既进它的缓冲、又经它转发到 IDE「控制台」页签。
70
+ */
71
+ export declare function injectAutomationScriptTag(html: string): string;
package/dist/index.d.ts CHANGED
@@ -17,4 +17,5 @@ export { adepPlugin, default } from './dev-server';
17
17
  export type { AdepConfigLoader, AdepDevServerFactory, AdepDevServerHandle, AdepVitePlugin, AdepVitePluginOptions, AdepViteServer, } from './dev-server';
18
18
  export { normalizeFunctionPrefix } from './prefix';
19
19
  export { createAdepProxyMiddleware, isAddrInUse } from './proxy';
20
- export { createAdepFnProxyScriptMiddleware, FN_FETCH_INTERCEPTOR_SCRIPT, injectFnProxyScriptTag, } from './ide-proxy';
20
+ export { createAdepAutomationScriptMiddleware, createAdepFnProxyScriptMiddleware, FN_FETCH_INTERCEPTOR_SCRIPT, injectAutomationScriptTag, injectFnProxyScriptTag, } from './ide-proxy';
21
+ export { PREVIEW_AUTOMATION_SCRIPT } from './preview-automation';
package/dist/index.js CHANGED
@@ -48,6 +48,477 @@ function createAdepProxyMiddleware(prefix, targetBase) {
48
48
  };
49
49
  }
50
50
 
51
+ // packages/vite-plugin/src/preview-automation.ts
52
+ var PREVIEW_AUTOMATION_SCRIPT = `(function () {
53
+ if (window.__adepAutomationInstalled) return;
54
+ window.__adepAutomationInstalled = true;
55
+
56
+ var CONSOLE_LIMIT = 200;
57
+ var DEFAULT_TIMEOUT_MS = 8000;
58
+ var MAX_TEXT_CHARS = 12000;
59
+ var MAX_HTML_CHARS = 20000;
60
+ var DEFAULT_INSPECT_SELECTOR = "a,button,input,select,textarea,img,h1,h2,h3,h4,label,[role],[data-testid]";
61
+ var consoleLog = [];
62
+ var consoleSeq = 0;
63
+
64
+ function fail(code, message) {
65
+ var error = new Error(message);
66
+ error.code = code;
67
+ return error;
68
+ }
69
+
70
+ function asNumber(value, fallback) {
71
+ return typeof value === "number" && isFinite(value) ? value : fallback;
72
+ }
73
+
74
+ function asString(value, fallback) {
75
+ return typeof value === "string" ? value : fallback;
76
+ }
77
+
78
+ function truncate(value, max) {
79
+ var text = value == null ? "" : String(value);
80
+ var limit = typeof max === "number" && isFinite(max) && max > 0 ? Math.floor(max) : 0;
81
+ if (limit === 0 || text.length <= limit) return text;
82
+ return text.slice(0, limit) + "...[truncated, total " + text.length + " chars]";
83
+ }
84
+
85
+ /* ---- console / error ring buffer ---- */
86
+ function record(level, text) {
87
+ consoleSeq += 1;
88
+ consoleLog.push({ seq: consoleSeq, level: level, text: truncate(text, 2000), at: Date.now() });
89
+ if (consoleLog.length > CONSOLE_LIMIT) consoleLog.splice(0, consoleLog.length - CONSOLE_LIMIT);
90
+ }
91
+
92
+ function fmt(value) {
93
+ try {
94
+ if (typeof value === "string") return value;
95
+ if (value === undefined) return "undefined";
96
+ if (value instanceof Error) return value.stack || (value.name + ": " + value.message);
97
+ var seen = [];
98
+ var json = JSON.stringify(value, function (key, val) {
99
+ if (val instanceof Error) return val.stack || (val.name + ": " + val.message);
100
+ if (typeof val === "function") return "[Function " + (val.name || "anonymous") + "]";
101
+ if (typeof val === "bigint") return String(val) + "n";
102
+ if (val && typeof val === "object") {
103
+ if (seen.indexOf(val) !== -1) return "[Circular]";
104
+ seen.push(val);
105
+ }
106
+ return val;
107
+ });
108
+ return json === undefined ? String(value) : json;
109
+ } catch (e) {
110
+ return String(value);
111
+ }
112
+ }
113
+
114
+ var LEVELS = { log: "log", info: "info", warn: "warn", error: "error", debug: "log" };
115
+ Object.keys(LEVELS).forEach(function (name) {
116
+ var native = console[name];
117
+ console[name] = function () {
118
+ try { record(LEVELS[name], Array.prototype.map.call(arguments, fmt).join(" ")); } catch (e) {}
119
+ native.apply(console, arguments);
120
+ };
121
+ });
122
+ window.addEventListener('error', function (event) {
123
+ var text = event.message || "Script error";
124
+ if (event.filename) text += " (" + event.filename + ":" + event.lineno + ":" + event.colno + ")";
125
+ record("error", text);
126
+ });
127
+ window.addEventListener('unhandledrejection', function (event) {
128
+ var reason = event.reason;
129
+ record("error", reason && reason.stack ? String(reason.stack) : "Unhandled rejection: " + fmt(reason));
130
+ });
131
+
132
+ /* ---- DOM read ---- */
133
+ function query(selector, nth) {
134
+ var list = document.querySelectorAll(selector);
135
+ if (list.length === 0) throw fail("ELEMENT_NOT_FOUND", "selector matched nothing: " + selector);
136
+ var index = asNumber(nth, 0);
137
+ var el = list[index];
138
+ if (!el) throw fail("ELEMENT_NOT_FOUND", "selector matched " + list.length + " elements; index " + index + " is out of range");
139
+ return el;
140
+ }
141
+
142
+ function isVisible(el) {
143
+ if (!el || !el.getBoundingClientRect) return false;
144
+ var rect = el.getBoundingClientRect();
145
+ if (rect.width <= 0 && rect.height <= 0) return false;
146
+ var style = window.getComputedStyle(el);
147
+ if (style.visibility === "hidden" || style.display === "none") return false;
148
+ if (Number(style.opacity) === 0) return false;
149
+ return true;
150
+ }
151
+
152
+ function rectOf(el) {
153
+ var rect = el.getBoundingClientRect();
154
+ return {
155
+ x: Math.round(rect.left + window.scrollX),
156
+ y: Math.round(rect.top + window.scrollY),
157
+ w: Math.round(rect.width),
158
+ h: Math.round(rect.height),
159
+ };
160
+ }
161
+
162
+ function describe(el, maxText) {
163
+ var tag = String(el.tagName || "").toLowerCase();
164
+ var text = "";
165
+ if (tag === "input" || tag === "textarea" || tag === "select") text = String(el.value || "");
166
+ else text = el.textContent || "";
167
+ var out = {
168
+ tag: tag,
169
+ testid: el.getAttribute ? el.getAttribute("data-testid") : null,
170
+ id: el.id || null,
171
+ cls: el.className && typeof el.className === "string" ? el.className : null,
172
+ role: el.getAttribute ? el.getAttribute("role") : null,
173
+ text: truncate(String(text).replace(/[\\s\\u00a0]+/g, " ").trim(), asNumber(maxText, 120)),
174
+ rect: rectOf(el),
175
+ visible: isVisible(el),
176
+ };
177
+ if (tag === "input" || tag === "textarea" || tag === "select") {
178
+ out.field = el.getAttribute("name") || el.getAttribute("placeholder") || null;
179
+ if (tag === "input") out.type = el.getAttribute("type") || "text";
180
+ }
181
+ if (tag === "a") out.href = el.getAttribute("href") || null;
182
+ if (el.disabled === true) out.disabled = true;
183
+ if (el.checked !== undefined && (tag === "input")) out.checked = el.checked === true;
184
+ return out;
185
+ }
186
+
187
+ /* ---- DOM write ---- */
188
+ function fireMouse(el, x, y, kind) {
189
+ var rect = el.getBoundingClientRect();
190
+ var clientX = typeof x === "number" ? x : rect.left + rect.width / 2;
191
+ var clientY = typeof y === "number" ? y : rect.top + rect.height / 2;
192
+ el.dispatchEvent(new MouseEvent(kind, {
193
+ bubbles: true, cancelable: true, composed: true, view: window,
194
+ clientX: clientX, clientY: clientY, button: 0,
195
+ }));
196
+ }
197
+
198
+ function clickElement(el, x, y) {
199
+ try { el.scrollIntoView({ block: "center", inline: "center" }); } catch (e) {}
200
+ fireMouse(el, x, y, "mousedown");
201
+ fireMouse(el, x, y, "mouseup");
202
+ fireMouse(el, x, y, "click");
203
+ return describe(el, 120);
204
+ }
205
+
206
+ function fireKey(el, key) {
207
+ var target = el || document.activeElement || document.body;
208
+ var init = { key: key, bubbles: true, cancelable: true, composed: true };
209
+ if (key === "Enter") { init.keyCode = 13; init.which = 13; }
210
+ if (key === "Escape") { init.keyCode = 27; init.which = 27; }
211
+ if (key === "Tab") { init.keyCode = 9; init.which = 9; }
212
+ var allowed = target.dispatchEvent(new KeyboardEvent("keydown", init));
213
+ if (allowed) target.dispatchEvent(new KeyboardEvent("keypress", init));
214
+ target.dispatchEvent(new KeyboardEvent("keyup", init));
215
+ return { key: key, target: describe(target, 80) };
216
+ }
217
+
218
+ function setNativeValue(el, value) {
219
+ var proto = null;
220
+ if (window.HTMLTextAreaElement && el instanceof window.HTMLTextAreaElement) proto = window.HTMLTextAreaElement.prototype;
221
+ else if (window.HTMLSelectElement && el instanceof window.HTMLSelectElement) proto = window.HTMLSelectElement.prototype;
222
+ else if (window.HTMLInputElement && el instanceof window.HTMLInputElement) proto = window.HTMLInputElement.prototype;
223
+ var descriptor = proto ? Object.getOwnPropertyDescriptor(proto, "value") : null;
224
+ if (descriptor && descriptor.set) descriptor.set.call(el, value);
225
+ else el.value = value;
226
+ }
227
+
228
+ function fireInput(el) {
229
+ el.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
230
+ el.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
231
+ }
232
+
233
+ function typeInto(el, value, clear, submit) {
234
+ try { el.focus(); } catch (e) {}
235
+ if (clear) {
236
+ setNativeValue(el, "");
237
+ fireInput(el);
238
+ }
239
+ setNativeValue(el, clear ? String(value) : String(el.value || "") + String(value));
240
+ fireInput(el);
241
+ if (submit) fireKey(el, "Enter");
242
+ return describe(el, 200);
243
+ }
244
+
245
+ function waitFor(selector, state, timeoutMs) {
246
+ var want = state === "hidden" || state === "detached" ? state : "visible";
247
+ var deadline = Date.now() + timeoutMs;
248
+ return new Promise(function (resolve, reject) {
249
+ function check() {
250
+ var el = document.querySelector(selector);
251
+ if (want === "detached" && el === null) return resolve({ state: want, selector: selector });
252
+ if (want === "hidden" && (el === null || !isVisible(el))) return resolve({ state: want, selector: selector });
253
+ if (want === "visible" && el !== null && isVisible(el)) return resolve(describe(el, 200));
254
+ if (Date.now() >= deadline) {
255
+ return reject(fail("WAIT_TIMEOUT", "waitFor " + want + " timed out after " + timeoutMs + "ms: " + selector));
256
+ }
257
+ setTimeout(check, 60);
258
+ }
259
+ check();
260
+ });
261
+ }
262
+
263
+ /* ---- screenshot (SVG foreignObject serialization, best effort) ---- */
264
+ function collectCss() {
265
+ var out = [];
266
+ var sheets = document.styleSheets;
267
+ for (var i = 0; i < sheets.length; i++) {
268
+ var rules = null;
269
+ try { rules = sheets[i].cssRules; } catch (e) { rules = null; }
270
+ if (!rules) continue;
271
+ for (var j = 0; j < rules.length; j++) out.push(rules[j].cssText);
272
+ }
273
+ return out.join("\\n");
274
+ }
275
+
276
+ function inlineImages(clone) {
277
+ var images = clone.querySelectorAll("img");
278
+ var jobs = [];
279
+ for (var i = 0; i < images.length; i++) {
280
+ (function (img) {
281
+ var src = img.getAttribute("src") || "";
282
+ if (src === "" || src.indexOf("data:") === 0) return;
283
+ jobs.push(window.fetch(src, { credentials: "omit" }).then(function (res) {
284
+ if (!res.ok) return null;
285
+ return res.blob().then(function (blob) {
286
+ return new Promise(function (resolve) {
287
+ var reader = new FileReader();
288
+ reader.onload = function () { img.setAttribute("src", String(reader.result)); resolve(null); };
289
+ reader.onerror = function () { resolve(null); };
290
+ reader.readAsDataURL(blob);
291
+ });
292
+ });
293
+ }).catch(function () { return null; }));
294
+ })(images[i]);
295
+ }
296
+ return Promise.all(jobs);
297
+ }
298
+
299
+ var QUOTE = String.fromCharCode(34);
300
+ function tag(name, pairs) {
301
+ var out = "<" + name;
302
+ for (var i = 0; i < pairs.length; i += 2) out += " " + pairs[i] + "=" + QUOTE + pairs[i + 1] + QUOTE;
303
+ return out + ">";
304
+ }
305
+
306
+ function screenshot(args) {
307
+ var scale = Math.min(asNumber(args.scale, 1), 2);
308
+ var maxHeight = asNumber(args.maxHeight, 2400);
309
+ var width = Math.max(1, document.documentElement.clientWidth || window.innerWidth || 1024);
310
+ var full = document.documentElement.scrollHeight || window.innerHeight || 768;
311
+ var height = Math.max(1, Math.min(full, maxHeight));
312
+ var clone = document.documentElement.cloneNode(true);
313
+ var scripts = clone.querySelectorAll("script");
314
+ for (var i = 0; i < scripts.length; i++) {
315
+ if (scripts[i].parentNode) scripts[i].parentNode.removeChild(scripts[i]);
316
+ }
317
+ clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
318
+ return inlineImages(clone).then(function () {
319
+ var style = document.createElement("style");
320
+ style.textContent = collectCss();
321
+ var head = clone.querySelector("head");
322
+ if (head) head.insertBefore(style, head.firstChild);
323
+ else clone.insertBefore(style, clone.firstChild);
324
+ var markup = new XMLSerializer().serializeToString(clone);
325
+ var svg = tag("svg", ["xmlns", "http://www.w3.org/2000/svg", "width", width, "height", height])
326
+ + tag("foreignObject", ["x", 0, "y", 0, "width", width, "height", height])
327
+ + markup + "</foreignObject></svg>";
328
+ var image = new Image();
329
+ return new Promise(function (resolve, reject) {
330
+ image.onload = function () {
331
+ var canvas = document.createElement("canvas");
332
+ canvas.width = Math.round(width * scale);
333
+ canvas.height = Math.round(height * scale);
334
+ var ctx = canvas.getContext("2d");
335
+ ctx.scale(scale, scale);
336
+ try { ctx.drawImage(image, 0, 0); } catch (e) {}
337
+ var dataUrl = null;
338
+ try { dataUrl = canvas.toDataURL("image/png"); }
339
+ catch (e2) {
340
+ reject(fail("SCREENSHOT_TAINTED", "canvas is tainted by a cross-origin resource that could not be inlined; fall back to snapshot / inspect"));
341
+ return;
342
+ }
343
+ resolve({ dataUrl: dataUrl, width: canvas.width, height: canvas.height, bytes: dataUrl.length, clipped: full > height });
344
+ };
345
+ image.onerror = function () {
346
+ reject(fail("SCREENSHOT_FAILED", "the browser refused to rasterize the serialized DOM"));
347
+ };
348
+ image.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
349
+ });
350
+ });
351
+ }
352
+
353
+ /* ---- console read ---- */
354
+ function readConsole(args) {
355
+ var since = asNumber(args.since, 0);
356
+ var limit = asNumber(args.limit, 60);
357
+ var level = asString(args.level, "");
358
+ var out = [];
359
+ for (var i = 0; i < consoleLog.length; i++) {
360
+ var entry = consoleLog[i];
361
+ if (entry.seq <= since) continue;
362
+ if (level !== "" && entry.level !== level) continue;
363
+ out.push(entry);
364
+ }
365
+ var dropped = 0;
366
+ if (out.length > limit) {
367
+ dropped = out.length - limit;
368
+ out = out.slice(out.length - limit);
369
+ }
370
+ return { entries: out, cursor: consoleSeq, total: consoleLog.length, dropped: dropped };
371
+ }
372
+
373
+ function snapshot(args) {
374
+ var body = document.body;
375
+ var raw = body === null ? "" : body.innerText || body.textContent || "";
376
+ return {
377
+ ping: {
378
+ href: String(window.location.href),
379
+ title: String(document.title || ""),
380
+ readyState: String(document.readyState),
381
+ width: window.innerWidth,
382
+ height: window.innerHeight,
383
+ scrollHeight: document.documentElement.scrollHeight,
384
+ scrollY: Math.round(window.scrollY),
385
+ },
386
+ text: truncate(raw, asNumber(args.maxChars, MAX_TEXT_CHARS)),
387
+ textLength: raw.length,
388
+ console: readConsole({ since: asNumber(args.consoleSince, 0), limit: asNumber(args.consoleLimit, 40) }),
389
+ };
390
+ }
391
+
392
+ function scrollPage(args) {
393
+ if (typeof args.selector === "string" && args.selector !== "") {
394
+ var el = query(args.selector, args.nth);
395
+ try { el.scrollIntoView({ block: asString(args.block, "center"), inline: "nearest" }); } catch (e) { el.scrollIntoView(); }
396
+ } else {
397
+ window.scrollTo(asNumber(args.x, window.scrollX), asNumber(args.y, window.scrollY));
398
+ }
399
+ return { scrollX: Math.round(window.scrollX), scrollY: Math.round(window.scrollY), scrollHeight: document.documentElement.scrollHeight };
400
+ }
401
+
402
+ function run(op, args) {
403
+ if (op === "ping") {
404
+ return {
405
+ href: String(window.location.href),
406
+ title: String(document.title || ""),
407
+ readyState: String(document.readyState),
408
+ width: window.innerWidth,
409
+ height: window.innerHeight,
410
+ consoleCursor: consoleSeq,
411
+ };
412
+ }
413
+ if (op === "snapshot") return snapshot(args);
414
+ if (op === "console") return readConsole(args);
415
+ if (op === "text") {
416
+ var body = document.body;
417
+ var raw = body === null ? "" : body.innerText || body.textContent || "";
418
+ return { title: String(document.title || ""), text: truncate(raw, asNumber(args.maxChars, MAX_TEXT_CHARS)), length: raw.length };
419
+ }
420
+ if (op === "inspect") {
421
+ var selector = asString(args.selector, DEFAULT_INSPECT_SELECTOR);
422
+ var limit = asNumber(args.limit, 60);
423
+ var nodes = document.querySelectorAll(selector);
424
+ var items = [];
425
+ var hidden = 0;
426
+ for (var i = 0; i < nodes.length && items.length < limit; i++) {
427
+ if (args.includeHidden !== true && !isVisible(nodes[i])) { hidden += 1; continue; }
428
+ items.push(describe(nodes[i], args.maxText));
429
+ }
430
+ return { selector: selector, matched: nodes.length, returned: items.length, hiddenSkipped: hidden, items: items };
431
+ }
432
+ if (op === "html") {
433
+ var hasSelector = typeof args.selector === "string" && args.selector !== "";
434
+ var target = hasSelector ? query(args.selector, args.nth) : document.body;
435
+ if (!target) throw fail("ELEMENT_NOT_FOUND", "cannot read html: document.body is unavailable");
436
+ var markup = target.outerHTML || "";
437
+ return { selector: hasSelector ? args.selector : "body", html: truncate(markup, asNumber(args.maxChars, MAX_HTML_CHARS)), length: markup.length };
438
+ }
439
+ if (op === "click") {
440
+ var hasTarget = typeof args.selector === "string" && args.selector !== "";
441
+ if (hasTarget) {
442
+ var el = query(args.selector, args.nth);
443
+ if (!isVisible(el)) throw fail("ELEMENT_NOT_INTERACTABLE", "element is not visible, scroll it into view first: " + args.selector);
444
+ return clickElement(el);
445
+ }
446
+ var x = asNumber(args.x, -1);
447
+ var y = asNumber(args.y, -1);
448
+ if (x < 0 || y < 0) throw fail("INVALID_ARGS", "click requires either selector or x/y");
449
+ var hit = document.elementFromPoint(x, y);
450
+ if (hit === null) throw fail("ELEMENT_NOT_FOUND", "no element at point (" + x + ", " + y + ")");
451
+ return clickElement(hit, x, y);
452
+ }
453
+ if (op === "type") {
454
+ if (typeof args.selector !== "string" || args.selector === "") {
455
+ throw fail("INVALID_ARGS", "type requires a selector");
456
+ }
457
+ var field = query(args.selector, args.nth);
458
+ var tagName = String(field.tagName || "").toLowerCase();
459
+ var editable = tagName === "input" || tagName === "textarea" || tagName === "select" || field.isContentEditable === true;
460
+ if (!editable) throw fail("ELEMENT_NOT_INTERACTABLE", "element is not a text field: " + tagName);
461
+ return typeInto(field, args.value, args.clear !== false, args.submit === true);
462
+ }
463
+ if (op === "press") {
464
+ var keyTarget = null;
465
+ if (typeof args.selector === "string" && args.selector !== "") keyTarget = query(args.selector, args.nth);
466
+ return fireKey(keyTarget, asString(args.key, "Enter"));
467
+ }
468
+ if (op === "waitFor") {
469
+ if (typeof args.selector !== "string" || args.selector === "") {
470
+ throw fail("INVALID_ARGS", "waitFor requires a selector");
471
+ }
472
+ return waitFor(args.selector, asString(args.state, "visible"), asNumber(args.timeoutMs, DEFAULT_TIMEOUT_MS));
473
+ }
474
+ if (op === "scroll") return scrollPage(args);
475
+ if (op === "screenshot") return screenshot(args);
476
+ throw fail("UNKNOWN_OP", "unknown automation op: " + op);
477
+ }
478
+
479
+ function bridgeWindow() {
480
+ if (window.parent !== window) return window.parent;
481
+ return window.opener || null;
482
+ }
483
+
484
+ window.addEventListener("message", function (event) {
485
+ var data = event.data;
486
+ if (!data || data.__adepAutomationRequest !== true) return;
487
+ var replyTo = bridgeWindow();
488
+ if (!replyTo) return;
489
+ var id = data.id;
490
+ function send(ok, payload) {
491
+ try {
492
+ replyTo.postMessage({
493
+ __adepAutomationResponse: true,
494
+ id: id,
495
+ ok: ok,
496
+ result: ok ? payload.result : null,
497
+ error: ok ? null : payload.error,
498
+ }, "*");
499
+ } catch (e) {}
500
+ }
501
+ Promise.resolve().then(function () {
502
+ return run(String(data.op || ""), data.args || {});
503
+ }).then(function (result) {
504
+ send(true, { result: result === undefined ? null : result });
505
+ }).catch(function (error) {
506
+ send(false, {
507
+ error: {
508
+ code: (error && error.code) || "AUTOMATION_FAILED",
509
+ message: error && error.message ? String(error.message) : String(error),
510
+ },
511
+ });
512
+ });
513
+ });
514
+
515
+ window.__adepAutomation = {
516
+ version: 1,
517
+ ops: ["ping", "snapshot", "text", "inspect", "html", "click", "type", "press", "waitFor", "scroll", "screenshot", "console"],
518
+ };
519
+ })();
520
+ `;
521
+
51
522
  // packages/vite-plugin/src/ide-proxy.ts
52
523
  var FN_FETCH_INTERCEPTOR_SCRIPT = `(function () {
53
524
  if (window.__adepFnProxyInstalled) return;
@@ -220,6 +691,18 @@ function injectFnProxyScriptTag(html) {
220
691
  if (html.includes("/@adep/fn-proxy.js")) return html;
221
692
  return html.replace("</head>", '<script src="/@adep/fn-proxy.js"></script></head>');
222
693
  }
694
+ function createAdepAutomationScriptMiddleware() {
695
+ return (req, res, next) => {
696
+ const pathname = (req.url ?? "").split("?")[0];
697
+ if (pathname !== "/@adep/automation.js") return next();
698
+ res.setHeader("content-type", "application/javascript; charset=utf-8");
699
+ res.end(PREVIEW_AUTOMATION_SCRIPT);
700
+ };
701
+ }
702
+ function injectAutomationScriptTag(html) {
703
+ if (html.includes("/@adep/automation.js")) return html;
704
+ return html.replace("</head>", '<script src="/@adep/automation.js"></script></head>');
705
+ }
223
706
 
224
707
  // packages/vite-plugin/src/dev-server.ts
225
708
  function adepPlugin(options = {}) {
@@ -278,6 +761,7 @@ function adepPlugin(options = {}) {
278
761
  server.middlewares.use(createAdepProxyMiddleware(prefixPath, dev.baseUrl));
279
762
  }
280
763
  server.middlewares.use(createAdepFnProxyScriptMiddleware());
764
+ server.middlewares.use(createAdepAutomationScriptMiddleware());
281
765
  };
282
766
  return {
283
767
  name: "adep-cloud-functions",
@@ -295,7 +779,7 @@ function adepPlugin(options = {}) {
295
779
  attachMiddlewares(server);
296
780
  },
297
781
  transformIndexHtml(html) {
298
- return injectFnProxyScriptTag(html);
782
+ return injectAutomationScriptTag(injectFnProxyScriptTag(html));
299
783
  },
300
784
  async closeBundle() {
301
785
  await disposeAdepDev();
@@ -305,10 +789,13 @@ function adepPlugin(options = {}) {
305
789
  var dev_server_default = adepPlugin;
306
790
  export {
307
791
  FN_FETCH_INTERCEPTOR_SCRIPT,
792
+ PREVIEW_AUTOMATION_SCRIPT,
308
793
  adepPlugin,
794
+ createAdepAutomationScriptMiddleware,
309
795
  createAdepFnProxyScriptMiddleware,
310
796
  createAdepProxyMiddleware,
311
797
  dev_server_default as default,
798
+ injectAutomationScriptTag,
312
799
  injectFnProxyScriptTag,
313
800
  isAddrInUse,
314
801
  normalizeFunctionPrefix
@@ -0,0 +1,20 @@
1
+ /**
2
+ * IDE 预览「自动化中继」脚本(`@adep/vite-plugin` 侧副本,**单一真相源**)。
3
+ *
4
+ * **同步纪律**:本字符串与 `packages/web-container/src/preview-automation.ts` 的
5
+ * `PREVIEW_AUTOMATION_SCRIPT`(浏览器内置 vite-dev 注入用)**逐字一致**——理由同
6
+ * `FN_FETCH_INTERCEPTOR_SCRIPT`:预览 iframe / 浏览器内 vite-dev 是两个独立加载上下文,
7
+ * 不共享 import,只共享文本契约。机检见
8
+ * `app/composables/__tests__/preview-inject-scripts.test.ts`(三份副本逐字比对 + 经典脚本语法 + 纯 ASCII)。
9
+ *
10
+ * 两条注入路径:
11
+ * - Nodebox:`app/composables/ide-nodebox-preview.ts` 经沙箱内注入插件(transformIndexHtml)
12
+ * 以 `<script src="/@adep/automation.js">` 注入;
13
+ * - 浏览器内置 dev server:`vite-dev.ts` 在 buildDocument 里内联进产物文档 `<head>` 第三位
14
+ * (控制台中继 → 云函数拦截器 → 本脚本);`dev-server.ts` / `@adep/cli/vite` 路径同款。
15
+ *
16
+ * ⚠️ 本文件是用生成器从 web-container 侧数组字面量转出来的(模板字面量里反斜杠必须双写,
17
+ * 手抄必然漂移)。改脚本请改 web-container 侧那份,再按同样的规则同步这里,最后跑逐字比对用例。
18
+ * 脚本正文只允许 ASCII(内联进 HTML 与 JSON.stringify 两条路都不做编码转换),故文案一律英文。
19
+ */
20
+ export declare const PREVIEW_AUTOMATION_SCRIPT = "(function () {\n if (window.__adepAutomationInstalled) return;\n window.__adepAutomationInstalled = true;\n\n var CONSOLE_LIMIT = 200;\n var DEFAULT_TIMEOUT_MS = 8000;\n var MAX_TEXT_CHARS = 12000;\n var MAX_HTML_CHARS = 20000;\n var DEFAULT_INSPECT_SELECTOR = \"a,button,input,select,textarea,img,h1,h2,h3,h4,label,[role],[data-testid]\";\n var consoleLog = [];\n var consoleSeq = 0;\n\n function fail(code, message) {\n var error = new Error(message);\n error.code = code;\n return error;\n }\n\n function asNumber(value, fallback) {\n return typeof value === \"number\" && isFinite(value) ? value : fallback;\n }\n\n function asString(value, fallback) {\n return typeof value === \"string\" ? value : fallback;\n }\n\n function truncate(value, max) {\n var text = value == null ? \"\" : String(value);\n var limit = typeof max === \"number\" && isFinite(max) && max > 0 ? Math.floor(max) : 0;\n if (limit === 0 || text.length <= limit) return text;\n return text.slice(0, limit) + \"...[truncated, total \" + text.length + \" chars]\";\n }\n\n /* ---- console / error ring buffer ---- */\n function record(level, text) {\n consoleSeq += 1;\n consoleLog.push({ seq: consoleSeq, level: level, text: truncate(text, 2000), at: Date.now() });\n if (consoleLog.length > CONSOLE_LIMIT) consoleLog.splice(0, consoleLog.length - CONSOLE_LIMIT);\n }\n\n function fmt(value) {\n try {\n if (typeof value === \"string\") return value;\n if (value === undefined) return \"undefined\";\n if (value instanceof Error) return value.stack || (value.name + \": \" + value.message);\n var seen = [];\n var json = JSON.stringify(value, function (key, val) {\n if (val instanceof Error) return val.stack || (val.name + \": \" + val.message);\n if (typeof val === \"function\") return \"[Function \" + (val.name || \"anonymous\") + \"]\";\n if (typeof val === \"bigint\") return String(val) + \"n\";\n if (val && typeof val === \"object\") {\n if (seen.indexOf(val) !== -1) return \"[Circular]\";\n seen.push(val);\n }\n return val;\n });\n return json === undefined ? String(value) : json;\n } catch (e) {\n return String(value);\n }\n }\n\n var LEVELS = { log: \"log\", info: \"info\", warn: \"warn\", error: \"error\", debug: \"log\" };\n Object.keys(LEVELS).forEach(function (name) {\n var native = console[name];\n console[name] = function () {\n try { record(LEVELS[name], Array.prototype.map.call(arguments, fmt).join(\" \")); } catch (e) {}\n native.apply(console, arguments);\n };\n });\n window.addEventListener('error', function (event) {\n var text = event.message || \"Script error\";\n if (event.filename) text += \" (\" + event.filename + \":\" + event.lineno + \":\" + event.colno + \")\";\n record(\"error\", text);\n });\n window.addEventListener('unhandledrejection', function (event) {\n var reason = event.reason;\n record(\"error\", reason && reason.stack ? String(reason.stack) : \"Unhandled rejection: \" + fmt(reason));\n });\n\n /* ---- DOM read ---- */\n function query(selector, nth) {\n var list = document.querySelectorAll(selector);\n if (list.length === 0) throw fail(\"ELEMENT_NOT_FOUND\", \"selector matched nothing: \" + selector);\n var index = asNumber(nth, 0);\n var el = list[index];\n if (!el) throw fail(\"ELEMENT_NOT_FOUND\", \"selector matched \" + list.length + \" elements; index \" + index + \" is out of range\");\n return el;\n }\n\n function isVisible(el) {\n if (!el || !el.getBoundingClientRect) return false;\n var rect = el.getBoundingClientRect();\n if (rect.width <= 0 && rect.height <= 0) return false;\n var style = window.getComputedStyle(el);\n if (style.visibility === \"hidden\" || style.display === \"none\") return false;\n if (Number(style.opacity) === 0) return false;\n return true;\n }\n\n function rectOf(el) {\n var rect = el.getBoundingClientRect();\n return {\n x: Math.round(rect.left + window.scrollX),\n y: Math.round(rect.top + window.scrollY),\n w: Math.round(rect.width),\n h: Math.round(rect.height),\n };\n }\n\n function describe(el, maxText) {\n var tag = String(el.tagName || \"\").toLowerCase();\n var text = \"\";\n if (tag === \"input\" || tag === \"textarea\" || tag === \"select\") text = String(el.value || \"\");\n else text = el.textContent || \"\";\n var out = {\n tag: tag,\n testid: el.getAttribute ? el.getAttribute(\"data-testid\") : null,\n id: el.id || null,\n cls: el.className && typeof el.className === \"string\" ? el.className : null,\n role: el.getAttribute ? el.getAttribute(\"role\") : null,\n text: truncate(String(text).replace(/[\\s\\u00a0]+/g, \" \").trim(), asNumber(maxText, 120)),\n rect: rectOf(el),\n visible: isVisible(el),\n };\n if (tag === \"input\" || tag === \"textarea\" || tag === \"select\") {\n out.field = el.getAttribute(\"name\") || el.getAttribute(\"placeholder\") || null;\n if (tag === \"input\") out.type = el.getAttribute(\"type\") || \"text\";\n }\n if (tag === \"a\") out.href = el.getAttribute(\"href\") || null;\n if (el.disabled === true) out.disabled = true;\n if (el.checked !== undefined && (tag === \"input\")) out.checked = el.checked === true;\n return out;\n }\n\n /* ---- DOM write ---- */\n function fireMouse(el, x, y, kind) {\n var rect = el.getBoundingClientRect();\n var clientX = typeof x === \"number\" ? x : rect.left + rect.width / 2;\n var clientY = typeof y === \"number\" ? y : rect.top + rect.height / 2;\n el.dispatchEvent(new MouseEvent(kind, {\n bubbles: true, cancelable: true, composed: true, view: window,\n clientX: clientX, clientY: clientY, button: 0,\n }));\n }\n\n function clickElement(el, x, y) {\n try { el.scrollIntoView({ block: \"center\", inline: \"center\" }); } catch (e) {}\n fireMouse(el, x, y, \"mousedown\");\n fireMouse(el, x, y, \"mouseup\");\n fireMouse(el, x, y, \"click\");\n return describe(el, 120);\n }\n\n function fireKey(el, key) {\n var target = el || document.activeElement || document.body;\n var init = { key: key, bubbles: true, cancelable: true, composed: true };\n if (key === \"Enter\") { init.keyCode = 13; init.which = 13; }\n if (key === \"Escape\") { init.keyCode = 27; init.which = 27; }\n if (key === \"Tab\") { init.keyCode = 9; init.which = 9; }\n var allowed = target.dispatchEvent(new KeyboardEvent(\"keydown\", init));\n if (allowed) target.dispatchEvent(new KeyboardEvent(\"keypress\", init));\n target.dispatchEvent(new KeyboardEvent(\"keyup\", init));\n return { key: key, target: describe(target, 80) };\n }\n\n function setNativeValue(el, value) {\n var proto = null;\n if (window.HTMLTextAreaElement && el instanceof window.HTMLTextAreaElement) proto = window.HTMLTextAreaElement.prototype;\n else if (window.HTMLSelectElement && el instanceof window.HTMLSelectElement) proto = window.HTMLSelectElement.prototype;\n else if (window.HTMLInputElement && el instanceof window.HTMLInputElement) proto = window.HTMLInputElement.prototype;\n var descriptor = proto ? Object.getOwnPropertyDescriptor(proto, \"value\") : null;\n if (descriptor && descriptor.set) descriptor.set.call(el, value);\n else el.value = value;\n }\n\n function fireInput(el) {\n el.dispatchEvent(new Event(\"input\", { bubbles: true, composed: true }));\n el.dispatchEvent(new Event(\"change\", { bubbles: true, composed: true }));\n }\n\n function typeInto(el, value, clear, submit) {\n try { el.focus(); } catch (e) {}\n if (clear) {\n setNativeValue(el, \"\");\n fireInput(el);\n }\n setNativeValue(el, clear ? String(value) : String(el.value || \"\") + String(value));\n fireInput(el);\n if (submit) fireKey(el, \"Enter\");\n return describe(el, 200);\n }\n\n function waitFor(selector, state, timeoutMs) {\n var want = state === \"hidden\" || state === \"detached\" ? state : \"visible\";\n var deadline = Date.now() + timeoutMs;\n return new Promise(function (resolve, reject) {\n function check() {\n var el = document.querySelector(selector);\n if (want === \"detached\" && el === null) return resolve({ state: want, selector: selector });\n if (want === \"hidden\" && (el === null || !isVisible(el))) return resolve({ state: want, selector: selector });\n if (want === \"visible\" && el !== null && isVisible(el)) return resolve(describe(el, 200));\n if (Date.now() >= deadline) {\n return reject(fail(\"WAIT_TIMEOUT\", \"waitFor \" + want + \" timed out after \" + timeoutMs + \"ms: \" + selector));\n }\n setTimeout(check, 60);\n }\n check();\n });\n }\n\n /* ---- screenshot (SVG foreignObject serialization, best effort) ---- */\n function collectCss() {\n var out = [];\n var sheets = document.styleSheets;\n for (var i = 0; i < sheets.length; i++) {\n var rules = null;\n try { rules = sheets[i].cssRules; } catch (e) { rules = null; }\n if (!rules) continue;\n for (var j = 0; j < rules.length; j++) out.push(rules[j].cssText);\n }\n return out.join(\"\\n\");\n }\n\n function inlineImages(clone) {\n var images = clone.querySelectorAll(\"img\");\n var jobs = [];\n for (var i = 0; i < images.length; i++) {\n (function (img) {\n var src = img.getAttribute(\"src\") || \"\";\n if (src === \"\" || src.indexOf(\"data:\") === 0) return;\n jobs.push(window.fetch(src, { credentials: \"omit\" }).then(function (res) {\n if (!res.ok) return null;\n return res.blob().then(function (blob) {\n return new Promise(function (resolve) {\n var reader = new FileReader();\n reader.onload = function () { img.setAttribute(\"src\", String(reader.result)); resolve(null); };\n reader.onerror = function () { resolve(null); };\n reader.readAsDataURL(blob);\n });\n });\n }).catch(function () { return null; }));\n })(images[i]);\n }\n return Promise.all(jobs);\n }\n\n var QUOTE = String.fromCharCode(34);\n function tag(name, pairs) {\n var out = \"<\" + name;\n for (var i = 0; i < pairs.length; i += 2) out += \" \" + pairs[i] + \"=\" + QUOTE + pairs[i + 1] + QUOTE;\n return out + \">\";\n }\n\n function screenshot(args) {\n var scale = Math.min(asNumber(args.scale, 1), 2);\n var maxHeight = asNumber(args.maxHeight, 2400);\n var width = Math.max(1, document.documentElement.clientWidth || window.innerWidth || 1024);\n var full = document.documentElement.scrollHeight || window.innerHeight || 768;\n var height = Math.max(1, Math.min(full, maxHeight));\n var clone = document.documentElement.cloneNode(true);\n var scripts = clone.querySelectorAll(\"script\");\n for (var i = 0; i < scripts.length; i++) {\n if (scripts[i].parentNode) scripts[i].parentNode.removeChild(scripts[i]);\n }\n clone.setAttribute(\"xmlns\", \"http://www.w3.org/1999/xhtml\");\n return inlineImages(clone).then(function () {\n var style = document.createElement(\"style\");\n style.textContent = collectCss();\n var head = clone.querySelector(\"head\");\n if (head) head.insertBefore(style, head.firstChild);\n else clone.insertBefore(style, clone.firstChild);\n var markup = new XMLSerializer().serializeToString(clone);\n var svg = tag(\"svg\", [\"xmlns\", \"http://www.w3.org/2000/svg\", \"width\", width, \"height\", height])\n + tag(\"foreignObject\", [\"x\", 0, \"y\", 0, \"width\", width, \"height\", height])\n + markup + \"</foreignObject></svg>\";\n var image = new Image();\n return new Promise(function (resolve, reject) {\n image.onload = function () {\n var canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(width * scale);\n canvas.height = Math.round(height * scale);\n var ctx = canvas.getContext(\"2d\");\n ctx.scale(scale, scale);\n try { ctx.drawImage(image, 0, 0); } catch (e) {}\n var dataUrl = null;\n try { dataUrl = canvas.toDataURL(\"image/png\"); }\n catch (e2) {\n reject(fail(\"SCREENSHOT_TAINTED\", \"canvas is tainted by a cross-origin resource that could not be inlined; fall back to snapshot / inspect\"));\n return;\n }\n resolve({ dataUrl: dataUrl, width: canvas.width, height: canvas.height, bytes: dataUrl.length, clipped: full > height });\n };\n image.onerror = function () {\n reject(fail(\"SCREENSHOT_FAILED\", \"the browser refused to rasterize the serialized DOM\"));\n };\n image.src = \"data:image/svg+xml;charset=utf-8,\" + encodeURIComponent(svg);\n });\n });\n }\n\n /* ---- console read ---- */\n function readConsole(args) {\n var since = asNumber(args.since, 0);\n var limit = asNumber(args.limit, 60);\n var level = asString(args.level, \"\");\n var out = [];\n for (var i = 0; i < consoleLog.length; i++) {\n var entry = consoleLog[i];\n if (entry.seq <= since) continue;\n if (level !== \"\" && entry.level !== level) continue;\n out.push(entry);\n }\n var dropped = 0;\n if (out.length > limit) {\n dropped = out.length - limit;\n out = out.slice(out.length - limit);\n }\n return { entries: out, cursor: consoleSeq, total: consoleLog.length, dropped: dropped };\n }\n\n function snapshot(args) {\n var body = document.body;\n var raw = body === null ? \"\" : body.innerText || body.textContent || \"\";\n return {\n ping: {\n href: String(window.location.href),\n title: String(document.title || \"\"),\n readyState: String(document.readyState),\n width: window.innerWidth,\n height: window.innerHeight,\n scrollHeight: document.documentElement.scrollHeight,\n scrollY: Math.round(window.scrollY),\n },\n text: truncate(raw, asNumber(args.maxChars, MAX_TEXT_CHARS)),\n textLength: raw.length,\n console: readConsole({ since: asNumber(args.consoleSince, 0), limit: asNumber(args.consoleLimit, 40) }),\n };\n }\n\n function scrollPage(args) {\n if (typeof args.selector === \"string\" && args.selector !== \"\") {\n var el = query(args.selector, args.nth);\n try { el.scrollIntoView({ block: asString(args.block, \"center\"), inline: \"nearest\" }); } catch (e) { el.scrollIntoView(); }\n } else {\n window.scrollTo(asNumber(args.x, window.scrollX), asNumber(args.y, window.scrollY));\n }\n return { scrollX: Math.round(window.scrollX), scrollY: Math.round(window.scrollY), scrollHeight: document.documentElement.scrollHeight };\n }\n\n function run(op, args) {\n if (op === \"ping\") {\n return {\n href: String(window.location.href),\n title: String(document.title || \"\"),\n readyState: String(document.readyState),\n width: window.innerWidth,\n height: window.innerHeight,\n consoleCursor: consoleSeq,\n };\n }\n if (op === \"snapshot\") return snapshot(args);\n if (op === \"console\") return readConsole(args);\n if (op === \"text\") {\n var body = document.body;\n var raw = body === null ? \"\" : body.innerText || body.textContent || \"\";\n return { title: String(document.title || \"\"), text: truncate(raw, asNumber(args.maxChars, MAX_TEXT_CHARS)), length: raw.length };\n }\n if (op === \"inspect\") {\n var selector = asString(args.selector, DEFAULT_INSPECT_SELECTOR);\n var limit = asNumber(args.limit, 60);\n var nodes = document.querySelectorAll(selector);\n var items = [];\n var hidden = 0;\n for (var i = 0; i < nodes.length && items.length < limit; i++) {\n if (args.includeHidden !== true && !isVisible(nodes[i])) { hidden += 1; continue; }\n items.push(describe(nodes[i], args.maxText));\n }\n return { selector: selector, matched: nodes.length, returned: items.length, hiddenSkipped: hidden, items: items };\n }\n if (op === \"html\") {\n var hasSelector = typeof args.selector === \"string\" && args.selector !== \"\";\n var target = hasSelector ? query(args.selector, args.nth) : document.body;\n if (!target) throw fail(\"ELEMENT_NOT_FOUND\", \"cannot read html: document.body is unavailable\");\n var markup = target.outerHTML || \"\";\n return { selector: hasSelector ? args.selector : \"body\", html: truncate(markup, asNumber(args.maxChars, MAX_HTML_CHARS)), length: markup.length };\n }\n if (op === \"click\") {\n var hasTarget = typeof args.selector === \"string\" && args.selector !== \"\";\n if (hasTarget) {\n var el = query(args.selector, args.nth);\n if (!isVisible(el)) throw fail(\"ELEMENT_NOT_INTERACTABLE\", \"element is not visible, scroll it into view first: \" + args.selector);\n return clickElement(el);\n }\n var x = asNumber(args.x, -1);\n var y = asNumber(args.y, -1);\n if (x < 0 || y < 0) throw fail(\"INVALID_ARGS\", \"click requires either selector or x/y\");\n var hit = document.elementFromPoint(x, y);\n if (hit === null) throw fail(\"ELEMENT_NOT_FOUND\", \"no element at point (\" + x + \", \" + y + \")\");\n return clickElement(hit, x, y);\n }\n if (op === \"type\") {\n if (typeof args.selector !== \"string\" || args.selector === \"\") {\n throw fail(\"INVALID_ARGS\", \"type requires a selector\");\n }\n var field = query(args.selector, args.nth);\n var tagName = String(field.tagName || \"\").toLowerCase();\n var editable = tagName === \"input\" || tagName === \"textarea\" || tagName === \"select\" || field.isContentEditable === true;\n if (!editable) throw fail(\"ELEMENT_NOT_INTERACTABLE\", \"element is not a text field: \" + tagName);\n return typeInto(field, args.value, args.clear !== false, args.submit === true);\n }\n if (op === \"press\") {\n var keyTarget = null;\n if (typeof args.selector === \"string\" && args.selector !== \"\") keyTarget = query(args.selector, args.nth);\n return fireKey(keyTarget, asString(args.key, \"Enter\"));\n }\n if (op === \"waitFor\") {\n if (typeof args.selector !== \"string\" || args.selector === \"\") {\n throw fail(\"INVALID_ARGS\", \"waitFor requires a selector\");\n }\n return waitFor(args.selector, asString(args.state, \"visible\"), asNumber(args.timeoutMs, DEFAULT_TIMEOUT_MS));\n }\n if (op === \"scroll\") return scrollPage(args);\n if (op === \"screenshot\") return screenshot(args);\n throw fail(\"UNKNOWN_OP\", \"unknown automation op: \" + op);\n }\n\n function bridgeWindow() {\n if (window.parent !== window) return window.parent;\n return window.opener || null;\n }\n\n window.addEventListener(\"message\", function (event) {\n var data = event.data;\n if (!data || data.__adepAutomationRequest !== true) return;\n var replyTo = bridgeWindow();\n if (!replyTo) return;\n var id = data.id;\n function send(ok, payload) {\n try {\n replyTo.postMessage({\n __adepAutomationResponse: true,\n id: id,\n ok: ok,\n result: ok ? payload.result : null,\n error: ok ? null : payload.error,\n }, \"*\");\n } catch (e) {}\n }\n Promise.resolve().then(function () {\n return run(String(data.op || \"\"), data.args || {});\n }).then(function (result) {\n send(true, { result: result === undefined ? null : result });\n }).catch(function (error) {\n send(false, {\n error: {\n code: (error && error.code) || \"AUTOMATION_FAILED\",\n message: error && error.message ? String(error.message) : String(error),\n },\n });\n });\n });\n\n window.__adepAutomation = {\n version: 1,\n ops: [\"ping\", \"snapshot\", \"text\", \"inspect\", \"html\", \"click\", \"type\", \"press\", \"waitFor\", \"scroll\", \"screenshot\", \"console\"],\n };\n})();\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adep/vite-plugin",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "云函数 Vite 插件(IDE-030,自 CLI-014 @adep/cli/vite 抽出):vite dev 进程内启动本地 adep dev server 并代理 /{prefix}/* 到云函数;同时 serve /@adep/fn-proxy.js(Web IDE 预览 fetch 拦截器)。本地运行时与配置加载经 createDevServer / loadConfig 注入端口接入,供 CLI / Web IDE / 非 CLI 用户独立使用。",