@veolab/discoverylab 1.3.2 → 1.3.3
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/dist/chunk-7EDIUVIO.js +4304 -0
- package/dist/{chunk-H4FYBUX6.js → chunk-AHVBE25Y.js} +23 -17
- package/dist/chunk-HGWEHWKJ.js +94 -0
- package/dist/{chunk-2RQ7BDPA.js → chunk-LXSWDEXV.js} +276 -56
- package/dist/{chunk-N6JJ2RGV.js → chunk-ZLHIHMSL.js} +1 -1
- package/dist/cli.js +26 -26
- package/dist/{esvp-GSISVXLC.js → esvp-KVOWYW6G.js} +2 -1
- package/dist/{esvp-mobile-GC7MAGMI.js → esvp-mobile-GZ5EMYPG.js} +3 -2
- package/dist/index.d.ts +13 -17
- package/dist/index.html +149 -29
- package/dist/index.js +6 -6
- package/dist/{server-RBJ2VROA.js → server-T5X6GGOO.js} +5 -5
- package/dist/templates/bundle/bundle.js +8 -4
- package/dist/templates/bundle/public/mockup-android-galaxy.png +0 -0
- package/dist/{tools-EYWRLTRB.js → tools-YGM5HRIB.js} +4 -4
- package/package.json +2 -2
- package/dist/chunk-GAKEFJ5T.js +0 -481
- package/dist/chunk-VEIZLLCI.js +0 -1696
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
APP_VERSION
|
|
4
|
-
} from "./chunk-6EGBXRDK.js";
|
|
5
2
|
import {
|
|
6
3
|
buildAppLabNetworkProfile
|
|
7
4
|
} from "./chunk-LB3RNE3O.js";
|
|
5
|
+
import {
|
|
6
|
+
APP_VERSION
|
|
7
|
+
} from "./chunk-6EGBXRDK.js";
|
|
8
8
|
import "./chunk-MLKGABMK.js";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
|
@@ -57,7 +57,7 @@ async function withESVPCli(action) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
async function getESVPBaseResult(serverUrl) {
|
|
60
|
-
const { getESVPConnection } = await import("./esvp-
|
|
60
|
+
const { getESVPConnection } = await import("./esvp-KVOWYW6G.js");
|
|
61
61
|
const connection = await getESVPConnection(serverUrl);
|
|
62
62
|
return {
|
|
63
63
|
serverUrl: connection.serverUrl,
|
|
@@ -72,7 +72,7 @@ function executorToPlatform(executor) {
|
|
|
72
72
|
var esvp = program.command("esvp").description("Access the public ESVP protocol and runtime from the CLI");
|
|
73
73
|
esvp.command("status").description("Check the configured ESVP server health").option("-s, --server <url>", "ESVP base URL").action(async (options) => {
|
|
74
74
|
await withESVPCli(async () => {
|
|
75
|
-
const { getESVPHealth } = await import("./esvp-
|
|
75
|
+
const { getESVPHealth } = await import("./esvp-KVOWYW6G.js");
|
|
76
76
|
return {
|
|
77
77
|
...await getESVPBaseResult(options.server),
|
|
78
78
|
health: await getESVPHealth(options.server)
|
|
@@ -81,7 +81,7 @@ esvp.command("status").description("Check the configured ESVP server health").op
|
|
|
81
81
|
});
|
|
82
82
|
esvp.command("devices").description("List ESVP-visible devices").option("-s, --server <url>", "ESVP base URL").option("-p, --platform <platform>", "adb | ios-sim | maestro-ios | all", "all").action(async (options) => {
|
|
83
83
|
await withESVPCli(async () => {
|
|
84
|
-
const { listESVPDevices } = await import("./esvp-
|
|
84
|
+
const { listESVPDevices } = await import("./esvp-KVOWYW6G.js");
|
|
85
85
|
return {
|
|
86
86
|
...await getESVPBaseResult(options.server),
|
|
87
87
|
devices: await listESVPDevices(options.platform, options.server)
|
|
@@ -90,7 +90,7 @@ esvp.command("devices").description("List ESVP-visible devices").option("-s, --s
|
|
|
90
90
|
});
|
|
91
91
|
esvp.command("sessions").description("List public ESVP sessions").option("-s, --server <url>", "ESVP base URL").action(async (options) => {
|
|
92
92
|
await withESVPCli(async () => {
|
|
93
|
-
const { listESVPSessions } = await import("./esvp-
|
|
93
|
+
const { listESVPSessions } = await import("./esvp-KVOWYW6G.js");
|
|
94
94
|
return {
|
|
95
95
|
...await getESVPBaseResult(options.server),
|
|
96
96
|
...await listESVPSessions(options.server)
|
|
@@ -99,7 +99,7 @@ esvp.command("sessions").description("List public ESVP sessions").option("-s, --
|
|
|
99
99
|
});
|
|
100
100
|
esvp.command("create").description("Create a new ESVP session").requiredOption("-e, --executor <executor>", "fake | adb | ios-sim | maestro-ios").option("-s, --server <url>", "ESVP base URL").option("-d, --device-id <id>", "Device or simulator ID").option("--meta-json <json>", "Session metadata as JSON").option("--meta-file <path>", "Path to session metadata JSON").option("--crash-clip-json <json>", "Crash clip config as JSON").option("--crash-clip-file <path>", "Path to crash clip config JSON").option("--with-network", "Auto-configure the default App Lab external-proxy profile after creating the session").action(async (options) => {
|
|
101
101
|
await withESVPCli(async () => {
|
|
102
|
-
const { createESVPSession, configureESVPNetwork } = await import("./esvp-
|
|
102
|
+
const { createESVPSession, configureESVPNetwork } = await import("./esvp-KVOWYW6G.js");
|
|
103
103
|
const meta = await readJsonSource(options.metaJson, options.metaFile, "meta");
|
|
104
104
|
const crashClip = await readJsonSource(options.crashClipJson, options.crashClipFile, "crash clip");
|
|
105
105
|
const createResult = await createESVPSession(
|
|
@@ -142,7 +142,7 @@ esvp.command("create").description("Create a new ESVP session").requiredOption("
|
|
|
142
142
|
});
|
|
143
143
|
esvp.command("get <sessionId>").description("Get a public ESVP session summary").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
144
144
|
await withESVPCli(async () => {
|
|
145
|
-
const { getESVPSession } = await import("./esvp-
|
|
145
|
+
const { getESVPSession } = await import("./esvp-KVOWYW6G.js");
|
|
146
146
|
return {
|
|
147
147
|
...await getESVPBaseResult(options.server),
|
|
148
148
|
...await getESVPSession(sessionId, options.server)
|
|
@@ -151,7 +151,7 @@ esvp.command("get <sessionId>").description("Get a public ESVP session summary")
|
|
|
151
151
|
});
|
|
152
152
|
esvp.command("inspect <sessionId>").description("Inspect a session and optionally load transcript and artifacts").option("-s, --server <url>", "ESVP base URL").option("--transcript", "Include transcript").option("--artifacts", "Include artifacts").action(async (sessionId, options) => {
|
|
153
153
|
await withESVPCli(async () => {
|
|
154
|
-
const { inspectESVPSession } = await import("./esvp-
|
|
154
|
+
const { inspectESVPSession } = await import("./esvp-KVOWYW6G.js");
|
|
155
155
|
return {
|
|
156
156
|
...await getESVPBaseResult(options.server),
|
|
157
157
|
...await inspectESVPSession(
|
|
@@ -167,7 +167,7 @@ esvp.command("inspect <sessionId>").description("Inspect a session and optionall
|
|
|
167
167
|
});
|
|
168
168
|
esvp.command("transcript <sessionId>").description("Fetch the canonical session transcript").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
169
169
|
await withESVPCli(async () => {
|
|
170
|
-
const { getESVPTranscript } = await import("./esvp-
|
|
170
|
+
const { getESVPTranscript } = await import("./esvp-KVOWYW6G.js");
|
|
171
171
|
return {
|
|
172
172
|
...await getESVPBaseResult(options.server),
|
|
173
173
|
sessionId,
|
|
@@ -177,7 +177,7 @@ esvp.command("transcript <sessionId>").description("Fetch the canonical session
|
|
|
177
177
|
});
|
|
178
178
|
esvp.command("artifacts <sessionId>").description("List session artifacts").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
179
179
|
await withESVPCli(async () => {
|
|
180
|
-
const { listESVPArtifacts } = await import("./esvp-
|
|
180
|
+
const { listESVPArtifacts } = await import("./esvp-KVOWYW6G.js");
|
|
181
181
|
return {
|
|
182
182
|
...await getESVPBaseResult(options.server),
|
|
183
183
|
sessionId,
|
|
@@ -187,13 +187,13 @@ esvp.command("artifacts <sessionId>").description("List session artifacts").opti
|
|
|
187
187
|
});
|
|
188
188
|
esvp.command("artifact <sessionId> <artifactPath>").description("Read a public artifact payload").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, artifactPath, options) => {
|
|
189
189
|
await withESVPCli(async () => {
|
|
190
|
-
const { getESVPArtifactContent } = await import("./esvp-
|
|
190
|
+
const { getESVPArtifactContent } = await import("./esvp-KVOWYW6G.js");
|
|
191
191
|
return await getESVPArtifactContent(sessionId, artifactPath, options.server);
|
|
192
192
|
});
|
|
193
193
|
});
|
|
194
194
|
esvp.command("actions <sessionId>").description("Run public ESVP actions inside a session").option("-s, --server <url>", "ESVP base URL").option("--actions-json <json>", "JSON array of ESVP actions").option("--actions-file <path>", "Path to a JSON file with ESVP actions").option("--finish", "Finish the session after actions").option("--capture-logcat", "Capture logcat on finish when supported").option("--checkpoint-after-each", "Set checkpointAfter on every action").option("--with-network", "Auto-configure the default App Lab external-proxy profile before running actions if not already configured").action(async (sessionId, options) => {
|
|
195
195
|
await withESVPCli(async () => {
|
|
196
|
-
const { runESVPActions, getESVPSessionNetwork, configureESVPNetwork } = await import("./esvp-
|
|
196
|
+
const { runESVPActions, getESVPSessionNetwork, configureESVPNetwork } = await import("./esvp-KVOWYW6G.js");
|
|
197
197
|
const actions = await readJsonSource(options.actionsJson, options.actionsFile, "actions");
|
|
198
198
|
if (!Array.isArray(actions) || actions.length === 0) {
|
|
199
199
|
failCli("Provide --actions-json or --actions-file with a non-empty array of ESVP actions.");
|
|
@@ -239,7 +239,7 @@ esvp.command("actions <sessionId>").description("Run public ESVP actions inside
|
|
|
239
239
|
});
|
|
240
240
|
esvp.command("checkpoint <sessionId>").description("Capture an ESVP checkpoint").option("-s, --server <url>", "ESVP base URL").option("-l, --label <label>", "Checkpoint label").action(async (sessionId, options) => {
|
|
241
241
|
await withESVPCli(async () => {
|
|
242
|
-
const { captureESVPCheckpoint } = await import("./esvp-
|
|
242
|
+
const { captureESVPCheckpoint } = await import("./esvp-KVOWYW6G.js");
|
|
243
243
|
return {
|
|
244
244
|
...await getESVPBaseResult(options.server),
|
|
245
245
|
...await captureESVPCheckpoint(
|
|
@@ -254,7 +254,7 @@ esvp.command("checkpoint <sessionId>").description("Capture an ESVP checkpoint")
|
|
|
254
254
|
});
|
|
255
255
|
esvp.command("finish <sessionId>").description("Finish an ESVP session").option("-s, --server <url>", "ESVP base URL").option("--capture-logcat", "Capture logcat on finish when supported").action(async (sessionId, options) => {
|
|
256
256
|
await withESVPCli(async () => {
|
|
257
|
-
const { finishESVPSession } = await import("./esvp-
|
|
257
|
+
const { finishESVPSession } = await import("./esvp-KVOWYW6G.js");
|
|
258
258
|
return {
|
|
259
259
|
...await getESVPBaseResult(options.server),
|
|
260
260
|
...await finishESVPSession(
|
|
@@ -269,7 +269,7 @@ esvp.command("finish <sessionId>").description("Finish an ESVP session").option(
|
|
|
269
269
|
});
|
|
270
270
|
esvp.command("preflight <sessionId>").description("Run preflight/bootstrap rules on an ESVP session").option("-s, --server <url>", "ESVP base URL").option("--policy <policy>", "Preflight policy name (e.g. fresh_install)").option("--app-id <appId>", "Target app ID").option("--json <json>", "Preflight config as JSON string").option("--file <path>", "Path to preflight config JSON file").action(async (sessionId, options) => {
|
|
271
271
|
await withESVPCli(async () => {
|
|
272
|
-
const { runESVPPreflight } = await import("./esvp-
|
|
272
|
+
const { runESVPPreflight } = await import("./esvp-KVOWYW6G.js");
|
|
273
273
|
const fromSource = await readJsonSource(options.json, options.file, "preflight config");
|
|
274
274
|
const config = {
|
|
275
275
|
...typeof fromSource === "object" && fromSource ? fromSource : {},
|
|
@@ -284,7 +284,7 @@ esvp.command("preflight <sessionId>").description("Run preflight/bootstrap rules
|
|
|
284
284
|
});
|
|
285
285
|
esvp.command("replay-run <sessionId>").description("Replay a session to a new ESVP session").option("-s, --server <url>", "ESVP base URL").option("-e, --executor <executor>", "fake | adb | ios-sim | maestro-ios").option("-d, --device-id <id>", "Replay target device ID").option("--capture-logcat", "Capture logcat on finish when supported").option("--meta-json <json>", "Replay metadata as JSON").option("--meta-file <path>", "Path to replay metadata JSON").action(async (sessionId, options) => {
|
|
286
286
|
await withESVPCli(async () => {
|
|
287
|
-
const { replayESVPSession, getESVPReplayConsistency } = await import("./esvp-
|
|
287
|
+
const { replayESVPSession, getESVPReplayConsistency } = await import("./esvp-KVOWYW6G.js");
|
|
288
288
|
const meta = await readJsonSource(options.metaJson, options.metaFile, "replay meta");
|
|
289
289
|
const replay = await replayESVPSession(
|
|
290
290
|
sessionId,
|
|
@@ -307,7 +307,7 @@ esvp.command("replay-run <sessionId>").description("Replay a session to a new ES
|
|
|
307
307
|
});
|
|
308
308
|
esvp.command("replay-validate <sessionId>").description("Validate whether a session supports public replay").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
309
309
|
await withESVPCli(async () => {
|
|
310
|
-
const { validateESVPReplay } = await import("./esvp-
|
|
310
|
+
const { validateESVPReplay } = await import("./esvp-KVOWYW6G.js");
|
|
311
311
|
return {
|
|
312
312
|
...await getESVPBaseResult(options.server),
|
|
313
313
|
...await validateESVPReplay(sessionId, options.server)
|
|
@@ -316,7 +316,7 @@ esvp.command("replay-validate <sessionId>").description("Validate whether a sess
|
|
|
316
316
|
});
|
|
317
317
|
esvp.command("replay-consistency <sessionId>").description("Inspect replay consistency for a replay session").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
318
318
|
await withESVPCli(async () => {
|
|
319
|
-
const { getESVPReplayConsistency } = await import("./esvp-
|
|
319
|
+
const { getESVPReplayConsistency } = await import("./esvp-KVOWYW6G.js");
|
|
320
320
|
return {
|
|
321
321
|
...await getESVPBaseResult(options.server),
|
|
322
322
|
...await getESVPReplayConsistency(sessionId, options.server)
|
|
@@ -325,7 +325,7 @@ esvp.command("replay-consistency <sessionId>").description("Inspect replay consi
|
|
|
325
325
|
});
|
|
326
326
|
esvp.command("network <sessionId>").description("Read the public network state for a session").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
327
327
|
await withESVPCli(async () => {
|
|
328
|
-
const { getESVPSessionNetwork } = await import("./esvp-
|
|
328
|
+
const { getESVPSessionNetwork } = await import("./esvp-KVOWYW6G.js");
|
|
329
329
|
return {
|
|
330
330
|
...await getESVPBaseResult(options.server),
|
|
331
331
|
...await getESVPSessionNetwork(sessionId, options.server)
|
|
@@ -334,7 +334,7 @@ esvp.command("network <sessionId>").description("Read the public network state f
|
|
|
334
334
|
});
|
|
335
335
|
esvp.command("network-configure <sessionId>").description("Apply a public ESVP network profile").option("-s, --server <url>", "ESVP base URL").option("--json <json>", "Raw network profile JSON").option("--file <path>", "Path to network profile JSON").option("--profile <name>", "Profile name").option("--label <label>", "Profile label").option("--connectivity <state>", "online | offline | reset").action(async (sessionId, options) => {
|
|
336
336
|
await withESVPCli(async () => {
|
|
337
|
-
const { configureESVPNetwork } = await import("./esvp-
|
|
337
|
+
const { configureESVPNetwork } = await import("./esvp-KVOWYW6G.js");
|
|
338
338
|
const payload = await readJsonSource(options.json, options.file, "network profile") || {};
|
|
339
339
|
const merged = {
|
|
340
340
|
...typeof payload === "object" && payload ? payload : {},
|
|
@@ -350,7 +350,7 @@ esvp.command("network-configure <sessionId>").description("Apply a public ESVP n
|
|
|
350
350
|
});
|
|
351
351
|
esvp.command("network-clear <sessionId>").description("Clear the active ESVP network profile").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
352
352
|
await withESVPCli(async () => {
|
|
353
|
-
const { clearESVPNetwork } = await import("./esvp-
|
|
353
|
+
const { clearESVPNetwork } = await import("./esvp-KVOWYW6G.js");
|
|
354
354
|
return {
|
|
355
355
|
...await getESVPBaseResult(options.server),
|
|
356
356
|
...await clearESVPNetwork(sessionId, options.server)
|
|
@@ -359,7 +359,7 @@ esvp.command("network-clear <sessionId>").description("Clear the active ESVP net
|
|
|
359
359
|
});
|
|
360
360
|
esvp.command("trace-attach <sessionId>").description("Attach a public network trace artifact to a session").requiredOption("--trace-kind <kind>", "Trace kind, e.g. http_trace or har").option("-s, --server <url>", "ESVP base URL").option("--json <json>", "Trace payload JSON").option("--file <path>", "Path to trace payload JSON/text").option("--label <label>", "Trace label").option("--source <source>", "Trace source").option("--request-id <id>", "Correlated request ID").option("--method <method>", "HTTP method").option("--url <url>", "Request URL").option("--status-code <code>", "HTTP status code").option("--format <format>", "Payload format label").action(async (sessionId, options) => {
|
|
361
361
|
await withESVPCli(async () => {
|
|
362
|
-
const { attachESVPNetworkTrace } = await import("./esvp-
|
|
362
|
+
const { attachESVPNetworkTrace } = await import("./esvp-KVOWYW6G.js");
|
|
363
363
|
const payload = await readJsonSource(options.json, options.file, "trace payload");
|
|
364
364
|
if (payload == null) {
|
|
365
365
|
failCli("Provide --json or --file with the trace payload to attach.");
|
|
@@ -389,7 +389,7 @@ program.command("serve").alias("server").description("Start the DiscoveryLab web
|
|
|
389
389
|
console.log(chalk.cyan("\n DiscoveryLab"));
|
|
390
390
|
console.log(chalk.gray(" AI-powered app testing & evidence generator\n"));
|
|
391
391
|
try {
|
|
392
|
-
const { startServer } = await import("./server-
|
|
392
|
+
const { startServer } = await import("./server-T5X6GGOO.js");
|
|
393
393
|
await startServer(port);
|
|
394
394
|
console.log(chalk.green(` Server running at http://localhost:${port}`));
|
|
395
395
|
console.log(chalk.gray(" Press Ctrl+C to stop\n"));
|
|
@@ -501,7 +501,7 @@ program.command("mcp").description("Run as MCP server (for Claude Code integrati
|
|
|
501
501
|
integrationTools,
|
|
502
502
|
taskHubTools,
|
|
503
503
|
esvpTools
|
|
504
|
-
} = await import("./tools-
|
|
504
|
+
} = await import("./tools-YGM5HRIB.js");
|
|
505
505
|
mcpServer.registerTools([
|
|
506
506
|
...uiTools,
|
|
507
507
|
...projectTools,
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
diagnoseESVPNetworkState,
|
|
5
5
|
translateMaestroActionsToESVP,
|
|
6
6
|
validateMaestroRecordingWithESVP
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZLHIHMSL.js";
|
|
8
8
|
import "./chunk-LB3RNE3O.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-7EDIUVIO.js";
|
|
10
|
+
import "./chunk-6EGBXRDK.js";
|
|
10
11
|
import "./chunk-SLNJEF32.js";
|
|
11
12
|
import "./chunk-VVIOB362.js";
|
|
12
13
|
import "./chunk-XFVDP332.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -1601,13 +1601,9 @@ interface ESVPResolvedConnection {
|
|
|
1601
1601
|
/**
|
|
1602
1602
|
* ESVP Public Client
|
|
1603
1603
|
*
|
|
1604
|
-
* Thin
|
|
1605
|
-
*
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1608
|
-
* Connection modes:
|
|
1609
|
-
* - remote: explicit serverUrl or ESVP_BASE_URL
|
|
1610
|
-
* - local: embedded OSS runtime via @entropylab/esvp-local or DISCOVERYLAB_ESVP_LOCAL_MODULE
|
|
1604
|
+
* Thin adapter for the public ESVP contract, backed by the in-process
|
|
1605
|
+
* App Lab local runtime. App Lab no longer routes ESVP traffic to an external
|
|
1606
|
+
* localhost sidecar or remote control-plane.
|
|
1611
1607
|
*/
|
|
1612
1608
|
|
|
1613
1609
|
type ESVPExecutor = 'fake' | 'adb' | 'ios-sim' | 'maestro-ios';
|
|
@@ -1664,6 +1660,16 @@ interface ESVPAction {
|
|
|
1664
1660
|
checkpointAfter?: boolean;
|
|
1665
1661
|
checkpointLabel?: string;
|
|
1666
1662
|
}
|
|
1663
|
+
interface ESVPPreflightRule {
|
|
1664
|
+
kind: 'permission' | 'dismiss_dialog' | 'wait_for_stable' | 'clear_data' | 'set_setting';
|
|
1665
|
+
[key: string]: unknown;
|
|
1666
|
+
}
|
|
1667
|
+
interface ESVPPreflightConfig {
|
|
1668
|
+
policy?: string;
|
|
1669
|
+
appId?: string;
|
|
1670
|
+
rules?: ESVPPreflightRule[];
|
|
1671
|
+
[key: string]: unknown;
|
|
1672
|
+
}
|
|
1667
1673
|
declare function getESVPBaseUrl(serverUrl?: string): string;
|
|
1668
1674
|
declare function resolveESVPBaseUrl(serverUrl?: string): Promise<string>;
|
|
1669
1675
|
declare function getESVPConnection(serverUrl?: string): Promise<ESVPResolvedConnection>;
|
|
@@ -1682,16 +1688,6 @@ declare function runESVPActions(sessionId: string, input: {
|
|
|
1682
1688
|
declare function finishESVPSession(sessionId: string, input?: {
|
|
1683
1689
|
captureLogcat?: boolean;
|
|
1684
1690
|
}, serverUrl?: string): Promise<any>;
|
|
1685
|
-
interface ESVPPreflightRule {
|
|
1686
|
-
kind: 'permission' | 'dismiss_dialog' | 'wait_for_stable' | 'clear_data' | 'set_setting';
|
|
1687
|
-
[key: string]: unknown;
|
|
1688
|
-
}
|
|
1689
|
-
interface ESVPPreflightConfig {
|
|
1690
|
-
policy?: string;
|
|
1691
|
-
appId?: string;
|
|
1692
|
-
rules?: ESVPPreflightRule[];
|
|
1693
|
-
[key: string]: unknown;
|
|
1694
|
-
}
|
|
1695
1691
|
declare function runESVPPreflight(sessionId: string, config: ESVPPreflightConfig, serverUrl?: string): Promise<any>;
|
|
1696
1692
|
declare function inspectESVPSession(sessionId: string, input?: {
|
|
1697
1693
|
includeTranscript?: boolean;
|
package/dist/index.html
CHANGED
|
@@ -5602,6 +5602,12 @@
|
|
|
5602
5602
|
width: fit-content;
|
|
5603
5603
|
}
|
|
5604
5604
|
|
|
5605
|
+
.template-restriction-note {
|
|
5606
|
+
margin-bottom: 12px;
|
|
5607
|
+
font-size: 12px;
|
|
5608
|
+
color: var(--text-muted);
|
|
5609
|
+
}
|
|
5610
|
+
|
|
5605
5611
|
.template-pill {
|
|
5606
5612
|
position: relative;
|
|
5607
5613
|
display: inline-flex;
|
|
@@ -11616,6 +11622,7 @@
|
|
|
11616
11622
|
<span class="label">View:</span>
|
|
11617
11623
|
<button class="template-pill active" data-template="raw" onclick="switchTemplate('raw')">Raw</button>
|
|
11618
11624
|
</div>
|
|
11625
|
+
<div class="template-restriction-note" id="templateRestrictionNote" style="display:none;"></div>
|
|
11619
11626
|
|
|
11620
11627
|
<!-- Raw video (default) -->
|
|
11621
11628
|
<div class="video-player-container" id="rawVideoContainer">
|
|
@@ -11795,7 +11802,7 @@
|
|
|
11795
11802
|
let templateStatus = null;
|
|
11796
11803
|
let activeTemplate = 'raw';
|
|
11797
11804
|
let favoriteTemplate = null;
|
|
11798
|
-
let currentTemplateProps = null; //
|
|
11805
|
+
let currentTemplateProps = null; // per-project template props + eligibility + mockup options
|
|
11799
11806
|
|
|
11800
11807
|
// Space = play/pause active video
|
|
11801
11808
|
document.addEventListener('keydown', (e) => {
|
|
@@ -11814,6 +11821,7 @@
|
|
|
11814
11821
|
|
|
11815
11822
|
async function initTemplateUI() {
|
|
11816
11823
|
try {
|
|
11824
|
+
currentTemplateProps = null;
|
|
11817
11825
|
const [statusRes, prefRes] = await Promise.all([
|
|
11818
11826
|
fetch('/api/templates/status'),
|
|
11819
11827
|
fetch('/api/settings/template-preference'),
|
|
@@ -11827,37 +11835,93 @@
|
|
|
11827
11835
|
const bar = document.getElementById('templateToggleBar');
|
|
11828
11836
|
if (!bar) return;
|
|
11829
11837
|
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
+
await loadTemplateProps();
|
|
11839
|
+
renderTemplatePills();
|
|
11840
|
+
applyTemplateAvailabilityState();
|
|
11841
|
+
|
|
11842
|
+
if (favoriteTemplate && currentTemplateProps?.templatesAllowed !== false) {
|
|
11843
|
+
switchTemplate(favoriteTemplate);
|
|
11844
|
+
}
|
|
11845
|
+
} catch (e) {
|
|
11846
|
+
console.log('[Templates] Init error:', e);
|
|
11847
|
+
}
|
|
11848
|
+
}
|
|
11849
|
+
|
|
11850
|
+
function getTemplateIcons() {
|
|
11851
|
+
return {
|
|
11852
|
+
raw: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>',
|
|
11853
|
+
studio: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>',
|
|
11854
|
+
showcase: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>',
|
|
11855
|
+
};
|
|
11856
|
+
}
|
|
11857
|
+
|
|
11858
|
+
function renderTemplatePills() {
|
|
11859
|
+
const bar = document.getElementById('templateToggleBar');
|
|
11860
|
+
if (!bar || !templateStatus?.available) return;
|
|
11861
|
+
|
|
11862
|
+
const allowTemplates = currentTemplateProps?.templatesAllowed !== false;
|
|
11863
|
+
const templateIcons = getTemplateIcons();
|
|
11864
|
+
let pills = '';
|
|
11865
|
+
pills += `<span class="label">View:</span>`;
|
|
11866
|
+
pills += `<button class="template-pill ${activeTemplate === 'raw' ? 'active' : ''}" data-template="raw" title="Raw video" tabindex="-1" onclick="switchTemplate('raw')">${templateIcons.raw}</button>`;
|
|
11867
|
+
if (allowTemplates) {
|
|
11838
11868
|
for (const t of templateStatus.templates) {
|
|
11839
11869
|
const isFav = favoriteTemplate === t.id;
|
|
11840
11870
|
const icon = templateIcons[t.id] || templateIcons.studio;
|
|
11841
|
-
pills += `<button class="template-pill" data-template="${t.id}" title="${t.name}" tabindex="-1" onclick="switchTemplate('${t.id}')" ondblclick="event.stopPropagation(); toggleFavoriteTemplate('${t.id}')">
|
|
11871
|
+
pills += `<button class="template-pill ${activeTemplate === t.id ? 'active' : ''}" data-template="${t.id}" title="${escapeHtml(t.name)}" tabindex="-1" onclick="switchTemplate('${t.id}')" ondblclick="event.stopPropagation(); toggleFavoriteTemplate('${t.id}')">
|
|
11842
11872
|
${icon}
|
|
11843
11873
|
<span class="star-dot ${isFav ? 'visible' : ''}"></span>
|
|
11844
11874
|
</button>`;
|
|
11845
11875
|
}
|
|
11846
|
-
pills += `<button class="template-pill template-edit-btn" title="Edit template text" tabindex="-1" onclick="openTemplateEditModal()" style="display:none;">
|
|
11876
|
+
pills += `<button class="template-pill template-edit-btn" title="Edit template text" tabindex="-1" onclick="openTemplateEditModal()" style="${activeTemplate === 'raw' ? 'display:none;' : ''}">
|
|
11847
11877
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
|
|
11848
11878
|
</button>`;
|
|
11849
|
-
|
|
11850
|
-
|
|
11879
|
+
}
|
|
11880
|
+
bar.innerHTML = pills;
|
|
11881
|
+
bar.style.display = 'flex';
|
|
11882
|
+
updateTemplateRestrictionNote();
|
|
11883
|
+
}
|
|
11851
11884
|
|
|
11852
|
-
|
|
11853
|
-
|
|
11885
|
+
function updateTemplateRestrictionNote() {
|
|
11886
|
+
const note = document.getElementById('templateRestrictionNote');
|
|
11887
|
+
if (!note) return;
|
|
11888
|
+
const blocked = currentTemplateProps?.templatesAllowed === false;
|
|
11889
|
+
if (!blocked) {
|
|
11890
|
+
note.style.display = 'none';
|
|
11891
|
+
note.textContent = '';
|
|
11892
|
+
return;
|
|
11893
|
+
}
|
|
11894
|
+
note.textContent = currentTemplateProps?.templateRestrictionReason
|
|
11895
|
+
|| `Templates are limited to videos up to ${currentTemplateProps?.maxTemplateDurationSeconds || 60} seconds.`;
|
|
11896
|
+
note.style.display = '';
|
|
11897
|
+
}
|
|
11854
11898
|
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11899
|
+
function setRawTemplateView() {
|
|
11900
|
+
activeTemplate = 'raw';
|
|
11901
|
+
const rawContainer = document.getElementById('rawVideoContainer');
|
|
11902
|
+
const templateContainer = document.getElementById('templatePreviewContainer');
|
|
11903
|
+
const templateVideo = document.getElementById('templateVideo');
|
|
11904
|
+
const downloadBtn = document.getElementById('downloadWithTemplateBtn');
|
|
11905
|
+
const editBtn = document.querySelector('.template-edit-btn');
|
|
11906
|
+
const skeleton = document.getElementById('templateSkeleton');
|
|
11907
|
+
|
|
11908
|
+
if (rawContainer) rawContainer.style.display = '';
|
|
11909
|
+
if (templateContainer) templateContainer.style.display = 'none';
|
|
11910
|
+
if (templateVideo) templateVideo.removeAttribute('src');
|
|
11911
|
+
if (downloadBtn) downloadBtn.style.display = 'none';
|
|
11912
|
+
if (editBtn) editBtn.style.display = 'none';
|
|
11913
|
+
if (skeleton) skeleton.style.display = 'none';
|
|
11914
|
+
|
|
11915
|
+
document.querySelectorAll('.template-pill').forEach(pill => {
|
|
11916
|
+
if (pill.classList.contains('template-edit-btn')) return;
|
|
11917
|
+
pill.classList.toggle('active', pill.dataset.template === 'raw');
|
|
11918
|
+
});
|
|
11919
|
+
}
|
|
11920
|
+
|
|
11921
|
+
function applyTemplateAvailabilityState() {
|
|
11922
|
+
renderTemplatePills();
|
|
11923
|
+
if (currentTemplateProps?.templatesAllowed === false) {
|
|
11924
|
+
setRawTemplateView();
|
|
11861
11925
|
}
|
|
11862
11926
|
}
|
|
11863
11927
|
|
|
@@ -11876,8 +11940,20 @@
|
|
|
11876
11940
|
titleLines: data.props.titleLines || undefined,
|
|
11877
11941
|
terminalTabs: data.props.terminalTabs || [],
|
|
11878
11942
|
hasNetworkData: data.props.hasNetworkData || false,
|
|
11943
|
+
platform: data.props.platform || 'web',
|
|
11879
11944
|
showcaseMode: data.props.showcaseMode || undefined,
|
|
11945
|
+
deviceMockup: data.props.deviceMockup || undefined,
|
|
11946
|
+
availableDeviceMockups: data.androidDeviceMockups || [],
|
|
11947
|
+
templatesAllowed: data.eligibility?.templatesAllowed !== false,
|
|
11948
|
+
templateRestrictionReason: data.eligibility?.reason || '',
|
|
11949
|
+
actualDurationSeconds: data.eligibility?.actualDurationSeconds || data.props.videoDuration || 0,
|
|
11950
|
+
maxTemplateDurationSeconds: data.eligibility?.maxTemplateDurationSeconds || 60,
|
|
11880
11951
|
};
|
|
11952
|
+
applyTemplateAvailabilityState();
|
|
11953
|
+
} else {
|
|
11954
|
+
currentTemplateProps = null;
|
|
11955
|
+
renderTemplatePills();
|
|
11956
|
+
updateTemplateRestrictionNote();
|
|
11881
11957
|
}
|
|
11882
11958
|
} catch (e) {
|
|
11883
11959
|
console.log('[Templates] Props load error:', e);
|
|
@@ -11887,6 +11963,11 @@
|
|
|
11887
11963
|
async function switchTemplate(templateId) {
|
|
11888
11964
|
// Skip if already on this template
|
|
11889
11965
|
if (templateId === activeTemplate) return;
|
|
11966
|
+
if (templateId !== 'raw' && currentTemplateProps?.templatesAllowed === false) {
|
|
11967
|
+
showToast(currentTemplateProps.templateRestrictionReason || 'Templates are disabled for long recordings', 'info');
|
|
11968
|
+
setRawTemplateView();
|
|
11969
|
+
return;
|
|
11970
|
+
}
|
|
11890
11971
|
activeTemplate = templateId;
|
|
11891
11972
|
const rawContainer = document.getElementById('rawVideoContainer');
|
|
11892
11973
|
const templateContainer = document.getElementById('templatePreviewContainer');
|
|
@@ -11900,10 +11981,7 @@
|
|
|
11900
11981
|
});
|
|
11901
11982
|
|
|
11902
11983
|
if (templateId === 'raw') {
|
|
11903
|
-
|
|
11904
|
-
if (templateContainer) templateContainer.style.display = 'none';
|
|
11905
|
-
if (downloadBtn) downloadBtn.style.display = 'none';
|
|
11906
|
-
if (editBtn) editBtn.style.display = 'none';
|
|
11984
|
+
setRawTemplateView();
|
|
11907
11985
|
return;
|
|
11908
11986
|
}
|
|
11909
11987
|
|
|
@@ -12008,6 +12086,10 @@
|
|
|
12008
12086
|
showToast('No template data loaded', 'info');
|
|
12009
12087
|
return;
|
|
12010
12088
|
}
|
|
12089
|
+
if (currentTemplateProps.templatesAllowed === false) {
|
|
12090
|
+
showToast(currentTemplateProps.templateRestrictionReason || 'Templates are disabled for this recording', 'info');
|
|
12091
|
+
return;
|
|
12092
|
+
}
|
|
12011
12093
|
const existing = document.getElementById('templateEditModal');
|
|
12012
12094
|
if (existing) existing.remove();
|
|
12013
12095
|
|
|
@@ -12027,7 +12109,9 @@
|
|
|
12027
12109
|
#templateEditModal .te-field-full { grid-column: 1 / -1; }
|
|
12028
12110
|
#templateEditModal .te-field label { display: block; font-size: 11px; font-weight: 500; color: var(--text-secondary); margin-bottom: 3px; }
|
|
12029
12111
|
#templateEditModal .te-field input[type="text"] { width: 100%; padding: 7px 10px; background: var(--bg-primary); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 12px; box-sizing: border-box; }
|
|
12112
|
+
#templateEditModal .te-field select { width: 100%; padding: 7px 10px; background: var(--bg-primary); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 12px; box-sizing: border-box; }
|
|
12030
12113
|
#templateEditModal .te-field input:focus { outline: none; border-color: var(--accent); }
|
|
12114
|
+
#templateEditModal .te-field select:focus { outline: none; border-color: var(--accent); }
|
|
12031
12115
|
#templateEditModal .te-btn-row { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }
|
|
12032
12116
|
#templateEditModal .te-tab-row { border: 1px solid var(--border); border-radius: 6px; margin-bottom: 6px; overflow: hidden; }
|
|
12033
12117
|
#templateEditModal .te-tab-header { display: flex; align-items: center; gap: 6px; padding: 6px 8px; cursor: pointer; background: var(--bg-elevated); }
|
|
@@ -12118,7 +12202,7 @@
|
|
|
12118
12202
|
lines.push(words.slice(i, i + 2).join(' '));
|
|
12119
12203
|
}
|
|
12120
12204
|
}
|
|
12121
|
-
fieldsArea.innerHTML = lines.map((line, i) => `
|
|
12205
|
+
fieldsArea.innerHTML = buildAndroidMockupFieldHtml(props) + lines.map((line, i) => `
|
|
12122
12206
|
<div class="te-field te-field-full">
|
|
12123
12207
|
<label>Line ${i + 1} <span style="opacity:0.5">(${fontLabels[i % fontLabels.length]})</span></label>
|
|
12124
12208
|
<input type="text" class="te-title-line" data-index="${i}" value="${(line || '').replace(/"/g, '"')}" autocomplete="off">
|
|
@@ -12131,6 +12215,22 @@
|
|
|
12131
12215
|
}
|
|
12132
12216
|
}
|
|
12133
12217
|
|
|
12218
|
+
function buildAndroidMockupFieldHtml(props) {
|
|
12219
|
+
if (props.platform !== 'android' || !Array.isArray(props.availableDeviceMockups) || props.availableDeviceMockups.length === 0) {
|
|
12220
|
+
return '';
|
|
12221
|
+
}
|
|
12222
|
+
const selected = props.deviceMockup || props.availableDeviceMockups[0]?.id || '';
|
|
12223
|
+
const options = props.availableDeviceMockups.map((option) => `
|
|
12224
|
+
<option value="${escapeHtml(option.id)}" ${option.id === selected ? 'selected' : ''}>${escapeHtml(option.label || option.id)}</option>
|
|
12225
|
+
`).join('');
|
|
12226
|
+
return `
|
|
12227
|
+
<div class="te-field te-field-full">
|
|
12228
|
+
<label>Android Mockup</label>
|
|
12229
|
+
<select id="teDeviceMockup">${options}</select>
|
|
12230
|
+
</div>
|
|
12231
|
+
`;
|
|
12232
|
+
}
|
|
12233
|
+
|
|
12134
12234
|
function buildTerminalEditorHtml(props, existingTabs) {
|
|
12135
12235
|
const tabRows = existingTabs.map((tab, i) => `
|
|
12136
12236
|
<div class="te-tab-row">
|
|
@@ -12149,6 +12249,7 @@
|
|
|
12149
12249
|
`).join('');
|
|
12150
12250
|
|
|
12151
12251
|
return `
|
|
12252
|
+
${buildAndroidMockupFieldHtml(props)}
|
|
12152
12253
|
<div class="te-field te-field-full">
|
|
12153
12254
|
<label>Title</label>
|
|
12154
12255
|
<input type="text" id="teTitle" value="${(props.title || '').replace(/"/g, '"')}" autocomplete="off">
|
|
@@ -12304,6 +12405,7 @@
|
|
|
12304
12405
|
let title = '';
|
|
12305
12406
|
let titleLines = undefined;
|
|
12306
12407
|
let showcaseMode = undefined;
|
|
12408
|
+
let deviceMockup = currentTemplateProps?.deviceMockup;
|
|
12307
12409
|
|
|
12308
12410
|
// Determine showcase mode from toggle
|
|
12309
12411
|
if (isShowcase) {
|
|
@@ -12322,6 +12424,11 @@
|
|
|
12322
12424
|
title = titleInput ? titleInput.value : (currentTemplateProps?.title || '');
|
|
12323
12425
|
}
|
|
12324
12426
|
|
|
12427
|
+
const deviceMockupSelect = modal.querySelector('#teDeviceMockup');
|
|
12428
|
+
if (deviceMockupSelect) {
|
|
12429
|
+
deviceMockup = deviceMockupSelect.value;
|
|
12430
|
+
}
|
|
12431
|
+
|
|
12325
12432
|
// Collect terminal tabs
|
|
12326
12433
|
const tabRows = modal.querySelectorAll('.te-tab-row');
|
|
12327
12434
|
const terminalTabs = Array.from(tabRows).map(row => {
|
|
@@ -12336,16 +12443,29 @@
|
|
|
12336
12443
|
});
|
|
12337
12444
|
|
|
12338
12445
|
try {
|
|
12339
|
-
await fetch(`/api/projects/${currentProject.id}/template-content`, {
|
|
12446
|
+
const res = await fetch(`/api/projects/${currentProject.id}/template-content`, {
|
|
12340
12447
|
method: 'PUT',
|
|
12341
12448
|
headers: { 'Content-Type': 'application/json' },
|
|
12342
|
-
body: JSON.stringify({ title, titleLines, terminalTabs, showcaseMode }),
|
|
12449
|
+
body: JSON.stringify({ title, titleLines, terminalTabs, showcaseMode, deviceMockup }),
|
|
12343
12450
|
});
|
|
12451
|
+
const data = await res.json();
|
|
12452
|
+
if (data.error) {
|
|
12453
|
+
showToast(data.error, 'error');
|
|
12454
|
+
return;
|
|
12455
|
+
}
|
|
12344
12456
|
showToast('Template content saved', 'success');
|
|
12345
12457
|
modal.remove();
|
|
12346
12458
|
|
|
12347
12459
|
// Update local props
|
|
12348
|
-
currentTemplateProps = {
|
|
12460
|
+
currentTemplateProps = {
|
|
12461
|
+
...currentTemplateProps,
|
|
12462
|
+
title: data.content?.title || title,
|
|
12463
|
+
titleLines: data.content?.titleLines || titleLines,
|
|
12464
|
+
terminalTabs,
|
|
12465
|
+
hasNetworkData: terminalTabs.length > 0,
|
|
12466
|
+
showcaseMode: data.content?.showcaseMode || showcaseMode,
|
|
12467
|
+
deviceMockup: data.content?.deviceMockup || deviceMockup,
|
|
12468
|
+
};
|
|
12349
12469
|
|
|
12350
12470
|
// Force re-render
|
|
12351
12471
|
if (activeTemplate !== 'raw') {
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
startServer,
|
|
4
4
|
stopServer
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LXSWDEXV.js";
|
|
6
6
|
import {
|
|
7
7
|
analyzeTools,
|
|
8
8
|
canvasTools,
|
|
@@ -15,17 +15,16 @@ import {
|
|
|
15
15
|
templateTools,
|
|
16
16
|
testingTools,
|
|
17
17
|
uiTools
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-AHVBE25Y.js";
|
|
19
19
|
import {
|
|
20
20
|
setupTools
|
|
21
21
|
} from "./chunk-FNUN7EPB.js";
|
|
22
22
|
import {
|
|
23
23
|
mcpServer
|
|
24
24
|
} from "./chunk-XKX6NBHF.js";
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import "./chunk-6EGBXRDK.js";
|
|
25
|
+
import "./chunk-HGWEHWKJ.js";
|
|
27
26
|
import "./chunk-FIL7IWEL.js";
|
|
28
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-ZLHIHMSL.js";
|
|
29
28
|
import "./chunk-LB3RNE3O.js";
|
|
30
29
|
import {
|
|
31
30
|
attachESVPNetworkTrace,
|
|
@@ -51,7 +50,8 @@ import {
|
|
|
51
50
|
runESVPActions,
|
|
52
51
|
runESVPPreflight,
|
|
53
52
|
validateESVPReplay
|
|
54
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-7EDIUVIO.js";
|
|
54
|
+
import "./chunk-6EGBXRDK.js";
|
|
55
55
|
import "./chunk-SLNJEF32.js";
|
|
56
56
|
import {
|
|
57
57
|
closeDatabase,
|